diff --git a/Cargo.lock b/Cargo.lock index 7e0a55b538..7d9ba67108 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3920,6 +3920,14 @@ dependencies = [ "zbus", ] +[[package]] +name = "rio-unicode" +version = "0.1.0" +dependencies = [ + "unicode-segmentation", + "unicode-width-16", +] + [[package]] name = "rio-vt" version = "0.5.20" @@ -3940,6 +3948,7 @@ dependencies = [ "regex-automata", "rio-grapheme-width", "rio-graphics", + "rio-unicode", "rio-window", "rustc-hash 2.1.3", "serde", @@ -3948,7 +3957,6 @@ dependencies = [ "sugarloaf", "teletypewriter", "tracing", - "unicode-width-16", "web-time", "windows-sys 0.61.2", ] @@ -4035,6 +4043,7 @@ dependencies = [ "regex", "rio-backend", "rio-notifier", + "rio-unicode", "rio-window", "rustc-hash 2.1.3", "serde", @@ -4045,7 +4054,6 @@ dependencies = [ "tinyvec", "tracing", "tracing-subscriber", - "unicode-width-16", "url", "wgpu", "windows-sys 0.60.2", @@ -4588,6 +4596,7 @@ dependencies = [ "rayon", "rio-fonts", "rio-graphics", + "rio-unicode", "rio-window", "rustc-hash 2.1.3", "serde", @@ -4600,7 +4609,6 @@ dependencies = [ "tracing", "ttf-parser", "twox-hash", - "unicode-width-16", "walkdir", "wasm-bindgen", "wasm-bindgen-futures", diff --git a/Cargo.toml b/Cargo.toml index 50dd01b2ad..1f0bb61d67 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ members = [ "rio-vt", "rio-backend", "rio-grapheme-width", + "rio-unicode", "rio-window", "rio-notifier", "frontends/rioterm", @@ -51,8 +52,10 @@ parking_lot = { version = "0.12.5", features = [ rustc-hash = "2.1.3" smallvec = { version = "1.15.2", default-features = false } -# unicode-width = "0.2.0" -unicode-width = { package = "unicode-width-16", version = "0.1.0" } +# One Unicode version for the whole tree: width tables and grapheme +# segmentation both come from rio-unicode (currently Unicode 17), +# replacing the alacritty unicode-width fork that froze at Unicode 16. +unicode-width = { package = "rio-unicode", path = "rio-unicode" } simdutf = "0.7.0" base64 = "0.23.0" image_rs = { package = "image", version = "0.25.10", default-features = false, features = [ diff --git a/rio-unicode/.gitignore b/rio-unicode/.gitignore new file mode 100644 index 0000000000..2211df63dd --- /dev/null +++ b/rio-unicode/.gitignore @@ -0,0 +1 @@ +*.txt diff --git a/rio-unicode/Cargo.toml b/rio-unicode/Cargo.toml new file mode 100644 index 0000000000..b3849701cb --- /dev/null +++ b/rio-unicode/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "rio-unicode" +version = "0.1.0" +edition = "2021" +description = """ +Unicode tables for rio, on a single Unicode version: character width +(vendored from unicode-width 0.1.14, tables regenerated for Unicode 17) +and grapheme cluster breaks (UAX #29 state machine). One crate so the +grid's widths and the renderer's segmentation can never disagree on +what Unicode says. +""" +license = "MIT OR Apache-2.0" +repository = "https://github.com/raphamorim/rio" + +[features] +default = ["cjk"] +cjk = [] +# Vendored from unicode-width; enables nightly benches upstream. +bench = [] + +[dev-dependencies] +unicode-segmentation = "1.13" +unicode-width-16 = "0.1.0" diff --git a/rio-unicode/scripts/.gitignore b/rio-unicode/scripts/.gitignore new file mode 100644 index 0000000000..586390d4b0 --- /dev/null +++ b/rio-unicode/scripts/.gitignore @@ -0,0 +1,2 @@ +*.txt +tables.rs diff --git a/rio-unicode/scripts/grapheme.py b/rio-unicode/scripts/grapheme.py new file mode 100644 index 0000000000..a1cc18180d --- /dev/null +++ b/rio-unicode/scripts/grapheme.py @@ -0,0 +1,175 @@ +#!/usr/bin/env python3 +"""Generate rio-unicode's grapheme-cluster-break tables. + +Reads (from the working directory, as fetched by unicode.py's runs): + - GraphemeBreakProperty.txt (UAX #29 GCB classes) + - emoji-data.txt (Extended_Pictographic) + - DerivedCoreProperties.txt (InCB=Consonant/Linker/Extend, for GB9c) + - GraphemeBreakTest.txt (conformance vectors) + +Emits: + - ../src/grapheme_tables.rs (class ranges + Unicode version) + - ../tests/grapheme_conformance.rs (every UCD test vector) + +Each codepoint gets exactly one class; InCB values refine the GCB +Extend/ZWJ/Other classes so the GB9c state machine can run on classes +alone. +""" +import re +from collections import defaultdict + +def parse_props(path, wanted_prop=None): + """Yield (lo, hi, value) from a UCD file.""" + out = [] + with open(path, encoding="utf-8") as f: + for line in f: + line = line.split("#", 1)[0].strip() + if not line: + continue + fields = [x.strip() for x in line.split(";")] + cps, value = fields[0], fields[1] + if wanted_prop is not None: + if value != wanted_prop: + continue + value = fields[2] if len(fields) > 2 else value + if ".." in cps: + lo, hi = (int(x, 16) for x in cps.split("..")) + else: + lo = hi = int(cps, 16) + out.append((lo, hi, value)) + return out + +gcb = {} +for lo, hi, v in parse_props("GraphemeBreakProperty.txt"): + for cp in range(lo, hi + 1): + gcb[cp] = v + +extpic = set() +for lo, hi, v in parse_props("emoji-data.txt"): + if v == "Extended_Pictographic": + extpic.update(range(lo, hi + 1)) + +incb = {} +with open("DerivedCoreProperties.txt", encoding="utf-8") as f: + for line in f: + line = line.split("#", 1)[0].strip() + if not line or "; InCB;" not in line: + continue + cps, _, value = [x.strip() for x in line.split(";")] + if ".." in cps: + lo, hi = (int(x, 16) for x in cps.split("..")) + else: + lo = hi = int(cps, 16) + for cp in range(lo, hi + 1): + incb[cp] = value + +CLASSES = ["Other", "CR", "LF", "Control", "Extend", "ExtendIncb", "Linker", + "Zwj", "RegionalIndicator", "Prepend", "SpacingMark", + "L", "V", "T", "LV", "LVT", "ExtPic", "Consonant"] + +def classify(cp): + g = gcb.get(cp, "Other") + ic = incb.get(cp) + if g == "CR": return "CR" + if g == "LF": return "LF" + if g == "Control": return "Control" + if g == "ZWJ": return "Zwj" + if g == "Extend": + if ic == "Linker": return "Linker" + if ic == "Extend": return "ExtendIncb" + return "Extend" + if g == "Regional_Indicator": return "RegionalIndicator" + if g == "Prepend": return "Prepend" + if g == "SpacingMark": return "SpacingMark" + if g in ("L", "V", "T", "LV", "LVT"): return g + # g == Other: + if cp in extpic: return "ExtPic" + if ic == "Consonant": return "Consonant" + return "Other" + +# Build merged ranges over all assigned-relevant codepoints. +ranges = [] +prev_class = None +start = None +for cp in range(0x110000): + c = classify(cp) + if c != prev_class: + if prev_class is not None and prev_class != "Other": + ranges.append((start, cp - 1, prev_class)) + prev_class = c + start = cp +if prev_class is not None and prev_class != "Other": + ranges.append((start, 0x10FFFF, prev_class)) + +version = "17.0.0" +with open("GraphemeBreakProperty.txt", encoding="utf-8") as f: + m = re.search(r"-(\d+\.\d+\.\d+)\.txt", f.readline()) + if m: + version = m.group(1) + +with open("../src/grapheme_tables.rs", "w", encoding="utf-8") as out: + out.write("// Generated by scripts/grapheme.py — do not edit.\n") + out.write(f"// Unicode {version}: GraphemeBreakProperty + Extended_Pictographic + InCB.\n\n") + out.write("use super::grapheme::GraphemeClass;\n\n") + v = version.split(".") + out.write("/// The Unicode version of the grapheme-break data; always equal\n") + out.write("/// to the width tables' [`UNICODE_VERSION`](crate::UNICODE_VERSION).\n") + out.write(f"pub const GRAPHEME_UNICODE_VERSION: (u8, u8, u8) = ({v[0]}, {v[1]}, {v[2]});\n\n") + out.write("/// Sorted, non-overlapping ranges; codepoints not listed are\n") + out.write("/// `GraphemeClass::Other`.\n") + out.write("pub(crate) static GRAPHEME_CLASS_RANGES: &[(u32, u32, GraphemeClass)] = &[\n") + for lo, hi, c in ranges: + out.write(f" (0x{lo:X}, 0x{hi:X}, GraphemeClass::{c}),\n") + out.write("];\n") +print(f"grapheme_tables.rs: {len(ranges)} ranges (Unicode {version})") + +# Conformance vectors. +tests = [] +with open("GraphemeBreakTest.txt", encoding="utf-8") as f: + for line in f: + line = line.split("#", 1)[0].strip() + if not line: + continue + # Format: ÷ 0020 × 0308 ÷ 0020 ÷ + parts = line.split() + chars = [] + breaks = [] # break BEFORE char i (excluding sot), plus eot ignored + expect = [] # byte offsets where clusters start + s = "" + for tok in parts[1:-1]: # drop leading ÷ and trailing ÷/× + if tok == "÷": + breaks.append(True) + elif tok == "×": + breaks.append(False) + else: + chars.append(int(tok, 16)) + # Reconstruct cluster strings. + clusters = [] + cur = "" + for i, cp in enumerate(chars): + ch = chr(cp) + if i > 0 and breaks[i - 1]: + clusters.append(cur) + cur = "" + cur += ch + clusters.append(cur) + tests.append((chars, clusters)) + +def rs_str(s): + return '"' + "".join(f"\\u{{{ord(ch):X}}}" for ch in s) + '"' + +with open("../tests/grapheme_conformance.rs", "w", encoding="utf-8") as out: + out.write("// Generated by scripts/grapheme.py from GraphemeBreakTest.txt — do not edit.\n") + out.write(f"// Unicode {version}: every UCD conformance vector.\n\n") + out.write("use rio_unicode::grapheme::Graphemes;\n\n") + out.write("#[test]\nfn ucd_grapheme_break_test() {\n") + out.write(" let cases: &[(&str, &[&str])] = &[\n") + for chars, clusters in tests: + full = "".join(chr(c) for c in chars) + out.write(f" ({rs_str(full)}, &[{', '.join(rs_str(c) for c in clusters)}]),\n") + out.write(" ];\n") + out.write(" for (i, (input, expected)) in cases.iter().enumerate() {\n") + out.write(" let got: Vec<&str> = Graphemes::new(input).collect();\n") + out.write(" assert_eq!(&got[..], *expected, \"case {i}: {input:?}\");\n") + out.write(" }\n}\n") +print(f"grapheme_conformance.rs: {len(tests)} vectors") diff --git a/rio-unicode/scripts/unicode.py b/rio-unicode/scripts/unicode.py new file mode 100644 index 0000000000..a6d58c5ef3 --- /dev/null +++ b/rio-unicode/scripts/unicode.py @@ -0,0 +1,505 @@ +#!/usr/bin/env python3 +# +# Copyright 2011-2022 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +# This script uses the following Unicode tables: +# - EastAsianWidth.txt +# - ReadMe.txt +# - UnicodeData.txt +# +# Since this should not require frequent updates, we just store this +# out-of-line and check the generated module into git. + +import enum +import math +import os +import re +import sys + +NUM_CODEPOINTS = 0x110000 +"""An upper bound for which `range(0, NUM_CODEPOINTS)` contains Unicode's codespace.""" + +MAX_CODEPOINT_BITS = math.ceil(math.log2(NUM_CODEPOINTS - 1)) +"""The maximum number of bits required to represent a Unicode codepoint.""" + + +class OffsetType(enum.IntEnum): + """Represents the data type of a lookup table's offsets. Each variant's value represents the + number of bits required to represent that variant's type.""" + + U2 = 2 + """Offsets are 2-bit unsigned integers, packed four-per-byte.""" + U4 = 4 + """Offsets are 4-bit unsigned integers, packed two-per-byte.""" + U8 = 8 + """Each offset is a single byte (u8).""" + + +TABLE_CFGS = [ + (13, MAX_CODEPOINT_BITS, OffsetType.U8), + (6, 13, OffsetType.U8), + (0, 6, OffsetType.U2), +] +"""Represents the format of each level of the multi-level lookup table. +A level's entry is of the form `(low_bit, cap_bit, offset_type)`. +This means that every sub-table in that level is indexed by bits `low_bit..cap_bit` of the +codepoint and those tables offsets are stored according to `offset_type`. + +If this is edited, you must ensure that `emit_module` reflects your changes.""" + +MODULE_FILENAME = "tables.rs" +"""The filename of the emitted Rust module (will be created in the working directory)""" + +Codepoint = int +BitPos = int + + +def fetch_open(filename: str): + """Opens `filename` and return its corresponding file object. If `filename` isn't on disk, + fetches it from `http://www.unicode.org/Public/UNIDATA/`. Exits with code 1 on failure.""" + if not os.path.exists(os.path.basename(filename)): + os.system(f"curl -O http://www.unicode.org/Public/UNIDATA/{filename}") + try: + return open(filename, encoding="utf-8") + except OSError: + sys.stderr.write(f"cannot load {filename}") + sys.exit(1) + + +def load_unicode_version() -> "tuple[int, int, int]": + """Returns the current Unicode version by fetching and processing `ReadMe.txt`.""" + with fetch_open("ReadMe.txt") as readme: + pattern = r"for Version (\d+)\.(\d+)\.(\d+) of the Unicode" + return tuple(map(int, re.search(pattern, readme.read()).groups())) + + +class EffectiveWidth(enum.IntEnum): + """Represents the width of a Unicode character. All East Asian Width classes resolve into + either `EffectiveWidth.NARROW`, `EffectiveWidth.WIDE`, or `EffectiveWidth.AMBIGUOUS`.""" + + ZERO = 0 + """ Zero columns wide. """ + NARROW = 1 + """ One column wide. """ + WIDE = 2 + """ Two columns wide. """ + AMBIGUOUS = 3 + """ Two columns wide in a CJK context. One column wide in all other contexts. """ + + +def load_east_asian_widths() -> "list[EffectiveWidth]": + """Return a list of effective widths, indexed by codepoint. + Widths are determined by fetching and parsing `EastAsianWidth.txt`. + + `Neutral`, `Narrow`, and `Halfwidth` characters are assigned `EffectiveWidth.NARROW`. + + `Wide` and `Fullwidth` characters are assigned `EffectiveWidth.WIDE`. + + `Ambiguous` chracters are assigned `EffectiveWidth.AMBIGUOUS`.""" + with fetch_open("EastAsianWidth.txt") as eaw: + # matches a width assignment for a single codepoint, i.e. "1F336;N # ..." + single = re.compile(r"^([0-9A-F]+)\s+;\s+(\w+) +# (\w+)") + # matches a width assignment for a range of codepoints, i.e. "3001..3003;W # ..." + multiple = re.compile(r"^([0-9A-F]+)\.\.([0-9A-F]+)\s+;\s+(\w+) +# (\w+)") + # map between width category code and condensed width + width_codes = { + **{c: EffectiveWidth.NARROW for c in ["N", "Na", "H"]}, + **{c: EffectiveWidth.WIDE for c in ["W", "F"]}, + "A": EffectiveWidth.AMBIGUOUS, + } + + width_map = [] + current = 0 + for line in eaw.readlines(): + raw_data = None # (low, high, width) + if match := single.match(line): + raw_data = (match.group(1), match.group(1), match.group(2)) + elif match := multiple.match(line): + raw_data = (match.group(1), match.group(2), match.group(3)) + else: + continue + low = int(raw_data[0], 16) + high = int(raw_data[1], 16) + width = width_codes[raw_data[2]] + + assert current <= high + while current <= high: + # Some codepoints don't fall into any of the ranges in EastAsianWidth.txt. + # All such codepoints are implicitly given Neural width (resolves to narrow) + width_map.append(EffectiveWidth.NARROW if current < low else width) + current += 1 + + while len(width_map) < NUM_CODEPOINTS: + # Catch any leftover codepoints and assign them implicit Neutral/narrow width. + width_map.append(EffectiveWidth.NARROW) + + return width_map + + +def load_zero_widths() -> "list[bool]": + """Returns a list `l` where `l[c]` is true if codepoint `c` is considered a zero-width + character. `c` is considered a zero-width character if `c` is in general categories + `Cc`, `Cf`, `Mn`, or `Me` (determined by fetching and processing `UnicodeData.txt`).""" + with fetch_open("UnicodeData.txt") as categories: + zw_map = [] + current = 0 + for line in categories.readlines(): + if len(raw_data := line.split(";")) != 15: + continue + [codepoint, name, cat_code] = [ + int(raw_data[0], 16), + raw_data[1], + raw_data[2], + ] + zero_width = cat_code in ["Cc", "Cf", "Mn", "Me"] + + assert current <= codepoint + while current <= codepoint: + if name.endswith(", Last>") or current == codepoint: + # if name ends with Last, we backfill the width value to all codepoints since + # the previous codepoint (aka the start of the range) + zw_map.append(zero_width) + else: + # unassigned characters are implicitly given Neutral width, which is nonzero + zw_map.append(False) + current += 1 + + while len(zw_map) < NUM_CODEPOINTS: + # Catch any leftover codepoints. They must be unassigned (so nonzero width) + zw_map.append(False) + + return zw_map + + +class Bucket: + """A bucket contains a group of codepoints and an ordered width list. If one bucket's width + list overlaps with another's width list, those buckets can be merged via `try_extend`.""" + + def __init__(self): + """Creates an empty bucket.""" + self.entry_set = set() + self.widths = [] + + def append(self, codepoint: Codepoint, width: EffectiveWidth): + """Adds a codepoint/width pair to the bucket, and appends `width` to the width list.""" + self.entry_set.add((codepoint, width)) + self.widths.append(width) + + def try_extend(self, attempt: "Bucket") -> bool: + """If either `self` or `attempt`'s width list starts with the other bucket's width list, + set `self`'s width list to the longer of the two, add all of `attempt`'s codepoints + into `self`, and return `True`. Otherwise, return `False`.""" + (less, more) = (self.widths, attempt.widths) + if len(self.widths) > len(attempt.widths): + (less, more) = (attempt.widths, self.widths) + if less != more[: len(less)]: + return False + self.entry_set |= attempt.entry_set + self.widths = more + return True + + def entries(self) -> "list[tuple[Codepoint, EffectiveWidth]]": + """Return a list of the codepoint/width pairs in this bucket, sorted by codepoint.""" + result = list(self.entry_set) + result.sort() + return result + + def width(self) -> "EffectiveWidth": + """If all codepoints in this bucket have the same width, return that width; otherwise, + return `None`.""" + if len(self.widths) == 0: + return None + potential_width = self.widths[0] + for width in self.widths[1:]: + if potential_width != width: + return None + return potential_width + + +def make_buckets(entries, low_bit: BitPos, cap_bit: BitPos) -> "list[Bucket]": + """Partitions the `(Codepoint, EffectiveWidth)` tuples in `entries` into `Bucket`s. All + codepoints with identical bits from `low_bit` to `cap_bit` (exclusive) are placed in the + same bucket. Returns a list of the buckets in increasing order of those bits.""" + num_bits = cap_bit - low_bit + assert num_bits > 0 + buckets = [Bucket() for _ in range(0, 2 ** num_bits)] + mask = (1 << num_bits) - 1 + for (codepoint, width) in entries: + buckets[(codepoint >> low_bit) & mask].append(codepoint, width) + return buckets + + +class Table: + """Represents a lookup table. Each table contains a certain number of subtables; each + subtable is indexed by a contiguous bit range of the codepoint and contains a list + of `2**(number of bits in bit range)` entries. (The bit range is the same for all subtables.) + + Typically, tables contain a list of buckets of codepoints. Bucket `i`'s codepoints should + be indexed by sub-table `i` in the next-level lookup table. The entries of this table are + indexes into the bucket list (~= indexes into the sub-tables of the next-level table.) The + key to compression is that two different buckets in two different sub-tables may have the + same width list, which means that they can be merged into the same bucket. + + If no bucket contains two codepoints with different widths, calling `indices_to_widths` will + discard the buckets and convert the entries into `EffectiveWidth` values.""" + + def __init__( + self, entry_groups, low_bit: BitPos, cap_bit: BitPos, offset_type: OffsetType + ): + """Create a lookup table with a sub-table for each `(Codepoint, EffectiveWidth)` iterator + in `entry_groups`. Each sub-table is indexed by codepoint bits in `low_bit..cap_bit`, + and each table entry is represented in the format specified by `offset_type`. Asserts + that this table is actually representable with `offset_type`.""" + self.low_bit = low_bit + self.cap_bit = cap_bit + self.offset_type = offset_type + self.entries = [] + self.indexed = [] + + buckets = [] + for entries in entry_groups: + buckets.extend(make_buckets(entries, self.low_bit, self.cap_bit)) + + for bucket in buckets: + for (i, existing) in enumerate(self.indexed): + if existing.try_extend(bucket): + self.entries.append(i) + break + else: + self.entries.append(len(self.indexed)) + self.indexed.append(bucket) + + # Validate offset type + for index in self.entries: + assert index < (1 << int(self.offset_type)) + + def indices_to_widths(self): + """Destructively converts the indices in this table to the `EffectiveWidth` values of + their buckets. Assumes that no bucket contains codepoints with different widths.""" + self.entries = list(map(lambda i: int(self.indexed[i].width()), self.entries)) + del self.indexed + + def buckets(self): + """Returns an iterator over this table's buckets.""" + return self.indexed + + def to_bytes(self) -> "list[int]": + """Returns this table's entries as a list of bytes. The bytes are formatted according to + the `OffsetType` which the table was created with, converting any `EffectiveWidth` entries + to their enum variant's integer value. For example, with `OffsetType.U2`, each byte will + contain four packed 2-bit entries.""" + entries_per_byte = 8 // int(self.offset_type) + byte_array = [] + for i in range(0, len(self.entries), entries_per_byte): + byte = 0 + for j in range(0, entries_per_byte): + byte |= self.entries[i + j] << (j * int(self.offset_type)) + byte_array.append(byte) + return byte_array + + +def make_tables( + table_cfgs: "list[tuple[BitPos, BitPos, OffsetType]]", entries +) -> "list[Table]": + """Creates a table for each configuration in `table_cfgs`, with the first config corresponding + to the top-level lookup table, the second config corresponding to the second-level lookup + table, and so forth. `entries` is an iterator over the `(Codepoint, EffectiveWidth)` pairs + to include in the top-level table.""" + tables = [] + entry_groups = [entries] + for (low_bit, cap_bit, offset_type) in table_cfgs: + table = Table(entry_groups, low_bit, cap_bit, offset_type) + entry_groups = map(lambda bucket: bucket.entries(), table.buckets()) + tables.append(table) + return tables + + +def emit_module( + out_name: str, unicode_version: "tuple[int, int, int]", tables: "list[Table]" +): + """Outputs a Rust module to `out_name` using table data from `tables`. + If `TABLE_CFGS` is edited, you may need to edit the included code for `lookup_width`.""" + if os.path.exists(out_name): + os.remove(out_name) + with open(out_name, "w", newline="\n", encoding="utf-8") as module: + module.write( + """// Copyright 2012-2022 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// NOTE: The following code was generated by "scripts/unicode.py", do not edit directly +""" + ) + module.write( + f""" +/// The version of [Unicode](http://www.unicode.org/) +/// that this version of unicode-width is based on. +pub const UNICODE_VERSION: (u8, u8, u8) = {unicode_version}; +""" + ) + + module.write( + """ +pub mod charwidth { + use core::option::Option::{self, None, Some}; + + /// Returns the [UAX #11](https://www.unicode.org/reports/tr11/) based width of `c` by + /// consulting a multi-level lookup table. + /// If `is_cjk == true`, ambiguous width characters are treated as double width; otherwise, + /// they're treated as single width. + /// + /// # Maintenance + /// The tables themselves are autogenerated but this function is hardcoded. You should have + /// nothing to worry about if you re-run `unicode.py` (for example, when updating Unicode.) + /// However, if you change the *actual structure* of the lookup tables (perhaps by editing the + /// `TABLE_CFGS` global in `unicode.py`) you must ensure that this code reflects those changes. + #[inline] + fn lookup_width(c: char, is_cjk: bool) -> usize { + let cp = c as usize; + + let t1_offset = TABLES_0[cp >> 13 & 0xFF]; + + // Each sub-table in TABLES_1 is 7 bits, and each stored entry is a byte, + // so each sub-table is 128 bytes in size. + // (Sub-tables are selected using the computed offset from the previous table.) + let t2_offset = TABLES_1[128 * usize::from(t1_offset) + (cp >> 6 & 0x7F)]; + + // Each sub-table in TABLES_2 is 6 bits, but each stored entry is 2 bits. + // This is accomplished by packing four stored entries into one byte. + // So each sub-table is 2**(6-2) == 16 bytes in size. + // Since this is the last table, each entry represents an encoded width. + let packed_widths = TABLES_2[16 * usize::from(t2_offset) + (cp >> 2 & 0xF)]; + + // Extract the packed width + let width = packed_widths >> (2 * (cp & 0b11)) & 0b11; + + // A width of 3 signifies that the codepoint is ambiguous width. + if width == 3 { + if is_cjk { + 2 + } else { + 1 + } + } else { + width.into() + } + } +""" + ) + + module.write( + """ + /// Returns the [UAX #11](https://www.unicode.org/reports/tr11/) based width of `c`, or + /// `None` if `c` is a control character other than `'\\x00'`. + /// If `is_cjk == true`, ambiguous width characters are treated as double width; otherwise, + /// they're treated as single width. + #[inline] + pub fn width(c: char, is_cjk: bool) -> Option { + if c < '\\u{7F}' { + if c >= '\\u{20}' { + // U+0020 to U+007F (exclusive) are single-width ASCII codepoints + Some(1) + } else if c == '\\0' { + // U+0000 *is* a control code, but it's special-cased + Some(0) + } else { + // U+0001 to U+0020 (exclusive) are control codes + None + } + } else if c >= '\\u{A0}' { + // No characters >= U+00A0 are control codes, so we can consult the lookup tables + Some(lookup_width(c, is_cjk)) + } else { + // U+007F to U+00A0 (exclusive) are control codes + None + } + } +""" + ) + + subtable_count = 1 + for (i, table) in enumerate(tables): + new_subtable_count = len(table.buckets()) + if i == len(tables) - 1: + table.indices_to_widths() # for the last table, indices == widths + byte_array = table.to_bytes() + module.write( + f""" + /// Autogenerated. {subtable_count} sub-table(s). Consult [`lookup_width`] for layout info. + static TABLES_{i}: [u8; {len(byte_array)}] = [""" + ) + for (j, byte) in enumerate(byte_array): + # Add line breaks for every 15th entry (chosen to match what rustfmt does) + if j % 15 == 0: + module.write("\n ") + module.write(f" 0x{byte:02X},") + module.write("\n ];\n") + subtable_count = new_subtable_count + module.write("}\n") + + +def main(module_filename: str): + """Obtain character data from the latest version of Unicode, transform it into a multi-level + lookup table for character width, and write a Rust module utilizing that table to + `module_filename`. + + We obey the following rules in decreasing order of importance: + - The soft hyphen (`U+00AD`) is single-width. + - Hangul Jamo medial vowels & final consonants (`U+1160..=U+11FF`) are zero-width. + - All codepoints in general categories `Cc`, `Cf`, `Mn`, and `Me` are zero-width. + - All codepoints with an East Asian Width of `Ambigous` are ambiguous-width. + - All codepoints with an East Asian Width of `Wide` or `Fullwidth` are double-width. + - All other codepoints (including unassigned codepoints and codepoints with an East Asian Width + of `Neutral`, `Narrow`, or `Halfwidth`) are single-width. + + These rules are based off of Markus Kuhn's free `wcwidth()` implementation: + http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c""" + version = load_unicode_version() + print(f"Generating module for Unicode {version[0]}.{version[1]}.{version[2]}") + + eaw_map = load_east_asian_widths() + zw_map = load_zero_widths() + + # Characters marked as zero-width in zw_map should be zero-width in the final map + width_map = list( + map(lambda x: EffectiveWidth.ZERO if x[1] else x[0], zip(eaw_map, zw_map)) + ) + + # Override for soft hyphen + width_map[0x00AD] = EffectiveWidth.NARROW + + # Override for Hangul Jamo medial vowels & final consonants + for i in range(0x1160, 0x11FF + 1): + width_map[i] = EffectiveWidth.ZERO + + tables = make_tables(TABLE_CFGS, enumerate(width_map)) + + print("------------------------") + total_size = 0 + for (i, table) in enumerate(tables): + size_bytes = len(table.to_bytes()) + print(f"Table {i} Size: {size_bytes} bytes") + total_size += size_bytes + print("------------------------") + print(f" Total Size: {total_size} bytes") + + emit_module(module_filename, version, tables) + print(f'Wrote to "{module_filename}"') + + +if __name__ == "__main__": + main(MODULE_FILENAME) diff --git a/rio-unicode/src/grapheme.rs b/rio-unicode/src/grapheme.rs new file mode 100644 index 0000000000..181fac2864 --- /dev/null +++ b/rio-unicode/src/grapheme.rs @@ -0,0 +1,310 @@ +//! Grapheme cluster segmentation (UAX #29, extended grapheme clusters). +//! +//! The break decision is a pairwise state machine, the shape a terminal +//! needs: `is_break(prev, next, &mut state)` answers whether a cluster +//! boundary falls between two adjacent codepoints while the state +//! carries the three pieces of history single-pair rules can't see — +//! emoji ZWJ sequences (GB11), regional-indicator pair parity +//! (GB12/13), and Indic conjunct linkage (GB9c). Grid code appending +//! codepoints cell by cell can run it without ever materializing a +//! string; [`Graphemes`]/[`GraphemeIndices`] wrap the same machine for +//! string callers. +//! +//! Property data is generated from the same UCD release as the width +//! tables (`scripts/grapheme.py`), so segmentation and width can never +//! disagree about what Unicode says. + +use crate::grapheme_tables::GRAPHEME_CLASS_RANGES; +pub use crate::grapheme_tables::GRAPHEME_UNICODE_VERSION; + +/// Grapheme_Cluster_Break class, refined with the Extended_Pictographic +/// and InCB properties so every rule can run on classes alone. The +/// undocumented variants are the plain UAX #29 GCB classes. +#[allow(missing_docs)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u8)] +pub enum GraphemeClass { + Other, + CR, + LF, + Control, + /// GCB=Extend without InCB=Extend. + Extend, + /// GCB=Extend with InCB=Extend: continues an Indic conjunct chain. + ExtendIncb, + /// GCB=Extend with InCB=Linker (viramas). + Linker, + Zwj, + RegionalIndicator, + Prepend, + SpacingMark, + L, + V, + T, + LV, + LVT, + /// Extended_Pictographic (GCB=Other). + ExtPic, + /// InCB=Consonant (GCB=Other). + Consonant, +} + +/// Class lookup: binary search over the generated ranges. +pub fn grapheme_class(c: char) -> GraphemeClass { + let cp = c as u32; + match GRAPHEME_CLASS_RANGES.binary_search_by(|&(lo, hi, _)| { + if cp < lo { + core::cmp::Ordering::Greater + } else if cp > hi { + core::cmp::Ordering::Less + } else { + core::cmp::Ordering::Equal + } + }) { + Ok(i) => GRAPHEME_CLASS_RANGES[i].2, + Err(_) => GraphemeClass::Other, + } +} + +/// Emoji ZWJ sequence progress (GB11): `\p{ExtPic} Extend* ZWJ × \p{ExtPic}`. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +enum EmojiSeq { + #[default] + None, + /// Saw Extended_Pictographic, possibly followed by Extends. + Emoji, + /// ...then a ZWJ: the very next ExtPic joins. + EmojiZwj, +} + +/// Indic conjunct progress (GB9c): +/// `Consonant [Extend Linker]* Linker [Extend Linker]* × Consonant`. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +enum Incb { + #[default] + None, + /// Saw a consonant; no linker in the chain yet. + Consonant, + /// Consonant then a chain containing at least one linker: the next + /// consonant joins. + LinkerSeen, +} + +/// Cross-pair segmentation state. Describes the codepoint run ending at +/// the `prev` side of the next [`is_break`] call. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +pub struct BreakState { + emoji: EmojiSeq, + incb: Incb, + /// The regional-indicator run ending at `prev` has odd length. + ri_odd: bool, +} + +impl BreakState { + /// State after the first codepoint of a sequence. + pub fn start(first: GraphemeClass) -> Self { + let mut state = Self::default(); + state.advance(first); + state + } + + fn advance(&mut self, class: GraphemeClass) { + use GraphemeClass as G; + self.emoji = match (self.emoji, class) { + (_, G::ExtPic) => EmojiSeq::Emoji, + (EmojiSeq::Emoji, G::Extend | G::ExtendIncb | G::Linker) => EmojiSeq::Emoji, + (EmojiSeq::Emoji, G::Zwj) => EmojiSeq::EmojiZwj, + _ => EmojiSeq::None, + }; + self.incb = match (self.incb, class) { + (_, G::Consonant) => Incb::Consonant, + (Incb::Consonant, G::Linker) => Incb::LinkerSeen, + (Incb::Consonant, G::ExtendIncb | G::Zwj) => Incb::Consonant, + (Incb::LinkerSeen, G::Linker | G::ExtendIncb | G::Zwj) => Incb::LinkerSeen, + _ => Incb::None, + }; + self.ri_odd = match class { + G::RegionalIndicator => !self.ri_odd, + _ => false, + }; + } +} + +/// Whether an extended-grapheme-cluster boundary falls between `prev` +/// and `next`. `state` must describe the sequence ending at `prev` +/// (see [`BreakState::start`]); it is advanced past `next` before +/// returning, ready for the following pair. +// One branch per numbered UAX #29 rule, in spec order — merging the +// identical-bodied arms would make the machine harder to audit against +// the standard for zero behavioral gain. +#[allow(clippy::if_same_then_else)] +pub fn is_break( + prev: GraphemeClass, + next: GraphemeClass, + state: &mut BreakState, +) -> bool { + use GraphemeClass as G; + let decision = { + // GB3: CR × LF. + if prev == G::CR && next == G::LF { + false + // GB4 / GB5: controls break on both sides. + } else if matches!(prev, G::Control | G::CR | G::LF) + || matches!(next, G::Control | G::CR | G::LF) + { + true + // GB6-8: Hangul jamo. + } else if prev == G::L && matches!(next, G::L | G::V | G::LV | G::LVT) { + false + } else if matches!(prev, G::LV | G::V) && matches!(next, G::V | G::T) { + false + } else if matches!(prev, G::LVT | G::T) && next == G::T { + false + // GB9 / GB9a / GB9b: extenders, spacing marks, prepends. + } else if matches!(next, G::Extend | G::ExtendIncb | G::Linker | G::Zwj) { + false + } else if next == G::SpacingMark { + false + } else if prev == G::Prepend { + false + // GB9c: Indic conjuncts join across a linker chain. + } else if next == G::Consonant && state.incb == Incb::LinkerSeen { + false + // GB11: emoji ZWJ sequences. + } else if prev == G::Zwj && next == G::ExtPic && state.emoji == EmojiSeq::EmojiZwj + { + false + // GB12/GB13: regional indicators pair up. + } else if prev == G::RegionalIndicator + && next == G::RegionalIndicator + && state.ri_odd + { + false + // GB999. + } else { + true + } + }; + state.advance(next); + decision +} + +/// Iterator over the extended grapheme clusters of a string. +#[derive(Debug, Clone)] +pub struct Graphemes<'a> { + text: &'a str, + offset: usize, +} + +impl<'a> Graphemes<'a> { + /// Segment `text` from its start. + pub fn new(text: &'a str) -> Self { + Self { text, offset: 0 } + } +} + +impl<'a> Iterator for Graphemes<'a> { + type Item = &'a str; + + fn next(&mut self) -> Option<&'a str> { + let rest = &self.text[self.offset..]; + let mut chars = rest.char_indices(); + let (_, first) = chars.next()?; + let mut prev = grapheme_class(first); + let mut state = BreakState::start(prev); + let end = loop { + match chars.next() { + Some((i, c)) => { + let class = grapheme_class(c); + if is_break(prev, class, &mut state) { + break i; + } + prev = class; + } + None => break rest.len(), + } + }; + let start = self.offset; + self.offset += end; + Some(&self.text[start..start + end]) + } +} + +/// Like [`Graphemes`], yielding `(byte_offset, cluster)` pairs. +#[derive(Debug, Clone)] +pub struct GraphemeIndices<'a> { + inner: Graphemes<'a>, +} + +impl<'a> GraphemeIndices<'a> { + /// Segment `text` from its start. + pub fn new(text: &'a str) -> Self { + Self { + inner: Graphemes::new(text), + } + } +} + +impl<'a> Iterator for GraphemeIndices<'a> { + type Item = (usize, &'a str); + + fn next(&mut self) -> Option<(usize, &'a str)> { + let offset = self.inner.offset; + self.inner.next().map(|g| (offset, g)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::vec::Vec; + + fn clusters(s: &str) -> Vec<&str> { + Graphemes::new(s).collect() + } + + #[test] + fn versions_stay_in_lockstep() { + // The whole point of this crate: one Unicode version. + assert_eq!(GRAPHEME_UNICODE_VERSION, crate::UNICODE_VERSION); + } + + #[test] + fn ascii_and_combining() { + assert_eq!(clusters("abc"), ["a", "b", "c"]); + assert_eq!(clusters("e\u{301}x"), ["e\u{301}", "x"]); + } + + #[test] + fn zwj_emoji_is_one_cluster() { + let family = "\u{1F468}\u{200D}\u{1F469}\u{200D}\u{1F467}"; + assert_eq!(clusters(family), [family]); + } + + #[test] + fn regional_indicators_pair() { + // Two flags: BR + AR = four RIs, two clusters. + let flags = "\u{1F1E7}\u{1F1F7}\u{1F1E6}\u{1F1F7}"; + assert_eq!( + clusters(flags), + ["\u{1F1E7}\u{1F1F7}", "\u{1F1E6}\u{1F1F7}"] + ); + } + + #[test] + fn crlf_and_controls() { + assert_eq!(clusters("a\r\nb"), ["a", "\r\n", "b"]); + } + + #[test] + fn devanagari_conjunct_joins() { + // ka + virama + ssa: GB9c keeps the conjunct together. + assert_eq!(clusters("\u{915}\u{94D}\u{937}"), ["\u{915}\u{94D}\u{937}"]); + } + + #[test] + fn indices_report_byte_offsets() { + let pairs: Vec<(usize, &str)> = GraphemeIndices::new("aé日").collect(); + assert_eq!(pairs, [(0, "a"), (1, "é"), (3, "日")]); + } +} diff --git a/rio-unicode/src/grapheme_tables.rs b/rio-unicode/src/grapheme_tables.rs new file mode 100644 index 0000000000..59eafa264d --- /dev/null +++ b/rio-unicode/src/grapheme_tables.rs @@ -0,0 +1,1644 @@ +// Generated by scripts/grapheme.py — do not edit. +// Unicode 17.0.0: GraphemeBreakProperty + Extended_Pictographic + InCB. + +use super::grapheme::GraphemeClass; + +/// The Unicode version of the grapheme-break data; always equal +/// to the width tables' [`UNICODE_VERSION`](crate::UNICODE_VERSION). +pub const GRAPHEME_UNICODE_VERSION: (u8, u8, u8) = (17, 0, 0); + +/// Sorted, non-overlapping ranges; codepoints not listed are +/// `GraphemeClass::Other`. +pub(crate) static GRAPHEME_CLASS_RANGES: &[(u32, u32, GraphemeClass)] = &[ + (0x0, 0x9, GraphemeClass::Control), + (0xA, 0xA, GraphemeClass::LF), + (0xB, 0xC, GraphemeClass::Control), + (0xD, 0xD, GraphemeClass::CR), + (0xE, 0x1F, GraphemeClass::Control), + (0x7F, 0x9F, GraphemeClass::Control), + (0xA9, 0xA9, GraphemeClass::ExtPic), + (0xAD, 0xAD, GraphemeClass::Control), + (0xAE, 0xAE, GraphemeClass::ExtPic), + (0x300, 0x36F, GraphemeClass::ExtendIncb), + (0x483, 0x489, GraphemeClass::ExtendIncb), + (0x591, 0x5BD, GraphemeClass::ExtendIncb), + (0x5BF, 0x5BF, GraphemeClass::ExtendIncb), + (0x5C1, 0x5C2, GraphemeClass::ExtendIncb), + (0x5C4, 0x5C5, GraphemeClass::ExtendIncb), + (0x5C7, 0x5C7, GraphemeClass::ExtendIncb), + (0x600, 0x605, GraphemeClass::Prepend), + (0x610, 0x61A, GraphemeClass::ExtendIncb), + (0x61C, 0x61C, GraphemeClass::Control), + (0x64B, 0x65F, GraphemeClass::ExtendIncb), + (0x670, 0x670, GraphemeClass::ExtendIncb), + (0x6D6, 0x6DC, GraphemeClass::ExtendIncb), + (0x6DD, 0x6DD, GraphemeClass::Prepend), + (0x6DF, 0x6E4, GraphemeClass::ExtendIncb), + (0x6E7, 0x6E8, GraphemeClass::ExtendIncb), + (0x6EA, 0x6ED, GraphemeClass::ExtendIncb), + (0x70F, 0x70F, GraphemeClass::Prepend), + (0x711, 0x711, GraphemeClass::ExtendIncb), + (0x730, 0x74A, GraphemeClass::ExtendIncb), + (0x7A6, 0x7B0, GraphemeClass::ExtendIncb), + (0x7EB, 0x7F3, GraphemeClass::ExtendIncb), + (0x7FD, 0x7FD, GraphemeClass::ExtendIncb), + (0x816, 0x819, GraphemeClass::ExtendIncb), + (0x81B, 0x823, GraphemeClass::ExtendIncb), + (0x825, 0x827, GraphemeClass::ExtendIncb), + (0x829, 0x82D, GraphemeClass::ExtendIncb), + (0x859, 0x85B, GraphemeClass::ExtendIncb), + (0x890, 0x891, GraphemeClass::Prepend), + (0x897, 0x89F, GraphemeClass::ExtendIncb), + (0x8CA, 0x8E1, GraphemeClass::ExtendIncb), + (0x8E2, 0x8E2, GraphemeClass::Prepend), + (0x8E3, 0x902, GraphemeClass::ExtendIncb), + (0x903, 0x903, GraphemeClass::SpacingMark), + (0x915, 0x939, GraphemeClass::Consonant), + (0x93A, 0x93A, GraphemeClass::ExtendIncb), + (0x93B, 0x93B, GraphemeClass::SpacingMark), + (0x93C, 0x93C, GraphemeClass::ExtendIncb), + (0x93E, 0x940, GraphemeClass::SpacingMark), + (0x941, 0x948, GraphemeClass::ExtendIncb), + (0x949, 0x94C, GraphemeClass::SpacingMark), + (0x94D, 0x94D, GraphemeClass::Linker), + (0x94E, 0x94F, GraphemeClass::SpacingMark), + (0x951, 0x957, GraphemeClass::ExtendIncb), + (0x958, 0x95F, GraphemeClass::Consonant), + (0x962, 0x963, GraphemeClass::ExtendIncb), + (0x978, 0x97F, GraphemeClass::Consonant), + (0x981, 0x981, GraphemeClass::ExtendIncb), + (0x982, 0x983, GraphemeClass::SpacingMark), + (0x995, 0x9A8, GraphemeClass::Consonant), + (0x9AA, 0x9B0, GraphemeClass::Consonant), + (0x9B2, 0x9B2, GraphemeClass::Consonant), + (0x9B6, 0x9B9, GraphemeClass::Consonant), + (0x9BC, 0x9BC, GraphemeClass::ExtendIncb), + (0x9BE, 0x9BE, GraphemeClass::ExtendIncb), + (0x9BF, 0x9C0, GraphemeClass::SpacingMark), + (0x9C1, 0x9C4, GraphemeClass::ExtendIncb), + (0x9C7, 0x9C8, GraphemeClass::SpacingMark), + (0x9CB, 0x9CC, GraphemeClass::SpacingMark), + (0x9CD, 0x9CD, GraphemeClass::Linker), + (0x9D7, 0x9D7, GraphemeClass::ExtendIncb), + (0x9DC, 0x9DD, GraphemeClass::Consonant), + (0x9DF, 0x9DF, GraphemeClass::Consonant), + (0x9E2, 0x9E3, GraphemeClass::ExtendIncb), + (0x9F0, 0x9F1, GraphemeClass::Consonant), + (0x9FE, 0x9FE, GraphemeClass::ExtendIncb), + (0xA01, 0xA02, GraphemeClass::ExtendIncb), + (0xA03, 0xA03, GraphemeClass::SpacingMark), + (0xA3C, 0xA3C, GraphemeClass::ExtendIncb), + (0xA3E, 0xA40, GraphemeClass::SpacingMark), + (0xA41, 0xA42, GraphemeClass::ExtendIncb), + (0xA47, 0xA48, GraphemeClass::ExtendIncb), + (0xA4B, 0xA4D, GraphemeClass::ExtendIncb), + (0xA51, 0xA51, GraphemeClass::ExtendIncb), + (0xA70, 0xA71, GraphemeClass::ExtendIncb), + (0xA75, 0xA75, GraphemeClass::ExtendIncb), + (0xA81, 0xA82, GraphemeClass::ExtendIncb), + (0xA83, 0xA83, GraphemeClass::SpacingMark), + (0xA95, 0xAA8, GraphemeClass::Consonant), + (0xAAA, 0xAB0, GraphemeClass::Consonant), + (0xAB2, 0xAB3, GraphemeClass::Consonant), + (0xAB5, 0xAB9, GraphemeClass::Consonant), + (0xABC, 0xABC, GraphemeClass::ExtendIncb), + (0xABE, 0xAC0, GraphemeClass::SpacingMark), + (0xAC1, 0xAC5, GraphemeClass::ExtendIncb), + (0xAC7, 0xAC8, GraphemeClass::ExtendIncb), + (0xAC9, 0xAC9, GraphemeClass::SpacingMark), + (0xACB, 0xACC, GraphemeClass::SpacingMark), + (0xACD, 0xACD, GraphemeClass::Linker), + (0xAE2, 0xAE3, GraphemeClass::ExtendIncb), + (0xAF9, 0xAF9, GraphemeClass::Consonant), + (0xAFA, 0xAFF, GraphemeClass::ExtendIncb), + (0xB01, 0xB01, GraphemeClass::ExtendIncb), + (0xB02, 0xB03, GraphemeClass::SpacingMark), + (0xB15, 0xB28, GraphemeClass::Consonant), + (0xB2A, 0xB30, GraphemeClass::Consonant), + (0xB32, 0xB33, GraphemeClass::Consonant), + (0xB35, 0xB39, GraphemeClass::Consonant), + (0xB3C, 0xB3C, GraphemeClass::ExtendIncb), + (0xB3E, 0xB3F, GraphemeClass::ExtendIncb), + (0xB40, 0xB40, GraphemeClass::SpacingMark), + (0xB41, 0xB44, GraphemeClass::ExtendIncb), + (0xB47, 0xB48, GraphemeClass::SpacingMark), + (0xB4B, 0xB4C, GraphemeClass::SpacingMark), + (0xB4D, 0xB4D, GraphemeClass::Linker), + (0xB55, 0xB57, GraphemeClass::ExtendIncb), + (0xB5C, 0xB5D, GraphemeClass::Consonant), + (0xB5F, 0xB5F, GraphemeClass::Consonant), + (0xB62, 0xB63, GraphemeClass::ExtendIncb), + (0xB71, 0xB71, GraphemeClass::Consonant), + (0xB82, 0xB82, GraphemeClass::ExtendIncb), + (0xBBE, 0xBBE, GraphemeClass::ExtendIncb), + (0xBBF, 0xBBF, GraphemeClass::SpacingMark), + (0xBC0, 0xBC0, GraphemeClass::ExtendIncb), + (0xBC1, 0xBC2, GraphemeClass::SpacingMark), + (0xBC6, 0xBC8, GraphemeClass::SpacingMark), + (0xBCA, 0xBCC, GraphemeClass::SpacingMark), + (0xBCD, 0xBCD, GraphemeClass::ExtendIncb), + (0xBD7, 0xBD7, GraphemeClass::ExtendIncb), + (0xC00, 0xC00, GraphemeClass::ExtendIncb), + (0xC01, 0xC03, GraphemeClass::SpacingMark), + (0xC04, 0xC04, GraphemeClass::ExtendIncb), + (0xC15, 0xC28, GraphemeClass::Consonant), + (0xC2A, 0xC39, GraphemeClass::Consonant), + (0xC3C, 0xC3C, GraphemeClass::ExtendIncb), + (0xC3E, 0xC40, GraphemeClass::ExtendIncb), + (0xC41, 0xC44, GraphemeClass::SpacingMark), + (0xC46, 0xC48, GraphemeClass::ExtendIncb), + (0xC4A, 0xC4C, GraphemeClass::ExtendIncb), + (0xC4D, 0xC4D, GraphemeClass::Linker), + (0xC55, 0xC56, GraphemeClass::ExtendIncb), + (0xC58, 0xC5A, GraphemeClass::Consonant), + (0xC62, 0xC63, GraphemeClass::ExtendIncb), + (0xC81, 0xC81, GraphemeClass::ExtendIncb), + (0xC82, 0xC83, GraphemeClass::SpacingMark), + (0xCBC, 0xCBC, GraphemeClass::ExtendIncb), + (0xCBE, 0xCBE, GraphemeClass::SpacingMark), + (0xCBF, 0xCC0, GraphemeClass::ExtendIncb), + (0xCC1, 0xCC1, GraphemeClass::SpacingMark), + (0xCC2, 0xCC2, GraphemeClass::ExtendIncb), + (0xCC3, 0xCC4, GraphemeClass::SpacingMark), + (0xCC6, 0xCC8, GraphemeClass::ExtendIncb), + (0xCCA, 0xCCD, GraphemeClass::ExtendIncb), + (0xCD5, 0xCD6, GraphemeClass::ExtendIncb), + (0xCE2, 0xCE3, GraphemeClass::ExtendIncb), + (0xCF3, 0xCF3, GraphemeClass::SpacingMark), + (0xD00, 0xD01, GraphemeClass::ExtendIncb), + (0xD02, 0xD03, GraphemeClass::SpacingMark), + (0xD15, 0xD3A, GraphemeClass::Consonant), + (0xD3B, 0xD3C, GraphemeClass::ExtendIncb), + (0xD3E, 0xD3E, GraphemeClass::ExtendIncb), + (0xD3F, 0xD40, GraphemeClass::SpacingMark), + (0xD41, 0xD44, GraphemeClass::ExtendIncb), + (0xD46, 0xD48, GraphemeClass::SpacingMark), + (0xD4A, 0xD4C, GraphemeClass::SpacingMark), + (0xD4D, 0xD4D, GraphemeClass::Linker), + (0xD4E, 0xD4E, GraphemeClass::Prepend), + (0xD57, 0xD57, GraphemeClass::ExtendIncb), + (0xD62, 0xD63, GraphemeClass::ExtendIncb), + (0xD81, 0xD81, GraphemeClass::ExtendIncb), + (0xD82, 0xD83, GraphemeClass::SpacingMark), + (0xDCA, 0xDCA, GraphemeClass::ExtendIncb), + (0xDCF, 0xDCF, GraphemeClass::ExtendIncb), + (0xDD0, 0xDD1, GraphemeClass::SpacingMark), + (0xDD2, 0xDD4, GraphemeClass::ExtendIncb), + (0xDD6, 0xDD6, GraphemeClass::ExtendIncb), + (0xDD8, 0xDDE, GraphemeClass::SpacingMark), + (0xDDF, 0xDDF, GraphemeClass::ExtendIncb), + (0xDF2, 0xDF3, GraphemeClass::SpacingMark), + (0xE31, 0xE31, GraphemeClass::ExtendIncb), + (0xE33, 0xE33, GraphemeClass::SpacingMark), + (0xE34, 0xE3A, GraphemeClass::ExtendIncb), + (0xE47, 0xE4E, GraphemeClass::ExtendIncb), + (0xEB1, 0xEB1, GraphemeClass::ExtendIncb), + (0xEB3, 0xEB3, GraphemeClass::SpacingMark), + (0xEB4, 0xEBC, GraphemeClass::ExtendIncb), + (0xEC8, 0xECE, GraphemeClass::ExtendIncb), + (0xF18, 0xF19, GraphemeClass::ExtendIncb), + (0xF35, 0xF35, GraphemeClass::ExtendIncb), + (0xF37, 0xF37, GraphemeClass::ExtendIncb), + (0xF39, 0xF39, GraphemeClass::ExtendIncb), + (0xF3E, 0xF3F, GraphemeClass::SpacingMark), + (0xF71, 0xF7E, GraphemeClass::ExtendIncb), + (0xF7F, 0xF7F, GraphemeClass::SpacingMark), + (0xF80, 0xF84, GraphemeClass::ExtendIncb), + (0xF86, 0xF87, GraphemeClass::ExtendIncb), + (0xF8D, 0xF97, GraphemeClass::ExtendIncb), + (0xF99, 0xFBC, GraphemeClass::ExtendIncb), + (0xFC6, 0xFC6, GraphemeClass::ExtendIncb), + (0x1000, 0x102A, GraphemeClass::Consonant), + (0x102D, 0x1030, GraphemeClass::ExtendIncb), + (0x1031, 0x1031, GraphemeClass::SpacingMark), + (0x1032, 0x1037, GraphemeClass::ExtendIncb), + (0x1039, 0x1039, GraphemeClass::Linker), + (0x103A, 0x103A, GraphemeClass::ExtendIncb), + (0x103B, 0x103C, GraphemeClass::SpacingMark), + (0x103D, 0x103E, GraphemeClass::ExtendIncb), + (0x103F, 0x103F, GraphemeClass::Consonant), + (0x1050, 0x1055, GraphemeClass::Consonant), + (0x1056, 0x1057, GraphemeClass::SpacingMark), + (0x1058, 0x1059, GraphemeClass::ExtendIncb), + (0x105A, 0x105D, GraphemeClass::Consonant), + (0x105E, 0x1060, GraphemeClass::ExtendIncb), + (0x1061, 0x1061, GraphemeClass::Consonant), + (0x1065, 0x1066, GraphemeClass::Consonant), + (0x106E, 0x1070, GraphemeClass::Consonant), + (0x1071, 0x1074, GraphemeClass::ExtendIncb), + (0x1075, 0x1081, GraphemeClass::Consonant), + (0x1082, 0x1082, GraphemeClass::ExtendIncb), + (0x1084, 0x1084, GraphemeClass::SpacingMark), + (0x1085, 0x1086, GraphemeClass::ExtendIncb), + (0x108D, 0x108D, GraphemeClass::ExtendIncb), + (0x108E, 0x108E, GraphemeClass::Consonant), + (0x109D, 0x109D, GraphemeClass::ExtendIncb), + (0x1100, 0x115F, GraphemeClass::L), + (0x1160, 0x11A7, GraphemeClass::V), + (0x11A8, 0x11FF, GraphemeClass::T), + (0x135D, 0x135F, GraphemeClass::ExtendIncb), + (0x1712, 0x1715, GraphemeClass::ExtendIncb), + (0x1732, 0x1734, GraphemeClass::ExtendIncb), + (0x1752, 0x1753, GraphemeClass::ExtendIncb), + (0x1772, 0x1773, GraphemeClass::ExtendIncb), + (0x1780, 0x17B3, GraphemeClass::Consonant), + (0x17B4, 0x17B5, GraphemeClass::ExtendIncb), + (0x17B6, 0x17B6, GraphemeClass::SpacingMark), + (0x17B7, 0x17BD, GraphemeClass::ExtendIncb), + (0x17BE, 0x17C5, GraphemeClass::SpacingMark), + (0x17C6, 0x17C6, GraphemeClass::ExtendIncb), + (0x17C7, 0x17C8, GraphemeClass::SpacingMark), + (0x17C9, 0x17D1, GraphemeClass::ExtendIncb), + (0x17D2, 0x17D2, GraphemeClass::Linker), + (0x17D3, 0x17D3, GraphemeClass::ExtendIncb), + (0x17DD, 0x17DD, GraphemeClass::ExtendIncb), + (0x180B, 0x180D, GraphemeClass::ExtendIncb), + (0x180E, 0x180E, GraphemeClass::Control), + (0x180F, 0x180F, GraphemeClass::ExtendIncb), + (0x1885, 0x1886, GraphemeClass::ExtendIncb), + (0x18A9, 0x18A9, GraphemeClass::ExtendIncb), + (0x1920, 0x1922, GraphemeClass::ExtendIncb), + (0x1923, 0x1926, GraphemeClass::SpacingMark), + (0x1927, 0x1928, GraphemeClass::ExtendIncb), + (0x1929, 0x192B, GraphemeClass::SpacingMark), + (0x1930, 0x1931, GraphemeClass::SpacingMark), + (0x1932, 0x1932, GraphemeClass::ExtendIncb), + (0x1933, 0x1938, GraphemeClass::SpacingMark), + (0x1939, 0x193B, GraphemeClass::ExtendIncb), + (0x1A17, 0x1A18, GraphemeClass::ExtendIncb), + (0x1A19, 0x1A1A, GraphemeClass::SpacingMark), + (0x1A1B, 0x1A1B, GraphemeClass::ExtendIncb), + (0x1A20, 0x1A54, GraphemeClass::Consonant), + (0x1A55, 0x1A55, GraphemeClass::SpacingMark), + (0x1A56, 0x1A56, GraphemeClass::ExtendIncb), + (0x1A57, 0x1A57, GraphemeClass::SpacingMark), + (0x1A58, 0x1A5E, GraphemeClass::ExtendIncb), + (0x1A60, 0x1A60, GraphemeClass::Linker), + (0x1A62, 0x1A62, GraphemeClass::ExtendIncb), + (0x1A65, 0x1A6C, GraphemeClass::ExtendIncb), + (0x1A6D, 0x1A72, GraphemeClass::SpacingMark), + (0x1A73, 0x1A7C, GraphemeClass::ExtendIncb), + (0x1A7F, 0x1A7F, GraphemeClass::ExtendIncb), + (0x1AB0, 0x1ADD, GraphemeClass::ExtendIncb), + (0x1AE0, 0x1AEB, GraphemeClass::ExtendIncb), + (0x1B00, 0x1B03, GraphemeClass::ExtendIncb), + (0x1B04, 0x1B04, GraphemeClass::SpacingMark), + (0x1B0B, 0x1B0C, GraphemeClass::Consonant), + (0x1B13, 0x1B33, GraphemeClass::Consonant), + (0x1B34, 0x1B3D, GraphemeClass::ExtendIncb), + (0x1B3E, 0x1B41, GraphemeClass::SpacingMark), + (0x1B42, 0x1B43, GraphemeClass::ExtendIncb), + (0x1B44, 0x1B44, GraphemeClass::Linker), + (0x1B45, 0x1B4C, GraphemeClass::Consonant), + (0x1B6B, 0x1B73, GraphemeClass::ExtendIncb), + (0x1B80, 0x1B81, GraphemeClass::ExtendIncb), + (0x1B82, 0x1B82, GraphemeClass::SpacingMark), + (0x1B83, 0x1BA0, GraphemeClass::Consonant), + (0x1BA1, 0x1BA1, GraphemeClass::SpacingMark), + (0x1BA2, 0x1BA5, GraphemeClass::ExtendIncb), + (0x1BA6, 0x1BA7, GraphemeClass::SpacingMark), + (0x1BA8, 0x1BAA, GraphemeClass::ExtendIncb), + (0x1BAB, 0x1BAB, GraphemeClass::Linker), + (0x1BAC, 0x1BAD, GraphemeClass::ExtendIncb), + (0x1BAE, 0x1BAF, GraphemeClass::Consonant), + (0x1BBB, 0x1BBD, GraphemeClass::Consonant), + (0x1BE6, 0x1BE6, GraphemeClass::ExtendIncb), + (0x1BE7, 0x1BE7, GraphemeClass::SpacingMark), + (0x1BE8, 0x1BE9, GraphemeClass::ExtendIncb), + (0x1BEA, 0x1BEC, GraphemeClass::SpacingMark), + (0x1BED, 0x1BED, GraphemeClass::ExtendIncb), + (0x1BEE, 0x1BEE, GraphemeClass::SpacingMark), + (0x1BEF, 0x1BF3, GraphemeClass::ExtendIncb), + (0x1C24, 0x1C2B, GraphemeClass::SpacingMark), + (0x1C2C, 0x1C33, GraphemeClass::ExtendIncb), + (0x1C34, 0x1C35, GraphemeClass::SpacingMark), + (0x1C36, 0x1C37, GraphemeClass::ExtendIncb), + (0x1CD0, 0x1CD2, GraphemeClass::ExtendIncb), + (0x1CD4, 0x1CE0, GraphemeClass::ExtendIncb), + (0x1CE1, 0x1CE1, GraphemeClass::SpacingMark), + (0x1CE2, 0x1CE8, GraphemeClass::ExtendIncb), + (0x1CED, 0x1CED, GraphemeClass::ExtendIncb), + (0x1CF4, 0x1CF4, GraphemeClass::ExtendIncb), + (0x1CF7, 0x1CF7, GraphemeClass::SpacingMark), + (0x1CF8, 0x1CF9, GraphemeClass::ExtendIncb), + (0x1DC0, 0x1DFF, GraphemeClass::ExtendIncb), + (0x200B, 0x200B, GraphemeClass::Control), + (0x200C, 0x200C, GraphemeClass::Extend), + (0x200D, 0x200D, GraphemeClass::Zwj), + (0x200E, 0x200F, GraphemeClass::Control), + (0x2028, 0x202E, GraphemeClass::Control), + (0x203C, 0x203C, GraphemeClass::ExtPic), + (0x2049, 0x2049, GraphemeClass::ExtPic), + (0x2060, 0x206F, GraphemeClass::Control), + (0x20D0, 0x20F0, GraphemeClass::ExtendIncb), + (0x2122, 0x2122, GraphemeClass::ExtPic), + (0x2139, 0x2139, GraphemeClass::ExtPic), + (0x2194, 0x2199, GraphemeClass::ExtPic), + (0x21A9, 0x21AA, GraphemeClass::ExtPic), + (0x231A, 0x231B, GraphemeClass::ExtPic), + (0x2328, 0x2328, GraphemeClass::ExtPic), + (0x23CF, 0x23CF, GraphemeClass::ExtPic), + (0x23E9, 0x23F3, GraphemeClass::ExtPic), + (0x23F8, 0x23FA, GraphemeClass::ExtPic), + (0x24C2, 0x24C2, GraphemeClass::ExtPic), + (0x25AA, 0x25AB, GraphemeClass::ExtPic), + (0x25B6, 0x25B6, GraphemeClass::ExtPic), + (0x25C0, 0x25C0, GraphemeClass::ExtPic), + (0x25FB, 0x25FE, GraphemeClass::ExtPic), + (0x2600, 0x2604, GraphemeClass::ExtPic), + (0x260E, 0x260E, GraphemeClass::ExtPic), + (0x2611, 0x2611, GraphemeClass::ExtPic), + (0x2614, 0x2615, GraphemeClass::ExtPic), + (0x2618, 0x2618, GraphemeClass::ExtPic), + (0x261D, 0x261D, GraphemeClass::ExtPic), + (0x2620, 0x2620, GraphemeClass::ExtPic), + (0x2622, 0x2623, GraphemeClass::ExtPic), + (0x2626, 0x2626, GraphemeClass::ExtPic), + (0x262A, 0x262A, GraphemeClass::ExtPic), + (0x262E, 0x262F, GraphemeClass::ExtPic), + (0x2638, 0x263A, GraphemeClass::ExtPic), + (0x2640, 0x2640, GraphemeClass::ExtPic), + (0x2642, 0x2642, GraphemeClass::ExtPic), + (0x2648, 0x2653, GraphemeClass::ExtPic), + (0x265F, 0x2660, GraphemeClass::ExtPic), + (0x2663, 0x2663, GraphemeClass::ExtPic), + (0x2665, 0x2666, GraphemeClass::ExtPic), + (0x2668, 0x2668, GraphemeClass::ExtPic), + (0x267B, 0x267B, GraphemeClass::ExtPic), + (0x267E, 0x267F, GraphemeClass::ExtPic), + (0x2692, 0x2697, GraphemeClass::ExtPic), + (0x2699, 0x2699, GraphemeClass::ExtPic), + (0x269B, 0x269C, GraphemeClass::ExtPic), + (0x26A0, 0x26A1, GraphemeClass::ExtPic), + (0x26A7, 0x26A7, GraphemeClass::ExtPic), + (0x26AA, 0x26AB, GraphemeClass::ExtPic), + (0x26B0, 0x26B1, GraphemeClass::ExtPic), + (0x26BD, 0x26BE, GraphemeClass::ExtPic), + (0x26C4, 0x26C5, GraphemeClass::ExtPic), + (0x26C8, 0x26C8, GraphemeClass::ExtPic), + (0x26CE, 0x26CF, GraphemeClass::ExtPic), + (0x26D1, 0x26D1, GraphemeClass::ExtPic), + (0x26D3, 0x26D4, GraphemeClass::ExtPic), + (0x26E9, 0x26EA, GraphemeClass::ExtPic), + (0x26F0, 0x26F5, GraphemeClass::ExtPic), + (0x26F7, 0x26FA, GraphemeClass::ExtPic), + (0x26FD, 0x26FD, GraphemeClass::ExtPic), + (0x2702, 0x2702, GraphemeClass::ExtPic), + (0x2705, 0x2705, GraphemeClass::ExtPic), + (0x2708, 0x270D, GraphemeClass::ExtPic), + (0x270F, 0x270F, GraphemeClass::ExtPic), + (0x2712, 0x2712, GraphemeClass::ExtPic), + (0x2714, 0x2714, GraphemeClass::ExtPic), + (0x2716, 0x2716, GraphemeClass::ExtPic), + (0x271D, 0x271D, GraphemeClass::ExtPic), + (0x2721, 0x2721, GraphemeClass::ExtPic), + (0x2728, 0x2728, GraphemeClass::ExtPic), + (0x2733, 0x2734, GraphemeClass::ExtPic), + (0x2744, 0x2744, GraphemeClass::ExtPic), + (0x2747, 0x2747, GraphemeClass::ExtPic), + (0x274C, 0x274C, GraphemeClass::ExtPic), + (0x274E, 0x274E, GraphemeClass::ExtPic), + (0x2753, 0x2755, GraphemeClass::ExtPic), + (0x2757, 0x2757, GraphemeClass::ExtPic), + (0x2763, 0x2764, GraphemeClass::ExtPic), + (0x2795, 0x2797, GraphemeClass::ExtPic), + (0x27A1, 0x27A1, GraphemeClass::ExtPic), + (0x27B0, 0x27B0, GraphemeClass::ExtPic), + (0x27BF, 0x27BF, GraphemeClass::ExtPic), + (0x2934, 0x2935, GraphemeClass::ExtPic), + (0x2B05, 0x2B07, GraphemeClass::ExtPic), + (0x2B1B, 0x2B1C, GraphemeClass::ExtPic), + (0x2B50, 0x2B50, GraphemeClass::ExtPic), + (0x2B55, 0x2B55, GraphemeClass::ExtPic), + (0x2CEF, 0x2CF1, GraphemeClass::ExtendIncb), + (0x2D7F, 0x2D7F, GraphemeClass::ExtendIncb), + (0x2DE0, 0x2DFF, GraphemeClass::ExtendIncb), + (0x302A, 0x302F, GraphemeClass::ExtendIncb), + (0x3030, 0x3030, GraphemeClass::ExtPic), + (0x303D, 0x303D, GraphemeClass::ExtPic), + (0x3099, 0x309A, GraphemeClass::ExtendIncb), + (0x3297, 0x3297, GraphemeClass::ExtPic), + (0x3299, 0x3299, GraphemeClass::ExtPic), + (0xA66F, 0xA672, GraphemeClass::ExtendIncb), + (0xA674, 0xA67D, GraphemeClass::ExtendIncb), + (0xA69E, 0xA69F, GraphemeClass::ExtendIncb), + (0xA6F0, 0xA6F1, GraphemeClass::ExtendIncb), + (0xA802, 0xA802, GraphemeClass::ExtendIncb), + (0xA806, 0xA806, GraphemeClass::ExtendIncb), + (0xA80B, 0xA80B, GraphemeClass::ExtendIncb), + (0xA823, 0xA824, GraphemeClass::SpacingMark), + (0xA825, 0xA826, GraphemeClass::ExtendIncb), + (0xA827, 0xA827, GraphemeClass::SpacingMark), + (0xA82C, 0xA82C, GraphemeClass::ExtendIncb), + (0xA880, 0xA881, GraphemeClass::SpacingMark), + (0xA8B4, 0xA8C3, GraphemeClass::SpacingMark), + (0xA8C4, 0xA8C5, GraphemeClass::ExtendIncb), + (0xA8E0, 0xA8F1, GraphemeClass::ExtendIncb), + (0xA8FF, 0xA8FF, GraphemeClass::ExtendIncb), + (0xA926, 0xA92D, GraphemeClass::ExtendIncb), + (0xA947, 0xA951, GraphemeClass::ExtendIncb), + (0xA952, 0xA952, GraphemeClass::SpacingMark), + (0xA953, 0xA953, GraphemeClass::ExtendIncb), + (0xA960, 0xA97C, GraphemeClass::L), + (0xA980, 0xA982, GraphemeClass::ExtendIncb), + (0xA983, 0xA983, GraphemeClass::SpacingMark), + (0xA989, 0xA98B, GraphemeClass::Consonant), + (0xA98F, 0xA9B2, GraphemeClass::Consonant), + (0xA9B3, 0xA9B3, GraphemeClass::ExtendIncb), + (0xA9B4, 0xA9B5, GraphemeClass::SpacingMark), + (0xA9B6, 0xA9B9, GraphemeClass::ExtendIncb), + (0xA9BA, 0xA9BB, GraphemeClass::SpacingMark), + (0xA9BC, 0xA9BD, GraphemeClass::ExtendIncb), + (0xA9BE, 0xA9BF, GraphemeClass::SpacingMark), + (0xA9C0, 0xA9C0, GraphemeClass::Linker), + (0xA9E0, 0xA9E4, GraphemeClass::Consonant), + (0xA9E5, 0xA9E5, GraphemeClass::ExtendIncb), + (0xA9E7, 0xA9EF, GraphemeClass::Consonant), + (0xA9FA, 0xA9FE, GraphemeClass::Consonant), + (0xAA29, 0xAA2E, GraphemeClass::ExtendIncb), + (0xAA2F, 0xAA30, GraphemeClass::SpacingMark), + (0xAA31, 0xAA32, GraphemeClass::ExtendIncb), + (0xAA33, 0xAA34, GraphemeClass::SpacingMark), + (0xAA35, 0xAA36, GraphemeClass::ExtendIncb), + (0xAA43, 0xAA43, GraphemeClass::ExtendIncb), + (0xAA4C, 0xAA4C, GraphemeClass::ExtendIncb), + (0xAA4D, 0xAA4D, GraphemeClass::SpacingMark), + (0xAA60, 0xAA6F, GraphemeClass::Consonant), + (0xAA71, 0xAA73, GraphemeClass::Consonant), + (0xAA7A, 0xAA7A, GraphemeClass::Consonant), + (0xAA7C, 0xAA7C, GraphemeClass::ExtendIncb), + (0xAA7E, 0xAA7F, GraphemeClass::Consonant), + (0xAAB0, 0xAAB0, GraphemeClass::ExtendIncb), + (0xAAB2, 0xAAB4, GraphemeClass::ExtendIncb), + (0xAAB7, 0xAAB8, GraphemeClass::ExtendIncb), + (0xAABE, 0xAABF, GraphemeClass::ExtendIncb), + (0xAAC1, 0xAAC1, GraphemeClass::ExtendIncb), + (0xAAE0, 0xAAEA, GraphemeClass::Consonant), + (0xAAEB, 0xAAEB, GraphemeClass::SpacingMark), + (0xAAEC, 0xAAED, GraphemeClass::ExtendIncb), + (0xAAEE, 0xAAEF, GraphemeClass::SpacingMark), + (0xAAF5, 0xAAF5, GraphemeClass::SpacingMark), + (0xAAF6, 0xAAF6, GraphemeClass::Linker), + (0xABC0, 0xABDA, GraphemeClass::Consonant), + (0xABE3, 0xABE4, GraphemeClass::SpacingMark), + (0xABE5, 0xABE5, GraphemeClass::ExtendIncb), + (0xABE6, 0xABE7, GraphemeClass::SpacingMark), + (0xABE8, 0xABE8, GraphemeClass::ExtendIncb), + (0xABE9, 0xABEA, GraphemeClass::SpacingMark), + (0xABEC, 0xABEC, GraphemeClass::SpacingMark), + (0xABED, 0xABED, GraphemeClass::ExtendIncb), + (0xAC00, 0xAC00, GraphemeClass::LV), + (0xAC01, 0xAC1B, GraphemeClass::LVT), + (0xAC1C, 0xAC1C, GraphemeClass::LV), + (0xAC1D, 0xAC37, GraphemeClass::LVT), + (0xAC38, 0xAC38, GraphemeClass::LV), + (0xAC39, 0xAC53, GraphemeClass::LVT), + (0xAC54, 0xAC54, GraphemeClass::LV), + (0xAC55, 0xAC6F, GraphemeClass::LVT), + (0xAC70, 0xAC70, GraphemeClass::LV), + (0xAC71, 0xAC8B, GraphemeClass::LVT), + (0xAC8C, 0xAC8C, GraphemeClass::LV), + (0xAC8D, 0xACA7, GraphemeClass::LVT), + (0xACA8, 0xACA8, GraphemeClass::LV), + (0xACA9, 0xACC3, GraphemeClass::LVT), + (0xACC4, 0xACC4, GraphemeClass::LV), + (0xACC5, 0xACDF, GraphemeClass::LVT), + (0xACE0, 0xACE0, GraphemeClass::LV), + (0xACE1, 0xACFB, GraphemeClass::LVT), + (0xACFC, 0xACFC, GraphemeClass::LV), + (0xACFD, 0xAD17, GraphemeClass::LVT), + (0xAD18, 0xAD18, GraphemeClass::LV), + (0xAD19, 0xAD33, GraphemeClass::LVT), + (0xAD34, 0xAD34, GraphemeClass::LV), + (0xAD35, 0xAD4F, GraphemeClass::LVT), + (0xAD50, 0xAD50, GraphemeClass::LV), + (0xAD51, 0xAD6B, GraphemeClass::LVT), + (0xAD6C, 0xAD6C, GraphemeClass::LV), + (0xAD6D, 0xAD87, GraphemeClass::LVT), + (0xAD88, 0xAD88, GraphemeClass::LV), + (0xAD89, 0xADA3, GraphemeClass::LVT), + (0xADA4, 0xADA4, GraphemeClass::LV), + (0xADA5, 0xADBF, GraphemeClass::LVT), + (0xADC0, 0xADC0, GraphemeClass::LV), + (0xADC1, 0xADDB, GraphemeClass::LVT), + (0xADDC, 0xADDC, GraphemeClass::LV), + (0xADDD, 0xADF7, GraphemeClass::LVT), + (0xADF8, 0xADF8, GraphemeClass::LV), + (0xADF9, 0xAE13, GraphemeClass::LVT), + (0xAE14, 0xAE14, GraphemeClass::LV), + (0xAE15, 0xAE2F, GraphemeClass::LVT), + (0xAE30, 0xAE30, GraphemeClass::LV), + (0xAE31, 0xAE4B, GraphemeClass::LVT), + (0xAE4C, 0xAE4C, GraphemeClass::LV), + (0xAE4D, 0xAE67, GraphemeClass::LVT), + (0xAE68, 0xAE68, GraphemeClass::LV), + (0xAE69, 0xAE83, GraphemeClass::LVT), + (0xAE84, 0xAE84, GraphemeClass::LV), + (0xAE85, 0xAE9F, GraphemeClass::LVT), + (0xAEA0, 0xAEA0, GraphemeClass::LV), + (0xAEA1, 0xAEBB, GraphemeClass::LVT), + (0xAEBC, 0xAEBC, GraphemeClass::LV), + (0xAEBD, 0xAED7, GraphemeClass::LVT), + (0xAED8, 0xAED8, GraphemeClass::LV), + (0xAED9, 0xAEF3, GraphemeClass::LVT), + (0xAEF4, 0xAEF4, GraphemeClass::LV), + (0xAEF5, 0xAF0F, GraphemeClass::LVT), + (0xAF10, 0xAF10, GraphemeClass::LV), + (0xAF11, 0xAF2B, GraphemeClass::LVT), + (0xAF2C, 0xAF2C, GraphemeClass::LV), + (0xAF2D, 0xAF47, GraphemeClass::LVT), + (0xAF48, 0xAF48, GraphemeClass::LV), + (0xAF49, 0xAF63, GraphemeClass::LVT), + (0xAF64, 0xAF64, GraphemeClass::LV), + (0xAF65, 0xAF7F, GraphemeClass::LVT), + (0xAF80, 0xAF80, GraphemeClass::LV), + (0xAF81, 0xAF9B, GraphemeClass::LVT), + (0xAF9C, 0xAF9C, GraphemeClass::LV), + (0xAF9D, 0xAFB7, GraphemeClass::LVT), + (0xAFB8, 0xAFB8, GraphemeClass::LV), + (0xAFB9, 0xAFD3, GraphemeClass::LVT), + (0xAFD4, 0xAFD4, GraphemeClass::LV), + (0xAFD5, 0xAFEF, GraphemeClass::LVT), + (0xAFF0, 0xAFF0, GraphemeClass::LV), + (0xAFF1, 0xB00B, GraphemeClass::LVT), + (0xB00C, 0xB00C, GraphemeClass::LV), + (0xB00D, 0xB027, GraphemeClass::LVT), + (0xB028, 0xB028, GraphemeClass::LV), + (0xB029, 0xB043, GraphemeClass::LVT), + (0xB044, 0xB044, GraphemeClass::LV), + (0xB045, 0xB05F, GraphemeClass::LVT), + (0xB060, 0xB060, GraphemeClass::LV), + (0xB061, 0xB07B, GraphemeClass::LVT), + (0xB07C, 0xB07C, GraphemeClass::LV), + (0xB07D, 0xB097, GraphemeClass::LVT), + (0xB098, 0xB098, GraphemeClass::LV), + (0xB099, 0xB0B3, GraphemeClass::LVT), + (0xB0B4, 0xB0B4, GraphemeClass::LV), + (0xB0B5, 0xB0CF, GraphemeClass::LVT), + (0xB0D0, 0xB0D0, GraphemeClass::LV), + (0xB0D1, 0xB0EB, GraphemeClass::LVT), + (0xB0EC, 0xB0EC, GraphemeClass::LV), + (0xB0ED, 0xB107, GraphemeClass::LVT), + (0xB108, 0xB108, GraphemeClass::LV), + (0xB109, 0xB123, GraphemeClass::LVT), + (0xB124, 0xB124, GraphemeClass::LV), + (0xB125, 0xB13F, GraphemeClass::LVT), + (0xB140, 0xB140, GraphemeClass::LV), + (0xB141, 0xB15B, GraphemeClass::LVT), + (0xB15C, 0xB15C, GraphemeClass::LV), + (0xB15D, 0xB177, GraphemeClass::LVT), + (0xB178, 0xB178, GraphemeClass::LV), + (0xB179, 0xB193, GraphemeClass::LVT), + (0xB194, 0xB194, GraphemeClass::LV), + (0xB195, 0xB1AF, GraphemeClass::LVT), + (0xB1B0, 0xB1B0, GraphemeClass::LV), + (0xB1B1, 0xB1CB, GraphemeClass::LVT), + (0xB1CC, 0xB1CC, GraphemeClass::LV), + (0xB1CD, 0xB1E7, GraphemeClass::LVT), + (0xB1E8, 0xB1E8, GraphemeClass::LV), + (0xB1E9, 0xB203, GraphemeClass::LVT), + (0xB204, 0xB204, GraphemeClass::LV), + (0xB205, 0xB21F, GraphemeClass::LVT), + (0xB220, 0xB220, GraphemeClass::LV), + (0xB221, 0xB23B, GraphemeClass::LVT), + (0xB23C, 0xB23C, GraphemeClass::LV), + (0xB23D, 0xB257, GraphemeClass::LVT), + (0xB258, 0xB258, GraphemeClass::LV), + (0xB259, 0xB273, GraphemeClass::LVT), + (0xB274, 0xB274, GraphemeClass::LV), + (0xB275, 0xB28F, GraphemeClass::LVT), + (0xB290, 0xB290, GraphemeClass::LV), + (0xB291, 0xB2AB, GraphemeClass::LVT), + (0xB2AC, 0xB2AC, GraphemeClass::LV), + (0xB2AD, 0xB2C7, GraphemeClass::LVT), + (0xB2C8, 0xB2C8, GraphemeClass::LV), + (0xB2C9, 0xB2E3, GraphemeClass::LVT), + (0xB2E4, 0xB2E4, GraphemeClass::LV), + (0xB2E5, 0xB2FF, GraphemeClass::LVT), + (0xB300, 0xB300, GraphemeClass::LV), + (0xB301, 0xB31B, GraphemeClass::LVT), + (0xB31C, 0xB31C, GraphemeClass::LV), + (0xB31D, 0xB337, GraphemeClass::LVT), + (0xB338, 0xB338, GraphemeClass::LV), + (0xB339, 0xB353, GraphemeClass::LVT), + (0xB354, 0xB354, GraphemeClass::LV), + (0xB355, 0xB36F, GraphemeClass::LVT), + (0xB370, 0xB370, GraphemeClass::LV), + (0xB371, 0xB38B, GraphemeClass::LVT), + (0xB38C, 0xB38C, GraphemeClass::LV), + (0xB38D, 0xB3A7, GraphemeClass::LVT), + (0xB3A8, 0xB3A8, GraphemeClass::LV), + (0xB3A9, 0xB3C3, GraphemeClass::LVT), + (0xB3C4, 0xB3C4, GraphemeClass::LV), + (0xB3C5, 0xB3DF, GraphemeClass::LVT), + (0xB3E0, 0xB3E0, GraphemeClass::LV), + (0xB3E1, 0xB3FB, GraphemeClass::LVT), + (0xB3FC, 0xB3FC, GraphemeClass::LV), + (0xB3FD, 0xB417, GraphemeClass::LVT), + (0xB418, 0xB418, GraphemeClass::LV), + (0xB419, 0xB433, GraphemeClass::LVT), + (0xB434, 0xB434, GraphemeClass::LV), + (0xB435, 0xB44F, GraphemeClass::LVT), + (0xB450, 0xB450, GraphemeClass::LV), + (0xB451, 0xB46B, GraphemeClass::LVT), + (0xB46C, 0xB46C, GraphemeClass::LV), + (0xB46D, 0xB487, GraphemeClass::LVT), + (0xB488, 0xB488, GraphemeClass::LV), + (0xB489, 0xB4A3, GraphemeClass::LVT), + (0xB4A4, 0xB4A4, GraphemeClass::LV), + (0xB4A5, 0xB4BF, GraphemeClass::LVT), + (0xB4C0, 0xB4C0, GraphemeClass::LV), + (0xB4C1, 0xB4DB, GraphemeClass::LVT), + (0xB4DC, 0xB4DC, GraphemeClass::LV), + (0xB4DD, 0xB4F7, GraphemeClass::LVT), + (0xB4F8, 0xB4F8, GraphemeClass::LV), + (0xB4F9, 0xB513, GraphemeClass::LVT), + (0xB514, 0xB514, GraphemeClass::LV), + (0xB515, 0xB52F, GraphemeClass::LVT), + (0xB530, 0xB530, GraphemeClass::LV), + (0xB531, 0xB54B, GraphemeClass::LVT), + (0xB54C, 0xB54C, GraphemeClass::LV), + (0xB54D, 0xB567, GraphemeClass::LVT), + (0xB568, 0xB568, GraphemeClass::LV), + (0xB569, 0xB583, GraphemeClass::LVT), + (0xB584, 0xB584, GraphemeClass::LV), + (0xB585, 0xB59F, GraphemeClass::LVT), + (0xB5A0, 0xB5A0, GraphemeClass::LV), + (0xB5A1, 0xB5BB, GraphemeClass::LVT), + (0xB5BC, 0xB5BC, GraphemeClass::LV), + (0xB5BD, 0xB5D7, GraphemeClass::LVT), + (0xB5D8, 0xB5D8, GraphemeClass::LV), + (0xB5D9, 0xB5F3, GraphemeClass::LVT), + (0xB5F4, 0xB5F4, GraphemeClass::LV), + (0xB5F5, 0xB60F, GraphemeClass::LVT), + (0xB610, 0xB610, GraphemeClass::LV), + (0xB611, 0xB62B, GraphemeClass::LVT), + (0xB62C, 0xB62C, GraphemeClass::LV), + (0xB62D, 0xB647, GraphemeClass::LVT), + (0xB648, 0xB648, GraphemeClass::LV), + (0xB649, 0xB663, GraphemeClass::LVT), + (0xB664, 0xB664, GraphemeClass::LV), + (0xB665, 0xB67F, GraphemeClass::LVT), + (0xB680, 0xB680, GraphemeClass::LV), + (0xB681, 0xB69B, GraphemeClass::LVT), + (0xB69C, 0xB69C, GraphemeClass::LV), + (0xB69D, 0xB6B7, GraphemeClass::LVT), + (0xB6B8, 0xB6B8, GraphemeClass::LV), + (0xB6B9, 0xB6D3, GraphemeClass::LVT), + (0xB6D4, 0xB6D4, GraphemeClass::LV), + (0xB6D5, 0xB6EF, GraphemeClass::LVT), + (0xB6F0, 0xB6F0, GraphemeClass::LV), + (0xB6F1, 0xB70B, GraphemeClass::LVT), + (0xB70C, 0xB70C, GraphemeClass::LV), + (0xB70D, 0xB727, GraphemeClass::LVT), + (0xB728, 0xB728, GraphemeClass::LV), + (0xB729, 0xB743, GraphemeClass::LVT), + (0xB744, 0xB744, GraphemeClass::LV), + (0xB745, 0xB75F, GraphemeClass::LVT), + (0xB760, 0xB760, GraphemeClass::LV), + (0xB761, 0xB77B, GraphemeClass::LVT), + (0xB77C, 0xB77C, GraphemeClass::LV), + (0xB77D, 0xB797, GraphemeClass::LVT), + (0xB798, 0xB798, GraphemeClass::LV), + (0xB799, 0xB7B3, GraphemeClass::LVT), + (0xB7B4, 0xB7B4, GraphemeClass::LV), + (0xB7B5, 0xB7CF, GraphemeClass::LVT), + (0xB7D0, 0xB7D0, GraphemeClass::LV), + (0xB7D1, 0xB7EB, GraphemeClass::LVT), + (0xB7EC, 0xB7EC, GraphemeClass::LV), + (0xB7ED, 0xB807, GraphemeClass::LVT), + (0xB808, 0xB808, GraphemeClass::LV), + (0xB809, 0xB823, GraphemeClass::LVT), + (0xB824, 0xB824, GraphemeClass::LV), + (0xB825, 0xB83F, GraphemeClass::LVT), + (0xB840, 0xB840, GraphemeClass::LV), + (0xB841, 0xB85B, GraphemeClass::LVT), + (0xB85C, 0xB85C, GraphemeClass::LV), + (0xB85D, 0xB877, GraphemeClass::LVT), + (0xB878, 0xB878, GraphemeClass::LV), + (0xB879, 0xB893, GraphemeClass::LVT), + (0xB894, 0xB894, GraphemeClass::LV), + (0xB895, 0xB8AF, GraphemeClass::LVT), + (0xB8B0, 0xB8B0, GraphemeClass::LV), + (0xB8B1, 0xB8CB, GraphemeClass::LVT), + (0xB8CC, 0xB8CC, GraphemeClass::LV), + (0xB8CD, 0xB8E7, GraphemeClass::LVT), + (0xB8E8, 0xB8E8, GraphemeClass::LV), + (0xB8E9, 0xB903, GraphemeClass::LVT), + (0xB904, 0xB904, GraphemeClass::LV), + (0xB905, 0xB91F, GraphemeClass::LVT), + (0xB920, 0xB920, GraphemeClass::LV), + (0xB921, 0xB93B, GraphemeClass::LVT), + (0xB93C, 0xB93C, GraphemeClass::LV), + (0xB93D, 0xB957, GraphemeClass::LVT), + (0xB958, 0xB958, GraphemeClass::LV), + (0xB959, 0xB973, GraphemeClass::LVT), + (0xB974, 0xB974, GraphemeClass::LV), + (0xB975, 0xB98F, GraphemeClass::LVT), + (0xB990, 0xB990, GraphemeClass::LV), + (0xB991, 0xB9AB, GraphemeClass::LVT), + (0xB9AC, 0xB9AC, GraphemeClass::LV), + (0xB9AD, 0xB9C7, GraphemeClass::LVT), + (0xB9C8, 0xB9C8, GraphemeClass::LV), + (0xB9C9, 0xB9E3, GraphemeClass::LVT), + (0xB9E4, 0xB9E4, GraphemeClass::LV), + (0xB9E5, 0xB9FF, GraphemeClass::LVT), + (0xBA00, 0xBA00, GraphemeClass::LV), + (0xBA01, 0xBA1B, GraphemeClass::LVT), + (0xBA1C, 0xBA1C, GraphemeClass::LV), + (0xBA1D, 0xBA37, GraphemeClass::LVT), + (0xBA38, 0xBA38, GraphemeClass::LV), + (0xBA39, 0xBA53, GraphemeClass::LVT), + (0xBA54, 0xBA54, GraphemeClass::LV), + (0xBA55, 0xBA6F, GraphemeClass::LVT), + (0xBA70, 0xBA70, GraphemeClass::LV), + (0xBA71, 0xBA8B, GraphemeClass::LVT), + (0xBA8C, 0xBA8C, GraphemeClass::LV), + (0xBA8D, 0xBAA7, GraphemeClass::LVT), + (0xBAA8, 0xBAA8, GraphemeClass::LV), + (0xBAA9, 0xBAC3, GraphemeClass::LVT), + (0xBAC4, 0xBAC4, GraphemeClass::LV), + (0xBAC5, 0xBADF, GraphemeClass::LVT), + (0xBAE0, 0xBAE0, GraphemeClass::LV), + (0xBAE1, 0xBAFB, GraphemeClass::LVT), + (0xBAFC, 0xBAFC, GraphemeClass::LV), + (0xBAFD, 0xBB17, GraphemeClass::LVT), + (0xBB18, 0xBB18, GraphemeClass::LV), + (0xBB19, 0xBB33, GraphemeClass::LVT), + (0xBB34, 0xBB34, GraphemeClass::LV), + (0xBB35, 0xBB4F, GraphemeClass::LVT), + (0xBB50, 0xBB50, GraphemeClass::LV), + (0xBB51, 0xBB6B, GraphemeClass::LVT), + (0xBB6C, 0xBB6C, GraphemeClass::LV), + (0xBB6D, 0xBB87, GraphemeClass::LVT), + (0xBB88, 0xBB88, GraphemeClass::LV), + (0xBB89, 0xBBA3, GraphemeClass::LVT), + (0xBBA4, 0xBBA4, GraphemeClass::LV), + (0xBBA5, 0xBBBF, GraphemeClass::LVT), + (0xBBC0, 0xBBC0, GraphemeClass::LV), + (0xBBC1, 0xBBDB, GraphemeClass::LVT), + (0xBBDC, 0xBBDC, GraphemeClass::LV), + (0xBBDD, 0xBBF7, GraphemeClass::LVT), + (0xBBF8, 0xBBF8, GraphemeClass::LV), + (0xBBF9, 0xBC13, GraphemeClass::LVT), + (0xBC14, 0xBC14, GraphemeClass::LV), + (0xBC15, 0xBC2F, GraphemeClass::LVT), + (0xBC30, 0xBC30, GraphemeClass::LV), + (0xBC31, 0xBC4B, GraphemeClass::LVT), + (0xBC4C, 0xBC4C, GraphemeClass::LV), + (0xBC4D, 0xBC67, GraphemeClass::LVT), + (0xBC68, 0xBC68, GraphemeClass::LV), + (0xBC69, 0xBC83, GraphemeClass::LVT), + (0xBC84, 0xBC84, GraphemeClass::LV), + (0xBC85, 0xBC9F, GraphemeClass::LVT), + (0xBCA0, 0xBCA0, GraphemeClass::LV), + (0xBCA1, 0xBCBB, GraphemeClass::LVT), + (0xBCBC, 0xBCBC, GraphemeClass::LV), + (0xBCBD, 0xBCD7, GraphemeClass::LVT), + (0xBCD8, 0xBCD8, GraphemeClass::LV), + (0xBCD9, 0xBCF3, GraphemeClass::LVT), + (0xBCF4, 0xBCF4, GraphemeClass::LV), + (0xBCF5, 0xBD0F, GraphemeClass::LVT), + (0xBD10, 0xBD10, GraphemeClass::LV), + (0xBD11, 0xBD2B, GraphemeClass::LVT), + (0xBD2C, 0xBD2C, GraphemeClass::LV), + (0xBD2D, 0xBD47, GraphemeClass::LVT), + (0xBD48, 0xBD48, GraphemeClass::LV), + (0xBD49, 0xBD63, GraphemeClass::LVT), + (0xBD64, 0xBD64, GraphemeClass::LV), + (0xBD65, 0xBD7F, GraphemeClass::LVT), + (0xBD80, 0xBD80, GraphemeClass::LV), + (0xBD81, 0xBD9B, GraphemeClass::LVT), + (0xBD9C, 0xBD9C, GraphemeClass::LV), + (0xBD9D, 0xBDB7, GraphemeClass::LVT), + (0xBDB8, 0xBDB8, GraphemeClass::LV), + (0xBDB9, 0xBDD3, GraphemeClass::LVT), + (0xBDD4, 0xBDD4, GraphemeClass::LV), + (0xBDD5, 0xBDEF, GraphemeClass::LVT), + (0xBDF0, 0xBDF0, GraphemeClass::LV), + (0xBDF1, 0xBE0B, GraphemeClass::LVT), + (0xBE0C, 0xBE0C, GraphemeClass::LV), + (0xBE0D, 0xBE27, GraphemeClass::LVT), + (0xBE28, 0xBE28, GraphemeClass::LV), + (0xBE29, 0xBE43, GraphemeClass::LVT), + (0xBE44, 0xBE44, GraphemeClass::LV), + (0xBE45, 0xBE5F, GraphemeClass::LVT), + (0xBE60, 0xBE60, GraphemeClass::LV), + (0xBE61, 0xBE7B, GraphemeClass::LVT), + (0xBE7C, 0xBE7C, GraphemeClass::LV), + (0xBE7D, 0xBE97, GraphemeClass::LVT), + (0xBE98, 0xBE98, GraphemeClass::LV), + (0xBE99, 0xBEB3, GraphemeClass::LVT), + (0xBEB4, 0xBEB4, GraphemeClass::LV), + (0xBEB5, 0xBECF, GraphemeClass::LVT), + (0xBED0, 0xBED0, GraphemeClass::LV), + (0xBED1, 0xBEEB, GraphemeClass::LVT), + (0xBEEC, 0xBEEC, GraphemeClass::LV), + (0xBEED, 0xBF07, GraphemeClass::LVT), + (0xBF08, 0xBF08, GraphemeClass::LV), + (0xBF09, 0xBF23, GraphemeClass::LVT), + (0xBF24, 0xBF24, GraphemeClass::LV), + (0xBF25, 0xBF3F, GraphemeClass::LVT), + (0xBF40, 0xBF40, GraphemeClass::LV), + (0xBF41, 0xBF5B, GraphemeClass::LVT), + (0xBF5C, 0xBF5C, GraphemeClass::LV), + (0xBF5D, 0xBF77, GraphemeClass::LVT), + (0xBF78, 0xBF78, GraphemeClass::LV), + (0xBF79, 0xBF93, GraphemeClass::LVT), + (0xBF94, 0xBF94, GraphemeClass::LV), + (0xBF95, 0xBFAF, GraphemeClass::LVT), + (0xBFB0, 0xBFB0, GraphemeClass::LV), + (0xBFB1, 0xBFCB, GraphemeClass::LVT), + (0xBFCC, 0xBFCC, GraphemeClass::LV), + (0xBFCD, 0xBFE7, GraphemeClass::LVT), + (0xBFE8, 0xBFE8, GraphemeClass::LV), + (0xBFE9, 0xC003, GraphemeClass::LVT), + (0xC004, 0xC004, GraphemeClass::LV), + (0xC005, 0xC01F, GraphemeClass::LVT), + (0xC020, 0xC020, GraphemeClass::LV), + (0xC021, 0xC03B, GraphemeClass::LVT), + (0xC03C, 0xC03C, GraphemeClass::LV), + (0xC03D, 0xC057, GraphemeClass::LVT), + (0xC058, 0xC058, GraphemeClass::LV), + (0xC059, 0xC073, GraphemeClass::LVT), + (0xC074, 0xC074, GraphemeClass::LV), + (0xC075, 0xC08F, GraphemeClass::LVT), + (0xC090, 0xC090, GraphemeClass::LV), + (0xC091, 0xC0AB, GraphemeClass::LVT), + (0xC0AC, 0xC0AC, GraphemeClass::LV), + (0xC0AD, 0xC0C7, GraphemeClass::LVT), + (0xC0C8, 0xC0C8, GraphemeClass::LV), + (0xC0C9, 0xC0E3, GraphemeClass::LVT), + (0xC0E4, 0xC0E4, GraphemeClass::LV), + (0xC0E5, 0xC0FF, GraphemeClass::LVT), + (0xC100, 0xC100, GraphemeClass::LV), + (0xC101, 0xC11B, GraphemeClass::LVT), + (0xC11C, 0xC11C, GraphemeClass::LV), + (0xC11D, 0xC137, GraphemeClass::LVT), + (0xC138, 0xC138, GraphemeClass::LV), + (0xC139, 0xC153, GraphemeClass::LVT), + (0xC154, 0xC154, GraphemeClass::LV), + (0xC155, 0xC16F, GraphemeClass::LVT), + (0xC170, 0xC170, GraphemeClass::LV), + (0xC171, 0xC18B, GraphemeClass::LVT), + (0xC18C, 0xC18C, GraphemeClass::LV), + (0xC18D, 0xC1A7, GraphemeClass::LVT), + (0xC1A8, 0xC1A8, GraphemeClass::LV), + (0xC1A9, 0xC1C3, GraphemeClass::LVT), + (0xC1C4, 0xC1C4, GraphemeClass::LV), + (0xC1C5, 0xC1DF, GraphemeClass::LVT), + (0xC1E0, 0xC1E0, GraphemeClass::LV), + (0xC1E1, 0xC1FB, GraphemeClass::LVT), + (0xC1FC, 0xC1FC, GraphemeClass::LV), + (0xC1FD, 0xC217, GraphemeClass::LVT), + (0xC218, 0xC218, GraphemeClass::LV), + (0xC219, 0xC233, GraphemeClass::LVT), + (0xC234, 0xC234, GraphemeClass::LV), + (0xC235, 0xC24F, GraphemeClass::LVT), + (0xC250, 0xC250, GraphemeClass::LV), + (0xC251, 0xC26B, GraphemeClass::LVT), + (0xC26C, 0xC26C, GraphemeClass::LV), + (0xC26D, 0xC287, GraphemeClass::LVT), + (0xC288, 0xC288, GraphemeClass::LV), + (0xC289, 0xC2A3, GraphemeClass::LVT), + (0xC2A4, 0xC2A4, GraphemeClass::LV), + (0xC2A5, 0xC2BF, GraphemeClass::LVT), + (0xC2C0, 0xC2C0, GraphemeClass::LV), + (0xC2C1, 0xC2DB, GraphemeClass::LVT), + (0xC2DC, 0xC2DC, GraphemeClass::LV), + (0xC2DD, 0xC2F7, GraphemeClass::LVT), + (0xC2F8, 0xC2F8, GraphemeClass::LV), + (0xC2F9, 0xC313, GraphemeClass::LVT), + (0xC314, 0xC314, GraphemeClass::LV), + (0xC315, 0xC32F, GraphemeClass::LVT), + (0xC330, 0xC330, GraphemeClass::LV), + (0xC331, 0xC34B, GraphemeClass::LVT), + (0xC34C, 0xC34C, GraphemeClass::LV), + (0xC34D, 0xC367, GraphemeClass::LVT), + (0xC368, 0xC368, GraphemeClass::LV), + (0xC369, 0xC383, GraphemeClass::LVT), + (0xC384, 0xC384, GraphemeClass::LV), + (0xC385, 0xC39F, GraphemeClass::LVT), + (0xC3A0, 0xC3A0, GraphemeClass::LV), + (0xC3A1, 0xC3BB, GraphemeClass::LVT), + (0xC3BC, 0xC3BC, GraphemeClass::LV), + (0xC3BD, 0xC3D7, GraphemeClass::LVT), + (0xC3D8, 0xC3D8, GraphemeClass::LV), + (0xC3D9, 0xC3F3, GraphemeClass::LVT), + (0xC3F4, 0xC3F4, GraphemeClass::LV), + (0xC3F5, 0xC40F, GraphemeClass::LVT), + (0xC410, 0xC410, GraphemeClass::LV), + (0xC411, 0xC42B, GraphemeClass::LVT), + (0xC42C, 0xC42C, GraphemeClass::LV), + (0xC42D, 0xC447, GraphemeClass::LVT), + (0xC448, 0xC448, GraphemeClass::LV), + (0xC449, 0xC463, GraphemeClass::LVT), + (0xC464, 0xC464, GraphemeClass::LV), + (0xC465, 0xC47F, GraphemeClass::LVT), + (0xC480, 0xC480, GraphemeClass::LV), + (0xC481, 0xC49B, GraphemeClass::LVT), + (0xC49C, 0xC49C, GraphemeClass::LV), + (0xC49D, 0xC4B7, GraphemeClass::LVT), + (0xC4B8, 0xC4B8, GraphemeClass::LV), + (0xC4B9, 0xC4D3, GraphemeClass::LVT), + (0xC4D4, 0xC4D4, GraphemeClass::LV), + (0xC4D5, 0xC4EF, GraphemeClass::LVT), + (0xC4F0, 0xC4F0, GraphemeClass::LV), + (0xC4F1, 0xC50B, GraphemeClass::LVT), + (0xC50C, 0xC50C, GraphemeClass::LV), + (0xC50D, 0xC527, GraphemeClass::LVT), + (0xC528, 0xC528, GraphemeClass::LV), + (0xC529, 0xC543, GraphemeClass::LVT), + (0xC544, 0xC544, GraphemeClass::LV), + (0xC545, 0xC55F, GraphemeClass::LVT), + (0xC560, 0xC560, GraphemeClass::LV), + (0xC561, 0xC57B, GraphemeClass::LVT), + (0xC57C, 0xC57C, GraphemeClass::LV), + (0xC57D, 0xC597, GraphemeClass::LVT), + (0xC598, 0xC598, GraphemeClass::LV), + (0xC599, 0xC5B3, GraphemeClass::LVT), + (0xC5B4, 0xC5B4, GraphemeClass::LV), + (0xC5B5, 0xC5CF, GraphemeClass::LVT), + (0xC5D0, 0xC5D0, GraphemeClass::LV), + (0xC5D1, 0xC5EB, GraphemeClass::LVT), + (0xC5EC, 0xC5EC, GraphemeClass::LV), + (0xC5ED, 0xC607, GraphemeClass::LVT), + (0xC608, 0xC608, GraphemeClass::LV), + (0xC609, 0xC623, GraphemeClass::LVT), + (0xC624, 0xC624, GraphemeClass::LV), + (0xC625, 0xC63F, GraphemeClass::LVT), + (0xC640, 0xC640, GraphemeClass::LV), + (0xC641, 0xC65B, GraphemeClass::LVT), + (0xC65C, 0xC65C, GraphemeClass::LV), + (0xC65D, 0xC677, GraphemeClass::LVT), + (0xC678, 0xC678, GraphemeClass::LV), + (0xC679, 0xC693, GraphemeClass::LVT), + (0xC694, 0xC694, GraphemeClass::LV), + (0xC695, 0xC6AF, GraphemeClass::LVT), + (0xC6B0, 0xC6B0, GraphemeClass::LV), + (0xC6B1, 0xC6CB, GraphemeClass::LVT), + (0xC6CC, 0xC6CC, GraphemeClass::LV), + (0xC6CD, 0xC6E7, GraphemeClass::LVT), + (0xC6E8, 0xC6E8, GraphemeClass::LV), + (0xC6E9, 0xC703, GraphemeClass::LVT), + (0xC704, 0xC704, GraphemeClass::LV), + (0xC705, 0xC71F, GraphemeClass::LVT), + (0xC720, 0xC720, GraphemeClass::LV), + (0xC721, 0xC73B, GraphemeClass::LVT), + (0xC73C, 0xC73C, GraphemeClass::LV), + (0xC73D, 0xC757, GraphemeClass::LVT), + (0xC758, 0xC758, GraphemeClass::LV), + (0xC759, 0xC773, GraphemeClass::LVT), + (0xC774, 0xC774, GraphemeClass::LV), + (0xC775, 0xC78F, GraphemeClass::LVT), + (0xC790, 0xC790, GraphemeClass::LV), + (0xC791, 0xC7AB, GraphemeClass::LVT), + (0xC7AC, 0xC7AC, GraphemeClass::LV), + (0xC7AD, 0xC7C7, GraphemeClass::LVT), + (0xC7C8, 0xC7C8, GraphemeClass::LV), + (0xC7C9, 0xC7E3, GraphemeClass::LVT), + (0xC7E4, 0xC7E4, GraphemeClass::LV), + (0xC7E5, 0xC7FF, GraphemeClass::LVT), + (0xC800, 0xC800, GraphemeClass::LV), + (0xC801, 0xC81B, GraphemeClass::LVT), + (0xC81C, 0xC81C, GraphemeClass::LV), + (0xC81D, 0xC837, GraphemeClass::LVT), + (0xC838, 0xC838, GraphemeClass::LV), + (0xC839, 0xC853, GraphemeClass::LVT), + (0xC854, 0xC854, GraphemeClass::LV), + (0xC855, 0xC86F, GraphemeClass::LVT), + (0xC870, 0xC870, GraphemeClass::LV), + (0xC871, 0xC88B, GraphemeClass::LVT), + (0xC88C, 0xC88C, GraphemeClass::LV), + (0xC88D, 0xC8A7, GraphemeClass::LVT), + (0xC8A8, 0xC8A8, GraphemeClass::LV), + (0xC8A9, 0xC8C3, GraphemeClass::LVT), + (0xC8C4, 0xC8C4, GraphemeClass::LV), + (0xC8C5, 0xC8DF, GraphemeClass::LVT), + (0xC8E0, 0xC8E0, GraphemeClass::LV), + (0xC8E1, 0xC8FB, GraphemeClass::LVT), + (0xC8FC, 0xC8FC, GraphemeClass::LV), + (0xC8FD, 0xC917, GraphemeClass::LVT), + (0xC918, 0xC918, GraphemeClass::LV), + (0xC919, 0xC933, GraphemeClass::LVT), + (0xC934, 0xC934, GraphemeClass::LV), + (0xC935, 0xC94F, GraphemeClass::LVT), + (0xC950, 0xC950, GraphemeClass::LV), + (0xC951, 0xC96B, GraphemeClass::LVT), + (0xC96C, 0xC96C, GraphemeClass::LV), + (0xC96D, 0xC987, GraphemeClass::LVT), + (0xC988, 0xC988, GraphemeClass::LV), + (0xC989, 0xC9A3, GraphemeClass::LVT), + (0xC9A4, 0xC9A4, GraphemeClass::LV), + (0xC9A5, 0xC9BF, GraphemeClass::LVT), + (0xC9C0, 0xC9C0, GraphemeClass::LV), + (0xC9C1, 0xC9DB, GraphemeClass::LVT), + (0xC9DC, 0xC9DC, GraphemeClass::LV), + (0xC9DD, 0xC9F7, GraphemeClass::LVT), + (0xC9F8, 0xC9F8, GraphemeClass::LV), + (0xC9F9, 0xCA13, GraphemeClass::LVT), + (0xCA14, 0xCA14, GraphemeClass::LV), + (0xCA15, 0xCA2F, GraphemeClass::LVT), + (0xCA30, 0xCA30, GraphemeClass::LV), + (0xCA31, 0xCA4B, GraphemeClass::LVT), + (0xCA4C, 0xCA4C, GraphemeClass::LV), + (0xCA4D, 0xCA67, GraphemeClass::LVT), + (0xCA68, 0xCA68, GraphemeClass::LV), + (0xCA69, 0xCA83, GraphemeClass::LVT), + (0xCA84, 0xCA84, GraphemeClass::LV), + (0xCA85, 0xCA9F, GraphemeClass::LVT), + (0xCAA0, 0xCAA0, GraphemeClass::LV), + (0xCAA1, 0xCABB, GraphemeClass::LVT), + (0xCABC, 0xCABC, GraphemeClass::LV), + (0xCABD, 0xCAD7, GraphemeClass::LVT), + (0xCAD8, 0xCAD8, GraphemeClass::LV), + (0xCAD9, 0xCAF3, GraphemeClass::LVT), + (0xCAF4, 0xCAF4, GraphemeClass::LV), + (0xCAF5, 0xCB0F, GraphemeClass::LVT), + (0xCB10, 0xCB10, GraphemeClass::LV), + (0xCB11, 0xCB2B, GraphemeClass::LVT), + (0xCB2C, 0xCB2C, GraphemeClass::LV), + (0xCB2D, 0xCB47, GraphemeClass::LVT), + (0xCB48, 0xCB48, GraphemeClass::LV), + (0xCB49, 0xCB63, GraphemeClass::LVT), + (0xCB64, 0xCB64, GraphemeClass::LV), + (0xCB65, 0xCB7F, GraphemeClass::LVT), + (0xCB80, 0xCB80, GraphemeClass::LV), + (0xCB81, 0xCB9B, GraphemeClass::LVT), + (0xCB9C, 0xCB9C, GraphemeClass::LV), + (0xCB9D, 0xCBB7, GraphemeClass::LVT), + (0xCBB8, 0xCBB8, GraphemeClass::LV), + (0xCBB9, 0xCBD3, GraphemeClass::LVT), + (0xCBD4, 0xCBD4, GraphemeClass::LV), + (0xCBD5, 0xCBEF, GraphemeClass::LVT), + (0xCBF0, 0xCBF0, GraphemeClass::LV), + (0xCBF1, 0xCC0B, GraphemeClass::LVT), + (0xCC0C, 0xCC0C, GraphemeClass::LV), + (0xCC0D, 0xCC27, GraphemeClass::LVT), + (0xCC28, 0xCC28, GraphemeClass::LV), + (0xCC29, 0xCC43, GraphemeClass::LVT), + (0xCC44, 0xCC44, GraphemeClass::LV), + (0xCC45, 0xCC5F, GraphemeClass::LVT), + (0xCC60, 0xCC60, GraphemeClass::LV), + (0xCC61, 0xCC7B, GraphemeClass::LVT), + (0xCC7C, 0xCC7C, GraphemeClass::LV), + (0xCC7D, 0xCC97, GraphemeClass::LVT), + (0xCC98, 0xCC98, GraphemeClass::LV), + (0xCC99, 0xCCB3, GraphemeClass::LVT), + (0xCCB4, 0xCCB4, GraphemeClass::LV), + (0xCCB5, 0xCCCF, GraphemeClass::LVT), + (0xCCD0, 0xCCD0, GraphemeClass::LV), + (0xCCD1, 0xCCEB, GraphemeClass::LVT), + (0xCCEC, 0xCCEC, GraphemeClass::LV), + (0xCCED, 0xCD07, GraphemeClass::LVT), + (0xCD08, 0xCD08, GraphemeClass::LV), + (0xCD09, 0xCD23, GraphemeClass::LVT), + (0xCD24, 0xCD24, GraphemeClass::LV), + (0xCD25, 0xCD3F, GraphemeClass::LVT), + (0xCD40, 0xCD40, GraphemeClass::LV), + (0xCD41, 0xCD5B, GraphemeClass::LVT), + (0xCD5C, 0xCD5C, GraphemeClass::LV), + (0xCD5D, 0xCD77, GraphemeClass::LVT), + (0xCD78, 0xCD78, GraphemeClass::LV), + (0xCD79, 0xCD93, GraphemeClass::LVT), + (0xCD94, 0xCD94, GraphemeClass::LV), + (0xCD95, 0xCDAF, GraphemeClass::LVT), + (0xCDB0, 0xCDB0, GraphemeClass::LV), + (0xCDB1, 0xCDCB, GraphemeClass::LVT), + (0xCDCC, 0xCDCC, GraphemeClass::LV), + (0xCDCD, 0xCDE7, GraphemeClass::LVT), + (0xCDE8, 0xCDE8, GraphemeClass::LV), + (0xCDE9, 0xCE03, GraphemeClass::LVT), + (0xCE04, 0xCE04, GraphemeClass::LV), + (0xCE05, 0xCE1F, GraphemeClass::LVT), + (0xCE20, 0xCE20, GraphemeClass::LV), + (0xCE21, 0xCE3B, GraphemeClass::LVT), + (0xCE3C, 0xCE3C, GraphemeClass::LV), + (0xCE3D, 0xCE57, GraphemeClass::LVT), + (0xCE58, 0xCE58, GraphemeClass::LV), + (0xCE59, 0xCE73, GraphemeClass::LVT), + (0xCE74, 0xCE74, GraphemeClass::LV), + (0xCE75, 0xCE8F, GraphemeClass::LVT), + (0xCE90, 0xCE90, GraphemeClass::LV), + (0xCE91, 0xCEAB, GraphemeClass::LVT), + (0xCEAC, 0xCEAC, GraphemeClass::LV), + (0xCEAD, 0xCEC7, GraphemeClass::LVT), + (0xCEC8, 0xCEC8, GraphemeClass::LV), + (0xCEC9, 0xCEE3, GraphemeClass::LVT), + (0xCEE4, 0xCEE4, GraphemeClass::LV), + (0xCEE5, 0xCEFF, GraphemeClass::LVT), + (0xCF00, 0xCF00, GraphemeClass::LV), + (0xCF01, 0xCF1B, GraphemeClass::LVT), + (0xCF1C, 0xCF1C, GraphemeClass::LV), + (0xCF1D, 0xCF37, GraphemeClass::LVT), + (0xCF38, 0xCF38, GraphemeClass::LV), + (0xCF39, 0xCF53, GraphemeClass::LVT), + (0xCF54, 0xCF54, GraphemeClass::LV), + (0xCF55, 0xCF6F, GraphemeClass::LVT), + (0xCF70, 0xCF70, GraphemeClass::LV), + (0xCF71, 0xCF8B, GraphemeClass::LVT), + (0xCF8C, 0xCF8C, GraphemeClass::LV), + (0xCF8D, 0xCFA7, GraphemeClass::LVT), + (0xCFA8, 0xCFA8, GraphemeClass::LV), + (0xCFA9, 0xCFC3, GraphemeClass::LVT), + (0xCFC4, 0xCFC4, GraphemeClass::LV), + (0xCFC5, 0xCFDF, GraphemeClass::LVT), + (0xCFE0, 0xCFE0, GraphemeClass::LV), + (0xCFE1, 0xCFFB, GraphemeClass::LVT), + (0xCFFC, 0xCFFC, GraphemeClass::LV), + (0xCFFD, 0xD017, GraphemeClass::LVT), + (0xD018, 0xD018, GraphemeClass::LV), + (0xD019, 0xD033, GraphemeClass::LVT), + (0xD034, 0xD034, GraphemeClass::LV), + (0xD035, 0xD04F, GraphemeClass::LVT), + (0xD050, 0xD050, GraphemeClass::LV), + (0xD051, 0xD06B, GraphemeClass::LVT), + (0xD06C, 0xD06C, GraphemeClass::LV), + (0xD06D, 0xD087, GraphemeClass::LVT), + (0xD088, 0xD088, GraphemeClass::LV), + (0xD089, 0xD0A3, GraphemeClass::LVT), + (0xD0A4, 0xD0A4, GraphemeClass::LV), + (0xD0A5, 0xD0BF, GraphemeClass::LVT), + (0xD0C0, 0xD0C0, GraphemeClass::LV), + (0xD0C1, 0xD0DB, GraphemeClass::LVT), + (0xD0DC, 0xD0DC, GraphemeClass::LV), + (0xD0DD, 0xD0F7, GraphemeClass::LVT), + (0xD0F8, 0xD0F8, GraphemeClass::LV), + (0xD0F9, 0xD113, GraphemeClass::LVT), + (0xD114, 0xD114, GraphemeClass::LV), + (0xD115, 0xD12F, GraphemeClass::LVT), + (0xD130, 0xD130, GraphemeClass::LV), + (0xD131, 0xD14B, GraphemeClass::LVT), + (0xD14C, 0xD14C, GraphemeClass::LV), + (0xD14D, 0xD167, GraphemeClass::LVT), + (0xD168, 0xD168, GraphemeClass::LV), + (0xD169, 0xD183, GraphemeClass::LVT), + (0xD184, 0xD184, GraphemeClass::LV), + (0xD185, 0xD19F, GraphemeClass::LVT), + (0xD1A0, 0xD1A0, GraphemeClass::LV), + (0xD1A1, 0xD1BB, GraphemeClass::LVT), + (0xD1BC, 0xD1BC, GraphemeClass::LV), + (0xD1BD, 0xD1D7, GraphemeClass::LVT), + (0xD1D8, 0xD1D8, GraphemeClass::LV), + (0xD1D9, 0xD1F3, GraphemeClass::LVT), + (0xD1F4, 0xD1F4, GraphemeClass::LV), + (0xD1F5, 0xD20F, GraphemeClass::LVT), + (0xD210, 0xD210, GraphemeClass::LV), + (0xD211, 0xD22B, GraphemeClass::LVT), + (0xD22C, 0xD22C, GraphemeClass::LV), + (0xD22D, 0xD247, GraphemeClass::LVT), + (0xD248, 0xD248, GraphemeClass::LV), + (0xD249, 0xD263, GraphemeClass::LVT), + (0xD264, 0xD264, GraphemeClass::LV), + (0xD265, 0xD27F, GraphemeClass::LVT), + (0xD280, 0xD280, GraphemeClass::LV), + (0xD281, 0xD29B, GraphemeClass::LVT), + (0xD29C, 0xD29C, GraphemeClass::LV), + (0xD29D, 0xD2B7, GraphemeClass::LVT), + (0xD2B8, 0xD2B8, GraphemeClass::LV), + (0xD2B9, 0xD2D3, GraphemeClass::LVT), + (0xD2D4, 0xD2D4, GraphemeClass::LV), + (0xD2D5, 0xD2EF, GraphemeClass::LVT), + (0xD2F0, 0xD2F0, GraphemeClass::LV), + (0xD2F1, 0xD30B, GraphemeClass::LVT), + (0xD30C, 0xD30C, GraphemeClass::LV), + (0xD30D, 0xD327, GraphemeClass::LVT), + (0xD328, 0xD328, GraphemeClass::LV), + (0xD329, 0xD343, GraphemeClass::LVT), + (0xD344, 0xD344, GraphemeClass::LV), + (0xD345, 0xD35F, GraphemeClass::LVT), + (0xD360, 0xD360, GraphemeClass::LV), + (0xD361, 0xD37B, GraphemeClass::LVT), + (0xD37C, 0xD37C, GraphemeClass::LV), + (0xD37D, 0xD397, GraphemeClass::LVT), + (0xD398, 0xD398, GraphemeClass::LV), + (0xD399, 0xD3B3, GraphemeClass::LVT), + (0xD3B4, 0xD3B4, GraphemeClass::LV), + (0xD3B5, 0xD3CF, GraphemeClass::LVT), + (0xD3D0, 0xD3D0, GraphemeClass::LV), + (0xD3D1, 0xD3EB, GraphemeClass::LVT), + (0xD3EC, 0xD3EC, GraphemeClass::LV), + (0xD3ED, 0xD407, GraphemeClass::LVT), + (0xD408, 0xD408, GraphemeClass::LV), + (0xD409, 0xD423, GraphemeClass::LVT), + (0xD424, 0xD424, GraphemeClass::LV), + (0xD425, 0xD43F, GraphemeClass::LVT), + (0xD440, 0xD440, GraphemeClass::LV), + (0xD441, 0xD45B, GraphemeClass::LVT), + (0xD45C, 0xD45C, GraphemeClass::LV), + (0xD45D, 0xD477, GraphemeClass::LVT), + (0xD478, 0xD478, GraphemeClass::LV), + (0xD479, 0xD493, GraphemeClass::LVT), + (0xD494, 0xD494, GraphemeClass::LV), + (0xD495, 0xD4AF, GraphemeClass::LVT), + (0xD4B0, 0xD4B0, GraphemeClass::LV), + (0xD4B1, 0xD4CB, GraphemeClass::LVT), + (0xD4CC, 0xD4CC, GraphemeClass::LV), + (0xD4CD, 0xD4E7, GraphemeClass::LVT), + (0xD4E8, 0xD4E8, GraphemeClass::LV), + (0xD4E9, 0xD503, GraphemeClass::LVT), + (0xD504, 0xD504, GraphemeClass::LV), + (0xD505, 0xD51F, GraphemeClass::LVT), + (0xD520, 0xD520, GraphemeClass::LV), + (0xD521, 0xD53B, GraphemeClass::LVT), + (0xD53C, 0xD53C, GraphemeClass::LV), + (0xD53D, 0xD557, GraphemeClass::LVT), + (0xD558, 0xD558, GraphemeClass::LV), + (0xD559, 0xD573, GraphemeClass::LVT), + (0xD574, 0xD574, GraphemeClass::LV), + (0xD575, 0xD58F, GraphemeClass::LVT), + (0xD590, 0xD590, GraphemeClass::LV), + (0xD591, 0xD5AB, GraphemeClass::LVT), + (0xD5AC, 0xD5AC, GraphemeClass::LV), + (0xD5AD, 0xD5C7, GraphemeClass::LVT), + (0xD5C8, 0xD5C8, GraphemeClass::LV), + (0xD5C9, 0xD5E3, GraphemeClass::LVT), + (0xD5E4, 0xD5E4, GraphemeClass::LV), + (0xD5E5, 0xD5FF, GraphemeClass::LVT), + (0xD600, 0xD600, GraphemeClass::LV), + (0xD601, 0xD61B, GraphemeClass::LVT), + (0xD61C, 0xD61C, GraphemeClass::LV), + (0xD61D, 0xD637, GraphemeClass::LVT), + (0xD638, 0xD638, GraphemeClass::LV), + (0xD639, 0xD653, GraphemeClass::LVT), + (0xD654, 0xD654, GraphemeClass::LV), + (0xD655, 0xD66F, GraphemeClass::LVT), + (0xD670, 0xD670, GraphemeClass::LV), + (0xD671, 0xD68B, GraphemeClass::LVT), + (0xD68C, 0xD68C, GraphemeClass::LV), + (0xD68D, 0xD6A7, GraphemeClass::LVT), + (0xD6A8, 0xD6A8, GraphemeClass::LV), + (0xD6A9, 0xD6C3, GraphemeClass::LVT), + (0xD6C4, 0xD6C4, GraphemeClass::LV), + (0xD6C5, 0xD6DF, GraphemeClass::LVT), + (0xD6E0, 0xD6E0, GraphemeClass::LV), + (0xD6E1, 0xD6FB, GraphemeClass::LVT), + (0xD6FC, 0xD6FC, GraphemeClass::LV), + (0xD6FD, 0xD717, GraphemeClass::LVT), + (0xD718, 0xD718, GraphemeClass::LV), + (0xD719, 0xD733, GraphemeClass::LVT), + (0xD734, 0xD734, GraphemeClass::LV), + (0xD735, 0xD74F, GraphemeClass::LVT), + (0xD750, 0xD750, GraphemeClass::LV), + (0xD751, 0xD76B, GraphemeClass::LVT), + (0xD76C, 0xD76C, GraphemeClass::LV), + (0xD76D, 0xD787, GraphemeClass::LVT), + (0xD788, 0xD788, GraphemeClass::LV), + (0xD789, 0xD7A3, GraphemeClass::LVT), + (0xD7B0, 0xD7C6, GraphemeClass::V), + (0xD7CB, 0xD7FB, GraphemeClass::T), + (0xFB1E, 0xFB1E, GraphemeClass::ExtendIncb), + (0xFE00, 0xFE0F, GraphemeClass::ExtendIncb), + (0xFE20, 0xFE2F, GraphemeClass::ExtendIncb), + (0xFEFF, 0xFEFF, GraphemeClass::Control), + (0xFF9E, 0xFF9F, GraphemeClass::ExtendIncb), + (0xFFF0, 0xFFFB, GraphemeClass::Control), + (0x101FD, 0x101FD, GraphemeClass::ExtendIncb), + (0x102E0, 0x102E0, GraphemeClass::ExtendIncb), + (0x10376, 0x1037A, GraphemeClass::ExtendIncb), + (0x10A00, 0x10A00, GraphemeClass::Consonant), + (0x10A01, 0x10A03, GraphemeClass::ExtendIncb), + (0x10A05, 0x10A06, GraphemeClass::ExtendIncb), + (0x10A0C, 0x10A0F, GraphemeClass::ExtendIncb), + (0x10A10, 0x10A13, GraphemeClass::Consonant), + (0x10A15, 0x10A17, GraphemeClass::Consonant), + (0x10A19, 0x10A35, GraphemeClass::Consonant), + (0x10A38, 0x10A3A, GraphemeClass::ExtendIncb), + (0x10A3F, 0x10A3F, GraphemeClass::Linker), + (0x10AE5, 0x10AE6, GraphemeClass::ExtendIncb), + (0x10D24, 0x10D27, GraphemeClass::ExtendIncb), + (0x10D69, 0x10D6D, GraphemeClass::ExtendIncb), + (0x10EAB, 0x10EAC, GraphemeClass::ExtendIncb), + (0x10EFA, 0x10EFF, GraphemeClass::ExtendIncb), + (0x10F46, 0x10F50, GraphemeClass::ExtendIncb), + (0x10F82, 0x10F85, GraphemeClass::ExtendIncb), + (0x11000, 0x11000, GraphemeClass::SpacingMark), + (0x11001, 0x11001, GraphemeClass::ExtendIncb), + (0x11002, 0x11002, GraphemeClass::SpacingMark), + (0x11038, 0x11046, GraphemeClass::ExtendIncb), + (0x11070, 0x11070, GraphemeClass::ExtendIncb), + (0x11073, 0x11074, GraphemeClass::ExtendIncb), + (0x1107F, 0x11081, GraphemeClass::ExtendIncb), + (0x11082, 0x11082, GraphemeClass::SpacingMark), + (0x110B0, 0x110B2, GraphemeClass::SpacingMark), + (0x110B3, 0x110B6, GraphemeClass::ExtendIncb), + (0x110B7, 0x110B8, GraphemeClass::SpacingMark), + (0x110B9, 0x110BA, GraphemeClass::ExtendIncb), + (0x110BD, 0x110BD, GraphemeClass::Prepend), + (0x110C2, 0x110C2, GraphemeClass::ExtendIncb), + (0x110CD, 0x110CD, GraphemeClass::Prepend), + (0x11100, 0x11102, GraphemeClass::ExtendIncb), + (0x11103, 0x11126, GraphemeClass::Consonant), + (0x11127, 0x1112B, GraphemeClass::ExtendIncb), + (0x1112C, 0x1112C, GraphemeClass::SpacingMark), + (0x1112D, 0x11132, GraphemeClass::ExtendIncb), + (0x11133, 0x11133, GraphemeClass::Linker), + (0x11134, 0x11134, GraphemeClass::ExtendIncb), + (0x11144, 0x11144, GraphemeClass::Consonant), + (0x11145, 0x11146, GraphemeClass::SpacingMark), + (0x11147, 0x11147, GraphemeClass::Consonant), + (0x11173, 0x11173, GraphemeClass::ExtendIncb), + (0x11180, 0x11181, GraphemeClass::ExtendIncb), + (0x11182, 0x11182, GraphemeClass::SpacingMark), + (0x111B3, 0x111B5, GraphemeClass::SpacingMark), + (0x111B6, 0x111BE, GraphemeClass::ExtendIncb), + (0x111BF, 0x111BF, GraphemeClass::SpacingMark), + (0x111C0, 0x111C0, GraphemeClass::ExtendIncb), + (0x111C2, 0x111C3, GraphemeClass::Prepend), + (0x111C9, 0x111CC, GraphemeClass::ExtendIncb), + (0x111CE, 0x111CE, GraphemeClass::SpacingMark), + (0x111CF, 0x111CF, GraphemeClass::ExtendIncb), + (0x1122C, 0x1122E, GraphemeClass::SpacingMark), + (0x1122F, 0x11231, GraphemeClass::ExtendIncb), + (0x11232, 0x11233, GraphemeClass::SpacingMark), + (0x11234, 0x11237, GraphemeClass::ExtendIncb), + (0x1123E, 0x1123E, GraphemeClass::ExtendIncb), + (0x11241, 0x11241, GraphemeClass::ExtendIncb), + (0x112DF, 0x112DF, GraphemeClass::ExtendIncb), + (0x112E0, 0x112E2, GraphemeClass::SpacingMark), + (0x112E3, 0x112EA, GraphemeClass::ExtendIncb), + (0x11300, 0x11301, GraphemeClass::ExtendIncb), + (0x11302, 0x11303, GraphemeClass::SpacingMark), + (0x1133B, 0x1133C, GraphemeClass::ExtendIncb), + (0x1133E, 0x1133E, GraphemeClass::ExtendIncb), + (0x1133F, 0x1133F, GraphemeClass::SpacingMark), + (0x11340, 0x11340, GraphemeClass::ExtendIncb), + (0x11341, 0x11344, GraphemeClass::SpacingMark), + (0x11347, 0x11348, GraphemeClass::SpacingMark), + (0x1134B, 0x1134C, GraphemeClass::SpacingMark), + (0x1134D, 0x1134D, GraphemeClass::ExtendIncb), + (0x11357, 0x11357, GraphemeClass::ExtendIncb), + (0x11362, 0x11363, GraphemeClass::SpacingMark), + (0x11366, 0x1136C, GraphemeClass::ExtendIncb), + (0x11370, 0x11374, GraphemeClass::ExtendIncb), + (0x11380, 0x11389, GraphemeClass::Consonant), + (0x1138B, 0x1138B, GraphemeClass::Consonant), + (0x1138E, 0x1138E, GraphemeClass::Consonant), + (0x11390, 0x113B5, GraphemeClass::Consonant), + (0x113B8, 0x113B8, GraphemeClass::ExtendIncb), + (0x113B9, 0x113BA, GraphemeClass::SpacingMark), + (0x113BB, 0x113C0, GraphemeClass::ExtendIncb), + (0x113C2, 0x113C2, GraphemeClass::ExtendIncb), + (0x113C5, 0x113C5, GraphemeClass::ExtendIncb), + (0x113C7, 0x113C9, GraphemeClass::ExtendIncb), + (0x113CA, 0x113CA, GraphemeClass::SpacingMark), + (0x113CC, 0x113CD, GraphemeClass::SpacingMark), + (0x113CE, 0x113CF, GraphemeClass::ExtendIncb), + (0x113D0, 0x113D0, GraphemeClass::Linker), + (0x113D1, 0x113D1, GraphemeClass::Prepend), + (0x113D2, 0x113D2, GraphemeClass::ExtendIncb), + (0x113E1, 0x113E2, GraphemeClass::ExtendIncb), + (0x11435, 0x11437, GraphemeClass::SpacingMark), + (0x11438, 0x1143F, GraphemeClass::ExtendIncb), + (0x11440, 0x11441, GraphemeClass::SpacingMark), + (0x11442, 0x11444, GraphemeClass::ExtendIncb), + (0x11445, 0x11445, GraphemeClass::SpacingMark), + (0x11446, 0x11446, GraphemeClass::ExtendIncb), + (0x1145E, 0x1145E, GraphemeClass::ExtendIncb), + (0x114B0, 0x114B0, GraphemeClass::ExtendIncb), + (0x114B1, 0x114B2, GraphemeClass::SpacingMark), + (0x114B3, 0x114B8, GraphemeClass::ExtendIncb), + (0x114B9, 0x114B9, GraphemeClass::SpacingMark), + (0x114BA, 0x114BA, GraphemeClass::ExtendIncb), + (0x114BB, 0x114BC, GraphemeClass::SpacingMark), + (0x114BD, 0x114BD, GraphemeClass::ExtendIncb), + (0x114BE, 0x114BE, GraphemeClass::SpacingMark), + (0x114BF, 0x114C0, GraphemeClass::ExtendIncb), + (0x114C1, 0x114C1, GraphemeClass::SpacingMark), + (0x114C2, 0x114C3, GraphemeClass::ExtendIncb), + (0x115AF, 0x115AF, GraphemeClass::ExtendIncb), + (0x115B0, 0x115B1, GraphemeClass::SpacingMark), + (0x115B2, 0x115B5, GraphemeClass::ExtendIncb), + (0x115B8, 0x115BB, GraphemeClass::SpacingMark), + (0x115BC, 0x115BD, GraphemeClass::ExtendIncb), + (0x115BE, 0x115BE, GraphemeClass::SpacingMark), + (0x115BF, 0x115C0, GraphemeClass::ExtendIncb), + (0x115DC, 0x115DD, GraphemeClass::ExtendIncb), + (0x11630, 0x11632, GraphemeClass::SpacingMark), + (0x11633, 0x1163A, GraphemeClass::ExtendIncb), + (0x1163B, 0x1163C, GraphemeClass::SpacingMark), + (0x1163D, 0x1163D, GraphemeClass::ExtendIncb), + (0x1163E, 0x1163E, GraphemeClass::SpacingMark), + (0x1163F, 0x11640, GraphemeClass::ExtendIncb), + (0x116AB, 0x116AB, GraphemeClass::ExtendIncb), + (0x116AC, 0x116AC, GraphemeClass::SpacingMark), + (0x116AD, 0x116AD, GraphemeClass::ExtendIncb), + (0x116AE, 0x116AF, GraphemeClass::SpacingMark), + (0x116B0, 0x116B7, GraphemeClass::ExtendIncb), + (0x1171D, 0x1171D, GraphemeClass::ExtendIncb), + (0x1171E, 0x1171E, GraphemeClass::SpacingMark), + (0x1171F, 0x1171F, GraphemeClass::ExtendIncb), + (0x11722, 0x11725, GraphemeClass::ExtendIncb), + (0x11726, 0x11726, GraphemeClass::SpacingMark), + (0x11727, 0x1172B, GraphemeClass::ExtendIncb), + (0x1182C, 0x1182E, GraphemeClass::SpacingMark), + (0x1182F, 0x11837, GraphemeClass::ExtendIncb), + (0x11838, 0x11838, GraphemeClass::SpacingMark), + (0x11839, 0x1183A, GraphemeClass::ExtendIncb), + (0x11900, 0x11906, GraphemeClass::Consonant), + (0x11909, 0x11909, GraphemeClass::Consonant), + (0x1190C, 0x11913, GraphemeClass::Consonant), + (0x11915, 0x11916, GraphemeClass::Consonant), + (0x11918, 0x1192F, GraphemeClass::Consonant), + (0x11930, 0x11930, GraphemeClass::ExtendIncb), + (0x11931, 0x11935, GraphemeClass::SpacingMark), + (0x11937, 0x11938, GraphemeClass::SpacingMark), + (0x1193B, 0x1193D, GraphemeClass::ExtendIncb), + (0x1193E, 0x1193E, GraphemeClass::Linker), + (0x1193F, 0x1193F, GraphemeClass::Prepend), + (0x11940, 0x11940, GraphemeClass::SpacingMark), + (0x11941, 0x11941, GraphemeClass::Prepend), + (0x11942, 0x11942, GraphemeClass::SpacingMark), + (0x11943, 0x11943, GraphemeClass::ExtendIncb), + (0x119D1, 0x119D3, GraphemeClass::SpacingMark), + (0x119D4, 0x119D7, GraphemeClass::ExtendIncb), + (0x119DA, 0x119DB, GraphemeClass::ExtendIncb), + (0x119DC, 0x119DF, GraphemeClass::SpacingMark), + (0x119E0, 0x119E0, GraphemeClass::ExtendIncb), + (0x119E4, 0x119E4, GraphemeClass::SpacingMark), + (0x11A00, 0x11A00, GraphemeClass::Consonant), + (0x11A01, 0x11A0A, GraphemeClass::ExtendIncb), + (0x11A0B, 0x11A32, GraphemeClass::Consonant), + (0x11A33, 0x11A38, GraphemeClass::ExtendIncb), + (0x11A39, 0x11A39, GraphemeClass::SpacingMark), + (0x11A3B, 0x11A3E, GraphemeClass::ExtendIncb), + (0x11A47, 0x11A47, GraphemeClass::Linker), + (0x11A50, 0x11A50, GraphemeClass::Consonant), + (0x11A51, 0x11A56, GraphemeClass::ExtendIncb), + (0x11A57, 0x11A58, GraphemeClass::SpacingMark), + (0x11A59, 0x11A5B, GraphemeClass::ExtendIncb), + (0x11A5C, 0x11A83, GraphemeClass::Consonant), + (0x11A84, 0x11A89, GraphemeClass::Prepend), + (0x11A8A, 0x11A96, GraphemeClass::ExtendIncb), + (0x11A97, 0x11A97, GraphemeClass::SpacingMark), + (0x11A98, 0x11A98, GraphemeClass::ExtendIncb), + (0x11A99, 0x11A99, GraphemeClass::Linker), + (0x11B60, 0x11B60, GraphemeClass::ExtendIncb), + (0x11B61, 0x11B61, GraphemeClass::SpacingMark), + (0x11B62, 0x11B64, GraphemeClass::ExtendIncb), + (0x11B65, 0x11B65, GraphemeClass::SpacingMark), + (0x11B66, 0x11B66, GraphemeClass::ExtendIncb), + (0x11B67, 0x11B67, GraphemeClass::SpacingMark), + (0x11C2F, 0x11C2F, GraphemeClass::SpacingMark), + (0x11C30, 0x11C36, GraphemeClass::ExtendIncb), + (0x11C38, 0x11C3D, GraphemeClass::ExtendIncb), + (0x11C3E, 0x11C3E, GraphemeClass::SpacingMark), + (0x11C3F, 0x11C3F, GraphemeClass::ExtendIncb), + (0x11C92, 0x11CA7, GraphemeClass::ExtendIncb), + (0x11CA9, 0x11CA9, GraphemeClass::SpacingMark), + (0x11CAA, 0x11CB0, GraphemeClass::ExtendIncb), + (0x11CB1, 0x11CB1, GraphemeClass::SpacingMark), + (0x11CB2, 0x11CB3, GraphemeClass::ExtendIncb), + (0x11CB4, 0x11CB4, GraphemeClass::SpacingMark), + (0x11CB5, 0x11CB6, GraphemeClass::ExtendIncb), + (0x11D31, 0x11D36, GraphemeClass::ExtendIncb), + (0x11D3A, 0x11D3A, GraphemeClass::ExtendIncb), + (0x11D3C, 0x11D3D, GraphemeClass::ExtendIncb), + (0x11D3F, 0x11D45, GraphemeClass::ExtendIncb), + (0x11D46, 0x11D46, GraphemeClass::Prepend), + (0x11D47, 0x11D47, GraphemeClass::ExtendIncb), + (0x11D8A, 0x11D8E, GraphemeClass::SpacingMark), + (0x11D90, 0x11D91, GraphemeClass::ExtendIncb), + (0x11D93, 0x11D94, GraphemeClass::SpacingMark), + (0x11D95, 0x11D95, GraphemeClass::ExtendIncb), + (0x11D96, 0x11D96, GraphemeClass::SpacingMark), + (0x11D97, 0x11D97, GraphemeClass::ExtendIncb), + (0x11EF3, 0x11EF4, GraphemeClass::ExtendIncb), + (0x11EF5, 0x11EF6, GraphemeClass::SpacingMark), + (0x11F00, 0x11F01, GraphemeClass::ExtendIncb), + (0x11F02, 0x11F02, GraphemeClass::Prepend), + (0x11F03, 0x11F03, GraphemeClass::SpacingMark), + (0x11F04, 0x11F10, GraphemeClass::Consonant), + (0x11F12, 0x11F33, GraphemeClass::Consonant), + (0x11F34, 0x11F35, GraphemeClass::SpacingMark), + (0x11F36, 0x11F3A, GraphemeClass::ExtendIncb), + (0x11F3E, 0x11F3F, GraphemeClass::SpacingMark), + (0x11F40, 0x11F41, GraphemeClass::ExtendIncb), + (0x11F42, 0x11F42, GraphemeClass::Linker), + (0x11F5A, 0x11F5A, GraphemeClass::ExtendIncb), + (0x13430, 0x1343F, GraphemeClass::Control), + (0x13440, 0x13440, GraphemeClass::ExtendIncb), + (0x13447, 0x13455, GraphemeClass::ExtendIncb), + (0x1611E, 0x16129, GraphemeClass::ExtendIncb), + (0x1612A, 0x1612C, GraphemeClass::SpacingMark), + (0x1612D, 0x1612F, GraphemeClass::ExtendIncb), + (0x16AF0, 0x16AF4, GraphemeClass::ExtendIncb), + (0x16B30, 0x16B36, GraphemeClass::ExtendIncb), + (0x16D63, 0x16D63, GraphemeClass::V), + (0x16D67, 0x16D6A, GraphemeClass::V), + (0x16F4F, 0x16F4F, GraphemeClass::ExtendIncb), + (0x16F51, 0x16F87, GraphemeClass::SpacingMark), + (0x16F8F, 0x16F92, GraphemeClass::ExtendIncb), + (0x16FE4, 0x16FE4, GraphemeClass::ExtendIncb), + (0x16FF0, 0x16FF1, GraphemeClass::ExtendIncb), + (0x1BC9D, 0x1BC9E, GraphemeClass::ExtendIncb), + (0x1BCA0, 0x1BCA3, GraphemeClass::Control), + (0x1CF00, 0x1CF2D, GraphemeClass::ExtendIncb), + (0x1CF30, 0x1CF46, GraphemeClass::ExtendIncb), + (0x1D165, 0x1D169, GraphemeClass::ExtendIncb), + (0x1D16D, 0x1D172, GraphemeClass::ExtendIncb), + (0x1D173, 0x1D17A, GraphemeClass::Control), + (0x1D17B, 0x1D182, GraphemeClass::ExtendIncb), + (0x1D185, 0x1D18B, GraphemeClass::ExtendIncb), + (0x1D1AA, 0x1D1AD, GraphemeClass::ExtendIncb), + (0x1D242, 0x1D244, GraphemeClass::ExtendIncb), + (0x1DA00, 0x1DA36, GraphemeClass::ExtendIncb), + (0x1DA3B, 0x1DA6C, GraphemeClass::ExtendIncb), + (0x1DA75, 0x1DA75, GraphemeClass::ExtendIncb), + (0x1DA84, 0x1DA84, GraphemeClass::ExtendIncb), + (0x1DA9B, 0x1DA9F, GraphemeClass::ExtendIncb), + (0x1DAA1, 0x1DAAF, GraphemeClass::ExtendIncb), + (0x1E000, 0x1E006, GraphemeClass::ExtendIncb), + (0x1E008, 0x1E018, GraphemeClass::ExtendIncb), + (0x1E01B, 0x1E021, GraphemeClass::ExtendIncb), + (0x1E023, 0x1E024, GraphemeClass::ExtendIncb), + (0x1E026, 0x1E02A, GraphemeClass::ExtendIncb), + (0x1E08F, 0x1E08F, GraphemeClass::ExtendIncb), + (0x1E130, 0x1E136, GraphemeClass::ExtendIncb), + (0x1E2AE, 0x1E2AE, GraphemeClass::ExtendIncb), + (0x1E2EC, 0x1E2EF, GraphemeClass::ExtendIncb), + (0x1E4EC, 0x1E4EF, GraphemeClass::ExtendIncb), + (0x1E5EE, 0x1E5EF, GraphemeClass::ExtendIncb), + (0x1E6E3, 0x1E6E3, GraphemeClass::ExtendIncb), + (0x1E6E6, 0x1E6E6, GraphemeClass::ExtendIncb), + (0x1E6EE, 0x1E6EF, GraphemeClass::ExtendIncb), + (0x1E6F5, 0x1E6F5, GraphemeClass::ExtendIncb), + (0x1E8D0, 0x1E8D6, GraphemeClass::ExtendIncb), + (0x1E944, 0x1E94A, GraphemeClass::ExtendIncb), + (0x1F004, 0x1F004, GraphemeClass::ExtPic), + (0x1F02C, 0x1F02F, GraphemeClass::ExtPic), + (0x1F094, 0x1F09F, GraphemeClass::ExtPic), + (0x1F0AF, 0x1F0B0, GraphemeClass::ExtPic), + (0x1F0C0, 0x1F0C0, GraphemeClass::ExtPic), + (0x1F0CF, 0x1F0D0, GraphemeClass::ExtPic), + (0x1F0F6, 0x1F0FF, GraphemeClass::ExtPic), + (0x1F170, 0x1F171, GraphemeClass::ExtPic), + (0x1F17E, 0x1F17F, GraphemeClass::ExtPic), + (0x1F18E, 0x1F18E, GraphemeClass::ExtPic), + (0x1F191, 0x1F19A, GraphemeClass::ExtPic), + (0x1F1AE, 0x1F1E5, GraphemeClass::ExtPic), + (0x1F1E6, 0x1F1FF, GraphemeClass::RegionalIndicator), + (0x1F201, 0x1F20F, GraphemeClass::ExtPic), + (0x1F21A, 0x1F21A, GraphemeClass::ExtPic), + (0x1F22F, 0x1F22F, GraphemeClass::ExtPic), + (0x1F232, 0x1F23A, GraphemeClass::ExtPic), + (0x1F23C, 0x1F23F, GraphemeClass::ExtPic), + (0x1F249, 0x1F25F, GraphemeClass::ExtPic), + (0x1F266, 0x1F321, GraphemeClass::ExtPic), + (0x1F324, 0x1F393, GraphemeClass::ExtPic), + (0x1F396, 0x1F397, GraphemeClass::ExtPic), + (0x1F399, 0x1F39B, GraphemeClass::ExtPic), + (0x1F39E, 0x1F3F0, GraphemeClass::ExtPic), + (0x1F3F3, 0x1F3F5, GraphemeClass::ExtPic), + (0x1F3F7, 0x1F3FA, GraphemeClass::ExtPic), + (0x1F3FB, 0x1F3FF, GraphemeClass::ExtendIncb), + (0x1F400, 0x1F4FD, GraphemeClass::ExtPic), + (0x1F4FF, 0x1F53D, GraphemeClass::ExtPic), + (0x1F549, 0x1F54E, GraphemeClass::ExtPic), + (0x1F550, 0x1F567, GraphemeClass::ExtPic), + (0x1F56F, 0x1F570, GraphemeClass::ExtPic), + (0x1F573, 0x1F57A, GraphemeClass::ExtPic), + (0x1F587, 0x1F587, GraphemeClass::ExtPic), + (0x1F58A, 0x1F58D, GraphemeClass::ExtPic), + (0x1F590, 0x1F590, GraphemeClass::ExtPic), + (0x1F595, 0x1F596, GraphemeClass::ExtPic), + (0x1F5A4, 0x1F5A5, GraphemeClass::ExtPic), + (0x1F5A8, 0x1F5A8, GraphemeClass::ExtPic), + (0x1F5B1, 0x1F5B2, GraphemeClass::ExtPic), + (0x1F5BC, 0x1F5BC, GraphemeClass::ExtPic), + (0x1F5C2, 0x1F5C4, GraphemeClass::ExtPic), + (0x1F5D1, 0x1F5D3, GraphemeClass::ExtPic), + (0x1F5DC, 0x1F5DE, GraphemeClass::ExtPic), + (0x1F5E1, 0x1F5E1, GraphemeClass::ExtPic), + (0x1F5E3, 0x1F5E3, GraphemeClass::ExtPic), + (0x1F5E8, 0x1F5E8, GraphemeClass::ExtPic), + (0x1F5EF, 0x1F5EF, GraphemeClass::ExtPic), + (0x1F5F3, 0x1F5F3, GraphemeClass::ExtPic), + (0x1F5FA, 0x1F64F, GraphemeClass::ExtPic), + (0x1F680, 0x1F6C5, GraphemeClass::ExtPic), + (0x1F6CB, 0x1F6D2, GraphemeClass::ExtPic), + (0x1F6D5, 0x1F6E5, GraphemeClass::ExtPic), + (0x1F6E9, 0x1F6E9, GraphemeClass::ExtPic), + (0x1F6EB, 0x1F6F0, GraphemeClass::ExtPic), + (0x1F6F3, 0x1F6FF, GraphemeClass::ExtPic), + (0x1F7DA, 0x1F7FF, GraphemeClass::ExtPic), + (0x1F80C, 0x1F80F, GraphemeClass::ExtPic), + (0x1F848, 0x1F84F, GraphemeClass::ExtPic), + (0x1F85A, 0x1F85F, GraphemeClass::ExtPic), + (0x1F888, 0x1F88F, GraphemeClass::ExtPic), + (0x1F8AE, 0x1F8AF, GraphemeClass::ExtPic), + (0x1F8BC, 0x1F8BF, GraphemeClass::ExtPic), + (0x1F8C2, 0x1F8CF, GraphemeClass::ExtPic), + (0x1F8D9, 0x1F8FF, GraphemeClass::ExtPic), + (0x1F90C, 0x1F93A, GraphemeClass::ExtPic), + (0x1F93C, 0x1F945, GraphemeClass::ExtPic), + (0x1F947, 0x1F9FF, GraphemeClass::ExtPic), + (0x1FA58, 0x1FA5F, GraphemeClass::ExtPic), + (0x1FA6E, 0x1FAFF, GraphemeClass::ExtPic), + (0x1FC00, 0x1FFFD, GraphemeClass::ExtPic), + (0xE0000, 0xE001F, GraphemeClass::Control), + (0xE0020, 0xE007F, GraphemeClass::ExtendIncb), + (0xE0080, 0xE00FF, GraphemeClass::Control), + (0xE0100, 0xE01EF, GraphemeClass::ExtendIncb), + (0xE01F0, 0xE0FFF, GraphemeClass::Control), +]; diff --git a/rio-unicode/src/lib.rs b/rio-unicode/src/lib.rs new file mode 100644 index 0000000000..4a6d41ae57 --- /dev/null +++ b/rio-unicode/src/lib.rs @@ -0,0 +1,139 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Determine displayed width of `char` and `str` types according to +//! [Unicode Standard Annex #11](http://www.unicode.org/reports/tr11/) +//! rules. +//! +//! ```rust +//! extern crate rio_unicode; +//! +//! use rio_unicode::UnicodeWidthStr; +//! +//! fn main() { +//! let teststr = "Hello, world!"; +//! let width = UnicodeWidthStr::width(teststr); +//! println!("{}", teststr); +//! println!("The above string is {} columns wide.", width); +//! let width = teststr.width_cjk(); +//! println!("The above string is {} columns wide (CJK).", width); +//! } +//! ``` +//! +//! # features +//! +//! unicode-width supports a `no_std` feature. This eliminates dependence +//! on std, and instead uses equivalent functions from core. +//! +//! # crates.io +//! +//! You can use this package in your project by adding the following +//! to your `Cargo.toml`: +//! +//! ```toml +//! [dependencies] +//! unicode-width = "0.1.5" +//! ``` + +#![deny(missing_docs, unsafe_code)] +#![doc( + html_logo_url = "https://unicode-rs.github.io/unicode-rs_sm.png", + html_favicon_url = "https://unicode-rs.github.io/unicode-rs_sm.png" +)] +#![cfg_attr(feature = "bench", feature(test))] +#![no_std] + +#[cfg(test)] +#[macro_use] +extern crate std; + +#[cfg(feature = "bench")] +extern crate test; + +use tables::charwidth as cw; +pub use tables::UNICODE_VERSION; + +mod tables; + +/// Grapheme cluster segmentation (UAX #29), on the same Unicode +/// version as the width tables. +pub mod grapheme; +mod grapheme_tables; + +#[cfg(test)] +mod tests; + +/// Methods for determining displayed width of Unicode characters. +pub trait UnicodeWidthChar { + /// Returns the character's displayed width in columns, or `None` if the + /// character is a control character other than `'\x00'`. + /// + /// This function treats characters in the Ambiguous category according + /// to [Unicode Standard Annex #11](http://www.unicode.org/reports/tr11/) + /// as 1 column wide. This is consistent with the recommendations for non-CJK + /// contexts, or when the context cannot be reliably determined. + fn width(self) -> Option; + + /// Returns the character's displayed width in columns, or `None` if the + /// character is a control character other than `'\x00'`. + /// + /// This function treats characters in the Ambiguous category according + /// to [Unicode Standard Annex #11](http://www.unicode.org/reports/tr11/) + /// as 2 columns wide. This is consistent with the recommendations for + /// CJK contexts. + fn width_cjk(self) -> Option; +} + +impl UnicodeWidthChar for char { + #[inline] + fn width(self) -> Option { + cw::width(self, false) + } + + #[inline] + fn width_cjk(self) -> Option { + cw::width(self, true) + } +} + +/// Methods for determining displayed width of Unicode strings. +pub trait UnicodeWidthStr { + /// Returns the string's displayed width in columns. + /// + /// Control characters are treated as having zero width. + /// + /// This function treats characters in the Ambiguous category according + /// to [Unicode Standard Annex #11](http://www.unicode.org/reports/tr11/) + /// as 1 column wide. This is consistent with the recommendations for + /// non-CJK contexts, or when the context cannot be reliably determined. + fn width(&self) -> usize; + + /// Returns the string's displayed width in columns. + /// + /// Control characters are treated as having zero width. + /// + /// This function treats characters in the Ambiguous category according + /// to [Unicode Standard Annex #11](http://www.unicode.org/reports/tr11/) + /// as 2 column wide. This is consistent with the recommendations for + /// CJK contexts. + fn width_cjk(&self) -> usize; +} + +impl UnicodeWidthStr for str { + #[inline] + fn width(&self) -> usize { + self.chars().map(|c| cw::width(c, false).unwrap_or(0)).sum() + } + + #[inline] + fn width_cjk(&self) -> usize { + self.chars().map(|c| cw::width(c, true).unwrap_or(0)).sum() + } +} diff --git a/rio-unicode/src/tables.rs b/rio-unicode/src/tables.rs new file mode 100644 index 0000000000..515daf2389 --- /dev/null +++ b/rio-unicode/src/tables.rs @@ -0,0 +1,606 @@ +// Copyright 2012-2022 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// NOTE: The following code was generated by "scripts/unicode.py", do not edit directly + +/// The version of [Unicode](http://www.unicode.org/) +/// that this version of unicode-width is based on. +pub const UNICODE_VERSION: (u8, u8, u8) = (17, 0, 0); + +pub mod charwidth { + use core::option::Option::{self, None, Some}; + + /// Returns the [UAX #11](https://www.unicode.org/reports/tr11/) based width of `c` by + /// consulting a multi-level lookup table. + /// If `is_cjk == true`, ambiguous width characters are treated as double width; otherwise, + /// they're treated as single width. + /// + /// # Maintenance + /// The tables themselves are autogenerated but this function is hardcoded. You should have + /// nothing to worry about if you re-run `unicode.py` (for example, when updating Unicode.) + /// However, if you change the *actual structure* of the lookup tables (perhaps by editing the + /// `TABLE_CFGS` global in `unicode.py`) you must ensure that this code reflects those changes. + #[inline] + fn lookup_width(c: char, is_cjk: bool) -> usize { + let cp = c as usize; + + let t1_offset = TABLES_0[cp >> 13 & 0xFF]; + + // Each sub-table in TABLES_1 is 7 bits, and each stored entry is a byte, + // so each sub-table is 128 bytes in size. + // (Sub-tables are selected using the computed offset from the previous table.) + let t2_offset = TABLES_1[128 * usize::from(t1_offset) + (cp >> 6 & 0x7F)]; + + // Each sub-table in TABLES_2 is 6 bits, but each stored entry is 2 bits. + // This is accomplished by packing four stored entries into one byte. + // So each sub-table is 2**(6-2) == 16 bytes in size. + // Since this is the last table, each entry represents an encoded width. + let packed_widths = TABLES_2[16 * usize::from(t2_offset) + (cp >> 2 & 0xF)]; + + // Extract the packed width + let width = packed_widths >> (2 * (cp & 0b11)) & 0b11; + + // A width of 3 signifies that the codepoint is ambiguous width. + if width == 3 { + if is_cjk { + 2 + } else { + 1 + } + } else { + width.into() + } + } + + /// Returns the [UAX #11](https://www.unicode.org/reports/tr11/) based width of `c`, or + /// `None` if `c` is a control character other than `'\x00'`. + /// If `is_cjk == true`, ambiguous width characters are treated as double width; otherwise, + /// they're treated as single width. + #[inline] + pub fn width(c: char, is_cjk: bool) -> Option { + if c < '\u{7F}' { + if c >= '\u{20}' { + // U+0020 to U+007F (exclusive) are single-width ASCII codepoints + Some(1) + } else if c == '\0' { + // U+0000 *is* a control code, but it's special-cased + Some(0) + } else { + // U+0001 to U+0020 (exclusive) are control codes + None + } + } else if c >= '\u{A0}' { + // No characters >= U+00A0 are control codes, so we can consult the lookup tables + Some(lookup_width(c, is_cjk)) + } else { + // U+007F to U+00A0 (exclusive) are control codes + None + } + } + + /// Autogenerated. 1 sub-table(s). Consult [`lookup_width`] for layout info. + static TABLES_0: [u8; 256] = [ + 0x00, 0x01, 0x02, 0x02, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, + 0x0B, 0x0C, 0x0D, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x0E, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x0E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0F, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x11, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ]; + + /// Autogenerated. 18 sub-table(s). Consult [`lookup_width`] for layout info. + static TABLES_1: [u8; 2304] = [ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x06, 0x08, 0x06, 0x09, 0x0A, + 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x06, 0x06, 0x06, 0x11, 0x12, 0x13, 0x14, + 0x06, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, + 0x21, 0x22, 0x23, 0x22, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x25, 0x2B, + 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, + 0x39, 0x3A, 0x06, 0x3B, 0x3C, 0x0A, 0x0A, 0x06, 0x06, 0x06, 0x06, 0x06, 0x3D, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x06, 0x43, 0x06, 0x44, 0x06, 0x06, 0x06, + 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x06, 0x06, 0x4E, 0x06, + 0x06, 0x06, 0x0A, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x4F, 0x50, + 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x06, 0x5A, 0x06, 0x06, + 0x5B, 0x06, 0x5C, 0x5D, 0x5E, 0x5D, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, + 0x66, 0x67, 0x68, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x69, 0x6A, 0x06, 0x06, 0x06, 0x06, 0x06, 0x6B, 0x06, 0x01, + 0x06, 0x6C, 0x06, 0x06, 0x6D, 0x6E, 0x3B, 0x3B, 0x3B, 0x6F, 0x70, 0x71, 0x72, + 0x3B, 0x73, 0x3B, 0x74, 0x75, 0x76, 0x77, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x78, + 0x79, 0x06, 0x06, 0x06, 0x06, 0x06, 0x7A, 0x7B, 0x7C, 0x06, 0x06, 0x06, 0x06, + 0x7D, 0x06, 0x06, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x06, + 0x06, 0x06, 0x87, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x88, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, + 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, + 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, + 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, + 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, + 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, + 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, + 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x3B, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x89, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x8A, 0x8B, 0x06, 0x01, 0x71, 0x8C, 0x06, + 0x8D, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x8E, 0x06, 0x06, 0x06, 0x8F, + 0x06, 0x90, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x91, 0x06, 0x06, 0x92, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x93, 0x94, 0x06, 0x06, 0x06, 0x06, 0x95, 0x96, 0x06, 0x97, 0x98, 0x06, + 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1, 0x2E, 0x06, 0xA2, 0x2C, + 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0x06, 0x06, 0xAA, 0xAB, 0xAC, 0xAD, + 0xAE, 0x06, 0xAF, 0x06, 0x06, 0x06, 0xB0, 0x06, 0x06, 0x06, 0xB1, 0xB2, 0x06, + 0xB3, 0xB4, 0xB5, 0xB6, 0x06, 0x06, 0xB7, 0x06, 0x06, 0xB8, 0x06, 0xB9, 0x06, + 0xBA, 0xBB, 0xBC, 0x06, 0x06, 0x06, 0x06, 0xBD, 0xBE, 0xBF, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x47, 0xC0, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0xC1, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0xC2, + 0xC3, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0xC4, 0xC5, 0xC6, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0xC7, 0xC8, 0x06, 0x3B, 0xC9, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0xCA, 0x3B, 0x3B, 0x3B, 0x3B, 0xCB, 0xCC, 0x3B, 0x3B, 0x3B, 0x3B, + 0x3B, 0xCD, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0xCE, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0xCF, 0xD0, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0xD1, 0xD2, 0x06, 0x06, 0xD3, 0x06, 0x06, + 0x3B, 0xD4, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0xD5, 0xD6, 0xD7, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0xD8, 0x06, 0xC4, 0x06, 0xC3, 0x06, 0x06, 0x06, 0x06, 0x06, 0xD9, 0xDA, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0xDA, 0x06, 0x06, 0x06, 0xDB, 0x06, 0x06, + 0x06, 0xDC, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0xDD, 0x06, 0xDE, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0xDF, + 0x06, 0x06, 0xE0, 0xE1, 0xE2, 0xE3, 0x06, 0xE4, 0xE5, 0x06, 0x06, 0xE6, 0xE7, + 0xE8, 0xE9, 0xEA, 0xEB, 0x3B, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0x3B, 0xF1, 0x3B, + 0xF2, 0x06, 0x06, 0x06, 0xF3, 0x06, 0x06, 0x06, 0x06, 0xF4, 0xF5, 0x3B, 0x3B, + 0x06, 0xF6, 0xF7, 0xF8, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x3B, 0x3B, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, + 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0xED, 0xF9, 0x0A, 0x06, 0x06, + 0x0A, 0x0A, 0x0A, 0x0B, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, + 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, + 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, + 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, + 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, + 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, + 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, + 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, + 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, + 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, + 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, + 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, + 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, + 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, + 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, + 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, + 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, + 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, + 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, + 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, + 0x5D, 0x5D, 0xFA, + ]; + + /// Autogenerated. 251 sub-table(s). Consult [`lookup_width`] for layout info. + static TABLES_2: [u8; 4016] = [ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x5D, 0xD7, 0x77, 0x75, 0xFF, 0xF7, 0x7F, 0xFF, 0x55, 0x75, 0x55, 0x55, + 0x57, 0xD5, 0x57, 0xF5, 0x5F, 0x75, 0x7F, 0x5F, 0xF7, 0xD5, 0x7F, 0x77, 0x5D, + 0x55, 0x55, 0x55, 0xDD, 0x55, 0xD5, 0x55, 0x55, 0xF5, 0xD5, 0x55, 0xFD, 0x55, + 0x57, 0xD5, 0x7F, 0x57, 0xFF, 0x5D, 0xF5, 0x55, 0x55, 0x55, 0x55, 0xF5, 0xD5, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x75, 0x77, + 0x77, 0x77, 0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x5D, 0x55, 0x55, 0x55, 0x5D, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0xD7, 0xFD, 0x5D, 0x57, 0x55, 0xFF, 0xDD, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0xFD, 0xFF, 0xFF, 0xFF, 0xDF, 0xFF, 0x5F, 0x55, 0xFD, 0xFF, 0xFF, 0xFF, + 0xDF, 0xFF, 0x5F, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x5D, 0x55, 0x55, 0x55, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x5D, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0x50, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x41, 0x10, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x00, 0x50, 0x55, 0x55, 0x00, 0x00, 0x40, 0x54, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x54, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x05, 0x00, 0x10, 0x00, 0x14, 0x04, 0x50, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x15, 0x51, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x05, 0x00, 0x00, 0x54, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0x00, 0x55, 0x55, 0x51, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x05, 0x10, 0x00, 0x00, 0x01, 0x01, 0x50, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x01, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x50, 0x15, 0x00, + 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x05, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x45, 0x54, 0x01, 0x00, 0x54, 0x51, 0x01, 0x00, 0x55, 0x55, 0x05, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x51, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x54, 0x01, 0x54, 0x55, 0x51, 0x55, + 0x55, 0x55, 0x55, 0x05, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x45, 0x41, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x54, 0x41, 0x15, 0x14, 0x50, 0x51, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x50, 0x51, 0x55, 0x55, 0x01, 0x10, 0x54, 0x51, 0x55, 0x55, 0x55, 0x55, 0x05, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x05, 0x00, 0x51, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x14, 0x01, 0x54, 0x55, + 0x51, 0x55, 0x41, 0x55, 0x55, 0x05, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x45, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x54, 0x55, 0x55, 0x51, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x54, 0x54, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x04, 0x54, 0x05, 0x04, 0x50, + 0x55, 0x41, 0x55, 0x55, 0x05, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x45, 0x55, 0x50, 0x55, 0x55, 0x55, 0x55, 0x05, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x50, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x15, 0x54, 0x01, 0x54, 0x55, 0x51, 0x55, 0x55, 0x55, 0x55, + 0x05, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x51, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x45, 0x55, 0x05, 0x44, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x51, 0x00, 0x40, 0x55, 0x55, 0x15, 0x00, 0x40, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x51, 0x00, 0x00, 0x54, 0x55, 0x55, 0x00, + 0x40, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x50, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x11, 0x51, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x01, 0x00, 0x00, 0x40, 0x00, 0x04, 0x55, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x55, 0x45, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x01, 0x04, 0x00, + 0x41, 0x41, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x50, 0x05, 0x54, 0x55, 0x55, + 0x55, 0x01, 0x54, 0x55, 0x55, 0x45, 0x41, 0x55, 0x51, 0x55, 0x55, 0x55, 0x51, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x01, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x05, 0x54, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x05, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x05, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x05, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x10, 0x00, 0x50, + 0x55, 0x45, 0x01, 0x00, 0x00, 0x55, 0x55, 0x51, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x41, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x51, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x40, 0x15, 0x54, 0x55, 0x45, 0x55, 0x01, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x15, 0x14, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x45, 0x00, 0x40, 0x44, 0x01, 0x00, + 0x54, 0x15, 0x00, 0x00, 0x14, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0x00, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x04, 0x40, + 0x54, 0x45, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, + 0x00, 0x55, 0x55, 0x55, 0x50, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x05, + 0x50, 0x10, 0x50, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x45, 0x50, 0x11, 0x50, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x05, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x40, 0x00, 0x00, 0x00, 0x04, 0x00, 0x54, 0x51, 0x55, + 0x54, 0x50, 0x55, 0x55, 0x55, 0x15, 0x00, 0xD7, 0x7F, 0x5F, 0x5F, 0x7F, 0xFF, + 0x05, 0x40, 0xF7, 0x5D, 0xD5, 0x75, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x00, 0x04, 0x00, 0x00, 0x55, 0x57, 0x55, 0xD5, 0xFD, 0x57, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x57, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x55, + 0x55, 0x55, 0xD5, 0x5D, 0x5D, 0x55, 0xD5, 0x75, 0x55, 0x55, 0x7D, 0x75, 0xD5, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xD5, 0x57, 0xD5, 0x7F, + 0xFF, 0xFF, 0xFF, 0x55, 0xFF, 0xFF, 0x5F, 0x55, 0x55, 0x55, 0x5D, 0x55, 0xFF, + 0xFF, 0x5F, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x5F, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x75, 0x57, 0x55, 0x55, 0x55, 0xD5, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0xF7, 0xD5, 0xD7, 0xD5, 0x5D, 0x5D, 0x75, 0xFD, 0xD7, 0xDD, 0xFF, 0x77, + 0x55, 0xFF, 0x55, 0x5F, 0x55, 0x55, 0x57, 0x57, 0x75, 0x55, 0x55, 0x55, 0x5F, + 0xFF, 0xF5, 0xF5, 0x55, 0x55, 0x55, 0x55, 0xF5, 0xF5, 0x55, 0x55, 0x55, 0x5D, + 0x5D, 0x55, 0x55, 0x5D, 0x55, 0x55, 0x55, 0x55, 0x55, 0xD5, 0x55, 0x55, 0x55, + 0x55, 0x75, 0x55, 0xA5, 0x55, 0x55, 0x55, 0x69, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xA9, 0x56, 0x96, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0x55, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x55, + 0x55, 0x55, 0xFF, 0xFF, 0xFF, 0xFF, 0xF5, 0x5F, 0x55, 0x55, 0xDF, 0xFF, 0x5F, + 0x55, 0xF5, 0xF5, 0x55, 0x5F, 0x5F, 0xF5, 0xD7, 0xF5, 0x5F, 0x55, 0x55, 0x55, + 0xF5, 0x5F, 0x55, 0xD5, 0x55, 0x55, 0x55, 0x69, 0x55, 0x7D, 0x5D, 0xF5, 0x55, + 0x5A, 0x55, 0x77, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55, 0x77, 0x55, + 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0xDF, 0xDF, 0x7F, 0xDF, 0x55, 0x55, 0x55, + 0x95, 0x55, 0x55, 0xA5, 0xAA, 0x95, 0x55, 0x55, 0xF5, 0x59, 0x55, 0xA5, 0x55, + 0x55, 0x55, 0x55, 0xE9, 0x55, 0xFA, 0xFF, 0xEF, 0xFF, 0xFE, 0xFF, 0xFF, 0xDF, + 0x55, 0xEF, 0xFF, 0xAF, 0xFB, 0xEF, 0xFB, 0x55, 0x59, 0xA5, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x56, 0x55, 0x55, 0x55, 0x55, 0x5D, 0x55, 0x55, 0x55, + 0x66, 0x95, 0x9A, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xF5, 0xFF, 0xFF, + 0x55, 0x55, 0x55, 0x55, 0x55, 0xA9, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x56, + 0x55, 0x55, 0x95, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x95, 0x56, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x56, 0xF9, 0x5F, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x50, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x9A, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0x5A, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x0A, 0xA0, 0xAA, 0xAA, 0xAA, + 0x6A, 0xA9, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x6A, 0x81, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0xA9, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xA9, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0x6A, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x5A, 0x55, 0x95, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x6A, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xFF, 0xFF, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x56, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0x6A, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x15, 0x40, 0x00, 0x00, 0x50, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x05, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x50, 0x55, 0x55, 0x55, 0x45, 0x45, + 0x15, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x41, 0x55, 0x54, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x50, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, + 0x50, 0x55, 0x55, 0x15, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x05, 0x00, 0x50, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0x00, 0x50, 0x55, + 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x56, 0x40, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x05, 0x50, 0x50, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x51, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x01, 0x40, 0x41, 0x41, 0x55, 0x55, 0x15, 0x55, 0x55, 0x54, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x54, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x04, 0x14, 0x54, 0x05, 0x51, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x50, 0x55, 0x45, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x51, 0x54, + 0x51, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x45, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, + 0x00, 0x00, 0xAA, 0xAA, 0x5A, 0x55, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x6A, 0xAA, 0xAA, 0xAA, 0xAA, 0x6A, 0xAA, 0x55, + 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x56, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0xAA, 0x6A, 0x55, 0x55, 0x55, 0x55, 0x01, 0x5D, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x51, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x54, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x05, 0x40, 0x55, 0x01, 0x41, 0x55, 0x00, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x40, 0x15, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x41, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x00, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x01, + 0x50, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x15, 0x54, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x05, 0x00, 0x55, 0x05, + 0x00, 0x00, 0x54, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x05, 0x50, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x51, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x40, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x14, 0x54, 0x55, 0x15, 0x50, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x40, 0x41, 0x51, + 0x45, 0x55, 0x55, 0x51, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x40, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, + 0x00, 0x01, 0x00, 0x54, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x55, 0x55, 0x55, 0x50, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x05, 0x00, 0x40, 0x55, + 0x55, 0x01, 0x14, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x15, 0x50, 0x04, 0x55, 0x45, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, + 0x15, 0x00, 0x40, 0x55, 0x55, 0x55, 0x55, 0x55, 0x54, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x05, 0x00, 0x54, 0x00, 0x54, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, + 0x00, 0x54, 0x55, 0x55, 0x45, 0x44, 0x55, 0x55, 0x55, 0x41, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x05, 0x44, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x45, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0x44, 0x15, + 0x04, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x05, 0x50, 0x55, 0x10, 0x54, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x50, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0x40, 0x11, 0x54, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, + 0x51, 0x00, 0x10, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x11, + 0x05, 0x10, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0x00, 0x41, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, + 0x44, 0x15, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x00, 0x05, 0x55, 0x54, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x01, 0x00, 0x40, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0x14, 0x40, 0x55, 0x15, 0x55, + 0x55, 0x01, 0x40, 0x01, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x05, 0x00, 0x00, 0x40, 0x50, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x04, 0x44, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x00, 0x40, 0x00, 0x10, 0x55, 0x55, 0x55, 0x55, + 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x41, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x01, 0x40, + 0x45, 0x10, 0x00, 0x10, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x50, 0x11, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x54, 0x55, 0x55, 0x50, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x05, 0x40, + 0x55, 0x44, 0x55, 0x55, 0x55, 0x55, 0x55, 0x45, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x54, 0x15, 0x00, 0x00, 0x00, 0x50, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x05, 0x00, 0x00, 0x50, 0x01, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x00, 0x54, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x00, + 0x40, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x40, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0xAA, 0x54, 0x55, 0x55, 0xAA, 0x6A, 0x55, 0x55, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0x5A, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x95, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x6A, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0x6A, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xA9, 0xAA, 0x69, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x6A, 0x55, 0x55, 0x55, 0x65, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x6A, 0x59, 0x55, 0x55, 0x55, 0xAA, 0x55, 0x55, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x41, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, + 0x50, 0x55, 0x15, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x05, 0x50, 0x55, 0x55, 0x55, 0x55, 0x05, 0x54, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0x6A, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x6A, + 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x40, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x54, 0x55, 0x51, 0x55, 0x55, 0x55, 0x54, 0x55, 0x55, 0x55, + 0x55, 0x15, 0x00, 0x01, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x00, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x10, 0x04, 0x40, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x45, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x05, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x45, 0x55, 0x05, 0x55, 0x51, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x00, 0x40, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x00, 0x40, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x56, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x95, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xFF, + 0xFF, 0x7F, 0x55, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x5F, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x5F, + 0x55, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xAB, 0xAA, 0xEA, 0xFF, + 0xFF, 0xFF, 0xFF, 0x57, 0x55, 0x55, 0x55, 0x55, 0x6A, 0x55, 0x55, 0x55, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0xAA, 0xAA, + 0x56, 0x55, 0x5A, 0x55, 0x55, 0x55, 0xAA, 0x5A, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x56, 0x55, 0x55, 0xA9, + 0xAA, 0x9A, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xA6, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, + 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x6A, + 0x95, 0xAA, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x56, 0x56, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0x6A, 0xA6, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x96, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x5A, 0x55, + 0x55, 0x95, 0x6A, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, + 0x65, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x69, 0x55, 0x55, 0x55, 0x56, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x95, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xAA, 0x5A, + 0x55, 0x56, 0x6A, 0xA9, 0x56, 0xAA, 0x55, 0x55, 0x95, 0x56, 0x55, 0xAA, 0xAA, + 0x56, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0x55, + 0x56, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x6A, 0xAA, 0xAA, 0x9A, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0x56, + 0xAA, 0xAA, 0x6A, 0xA5, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0x6A, 0x56, 0xA9, 0xAA, 0xAA, 0xAA, 0x96, 0xAA, 0xAA, + 0x6A, 0x95, 0xAA, 0xAA, 0x56, 0x55, 0x51, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x5F, + ]; +} diff --git a/rio-unicode/src/tests.rs b/rio-unicode/src/tests.rs new file mode 100644 index 0000000000..04d1f74622 --- /dev/null +++ b/rio-unicode/src/tests.rs @@ -0,0 +1,194 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[cfg(feature = "bench")] +use super::{UnicodeWidthChar, UnicodeWidthStr}; +#[cfg(feature = "bench")] +use std::iter; +#[cfg(feature = "bench")] +use test::{self, Bencher}; + +use std::prelude::v1::*; + +#[cfg(feature = "bench")] +#[bench] +fn cargo(b: &mut Bencher) { + let string = iter::repeat('a').take(4096).collect::(); + + b.iter(|| { + for c in string.chars() { + test::black_box(UnicodeWidthChar::width(c)); + } + }); +} + +#[cfg(feature = "bench")] +#[bench] +#[allow(deprecated)] +fn stdlib(b: &mut Bencher) { + let string = iter::repeat('a').take(4096).collect::(); + + b.iter(|| { + for c in string.chars() { + test::black_box(c.width()); + } + }); +} + +#[cfg(feature = "bench")] +#[bench] +fn simple_if(b: &mut Bencher) { + let string = iter::repeat('a').take(4096).collect::(); + + b.iter(|| { + for c in string.chars() { + test::black_box(simple_width_if(c)); + } + }); +} + +#[cfg(feature = "bench")] +#[bench] +fn simple_match(b: &mut Bencher) { + let string = iter::repeat('a').take(4096).collect::(); + + b.iter(|| { + for c in string.chars() { + test::black_box(simple_width_match(c)); + } + }); +} + +#[cfg(feature = "bench")] +#[inline] +fn simple_width_if(c: char) -> Option { + let cu = c as u32; + if cu < 127 { + if cu > 31 { + Some(1) + } else if cu == 0 { + Some(0) + } else { + None + } + } else { + UnicodeWidthChar::width(c) + } +} + +#[cfg(feature = "bench")] +#[inline] +fn simple_width_match(c: char) -> Option { + match c as u32 { + cu if cu == 0 => Some(0), + cu if cu < 0x20 => None, + cu if cu < 0x7f => Some(1), + _ => UnicodeWidthChar::width(c), + } +} +#[cfg(all(feature = "bench", not(feature = "no_std")))] +#[bench] +fn enwik8(b: &mut Bencher) { + // To benchmark, download & unzip `enwik8` from https://data.deepai.org/enwik8.zip + let data_path = "bench_data/enwik8"; + let string = std::fs::read_to_string(data_path).unwrap_or_default(); + b.iter(|| test::black_box(UnicodeWidthStr::width(string.as_str()))); +} +#[cfg(all(feature = "bench", not(feature = "no_std")))] +#[bench] +fn jawiki(b: &mut Bencher) { + // To benchmark, download & extract `jawiki-20220501-pages-articles-multistream-index.txt` from + // https://dumps.wikimedia.org/jawiki/20220501/jawiki-20220501-pages-articles-multistream-index.txt.bz2 + let data_path = "bench_data/jawiki-20220501-pages-articles-multistream-index.txt"; + let string = std::fs::read_to_string(data_path).unwrap_or_default(); + b.iter(|| test::black_box(UnicodeWidthStr::width(string.as_str()))); +} +#[test] +fn test_str() { + use super::UnicodeWidthStr; + + assert_eq!(UnicodeWidthStr::width("hello"), 10); + assert_eq!("hello".width_cjk(), 10); + assert_eq!(UnicodeWidthStr::width("\0\0\0\x01\x01"), 0); + assert_eq!("\0\0\0\x01\x01".width_cjk(), 0); + assert_eq!(UnicodeWidthStr::width(""), 0); + assert_eq!("".width_cjk(), 0); + assert_eq!( + UnicodeWidthStr::width("\u{2081}\u{2082}\u{2083}\u{2084}"), + 4 + ); + assert_eq!("\u{2081}\u{2082}\u{2083}\u{2084}".width_cjk(), 8); +} + +#[test] +fn test_emoji() { + // Example from the README. + use super::UnicodeWidthStr; + + assert_eq!(UnicodeWidthStr::width("👩"), 2); // Woman + assert_eq!(UnicodeWidthStr::width("🔬"), 2); // Microscope + assert_eq!(UnicodeWidthStr::width("👩‍🔬"), 4); // Woman scientist +} + +#[test] +fn test_char() { + use super::UnicodeWidthChar; + #[cfg(feature = "no_std")] + use core::option::Option::{None, Some}; + + assert_eq!(UnicodeWidthChar::width('h'), Some(2)); + assert_eq!('h'.width_cjk(), Some(2)); + assert_eq!(UnicodeWidthChar::width('\x00'), Some(0)); + assert_eq!('\x00'.width_cjk(), Some(0)); + assert_eq!(UnicodeWidthChar::width('\x01'), None); + assert_eq!('\x01'.width_cjk(), None); + assert_eq!(UnicodeWidthChar::width('\u{2081}'), Some(1)); + assert_eq!('\u{2081}'.width_cjk(), Some(2)); +} + +#[test] +fn test_char2() { + use super::UnicodeWidthChar; + #[cfg(feature = "no_std")] + use core::option::Option::{None, Some}; + + assert_eq!(UnicodeWidthChar::width('\x00'), Some(0)); + assert_eq!('\x00'.width_cjk(), Some(0)); + + assert_eq!(UnicodeWidthChar::width('\x0A'), None); + assert_eq!('\x0A'.width_cjk(), None); + + assert_eq!(UnicodeWidthChar::width('w'), Some(1)); + assert_eq!('w'.width_cjk(), Some(1)); + + assert_eq!(UnicodeWidthChar::width('h'), Some(2)); + assert_eq!('h'.width_cjk(), Some(2)); + + assert_eq!(UnicodeWidthChar::width('\u{AD}'), Some(1)); + assert_eq!('\u{AD}'.width_cjk(), Some(1)); + + assert_eq!(UnicodeWidthChar::width('\u{1160}'), Some(0)); + assert_eq!('\u{1160}'.width_cjk(), Some(0)); + + assert_eq!(UnicodeWidthChar::width('\u{a1}'), Some(1)); + assert_eq!('\u{a1}'.width_cjk(), Some(2)); + + assert_eq!(UnicodeWidthChar::width('\u{300}'), Some(0)); + assert_eq!('\u{300}'.width_cjk(), Some(0)); +} + +#[test] +fn unicode_12() { + use super::UnicodeWidthChar; + #[cfg(feature = "no_std")] + use core::option::Option::{None, Some}; + + assert_eq!(UnicodeWidthChar::width('\u{1F971}'), Some(2)); +} diff --git a/rio-unicode/tests/grapheme_conformance.rs b/rio-unicode/tests/grapheme_conformance.rs new file mode 100644 index 0000000000..1206513c2d --- /dev/null +++ b/rio-unicode/tests/grapheme_conformance.rs @@ -0,0 +1,780 @@ +// Generated by scripts/grapheme.py from GraphemeBreakTest.txt — do not edit. +// Unicode 17.0.0: every UCD conformance vector. + +use rio_unicode::grapheme::Graphemes; + +#[test] +fn ucd_grapheme_break_test() { + let cases: &[(&str, &[&str])] = &[ + ("\u{D}\u{D}", &["\u{D}", "\u{D}"]), + ("\u{D}\u{308}\u{D}", &["\u{D}", "\u{308}", "\u{D}"]), + ("\u{D}\u{A}", &["\u{D}\u{A}"]), + ("\u{D}\u{308}\u{A}", &["\u{D}", "\u{308}", "\u{A}"]), + ("\u{D}\u{0}", &["\u{D}", "\u{0}"]), + ("\u{D}\u{308}\u{0}", &["\u{D}", "\u{308}", "\u{0}"]), + ("\u{D}\u{94D}", &["\u{D}", "\u{94D}"]), + ("\u{D}\u{308}\u{94D}", &["\u{D}", "\u{308}\u{94D}"]), + ("\u{D}\u{300}", &["\u{D}", "\u{300}"]), + ("\u{D}\u{308}\u{300}", &["\u{D}", "\u{308}\u{300}"]), + ("\u{D}\u{200C}", &["\u{D}", "\u{200C}"]), + ("\u{D}\u{308}\u{200C}", &["\u{D}", "\u{308}\u{200C}"]), + ("\u{D}\u{200D}", &["\u{D}", "\u{200D}"]), + ("\u{D}\u{308}\u{200D}", &["\u{D}", "\u{308}\u{200D}"]), + ("\u{D}\u{1F1E6}", &["\u{D}", "\u{1F1E6}"]), + ("\u{D}\u{308}\u{1F1E6}", &["\u{D}", "\u{308}", "\u{1F1E6}"]), + ("\u{D}\u{6DD}", &["\u{D}", "\u{6DD}"]), + ("\u{D}\u{308}\u{6DD}", &["\u{D}", "\u{308}", "\u{6DD}"]), + ("\u{D}\u{903}", &["\u{D}", "\u{903}"]), + ("\u{D}\u{308}\u{903}", &["\u{D}", "\u{308}\u{903}"]), + ("\u{D}\u{1100}", &["\u{D}", "\u{1100}"]), + ("\u{D}\u{308}\u{1100}", &["\u{D}", "\u{308}", "\u{1100}"]), + ("\u{D}\u{1160}", &["\u{D}", "\u{1160}"]), + ("\u{D}\u{308}\u{1160}", &["\u{D}", "\u{308}", "\u{1160}"]), + ("\u{D}\u{11A8}", &["\u{D}", "\u{11A8}"]), + ("\u{D}\u{308}\u{11A8}", &["\u{D}", "\u{308}", "\u{11A8}"]), + ("\u{D}\u{AC00}", &["\u{D}", "\u{AC00}"]), + ("\u{D}\u{308}\u{AC00}", &["\u{D}", "\u{308}", "\u{AC00}"]), + ("\u{D}\u{AC01}", &["\u{D}", "\u{AC01}"]), + ("\u{D}\u{308}\u{AC01}", &["\u{D}", "\u{308}", "\u{AC01}"]), + ("\u{D}\u{915}", &["\u{D}", "\u{915}"]), + ("\u{D}\u{308}\u{915}", &["\u{D}", "\u{308}", "\u{915}"]), + ("\u{D}\u{A9}", &["\u{D}", "\u{A9}"]), + ("\u{D}\u{308}\u{A9}", &["\u{D}", "\u{308}", "\u{A9}"]), + ("\u{D}\u{20}", &["\u{D}", "\u{20}"]), + ("\u{D}\u{308}\u{20}", &["\u{D}", "\u{308}", "\u{20}"]), + ("\u{D}\u{378}", &["\u{D}", "\u{378}"]), + ("\u{D}\u{308}\u{378}", &["\u{D}", "\u{308}", "\u{378}"]), + ("\u{A}\u{D}", &["\u{A}", "\u{D}"]), + ("\u{A}\u{308}\u{D}", &["\u{A}", "\u{308}", "\u{D}"]), + ("\u{A}\u{A}", &["\u{A}", "\u{A}"]), + ("\u{A}\u{308}\u{A}", &["\u{A}", "\u{308}", "\u{A}"]), + ("\u{A}\u{0}", &["\u{A}", "\u{0}"]), + ("\u{A}\u{308}\u{0}", &["\u{A}", "\u{308}", "\u{0}"]), + ("\u{A}\u{94D}", &["\u{A}", "\u{94D}"]), + ("\u{A}\u{308}\u{94D}", &["\u{A}", "\u{308}\u{94D}"]), + ("\u{A}\u{300}", &["\u{A}", "\u{300}"]), + ("\u{A}\u{308}\u{300}", &["\u{A}", "\u{308}\u{300}"]), + ("\u{A}\u{200C}", &["\u{A}", "\u{200C}"]), + ("\u{A}\u{308}\u{200C}", &["\u{A}", "\u{308}\u{200C}"]), + ("\u{A}\u{200D}", &["\u{A}", "\u{200D}"]), + ("\u{A}\u{308}\u{200D}", &["\u{A}", "\u{308}\u{200D}"]), + ("\u{A}\u{1F1E6}", &["\u{A}", "\u{1F1E6}"]), + ("\u{A}\u{308}\u{1F1E6}", &["\u{A}", "\u{308}", "\u{1F1E6}"]), + ("\u{A}\u{6DD}", &["\u{A}", "\u{6DD}"]), + ("\u{A}\u{308}\u{6DD}", &["\u{A}", "\u{308}", "\u{6DD}"]), + ("\u{A}\u{903}", &["\u{A}", "\u{903}"]), + ("\u{A}\u{308}\u{903}", &["\u{A}", "\u{308}\u{903}"]), + ("\u{A}\u{1100}", &["\u{A}", "\u{1100}"]), + ("\u{A}\u{308}\u{1100}", &["\u{A}", "\u{308}", "\u{1100}"]), + ("\u{A}\u{1160}", &["\u{A}", "\u{1160}"]), + ("\u{A}\u{308}\u{1160}", &["\u{A}", "\u{308}", "\u{1160}"]), + ("\u{A}\u{11A8}", &["\u{A}", "\u{11A8}"]), + ("\u{A}\u{308}\u{11A8}", &["\u{A}", "\u{308}", "\u{11A8}"]), + ("\u{A}\u{AC00}", &["\u{A}", "\u{AC00}"]), + ("\u{A}\u{308}\u{AC00}", &["\u{A}", "\u{308}", "\u{AC00}"]), + ("\u{A}\u{AC01}", &["\u{A}", "\u{AC01}"]), + ("\u{A}\u{308}\u{AC01}", &["\u{A}", "\u{308}", "\u{AC01}"]), + ("\u{A}\u{915}", &["\u{A}", "\u{915}"]), + ("\u{A}\u{308}\u{915}", &["\u{A}", "\u{308}", "\u{915}"]), + ("\u{A}\u{A9}", &["\u{A}", "\u{A9}"]), + ("\u{A}\u{308}\u{A9}", &["\u{A}", "\u{308}", "\u{A9}"]), + ("\u{A}\u{20}", &["\u{A}", "\u{20}"]), + ("\u{A}\u{308}\u{20}", &["\u{A}", "\u{308}", "\u{20}"]), + ("\u{A}\u{378}", &["\u{A}", "\u{378}"]), + ("\u{A}\u{308}\u{378}", &["\u{A}", "\u{308}", "\u{378}"]), + ("\u{0}\u{D}", &["\u{0}", "\u{D}"]), + ("\u{0}\u{308}\u{D}", &["\u{0}", "\u{308}", "\u{D}"]), + ("\u{0}\u{A}", &["\u{0}", "\u{A}"]), + ("\u{0}\u{308}\u{A}", &["\u{0}", "\u{308}", "\u{A}"]), + ("\u{0}\u{0}", &["\u{0}", "\u{0}"]), + ("\u{0}\u{308}\u{0}", &["\u{0}", "\u{308}", "\u{0}"]), + ("\u{0}\u{94D}", &["\u{0}", "\u{94D}"]), + ("\u{0}\u{308}\u{94D}", &["\u{0}", "\u{308}\u{94D}"]), + ("\u{0}\u{300}", &["\u{0}", "\u{300}"]), + ("\u{0}\u{308}\u{300}", &["\u{0}", "\u{308}\u{300}"]), + ("\u{0}\u{200C}", &["\u{0}", "\u{200C}"]), + ("\u{0}\u{308}\u{200C}", &["\u{0}", "\u{308}\u{200C}"]), + ("\u{0}\u{200D}", &["\u{0}", "\u{200D}"]), + ("\u{0}\u{308}\u{200D}", &["\u{0}", "\u{308}\u{200D}"]), + ("\u{0}\u{1F1E6}", &["\u{0}", "\u{1F1E6}"]), + ("\u{0}\u{308}\u{1F1E6}", &["\u{0}", "\u{308}", "\u{1F1E6}"]), + ("\u{0}\u{6DD}", &["\u{0}", "\u{6DD}"]), + ("\u{0}\u{308}\u{6DD}", &["\u{0}", "\u{308}", "\u{6DD}"]), + ("\u{0}\u{903}", &["\u{0}", "\u{903}"]), + ("\u{0}\u{308}\u{903}", &["\u{0}", "\u{308}\u{903}"]), + ("\u{0}\u{1100}", &["\u{0}", "\u{1100}"]), + ("\u{0}\u{308}\u{1100}", &["\u{0}", "\u{308}", "\u{1100}"]), + ("\u{0}\u{1160}", &["\u{0}", "\u{1160}"]), + ("\u{0}\u{308}\u{1160}", &["\u{0}", "\u{308}", "\u{1160}"]), + ("\u{0}\u{11A8}", &["\u{0}", "\u{11A8}"]), + ("\u{0}\u{308}\u{11A8}", &["\u{0}", "\u{308}", "\u{11A8}"]), + ("\u{0}\u{AC00}", &["\u{0}", "\u{AC00}"]), + ("\u{0}\u{308}\u{AC00}", &["\u{0}", "\u{308}", "\u{AC00}"]), + ("\u{0}\u{AC01}", &["\u{0}", "\u{AC01}"]), + ("\u{0}\u{308}\u{AC01}", &["\u{0}", "\u{308}", "\u{AC01}"]), + ("\u{0}\u{915}", &["\u{0}", "\u{915}"]), + ("\u{0}\u{308}\u{915}", &["\u{0}", "\u{308}", "\u{915}"]), + ("\u{0}\u{A9}", &["\u{0}", "\u{A9}"]), + ("\u{0}\u{308}\u{A9}", &["\u{0}", "\u{308}", "\u{A9}"]), + ("\u{0}\u{20}", &["\u{0}", "\u{20}"]), + ("\u{0}\u{308}\u{20}", &["\u{0}", "\u{308}", "\u{20}"]), + ("\u{0}\u{378}", &["\u{0}", "\u{378}"]), + ("\u{0}\u{308}\u{378}", &["\u{0}", "\u{308}", "\u{378}"]), + ("\u{94D}\u{D}", &["\u{94D}", "\u{D}"]), + ("\u{94D}\u{308}\u{D}", &["\u{94D}\u{308}", "\u{D}"]), + ("\u{94D}\u{A}", &["\u{94D}", "\u{A}"]), + ("\u{94D}\u{308}\u{A}", &["\u{94D}\u{308}", "\u{A}"]), + ("\u{94D}\u{0}", &["\u{94D}", "\u{0}"]), + ("\u{94D}\u{308}\u{0}", &["\u{94D}\u{308}", "\u{0}"]), + ("\u{94D}\u{94D}", &["\u{94D}\u{94D}"]), + ("\u{94D}\u{308}\u{94D}", &["\u{94D}\u{308}\u{94D}"]), + ("\u{94D}\u{300}", &["\u{94D}\u{300}"]), + ("\u{94D}\u{308}\u{300}", &["\u{94D}\u{308}\u{300}"]), + ("\u{94D}\u{200C}", &["\u{94D}\u{200C}"]), + ("\u{94D}\u{308}\u{200C}", &["\u{94D}\u{308}\u{200C}"]), + ("\u{94D}\u{200D}", &["\u{94D}\u{200D}"]), + ("\u{94D}\u{308}\u{200D}", &["\u{94D}\u{308}\u{200D}"]), + ("\u{94D}\u{1F1E6}", &["\u{94D}", "\u{1F1E6}"]), + ("\u{94D}\u{308}\u{1F1E6}", &["\u{94D}\u{308}", "\u{1F1E6}"]), + ("\u{94D}\u{6DD}", &["\u{94D}", "\u{6DD}"]), + ("\u{94D}\u{308}\u{6DD}", &["\u{94D}\u{308}", "\u{6DD}"]), + ("\u{94D}\u{903}", &["\u{94D}\u{903}"]), + ("\u{94D}\u{308}\u{903}", &["\u{94D}\u{308}\u{903}"]), + ("\u{94D}\u{1100}", &["\u{94D}", "\u{1100}"]), + ("\u{94D}\u{308}\u{1100}", &["\u{94D}\u{308}", "\u{1100}"]), + ("\u{94D}\u{1160}", &["\u{94D}", "\u{1160}"]), + ("\u{94D}\u{308}\u{1160}", &["\u{94D}\u{308}", "\u{1160}"]), + ("\u{94D}\u{11A8}", &["\u{94D}", "\u{11A8}"]), + ("\u{94D}\u{308}\u{11A8}", &["\u{94D}\u{308}", "\u{11A8}"]), + ("\u{94D}\u{AC00}", &["\u{94D}", "\u{AC00}"]), + ("\u{94D}\u{308}\u{AC00}", &["\u{94D}\u{308}", "\u{AC00}"]), + ("\u{94D}\u{AC01}", &["\u{94D}", "\u{AC01}"]), + ("\u{94D}\u{308}\u{AC01}", &["\u{94D}\u{308}", "\u{AC01}"]), + ("\u{94D}\u{915}", &["\u{94D}", "\u{915}"]), + ("\u{94D}\u{308}\u{915}", &["\u{94D}\u{308}", "\u{915}"]), + ("\u{94D}\u{A9}", &["\u{94D}", "\u{A9}"]), + ("\u{94D}\u{308}\u{A9}", &["\u{94D}\u{308}", "\u{A9}"]), + ("\u{94D}\u{20}", &["\u{94D}", "\u{20}"]), + ("\u{94D}\u{308}\u{20}", &["\u{94D}\u{308}", "\u{20}"]), + ("\u{94D}\u{378}", &["\u{94D}", "\u{378}"]), + ("\u{94D}\u{308}\u{378}", &["\u{94D}\u{308}", "\u{378}"]), + ("\u{300}\u{D}", &["\u{300}", "\u{D}"]), + ("\u{300}\u{308}\u{D}", &["\u{300}\u{308}", "\u{D}"]), + ("\u{300}\u{A}", &["\u{300}", "\u{A}"]), + ("\u{300}\u{308}\u{A}", &["\u{300}\u{308}", "\u{A}"]), + ("\u{300}\u{0}", &["\u{300}", "\u{0}"]), + ("\u{300}\u{308}\u{0}", &["\u{300}\u{308}", "\u{0}"]), + ("\u{300}\u{94D}", &["\u{300}\u{94D}"]), + ("\u{300}\u{308}\u{94D}", &["\u{300}\u{308}\u{94D}"]), + ("\u{300}\u{300}", &["\u{300}\u{300}"]), + ("\u{300}\u{308}\u{300}", &["\u{300}\u{308}\u{300}"]), + ("\u{300}\u{200C}", &["\u{300}\u{200C}"]), + ("\u{300}\u{308}\u{200C}", &["\u{300}\u{308}\u{200C}"]), + ("\u{300}\u{200D}", &["\u{300}\u{200D}"]), + ("\u{300}\u{308}\u{200D}", &["\u{300}\u{308}\u{200D}"]), + ("\u{300}\u{1F1E6}", &["\u{300}", "\u{1F1E6}"]), + ("\u{300}\u{308}\u{1F1E6}", &["\u{300}\u{308}", "\u{1F1E6}"]), + ("\u{300}\u{6DD}", &["\u{300}", "\u{6DD}"]), + ("\u{300}\u{308}\u{6DD}", &["\u{300}\u{308}", "\u{6DD}"]), + ("\u{300}\u{903}", &["\u{300}\u{903}"]), + ("\u{300}\u{308}\u{903}", &["\u{300}\u{308}\u{903}"]), + ("\u{300}\u{1100}", &["\u{300}", "\u{1100}"]), + ("\u{300}\u{308}\u{1100}", &["\u{300}\u{308}", "\u{1100}"]), + ("\u{300}\u{1160}", &["\u{300}", "\u{1160}"]), + ("\u{300}\u{308}\u{1160}", &["\u{300}\u{308}", "\u{1160}"]), + ("\u{300}\u{11A8}", &["\u{300}", "\u{11A8}"]), + ("\u{300}\u{308}\u{11A8}", &["\u{300}\u{308}", "\u{11A8}"]), + ("\u{300}\u{AC00}", &["\u{300}", "\u{AC00}"]), + ("\u{300}\u{308}\u{AC00}", &["\u{300}\u{308}", "\u{AC00}"]), + ("\u{300}\u{AC01}", &["\u{300}", "\u{AC01}"]), + ("\u{300}\u{308}\u{AC01}", &["\u{300}\u{308}", "\u{AC01}"]), + ("\u{300}\u{915}", &["\u{300}", "\u{915}"]), + ("\u{300}\u{308}\u{915}", &["\u{300}\u{308}", "\u{915}"]), + ("\u{300}\u{A9}", &["\u{300}", "\u{A9}"]), + ("\u{300}\u{308}\u{A9}", &["\u{300}\u{308}", "\u{A9}"]), + ("\u{300}\u{20}", &["\u{300}", "\u{20}"]), + ("\u{300}\u{308}\u{20}", &["\u{300}\u{308}", "\u{20}"]), + ("\u{300}\u{378}", &["\u{300}", "\u{378}"]), + ("\u{300}\u{308}\u{378}", &["\u{300}\u{308}", "\u{378}"]), + ("\u{200C}\u{D}", &["\u{200C}", "\u{D}"]), + ("\u{200C}\u{308}\u{D}", &["\u{200C}\u{308}", "\u{D}"]), + ("\u{200C}\u{A}", &["\u{200C}", "\u{A}"]), + ("\u{200C}\u{308}\u{A}", &["\u{200C}\u{308}", "\u{A}"]), + ("\u{200C}\u{0}", &["\u{200C}", "\u{0}"]), + ("\u{200C}\u{308}\u{0}", &["\u{200C}\u{308}", "\u{0}"]), + ("\u{200C}\u{94D}", &["\u{200C}\u{94D}"]), + ("\u{200C}\u{308}\u{94D}", &["\u{200C}\u{308}\u{94D}"]), + ("\u{200C}\u{300}", &["\u{200C}\u{300}"]), + ("\u{200C}\u{308}\u{300}", &["\u{200C}\u{308}\u{300}"]), + ("\u{200C}\u{200C}", &["\u{200C}\u{200C}"]), + ("\u{200C}\u{308}\u{200C}", &["\u{200C}\u{308}\u{200C}"]), + ("\u{200C}\u{200D}", &["\u{200C}\u{200D}"]), + ("\u{200C}\u{308}\u{200D}", &["\u{200C}\u{308}\u{200D}"]), + ("\u{200C}\u{1F1E6}", &["\u{200C}", "\u{1F1E6}"]), + ("\u{200C}\u{308}\u{1F1E6}", &["\u{200C}\u{308}", "\u{1F1E6}"]), + ("\u{200C}\u{6DD}", &["\u{200C}", "\u{6DD}"]), + ("\u{200C}\u{308}\u{6DD}", &["\u{200C}\u{308}", "\u{6DD}"]), + ("\u{200C}\u{903}", &["\u{200C}\u{903}"]), + ("\u{200C}\u{308}\u{903}", &["\u{200C}\u{308}\u{903}"]), + ("\u{200C}\u{1100}", &["\u{200C}", "\u{1100}"]), + ("\u{200C}\u{308}\u{1100}", &["\u{200C}\u{308}", "\u{1100}"]), + ("\u{200C}\u{1160}", &["\u{200C}", "\u{1160}"]), + ("\u{200C}\u{308}\u{1160}", &["\u{200C}\u{308}", "\u{1160}"]), + ("\u{200C}\u{11A8}", &["\u{200C}", "\u{11A8}"]), + ("\u{200C}\u{308}\u{11A8}", &["\u{200C}\u{308}", "\u{11A8}"]), + ("\u{200C}\u{AC00}", &["\u{200C}", "\u{AC00}"]), + ("\u{200C}\u{308}\u{AC00}", &["\u{200C}\u{308}", "\u{AC00}"]), + ("\u{200C}\u{AC01}", &["\u{200C}", "\u{AC01}"]), + ("\u{200C}\u{308}\u{AC01}", &["\u{200C}\u{308}", "\u{AC01}"]), + ("\u{200C}\u{915}", &["\u{200C}", "\u{915}"]), + ("\u{200C}\u{308}\u{915}", &["\u{200C}\u{308}", "\u{915}"]), + ("\u{200C}\u{A9}", &["\u{200C}", "\u{A9}"]), + ("\u{200C}\u{308}\u{A9}", &["\u{200C}\u{308}", "\u{A9}"]), + ("\u{200C}\u{20}", &["\u{200C}", "\u{20}"]), + ("\u{200C}\u{308}\u{20}", &["\u{200C}\u{308}", "\u{20}"]), + ("\u{200C}\u{378}", &["\u{200C}", "\u{378}"]), + ("\u{200C}\u{308}\u{378}", &["\u{200C}\u{308}", "\u{378}"]), + ("\u{200D}\u{D}", &["\u{200D}", "\u{D}"]), + ("\u{200D}\u{308}\u{D}", &["\u{200D}\u{308}", "\u{D}"]), + ("\u{200D}\u{A}", &["\u{200D}", "\u{A}"]), + ("\u{200D}\u{308}\u{A}", &["\u{200D}\u{308}", "\u{A}"]), + ("\u{200D}\u{0}", &["\u{200D}", "\u{0}"]), + ("\u{200D}\u{308}\u{0}", &["\u{200D}\u{308}", "\u{0}"]), + ("\u{200D}\u{94D}", &["\u{200D}\u{94D}"]), + ("\u{200D}\u{308}\u{94D}", &["\u{200D}\u{308}\u{94D}"]), + ("\u{200D}\u{300}", &["\u{200D}\u{300}"]), + ("\u{200D}\u{308}\u{300}", &["\u{200D}\u{308}\u{300}"]), + ("\u{200D}\u{200C}", &["\u{200D}\u{200C}"]), + ("\u{200D}\u{308}\u{200C}", &["\u{200D}\u{308}\u{200C}"]), + ("\u{200D}\u{200D}", &["\u{200D}\u{200D}"]), + ("\u{200D}\u{308}\u{200D}", &["\u{200D}\u{308}\u{200D}"]), + ("\u{200D}\u{1F1E6}", &["\u{200D}", "\u{1F1E6}"]), + ("\u{200D}\u{308}\u{1F1E6}", &["\u{200D}\u{308}", "\u{1F1E6}"]), + ("\u{200D}\u{6DD}", &["\u{200D}", "\u{6DD}"]), + ("\u{200D}\u{308}\u{6DD}", &["\u{200D}\u{308}", "\u{6DD}"]), + ("\u{200D}\u{903}", &["\u{200D}\u{903}"]), + ("\u{200D}\u{308}\u{903}", &["\u{200D}\u{308}\u{903}"]), + ("\u{200D}\u{1100}", &["\u{200D}", "\u{1100}"]), + ("\u{200D}\u{308}\u{1100}", &["\u{200D}\u{308}", "\u{1100}"]), + ("\u{200D}\u{1160}", &["\u{200D}", "\u{1160}"]), + ("\u{200D}\u{308}\u{1160}", &["\u{200D}\u{308}", "\u{1160}"]), + ("\u{200D}\u{11A8}", &["\u{200D}", "\u{11A8}"]), + ("\u{200D}\u{308}\u{11A8}", &["\u{200D}\u{308}", "\u{11A8}"]), + ("\u{200D}\u{AC00}", &["\u{200D}", "\u{AC00}"]), + ("\u{200D}\u{308}\u{AC00}", &["\u{200D}\u{308}", "\u{AC00}"]), + ("\u{200D}\u{AC01}", &["\u{200D}", "\u{AC01}"]), + ("\u{200D}\u{308}\u{AC01}", &["\u{200D}\u{308}", "\u{AC01}"]), + ("\u{200D}\u{915}", &["\u{200D}", "\u{915}"]), + ("\u{200D}\u{308}\u{915}", &["\u{200D}\u{308}", "\u{915}"]), + ("\u{200D}\u{A9}", &["\u{200D}", "\u{A9}"]), + ("\u{200D}\u{308}\u{A9}", &["\u{200D}\u{308}", "\u{A9}"]), + ("\u{200D}\u{20}", &["\u{200D}", "\u{20}"]), + ("\u{200D}\u{308}\u{20}", &["\u{200D}\u{308}", "\u{20}"]), + ("\u{200D}\u{378}", &["\u{200D}", "\u{378}"]), + ("\u{200D}\u{308}\u{378}", &["\u{200D}\u{308}", "\u{378}"]), + ("\u{1F1E6}\u{D}", &["\u{1F1E6}", "\u{D}"]), + ("\u{1F1E6}\u{308}\u{D}", &["\u{1F1E6}\u{308}", "\u{D}"]), + ("\u{1F1E6}\u{A}", &["\u{1F1E6}", "\u{A}"]), + ("\u{1F1E6}\u{308}\u{A}", &["\u{1F1E6}\u{308}", "\u{A}"]), + ("\u{1F1E6}\u{0}", &["\u{1F1E6}", "\u{0}"]), + ("\u{1F1E6}\u{308}\u{0}", &["\u{1F1E6}\u{308}", "\u{0}"]), + ("\u{1F1E6}\u{94D}", &["\u{1F1E6}\u{94D}"]), + ("\u{1F1E6}\u{308}\u{94D}", &["\u{1F1E6}\u{308}\u{94D}"]), + ("\u{1F1E6}\u{300}", &["\u{1F1E6}\u{300}"]), + ("\u{1F1E6}\u{308}\u{300}", &["\u{1F1E6}\u{308}\u{300}"]), + ("\u{1F1E6}\u{200C}", &["\u{1F1E6}\u{200C}"]), + ("\u{1F1E6}\u{308}\u{200C}", &["\u{1F1E6}\u{308}\u{200C}"]), + ("\u{1F1E6}\u{200D}", &["\u{1F1E6}\u{200D}"]), + ("\u{1F1E6}\u{308}\u{200D}", &["\u{1F1E6}\u{308}\u{200D}"]), + ("\u{1F1E6}\u{1F1E6}", &["\u{1F1E6}\u{1F1E6}"]), + ("\u{1F1E6}\u{308}\u{1F1E6}", &["\u{1F1E6}\u{308}", "\u{1F1E6}"]), + ("\u{1F1E6}\u{6DD}", &["\u{1F1E6}", "\u{6DD}"]), + ("\u{1F1E6}\u{308}\u{6DD}", &["\u{1F1E6}\u{308}", "\u{6DD}"]), + ("\u{1F1E6}\u{903}", &["\u{1F1E6}\u{903}"]), + ("\u{1F1E6}\u{308}\u{903}", &["\u{1F1E6}\u{308}\u{903}"]), + ("\u{1F1E6}\u{1100}", &["\u{1F1E6}", "\u{1100}"]), + ("\u{1F1E6}\u{308}\u{1100}", &["\u{1F1E6}\u{308}", "\u{1100}"]), + ("\u{1F1E6}\u{1160}", &["\u{1F1E6}", "\u{1160}"]), + ("\u{1F1E6}\u{308}\u{1160}", &["\u{1F1E6}\u{308}", "\u{1160}"]), + ("\u{1F1E6}\u{11A8}", &["\u{1F1E6}", "\u{11A8}"]), + ("\u{1F1E6}\u{308}\u{11A8}", &["\u{1F1E6}\u{308}", "\u{11A8}"]), + ("\u{1F1E6}\u{AC00}", &["\u{1F1E6}", "\u{AC00}"]), + ("\u{1F1E6}\u{308}\u{AC00}", &["\u{1F1E6}\u{308}", "\u{AC00}"]), + ("\u{1F1E6}\u{AC01}", &["\u{1F1E6}", "\u{AC01}"]), + ("\u{1F1E6}\u{308}\u{AC01}", &["\u{1F1E6}\u{308}", "\u{AC01}"]), + ("\u{1F1E6}\u{915}", &["\u{1F1E6}", "\u{915}"]), + ("\u{1F1E6}\u{308}\u{915}", &["\u{1F1E6}\u{308}", "\u{915}"]), + ("\u{1F1E6}\u{A9}", &["\u{1F1E6}", "\u{A9}"]), + ("\u{1F1E6}\u{308}\u{A9}", &["\u{1F1E6}\u{308}", "\u{A9}"]), + ("\u{1F1E6}\u{20}", &["\u{1F1E6}", "\u{20}"]), + ("\u{1F1E6}\u{308}\u{20}", &["\u{1F1E6}\u{308}", "\u{20}"]), + ("\u{1F1E6}\u{378}", &["\u{1F1E6}", "\u{378}"]), + ("\u{1F1E6}\u{308}\u{378}", &["\u{1F1E6}\u{308}", "\u{378}"]), + ("\u{6DD}\u{D}", &["\u{6DD}", "\u{D}"]), + ("\u{6DD}\u{308}\u{D}", &["\u{6DD}\u{308}", "\u{D}"]), + ("\u{6DD}\u{A}", &["\u{6DD}", "\u{A}"]), + ("\u{6DD}\u{308}\u{A}", &["\u{6DD}\u{308}", "\u{A}"]), + ("\u{6DD}\u{0}", &["\u{6DD}", "\u{0}"]), + ("\u{6DD}\u{308}\u{0}", &["\u{6DD}\u{308}", "\u{0}"]), + ("\u{6DD}\u{94D}", &["\u{6DD}\u{94D}"]), + ("\u{6DD}\u{308}\u{94D}", &["\u{6DD}\u{308}\u{94D}"]), + ("\u{6DD}\u{300}", &["\u{6DD}\u{300}"]), + ("\u{6DD}\u{308}\u{300}", &["\u{6DD}\u{308}\u{300}"]), + ("\u{6DD}\u{200C}", &["\u{6DD}\u{200C}"]), + ("\u{6DD}\u{308}\u{200C}", &["\u{6DD}\u{308}\u{200C}"]), + ("\u{6DD}\u{200D}", &["\u{6DD}\u{200D}"]), + ("\u{6DD}\u{308}\u{200D}", &["\u{6DD}\u{308}\u{200D}"]), + ("\u{6DD}\u{1F1E6}", &["\u{6DD}\u{1F1E6}"]), + ("\u{6DD}\u{308}\u{1F1E6}", &["\u{6DD}\u{308}", "\u{1F1E6}"]), + ("\u{6DD}\u{6DD}", &["\u{6DD}\u{6DD}"]), + ("\u{6DD}\u{308}\u{6DD}", &["\u{6DD}\u{308}", "\u{6DD}"]), + ("\u{6DD}\u{903}", &["\u{6DD}\u{903}"]), + ("\u{6DD}\u{308}\u{903}", &["\u{6DD}\u{308}\u{903}"]), + ("\u{6DD}\u{1100}", &["\u{6DD}\u{1100}"]), + ("\u{6DD}\u{308}\u{1100}", &["\u{6DD}\u{308}", "\u{1100}"]), + ("\u{6DD}\u{1160}", &["\u{6DD}\u{1160}"]), + ("\u{6DD}\u{308}\u{1160}", &["\u{6DD}\u{308}", "\u{1160}"]), + ("\u{6DD}\u{11A8}", &["\u{6DD}\u{11A8}"]), + ("\u{6DD}\u{308}\u{11A8}", &["\u{6DD}\u{308}", "\u{11A8}"]), + ("\u{6DD}\u{AC00}", &["\u{6DD}\u{AC00}"]), + ("\u{6DD}\u{308}\u{AC00}", &["\u{6DD}\u{308}", "\u{AC00}"]), + ("\u{6DD}\u{AC01}", &["\u{6DD}\u{AC01}"]), + ("\u{6DD}\u{308}\u{AC01}", &["\u{6DD}\u{308}", "\u{AC01}"]), + ("\u{6DD}\u{915}", &["\u{6DD}\u{915}"]), + ("\u{6DD}\u{308}\u{915}", &["\u{6DD}\u{308}", "\u{915}"]), + ("\u{6DD}\u{A9}", &["\u{6DD}\u{A9}"]), + ("\u{6DD}\u{308}\u{A9}", &["\u{6DD}\u{308}", "\u{A9}"]), + ("\u{6DD}\u{20}", &["\u{6DD}\u{20}"]), + ("\u{6DD}\u{308}\u{20}", &["\u{6DD}\u{308}", "\u{20}"]), + ("\u{6DD}\u{378}", &["\u{6DD}\u{378}"]), + ("\u{6DD}\u{308}\u{378}", &["\u{6DD}\u{308}", "\u{378}"]), + ("\u{903}\u{D}", &["\u{903}", "\u{D}"]), + ("\u{903}\u{308}\u{D}", &["\u{903}\u{308}", "\u{D}"]), + ("\u{903}\u{A}", &["\u{903}", "\u{A}"]), + ("\u{903}\u{308}\u{A}", &["\u{903}\u{308}", "\u{A}"]), + ("\u{903}\u{0}", &["\u{903}", "\u{0}"]), + ("\u{903}\u{308}\u{0}", &["\u{903}\u{308}", "\u{0}"]), + ("\u{903}\u{94D}", &["\u{903}\u{94D}"]), + ("\u{903}\u{308}\u{94D}", &["\u{903}\u{308}\u{94D}"]), + ("\u{903}\u{300}", &["\u{903}\u{300}"]), + ("\u{903}\u{308}\u{300}", &["\u{903}\u{308}\u{300}"]), + ("\u{903}\u{200C}", &["\u{903}\u{200C}"]), + ("\u{903}\u{308}\u{200C}", &["\u{903}\u{308}\u{200C}"]), + ("\u{903}\u{200D}", &["\u{903}\u{200D}"]), + ("\u{903}\u{308}\u{200D}", &["\u{903}\u{308}\u{200D}"]), + ("\u{903}\u{1F1E6}", &["\u{903}", "\u{1F1E6}"]), + ("\u{903}\u{308}\u{1F1E6}", &["\u{903}\u{308}", "\u{1F1E6}"]), + ("\u{903}\u{6DD}", &["\u{903}", "\u{6DD}"]), + ("\u{903}\u{308}\u{6DD}", &["\u{903}\u{308}", "\u{6DD}"]), + ("\u{903}\u{903}", &["\u{903}\u{903}"]), + ("\u{903}\u{308}\u{903}", &["\u{903}\u{308}\u{903}"]), + ("\u{903}\u{1100}", &["\u{903}", "\u{1100}"]), + ("\u{903}\u{308}\u{1100}", &["\u{903}\u{308}", "\u{1100}"]), + ("\u{903}\u{1160}", &["\u{903}", "\u{1160}"]), + ("\u{903}\u{308}\u{1160}", &["\u{903}\u{308}", "\u{1160}"]), + ("\u{903}\u{11A8}", &["\u{903}", "\u{11A8}"]), + ("\u{903}\u{308}\u{11A8}", &["\u{903}\u{308}", "\u{11A8}"]), + ("\u{903}\u{AC00}", &["\u{903}", "\u{AC00}"]), + ("\u{903}\u{308}\u{AC00}", &["\u{903}\u{308}", "\u{AC00}"]), + ("\u{903}\u{AC01}", &["\u{903}", "\u{AC01}"]), + ("\u{903}\u{308}\u{AC01}", &["\u{903}\u{308}", "\u{AC01}"]), + ("\u{903}\u{915}", &["\u{903}", "\u{915}"]), + ("\u{903}\u{308}\u{915}", &["\u{903}\u{308}", "\u{915}"]), + ("\u{903}\u{A9}", &["\u{903}", "\u{A9}"]), + ("\u{903}\u{308}\u{A9}", &["\u{903}\u{308}", "\u{A9}"]), + ("\u{903}\u{20}", &["\u{903}", "\u{20}"]), + ("\u{903}\u{308}\u{20}", &["\u{903}\u{308}", "\u{20}"]), + ("\u{903}\u{378}", &["\u{903}", "\u{378}"]), + ("\u{903}\u{308}\u{378}", &["\u{903}\u{308}", "\u{378}"]), + ("\u{1100}\u{D}", &["\u{1100}", "\u{D}"]), + ("\u{1100}\u{308}\u{D}", &["\u{1100}\u{308}", "\u{D}"]), + ("\u{1100}\u{A}", &["\u{1100}", "\u{A}"]), + ("\u{1100}\u{308}\u{A}", &["\u{1100}\u{308}", "\u{A}"]), + ("\u{1100}\u{0}", &["\u{1100}", "\u{0}"]), + ("\u{1100}\u{308}\u{0}", &["\u{1100}\u{308}", "\u{0}"]), + ("\u{1100}\u{94D}", &["\u{1100}\u{94D}"]), + ("\u{1100}\u{308}\u{94D}", &["\u{1100}\u{308}\u{94D}"]), + ("\u{1100}\u{300}", &["\u{1100}\u{300}"]), + ("\u{1100}\u{308}\u{300}", &["\u{1100}\u{308}\u{300}"]), + ("\u{1100}\u{200C}", &["\u{1100}\u{200C}"]), + ("\u{1100}\u{308}\u{200C}", &["\u{1100}\u{308}\u{200C}"]), + ("\u{1100}\u{200D}", &["\u{1100}\u{200D}"]), + ("\u{1100}\u{308}\u{200D}", &["\u{1100}\u{308}\u{200D}"]), + ("\u{1100}\u{1F1E6}", &["\u{1100}", "\u{1F1E6}"]), + ("\u{1100}\u{308}\u{1F1E6}", &["\u{1100}\u{308}", "\u{1F1E6}"]), + ("\u{1100}\u{6DD}", &["\u{1100}", "\u{6DD}"]), + ("\u{1100}\u{308}\u{6DD}", &["\u{1100}\u{308}", "\u{6DD}"]), + ("\u{1100}\u{903}", &["\u{1100}\u{903}"]), + ("\u{1100}\u{308}\u{903}", &["\u{1100}\u{308}\u{903}"]), + ("\u{1100}\u{1100}", &["\u{1100}\u{1100}"]), + ("\u{1100}\u{308}\u{1100}", &["\u{1100}\u{308}", "\u{1100}"]), + ("\u{1100}\u{1160}", &["\u{1100}\u{1160}"]), + ("\u{1100}\u{308}\u{1160}", &["\u{1100}\u{308}", "\u{1160}"]), + ("\u{1100}\u{11A8}", &["\u{1100}", "\u{11A8}"]), + ("\u{1100}\u{308}\u{11A8}", &["\u{1100}\u{308}", "\u{11A8}"]), + ("\u{1100}\u{AC00}", &["\u{1100}\u{AC00}"]), + ("\u{1100}\u{308}\u{AC00}", &["\u{1100}\u{308}", "\u{AC00}"]), + ("\u{1100}\u{AC01}", &["\u{1100}\u{AC01}"]), + ("\u{1100}\u{308}\u{AC01}", &["\u{1100}\u{308}", "\u{AC01}"]), + ("\u{1100}\u{915}", &["\u{1100}", "\u{915}"]), + ("\u{1100}\u{308}\u{915}", &["\u{1100}\u{308}", "\u{915}"]), + ("\u{1100}\u{A9}", &["\u{1100}", "\u{A9}"]), + ("\u{1100}\u{308}\u{A9}", &["\u{1100}\u{308}", "\u{A9}"]), + ("\u{1100}\u{20}", &["\u{1100}", "\u{20}"]), + ("\u{1100}\u{308}\u{20}", &["\u{1100}\u{308}", "\u{20}"]), + ("\u{1100}\u{378}", &["\u{1100}", "\u{378}"]), + ("\u{1100}\u{308}\u{378}", &["\u{1100}\u{308}", "\u{378}"]), + ("\u{1160}\u{D}", &["\u{1160}", "\u{D}"]), + ("\u{1160}\u{308}\u{D}", &["\u{1160}\u{308}", "\u{D}"]), + ("\u{1160}\u{A}", &["\u{1160}", "\u{A}"]), + ("\u{1160}\u{308}\u{A}", &["\u{1160}\u{308}", "\u{A}"]), + ("\u{1160}\u{0}", &["\u{1160}", "\u{0}"]), + ("\u{1160}\u{308}\u{0}", &["\u{1160}\u{308}", "\u{0}"]), + ("\u{1160}\u{94D}", &["\u{1160}\u{94D}"]), + ("\u{1160}\u{308}\u{94D}", &["\u{1160}\u{308}\u{94D}"]), + ("\u{1160}\u{300}", &["\u{1160}\u{300}"]), + ("\u{1160}\u{308}\u{300}", &["\u{1160}\u{308}\u{300}"]), + ("\u{1160}\u{200C}", &["\u{1160}\u{200C}"]), + ("\u{1160}\u{308}\u{200C}", &["\u{1160}\u{308}\u{200C}"]), + ("\u{1160}\u{200D}", &["\u{1160}\u{200D}"]), + ("\u{1160}\u{308}\u{200D}", &["\u{1160}\u{308}\u{200D}"]), + ("\u{1160}\u{1F1E6}", &["\u{1160}", "\u{1F1E6}"]), + ("\u{1160}\u{308}\u{1F1E6}", &["\u{1160}\u{308}", "\u{1F1E6}"]), + ("\u{1160}\u{6DD}", &["\u{1160}", "\u{6DD}"]), + ("\u{1160}\u{308}\u{6DD}", &["\u{1160}\u{308}", "\u{6DD}"]), + ("\u{1160}\u{903}", &["\u{1160}\u{903}"]), + ("\u{1160}\u{308}\u{903}", &["\u{1160}\u{308}\u{903}"]), + ("\u{1160}\u{1100}", &["\u{1160}", "\u{1100}"]), + ("\u{1160}\u{308}\u{1100}", &["\u{1160}\u{308}", "\u{1100}"]), + ("\u{1160}\u{1160}", &["\u{1160}\u{1160}"]), + ("\u{1160}\u{308}\u{1160}", &["\u{1160}\u{308}", "\u{1160}"]), + ("\u{1160}\u{11A8}", &["\u{1160}\u{11A8}"]), + ("\u{1160}\u{308}\u{11A8}", &["\u{1160}\u{308}", "\u{11A8}"]), + ("\u{1160}\u{AC00}", &["\u{1160}", "\u{AC00}"]), + ("\u{1160}\u{308}\u{AC00}", &["\u{1160}\u{308}", "\u{AC00}"]), + ("\u{1160}\u{AC01}", &["\u{1160}", "\u{AC01}"]), + ("\u{1160}\u{308}\u{AC01}", &["\u{1160}\u{308}", "\u{AC01}"]), + ("\u{1160}\u{915}", &["\u{1160}", "\u{915}"]), + ("\u{1160}\u{308}\u{915}", &["\u{1160}\u{308}", "\u{915}"]), + ("\u{1160}\u{A9}", &["\u{1160}", "\u{A9}"]), + ("\u{1160}\u{308}\u{A9}", &["\u{1160}\u{308}", "\u{A9}"]), + ("\u{1160}\u{20}", &["\u{1160}", "\u{20}"]), + ("\u{1160}\u{308}\u{20}", &["\u{1160}\u{308}", "\u{20}"]), + ("\u{1160}\u{378}", &["\u{1160}", "\u{378}"]), + ("\u{1160}\u{308}\u{378}", &["\u{1160}\u{308}", "\u{378}"]), + ("\u{11A8}\u{D}", &["\u{11A8}", "\u{D}"]), + ("\u{11A8}\u{308}\u{D}", &["\u{11A8}\u{308}", "\u{D}"]), + ("\u{11A8}\u{A}", &["\u{11A8}", "\u{A}"]), + ("\u{11A8}\u{308}\u{A}", &["\u{11A8}\u{308}", "\u{A}"]), + ("\u{11A8}\u{0}", &["\u{11A8}", "\u{0}"]), + ("\u{11A8}\u{308}\u{0}", &["\u{11A8}\u{308}", "\u{0}"]), + ("\u{11A8}\u{94D}", &["\u{11A8}\u{94D}"]), + ("\u{11A8}\u{308}\u{94D}", &["\u{11A8}\u{308}\u{94D}"]), + ("\u{11A8}\u{300}", &["\u{11A8}\u{300}"]), + ("\u{11A8}\u{308}\u{300}", &["\u{11A8}\u{308}\u{300}"]), + ("\u{11A8}\u{200C}", &["\u{11A8}\u{200C}"]), + ("\u{11A8}\u{308}\u{200C}", &["\u{11A8}\u{308}\u{200C}"]), + ("\u{11A8}\u{200D}", &["\u{11A8}\u{200D}"]), + ("\u{11A8}\u{308}\u{200D}", &["\u{11A8}\u{308}\u{200D}"]), + ("\u{11A8}\u{1F1E6}", &["\u{11A8}", "\u{1F1E6}"]), + ("\u{11A8}\u{308}\u{1F1E6}", &["\u{11A8}\u{308}", "\u{1F1E6}"]), + ("\u{11A8}\u{6DD}", &["\u{11A8}", "\u{6DD}"]), + ("\u{11A8}\u{308}\u{6DD}", &["\u{11A8}\u{308}", "\u{6DD}"]), + ("\u{11A8}\u{903}", &["\u{11A8}\u{903}"]), + ("\u{11A8}\u{308}\u{903}", &["\u{11A8}\u{308}\u{903}"]), + ("\u{11A8}\u{1100}", &["\u{11A8}", "\u{1100}"]), + ("\u{11A8}\u{308}\u{1100}", &["\u{11A8}\u{308}", "\u{1100}"]), + ("\u{11A8}\u{1160}", &["\u{11A8}", "\u{1160}"]), + ("\u{11A8}\u{308}\u{1160}", &["\u{11A8}\u{308}", "\u{1160}"]), + ("\u{11A8}\u{11A8}", &["\u{11A8}\u{11A8}"]), + ("\u{11A8}\u{308}\u{11A8}", &["\u{11A8}\u{308}", "\u{11A8}"]), + ("\u{11A8}\u{AC00}", &["\u{11A8}", "\u{AC00}"]), + ("\u{11A8}\u{308}\u{AC00}", &["\u{11A8}\u{308}", "\u{AC00}"]), + ("\u{11A8}\u{AC01}", &["\u{11A8}", "\u{AC01}"]), + ("\u{11A8}\u{308}\u{AC01}", &["\u{11A8}\u{308}", "\u{AC01}"]), + ("\u{11A8}\u{915}", &["\u{11A8}", "\u{915}"]), + ("\u{11A8}\u{308}\u{915}", &["\u{11A8}\u{308}", "\u{915}"]), + ("\u{11A8}\u{A9}", &["\u{11A8}", "\u{A9}"]), + ("\u{11A8}\u{308}\u{A9}", &["\u{11A8}\u{308}", "\u{A9}"]), + ("\u{11A8}\u{20}", &["\u{11A8}", "\u{20}"]), + ("\u{11A8}\u{308}\u{20}", &["\u{11A8}\u{308}", "\u{20}"]), + ("\u{11A8}\u{378}", &["\u{11A8}", "\u{378}"]), + ("\u{11A8}\u{308}\u{378}", &["\u{11A8}\u{308}", "\u{378}"]), + ("\u{AC00}\u{D}", &["\u{AC00}", "\u{D}"]), + ("\u{AC00}\u{308}\u{D}", &["\u{AC00}\u{308}", "\u{D}"]), + ("\u{AC00}\u{A}", &["\u{AC00}", "\u{A}"]), + ("\u{AC00}\u{308}\u{A}", &["\u{AC00}\u{308}", "\u{A}"]), + ("\u{AC00}\u{0}", &["\u{AC00}", "\u{0}"]), + ("\u{AC00}\u{308}\u{0}", &["\u{AC00}\u{308}", "\u{0}"]), + ("\u{AC00}\u{94D}", &["\u{AC00}\u{94D}"]), + ("\u{AC00}\u{308}\u{94D}", &["\u{AC00}\u{308}\u{94D}"]), + ("\u{AC00}\u{300}", &["\u{AC00}\u{300}"]), + ("\u{AC00}\u{308}\u{300}", &["\u{AC00}\u{308}\u{300}"]), + ("\u{AC00}\u{200C}", &["\u{AC00}\u{200C}"]), + ("\u{AC00}\u{308}\u{200C}", &["\u{AC00}\u{308}\u{200C}"]), + ("\u{AC00}\u{200D}", &["\u{AC00}\u{200D}"]), + ("\u{AC00}\u{308}\u{200D}", &["\u{AC00}\u{308}\u{200D}"]), + ("\u{AC00}\u{1F1E6}", &["\u{AC00}", "\u{1F1E6}"]), + ("\u{AC00}\u{308}\u{1F1E6}", &["\u{AC00}\u{308}", "\u{1F1E6}"]), + ("\u{AC00}\u{6DD}", &["\u{AC00}", "\u{6DD}"]), + ("\u{AC00}\u{308}\u{6DD}", &["\u{AC00}\u{308}", "\u{6DD}"]), + ("\u{AC00}\u{903}", &["\u{AC00}\u{903}"]), + ("\u{AC00}\u{308}\u{903}", &["\u{AC00}\u{308}\u{903}"]), + ("\u{AC00}\u{1100}", &["\u{AC00}", "\u{1100}"]), + ("\u{AC00}\u{308}\u{1100}", &["\u{AC00}\u{308}", "\u{1100}"]), + ("\u{AC00}\u{1160}", &["\u{AC00}\u{1160}"]), + ("\u{AC00}\u{308}\u{1160}", &["\u{AC00}\u{308}", "\u{1160}"]), + ("\u{AC00}\u{11A8}", &["\u{AC00}\u{11A8}"]), + ("\u{AC00}\u{308}\u{11A8}", &["\u{AC00}\u{308}", "\u{11A8}"]), + ("\u{AC00}\u{AC00}", &["\u{AC00}", "\u{AC00}"]), + ("\u{AC00}\u{308}\u{AC00}", &["\u{AC00}\u{308}", "\u{AC00}"]), + ("\u{AC00}\u{AC01}", &["\u{AC00}", "\u{AC01}"]), + ("\u{AC00}\u{308}\u{AC01}", &["\u{AC00}\u{308}", "\u{AC01}"]), + ("\u{AC00}\u{915}", &["\u{AC00}", "\u{915}"]), + ("\u{AC00}\u{308}\u{915}", &["\u{AC00}\u{308}", "\u{915}"]), + ("\u{AC00}\u{A9}", &["\u{AC00}", "\u{A9}"]), + ("\u{AC00}\u{308}\u{A9}", &["\u{AC00}\u{308}", "\u{A9}"]), + ("\u{AC00}\u{20}", &["\u{AC00}", "\u{20}"]), + ("\u{AC00}\u{308}\u{20}", &["\u{AC00}\u{308}", "\u{20}"]), + ("\u{AC00}\u{378}", &["\u{AC00}", "\u{378}"]), + ("\u{AC00}\u{308}\u{378}", &["\u{AC00}\u{308}", "\u{378}"]), + ("\u{AC01}\u{D}", &["\u{AC01}", "\u{D}"]), + ("\u{AC01}\u{308}\u{D}", &["\u{AC01}\u{308}", "\u{D}"]), + ("\u{AC01}\u{A}", &["\u{AC01}", "\u{A}"]), + ("\u{AC01}\u{308}\u{A}", &["\u{AC01}\u{308}", "\u{A}"]), + ("\u{AC01}\u{0}", &["\u{AC01}", "\u{0}"]), + ("\u{AC01}\u{308}\u{0}", &["\u{AC01}\u{308}", "\u{0}"]), + ("\u{AC01}\u{94D}", &["\u{AC01}\u{94D}"]), + ("\u{AC01}\u{308}\u{94D}", &["\u{AC01}\u{308}\u{94D}"]), + ("\u{AC01}\u{300}", &["\u{AC01}\u{300}"]), + ("\u{AC01}\u{308}\u{300}", &["\u{AC01}\u{308}\u{300}"]), + ("\u{AC01}\u{200C}", &["\u{AC01}\u{200C}"]), + ("\u{AC01}\u{308}\u{200C}", &["\u{AC01}\u{308}\u{200C}"]), + ("\u{AC01}\u{200D}", &["\u{AC01}\u{200D}"]), + ("\u{AC01}\u{308}\u{200D}", &["\u{AC01}\u{308}\u{200D}"]), + ("\u{AC01}\u{1F1E6}", &["\u{AC01}", "\u{1F1E6}"]), + ("\u{AC01}\u{308}\u{1F1E6}", &["\u{AC01}\u{308}", "\u{1F1E6}"]), + ("\u{AC01}\u{6DD}", &["\u{AC01}", "\u{6DD}"]), + ("\u{AC01}\u{308}\u{6DD}", &["\u{AC01}\u{308}", "\u{6DD}"]), + ("\u{AC01}\u{903}", &["\u{AC01}\u{903}"]), + ("\u{AC01}\u{308}\u{903}", &["\u{AC01}\u{308}\u{903}"]), + ("\u{AC01}\u{1100}", &["\u{AC01}", "\u{1100}"]), + ("\u{AC01}\u{308}\u{1100}", &["\u{AC01}\u{308}", "\u{1100}"]), + ("\u{AC01}\u{1160}", &["\u{AC01}", "\u{1160}"]), + ("\u{AC01}\u{308}\u{1160}", &["\u{AC01}\u{308}", "\u{1160}"]), + ("\u{AC01}\u{11A8}", &["\u{AC01}\u{11A8}"]), + ("\u{AC01}\u{308}\u{11A8}", &["\u{AC01}\u{308}", "\u{11A8}"]), + ("\u{AC01}\u{AC00}", &["\u{AC01}", "\u{AC00}"]), + ("\u{AC01}\u{308}\u{AC00}", &["\u{AC01}\u{308}", "\u{AC00}"]), + ("\u{AC01}\u{AC01}", &["\u{AC01}", "\u{AC01}"]), + ("\u{AC01}\u{308}\u{AC01}", &["\u{AC01}\u{308}", "\u{AC01}"]), + ("\u{AC01}\u{915}", &["\u{AC01}", "\u{915}"]), + ("\u{AC01}\u{308}\u{915}", &["\u{AC01}\u{308}", "\u{915}"]), + ("\u{AC01}\u{A9}", &["\u{AC01}", "\u{A9}"]), + ("\u{AC01}\u{308}\u{A9}", &["\u{AC01}\u{308}", "\u{A9}"]), + ("\u{AC01}\u{20}", &["\u{AC01}", "\u{20}"]), + ("\u{AC01}\u{308}\u{20}", &["\u{AC01}\u{308}", "\u{20}"]), + ("\u{AC01}\u{378}", &["\u{AC01}", "\u{378}"]), + ("\u{AC01}\u{308}\u{378}", &["\u{AC01}\u{308}", "\u{378}"]), + ("\u{915}\u{D}", &["\u{915}", "\u{D}"]), + ("\u{915}\u{308}\u{D}", &["\u{915}\u{308}", "\u{D}"]), + ("\u{915}\u{A}", &["\u{915}", "\u{A}"]), + ("\u{915}\u{308}\u{A}", &["\u{915}\u{308}", "\u{A}"]), + ("\u{915}\u{0}", &["\u{915}", "\u{0}"]), + ("\u{915}\u{308}\u{0}", &["\u{915}\u{308}", "\u{0}"]), + ("\u{915}\u{94D}", &["\u{915}\u{94D}"]), + ("\u{915}\u{308}\u{94D}", &["\u{915}\u{308}\u{94D}"]), + ("\u{915}\u{300}", &["\u{915}\u{300}"]), + ("\u{915}\u{308}\u{300}", &["\u{915}\u{308}\u{300}"]), + ("\u{915}\u{200C}", &["\u{915}\u{200C}"]), + ("\u{915}\u{308}\u{200C}", &["\u{915}\u{308}\u{200C}"]), + ("\u{915}\u{200D}", &["\u{915}\u{200D}"]), + ("\u{915}\u{308}\u{200D}", &["\u{915}\u{308}\u{200D}"]), + ("\u{915}\u{1F1E6}", &["\u{915}", "\u{1F1E6}"]), + ("\u{915}\u{308}\u{1F1E6}", &["\u{915}\u{308}", "\u{1F1E6}"]), + ("\u{915}\u{6DD}", &["\u{915}", "\u{6DD}"]), + ("\u{915}\u{308}\u{6DD}", &["\u{915}\u{308}", "\u{6DD}"]), + ("\u{915}\u{903}", &["\u{915}\u{903}"]), + ("\u{915}\u{308}\u{903}", &["\u{915}\u{308}\u{903}"]), + ("\u{915}\u{1100}", &["\u{915}", "\u{1100}"]), + ("\u{915}\u{308}\u{1100}", &["\u{915}\u{308}", "\u{1100}"]), + ("\u{915}\u{1160}", &["\u{915}", "\u{1160}"]), + ("\u{915}\u{308}\u{1160}", &["\u{915}\u{308}", "\u{1160}"]), + ("\u{915}\u{11A8}", &["\u{915}", "\u{11A8}"]), + ("\u{915}\u{308}\u{11A8}", &["\u{915}\u{308}", "\u{11A8}"]), + ("\u{915}\u{AC00}", &["\u{915}", "\u{AC00}"]), + ("\u{915}\u{308}\u{AC00}", &["\u{915}\u{308}", "\u{AC00}"]), + ("\u{915}\u{AC01}", &["\u{915}", "\u{AC01}"]), + ("\u{915}\u{308}\u{AC01}", &["\u{915}\u{308}", "\u{AC01}"]), + ("\u{915}\u{915}", &["\u{915}", "\u{915}"]), + ("\u{915}\u{308}\u{915}", &["\u{915}\u{308}", "\u{915}"]), + ("\u{915}\u{A9}", &["\u{915}", "\u{A9}"]), + ("\u{915}\u{308}\u{A9}", &["\u{915}\u{308}", "\u{A9}"]), + ("\u{915}\u{20}", &["\u{915}", "\u{20}"]), + ("\u{915}\u{308}\u{20}", &["\u{915}\u{308}", "\u{20}"]), + ("\u{915}\u{378}", &["\u{915}", "\u{378}"]), + ("\u{915}\u{308}\u{378}", &["\u{915}\u{308}", "\u{378}"]), + ("\u{A9}\u{D}", &["\u{A9}", "\u{D}"]), + ("\u{A9}\u{308}\u{D}", &["\u{A9}\u{308}", "\u{D}"]), + ("\u{A9}\u{A}", &["\u{A9}", "\u{A}"]), + ("\u{A9}\u{308}\u{A}", &["\u{A9}\u{308}", "\u{A}"]), + ("\u{A9}\u{0}", &["\u{A9}", "\u{0}"]), + ("\u{A9}\u{308}\u{0}", &["\u{A9}\u{308}", "\u{0}"]), + ("\u{A9}\u{94D}", &["\u{A9}\u{94D}"]), + ("\u{A9}\u{308}\u{94D}", &["\u{A9}\u{308}\u{94D}"]), + ("\u{A9}\u{300}", &["\u{A9}\u{300}"]), + ("\u{A9}\u{308}\u{300}", &["\u{A9}\u{308}\u{300}"]), + ("\u{A9}\u{200C}", &["\u{A9}\u{200C}"]), + ("\u{A9}\u{308}\u{200C}", &["\u{A9}\u{308}\u{200C}"]), + ("\u{A9}\u{200D}", &["\u{A9}\u{200D}"]), + ("\u{A9}\u{308}\u{200D}", &["\u{A9}\u{308}\u{200D}"]), + ("\u{A9}\u{1F1E6}", &["\u{A9}", "\u{1F1E6}"]), + ("\u{A9}\u{308}\u{1F1E6}", &["\u{A9}\u{308}", "\u{1F1E6}"]), + ("\u{A9}\u{6DD}", &["\u{A9}", "\u{6DD}"]), + ("\u{A9}\u{308}\u{6DD}", &["\u{A9}\u{308}", "\u{6DD}"]), + ("\u{A9}\u{903}", &["\u{A9}\u{903}"]), + ("\u{A9}\u{308}\u{903}", &["\u{A9}\u{308}\u{903}"]), + ("\u{A9}\u{1100}", &["\u{A9}", "\u{1100}"]), + ("\u{A9}\u{308}\u{1100}", &["\u{A9}\u{308}", "\u{1100}"]), + ("\u{A9}\u{1160}", &["\u{A9}", "\u{1160}"]), + ("\u{A9}\u{308}\u{1160}", &["\u{A9}\u{308}", "\u{1160}"]), + ("\u{A9}\u{11A8}", &["\u{A9}", "\u{11A8}"]), + ("\u{A9}\u{308}\u{11A8}", &["\u{A9}\u{308}", "\u{11A8}"]), + ("\u{A9}\u{AC00}", &["\u{A9}", "\u{AC00}"]), + ("\u{A9}\u{308}\u{AC00}", &["\u{A9}\u{308}", "\u{AC00}"]), + ("\u{A9}\u{AC01}", &["\u{A9}", "\u{AC01}"]), + ("\u{A9}\u{308}\u{AC01}", &["\u{A9}\u{308}", "\u{AC01}"]), + ("\u{A9}\u{915}", &["\u{A9}", "\u{915}"]), + ("\u{A9}\u{308}\u{915}", &["\u{A9}\u{308}", "\u{915}"]), + ("\u{A9}\u{A9}", &["\u{A9}", "\u{A9}"]), + ("\u{A9}\u{308}\u{A9}", &["\u{A9}\u{308}", "\u{A9}"]), + ("\u{A9}\u{20}", &["\u{A9}", "\u{20}"]), + ("\u{A9}\u{308}\u{20}", &["\u{A9}\u{308}", "\u{20}"]), + ("\u{A9}\u{378}", &["\u{A9}", "\u{378}"]), + ("\u{A9}\u{308}\u{378}", &["\u{A9}\u{308}", "\u{378}"]), + ("\u{20}\u{D}", &["\u{20}", "\u{D}"]), + ("\u{20}\u{308}\u{D}", &["\u{20}\u{308}", "\u{D}"]), + ("\u{20}\u{A}", &["\u{20}", "\u{A}"]), + ("\u{20}\u{308}\u{A}", &["\u{20}\u{308}", "\u{A}"]), + ("\u{20}\u{0}", &["\u{20}", "\u{0}"]), + ("\u{20}\u{308}\u{0}", &["\u{20}\u{308}", "\u{0}"]), + ("\u{20}\u{94D}", &["\u{20}\u{94D}"]), + ("\u{20}\u{308}\u{94D}", &["\u{20}\u{308}\u{94D}"]), + ("\u{20}\u{300}", &["\u{20}\u{300}"]), + ("\u{20}\u{308}\u{300}", &["\u{20}\u{308}\u{300}"]), + ("\u{20}\u{200C}", &["\u{20}\u{200C}"]), + ("\u{20}\u{308}\u{200C}", &["\u{20}\u{308}\u{200C}"]), + ("\u{20}\u{200D}", &["\u{20}\u{200D}"]), + ("\u{20}\u{308}\u{200D}", &["\u{20}\u{308}\u{200D}"]), + ("\u{20}\u{1F1E6}", &["\u{20}", "\u{1F1E6}"]), + ("\u{20}\u{308}\u{1F1E6}", &["\u{20}\u{308}", "\u{1F1E6}"]), + ("\u{20}\u{6DD}", &["\u{20}", "\u{6DD}"]), + ("\u{20}\u{308}\u{6DD}", &["\u{20}\u{308}", "\u{6DD}"]), + ("\u{20}\u{903}", &["\u{20}\u{903}"]), + ("\u{20}\u{308}\u{903}", &["\u{20}\u{308}\u{903}"]), + ("\u{20}\u{1100}", &["\u{20}", "\u{1100}"]), + ("\u{20}\u{308}\u{1100}", &["\u{20}\u{308}", "\u{1100}"]), + ("\u{20}\u{1160}", &["\u{20}", "\u{1160}"]), + ("\u{20}\u{308}\u{1160}", &["\u{20}\u{308}", "\u{1160}"]), + ("\u{20}\u{11A8}", &["\u{20}", "\u{11A8}"]), + ("\u{20}\u{308}\u{11A8}", &["\u{20}\u{308}", "\u{11A8}"]), + ("\u{20}\u{AC00}", &["\u{20}", "\u{AC00}"]), + ("\u{20}\u{308}\u{AC00}", &["\u{20}\u{308}", "\u{AC00}"]), + ("\u{20}\u{AC01}", &["\u{20}", "\u{AC01}"]), + ("\u{20}\u{308}\u{AC01}", &["\u{20}\u{308}", "\u{AC01}"]), + ("\u{20}\u{915}", &["\u{20}", "\u{915}"]), + ("\u{20}\u{308}\u{915}", &["\u{20}\u{308}", "\u{915}"]), + ("\u{20}\u{A9}", &["\u{20}", "\u{A9}"]), + ("\u{20}\u{308}\u{A9}", &["\u{20}\u{308}", "\u{A9}"]), + ("\u{20}\u{20}", &["\u{20}", "\u{20}"]), + ("\u{20}\u{308}\u{20}", &["\u{20}\u{308}", "\u{20}"]), + ("\u{20}\u{378}", &["\u{20}", "\u{378}"]), + ("\u{20}\u{308}\u{378}", &["\u{20}\u{308}", "\u{378}"]), + ("\u{378}\u{D}", &["\u{378}", "\u{D}"]), + ("\u{378}\u{308}\u{D}", &["\u{378}\u{308}", "\u{D}"]), + ("\u{378}\u{A}", &["\u{378}", "\u{A}"]), + ("\u{378}\u{308}\u{A}", &["\u{378}\u{308}", "\u{A}"]), + ("\u{378}\u{0}", &["\u{378}", "\u{0}"]), + ("\u{378}\u{308}\u{0}", &["\u{378}\u{308}", "\u{0}"]), + ("\u{378}\u{94D}", &["\u{378}\u{94D}"]), + ("\u{378}\u{308}\u{94D}", &["\u{378}\u{308}\u{94D}"]), + ("\u{378}\u{300}", &["\u{378}\u{300}"]), + ("\u{378}\u{308}\u{300}", &["\u{378}\u{308}\u{300}"]), + ("\u{378}\u{200C}", &["\u{378}\u{200C}"]), + ("\u{378}\u{308}\u{200C}", &["\u{378}\u{308}\u{200C}"]), + ("\u{378}\u{200D}", &["\u{378}\u{200D}"]), + ("\u{378}\u{308}\u{200D}", &["\u{378}\u{308}\u{200D}"]), + ("\u{378}\u{1F1E6}", &["\u{378}", "\u{1F1E6}"]), + ("\u{378}\u{308}\u{1F1E6}", &["\u{378}\u{308}", "\u{1F1E6}"]), + ("\u{378}\u{6DD}", &["\u{378}", "\u{6DD}"]), + ("\u{378}\u{308}\u{6DD}", &["\u{378}\u{308}", "\u{6DD}"]), + ("\u{378}\u{903}", &["\u{378}\u{903}"]), + ("\u{378}\u{308}\u{903}", &["\u{378}\u{308}\u{903}"]), + ("\u{378}\u{1100}", &["\u{378}", "\u{1100}"]), + ("\u{378}\u{308}\u{1100}", &["\u{378}\u{308}", "\u{1100}"]), + ("\u{378}\u{1160}", &["\u{378}", "\u{1160}"]), + ("\u{378}\u{308}\u{1160}", &["\u{378}\u{308}", "\u{1160}"]), + ("\u{378}\u{11A8}", &["\u{378}", "\u{11A8}"]), + ("\u{378}\u{308}\u{11A8}", &["\u{378}\u{308}", "\u{11A8}"]), + ("\u{378}\u{AC00}", &["\u{378}", "\u{AC00}"]), + ("\u{378}\u{308}\u{AC00}", &["\u{378}\u{308}", "\u{AC00}"]), + ("\u{378}\u{AC01}", &["\u{378}", "\u{AC01}"]), + ("\u{378}\u{308}\u{AC01}", &["\u{378}\u{308}", "\u{AC01}"]), + ("\u{378}\u{915}", &["\u{378}", "\u{915}"]), + ("\u{378}\u{308}\u{915}", &["\u{378}\u{308}", "\u{915}"]), + ("\u{378}\u{A9}", &["\u{378}", "\u{A9}"]), + ("\u{378}\u{308}\u{A9}", &["\u{378}\u{308}", "\u{A9}"]), + ("\u{378}\u{20}", &["\u{378}", "\u{20}"]), + ("\u{378}\u{308}\u{20}", &["\u{378}\u{308}", "\u{20}"]), + ("\u{378}\u{378}", &["\u{378}", "\u{378}"]), + ("\u{378}\u{308}\u{378}", &["\u{378}\u{308}", "\u{378}"]), + ("\u{D}\u{A}\u{61}\u{A}\u{308}", &["\u{D}\u{A}", "\u{61}", "\u{A}", "\u{308}"]), + ("\u{61}\u{308}", &["\u{61}\u{308}"]), + ("\u{20}\u{200D}\u{646}", &["\u{20}\u{200D}", "\u{646}"]), + ("\u{646}\u{200D}\u{20}", &["\u{646}\u{200D}", "\u{20}"]), + ("\u{1100}\u{1100}", &["\u{1100}\u{1100}"]), + ("\u{AC00}\u{11A8}\u{1100}", &["\u{AC00}\u{11A8}", "\u{1100}"]), + ("\u{AC01}\u{11A8}\u{1100}", &["\u{AC01}\u{11A8}", "\u{1100}"]), + ("\u{1F1E6}\u{1F1E7}\u{1F1E8}\u{62}", &["\u{1F1E6}\u{1F1E7}", "\u{1F1E8}", "\u{62}"]), + ("\u{61}\u{1F1E6}\u{1F1E7}\u{1F1E8}\u{62}", &["\u{61}", "\u{1F1E6}\u{1F1E7}", "\u{1F1E8}", "\u{62}"]), + ("\u{61}\u{1F1E6}\u{1F1E7}\u{200D}\u{1F1E8}\u{62}", &["\u{61}", "\u{1F1E6}\u{1F1E7}\u{200D}", "\u{1F1E8}", "\u{62}"]), + ("\u{61}\u{1F1E6}\u{200D}\u{1F1E7}\u{1F1E8}\u{62}", &["\u{61}", "\u{1F1E6}\u{200D}", "\u{1F1E7}\u{1F1E8}", "\u{62}"]), + ("\u{61}\u{1F1E6}\u{1F1E7}\u{1F1E8}\u{1F1E9}\u{62}", &["\u{61}", "\u{1F1E6}\u{1F1E7}", "\u{1F1E8}\u{1F1E9}", "\u{62}"]), + ("\u{61}\u{200D}", &["\u{61}\u{200D}"]), + ("\u{61}\u{308}\u{62}", &["\u{61}\u{308}", "\u{62}"]), + ("\u{61}\u{903}\u{62}", &["\u{61}\u{903}", "\u{62}"]), + ("\u{61}\u{600}\u{62}", &["\u{61}", "\u{600}\u{62}"]), + ("\u{1F476}\u{1F3FF}\u{1F476}", &["\u{1F476}\u{1F3FF}", "\u{1F476}"]), + ("\u{61}\u{1F3FF}\u{1F476}", &["\u{61}\u{1F3FF}", "\u{1F476}"]), + ("\u{61}\u{1F3FF}\u{1F476}\u{200D}\u{1F6D1}", &["\u{61}\u{1F3FF}", "\u{1F476}\u{200D}\u{1F6D1}"]), + ("\u{1F476}\u{1F3FF}\u{308}\u{200D}\u{1F476}\u{1F3FF}", &["\u{1F476}\u{1F3FF}\u{308}\u{200D}\u{1F476}\u{1F3FF}"]), + ("\u{1F6D1}\u{200D}\u{1F6D1}", &["\u{1F6D1}\u{200D}\u{1F6D1}"]), + ("\u{61}\u{200D}\u{1F6D1}", &["\u{61}\u{200D}", "\u{1F6D1}"]), + ("\u{2701}\u{200D}\u{2701}", &["\u{2701}\u{200D}", "\u{2701}"]), + ("\u{61}\u{200D}\u{2701}", &["\u{61}\u{200D}", "\u{2701}"]), + ("\u{915}\u{924}", &["\u{915}", "\u{924}"]), + ("\u{915}\u{94D}\u{924}", &["\u{915}\u{94D}\u{924}"]), + ("\u{915}\u{94D}\u{94D}\u{924}", &["\u{915}\u{94D}\u{94D}\u{924}"]), + ("\u{915}\u{94D}\u{200D}\u{924}", &["\u{915}\u{94D}\u{200D}\u{924}"]), + ("\u{915}\u{93C}\u{200D}\u{94D}\u{924}", &["\u{915}\u{93C}\u{200D}\u{94D}\u{924}"]), + ("\u{915}\u{93C}\u{94D}\u{200D}\u{924}", &["\u{915}\u{93C}\u{94D}\u{200D}\u{924}"]), + ("\u{915}\u{94D}\u{924}\u{94D}\u{92F}", &["\u{915}\u{94D}\u{924}\u{94D}\u{92F}"]), + ("\u{915}\u{94D}\u{61}", &["\u{915}\u{94D}", "\u{61}"]), + ("\u{61}\u{94D}\u{924}", &["\u{61}\u{94D}", "\u{924}"]), + ("\u{3F}\u{94D}\u{924}", &["\u{3F}\u{94D}", "\u{924}"]), + ("\u{915}\u{94D}\u{94D}\u{924}", &["\u{915}\u{94D}\u{94D}\u{924}"]), + ("\u{AB8}\u{AFB}\u{ACD}\u{AB8}\u{AFB}", &["\u{AB8}\u{AFB}\u{ACD}\u{AB8}\u{AFB}"]), + ("\u{1019}\u{1039}\u{1018}\u{102C}\u{1037}", &["\u{1019}\u{1039}\u{1018}", "\u{102C}\u{1037}"]), + ("\u{1004}\u{103A}\u{1039}\u{1011}\u{1039}\u{1011}", &["\u{1004}\u{103A}\u{1039}\u{1011}\u{1039}\u{1011}"]), + ("\u{1B12}\u{1B01}\u{1B32}\u{1B44}\u{1B2F}\u{1B32}\u{1B44}\u{1B22}\u{1B44}\u{1B2C}\u{1B32}\u{1B44}\u{1B22}\u{1B38}", &["\u{1B12}\u{1B01}", "\u{1B32}\u{1B44}\u{1B2F}", "\u{1B32}\u{1B44}\u{1B22}\u{1B44}\u{1B2C}", "\u{1B32}\u{1B44}\u{1B22}\u{1B38}"]), + ("\u{179F}\u{17D2}\u{178F}\u{17D2}\u{179A}\u{17B8}", &["\u{179F}\u{17D2}\u{178F}\u{17D2}\u{179A}\u{17B8}"]), + ("\u{1B26}\u{1B17}\u{1B44}\u{1B13}", &["\u{1B26}", "\u{1B17}\u{1B44}\u{1B13}"]), + ("\u{1B27}\u{1B13}\u{1B44}\u{1B0B}\u{1B0B}\u{1B04}", &["\u{1B27}", "\u{1B13}\u{1B44}\u{1B0B}", "\u{1B0B}\u{1B04}"]), + ("\u{1795}\u{17D2}\u{17AF}\u{1798}", &["\u{1795}\u{17D2}\u{17AF}", "\u{1798}"]), + ("\u{17A0}\u{17D2}\u{17AB}\u{1791}\u{17D0}\u{1799}", &["\u{17A0}\u{17D2}\u{17AB}", "\u{1791}\u{17D0}", "\u{1799}"]), + ]; + for (i, (input, expected)) in cases.iter().enumerate() { + let got: Vec<&str> = Graphemes::new(input).collect(); + assert_eq!(&got[..], *expected, "case {i}: {input:?}"); + } +} diff --git a/rio-unicode/tests/width_drift_vs_u16.rs b/rio-unicode/tests/width_drift_vs_u16.rs new file mode 100644 index 0000000000..9801eaf513 --- /dev/null +++ b/rio-unicode/tests/width_drift_vs_u16.rs @@ -0,0 +1,39 @@ +//! Temporary audit: quantify per-char width drift vs unicode-width-16 +//! (the crate rio ships today). Differences should be attributable to +//! Unicode 16→17 additions and upstream 0.2.x per-char corrections. +use rio_unicode::UnicodeWidthChar as New; +use unicode_width_16::UnicodeWidthChar as Old; + +#[test] +fn report_char_width_drift() { + let mut diffs: Vec<(u32, Option, Option)> = Vec::new(); + for cp in 0..=0x10FFFFu32 { + let Some(c) = char::from_u32(cp) else { + continue; + }; + let old = Old::width(c); + let new = New::width(c); + if old != new { + diffs.push((cp, old, new)); + } + } + eprintln!("total differing codepoints: {}", diffs.len()); + // Group into ranges for readability. + let mut i = 0; + while i < diffs.len() { + let start = diffs[i]; + let mut j = i; + while j + 1 < diffs.len() + && diffs[j + 1].0 == diffs[j].0 + 1 + && diffs[j + 1].1 == start.1 + && diffs[j + 1].2 == start.2 + { + j += 1; + } + eprintln!( + "U+{:04X}..U+{:04X} old={:?} new={:?}", + start.0, diffs[j].0, start.1, start.2 + ); + i = j + 1; + } +}