1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
//! Compact Unicode simple case-folding.
//!
//! Maps each character to its lower-case fold form as defined by the Unicode
//! [Case Folding](https://www.unicode.org/Public/UCD/latest/ucd/CaseFolding.txt)
//! data file, restricted to the **simple** (1-to-1) folds (statuses `C` and
//! `S`). Full multi-character folds (`F`) and Turkic locale folds (`T`) are
//! intentionally not supported.
//!
//! # Why this exists
//!
//! Unicode 16.0 defines roughly 1500 simple-fold mappings. A naive table
//! storing `(from, to)` pairs as `(u32, u32)` would consume ~12 KB, and the
//! representation chosen by the Go standard library (`unicode.SimpleFold`)
//! consumes ~7 KB. The 1500 mappings exhibit a great deal of structure:
//! adjacent code points typically share the same delta to their fold, and the
//! whole table can be compressed into about **1 KB** while remaining trivially
//! queryable with byte-wise loads.
//!
//! The encoding uses three ideas:
//!
//! 1. **Run-length grouping with stride.** Consecutive code points sharing a
//! delta are coalesced into a single run. A 1-bit `stride` field allows
//! runs that alternate (e.g. `0x0100, 0x0102, 0x0104 …`), which is the
//! common pattern for paired upper/lower Latin Extended letters.
//! 2. **Paged bitmap index.** A `PAGE_BITMAP` of 64-cp pages (one bit per
//! page) plus a cumulative-popcount sidetable lets us test in *one* bit
//! load whether `cp`'s page contains any fold run at all. An unset bit is
//! a definitive "no fold" — no cross-page search is ever required. Within
//! a populated page, a short branch-predictable linear scan over the
//! page's slice of `RUN_END_LOW` (located via `PAGE_OFFSET`) finds the
//! candidate run.
//! 3. **Per-page run splitting and split byte records.** Any run whose
//! `[start, end]` would straddle a 64-cp boundary is split at the boundary
//! during the build, so every run lives in exactly one page (which is what
//! makes "empty bit ⇒ no fold" sound). Because both ends then fit in 6
//! bits, a run needs only two bytes: `RUN_END_LOW[i]` (the clean scan key,
//! compared byte-to-byte against `cp & 0x3F` with no masking) and
//! `RUN_START_STRIDE[i]` (`start_low | (stride−1) << 6`, read only on a
//! hit). The membership test compares `cp & 0x3F` directly — no code-point
//! reconstruction. The fold itself is a little-endian byte delta stored in
//! the parallel `BYTE_DELTA` table (see idea 5).
//! 4. **Page-precision byte-level reject.** The bulk [`simple_fold`] path
//! probes `PAGE_BITMAP` straight from the first one or two UTF-8 bytes —
//! `cp >> 6` (the page index) is fully determined by `b0` (2-byte) or
//! `b0,b1` (3-byte); only the final continuation byte holds the within-page
//! offset `cp & 0x3F`. A clear page bit copies the whole character verbatim
//! without assembling `cp` or consulting the run table, so fold-free scripts
//! (CJK, Hangul, Kana, Arabic, Hebrew, Indic) *and* the empty 64-cp pages
//! inside otherwise-foldable blocks are skipped at memory speed. No extra
//! table: it reuses the same `PAGE_BITMAP` the run lookup uses.
//! 5. **Little-endian byte-delta fold.** On a little-endian machine a folded
//! character is the source character's UTF-8 bytes, read as a `u32`, plus a
//! per-run constant. `BYTE_DELTA[i]` stores that constant (32 b, since the
//! low code-point bits land in the high word byte), so folding is a masked
//! load + `wrapping_add` + a single 4-byte store — no decode, no encode, and
//! it handles length-changing folds (`K`→`k`, `Ⱥ`→`ⱥ`) by writing fewer or
//! more bytes than were read.
//!
//! # Example
//!
//! ```
//! use casefold::simple_fold;
//! assert_eq!(simple_fold("Hello, WORLD!".to_string()), "hello, world!");
//! assert_eq!(simple_fold("ÜBER".to_string()), "über");
//! ```
pub use ;
pub use ;
use *;
/// Number of bytes in the UTF-8 sequence whose lead byte is `lead`.
///
/// The length only depends on the top 4 bits of the lead byte, so the 16
/// possible lengths are packed one-nibble-each into a `u64` lookup constant
/// (`0x0..7` ASCII → 1; `0x8..0xB` continuation → 1, never a valid lead;
/// `0xC/0xD` → 2; `0xE` → 3; `0xF` → 4). The length is then a single shift and
/// mask rather than a comparison chain.
/// Total compressed size of the embedded table, in bytes. Used by the
/// size-budget test.
const
// ---- Paged bitmap lookup ------------------------------------------------
//
// `PAGE_BITMAP` is a 1-bit-per-64-cp-page bitmap. A bit set at position
// `cp >> PAGE_BITS` means "the slot containing `cp` overlaps at least one
// (post-split) interval". Because every interval is fully contained in a
// single page (we split runs at page boundaries during the build), an empty
// page means definitively no fold — there is *no* need to look at any other
// page. `POPCNT_SAMPLES[i]` holds the cumulative popcount of
// `PAGE_BITMAP[0..i]`, so the dense index of any page is one load plus one
// `PAGE_OFFSET[j] .. PAGE_OFFSET[j+1]` is the slice of `RUN_END_LOW` /
// `RUN_START_STRIDE` / `BYTE_DELTA` belonging to the `j`-th populated page,
// sorted by end-low.
//
// The run record is split across two byte arrays so the hot scan reads clean
// keys with no masking:
// RUN_END_LOW[i] = end & PAGE_MASK (the within-page scan key)
// RUN_START_STRIDE[i] = (start & PAGE_MASK) | ((stride - 1) << 6)
// (membership, vs `cp & 0x3F`)
/// Number of populated pages strictly before the page located at
/// `PAGE_BITMAP[word_idx]` bit `bit_idx`.
/// Offset of the first run with `end_low >= low_v` in a page of `n` runs at
/// `RUN_END_LOW[lo..]`, or `n` if none. Scans 8 `end_low` bytes at a time via
/// SWAR: one branchless chunk covers the average ~3.8-run page; the outer loop
/// advances only for the rare page with >8 runs. Padding / next-page bytes that
/// the over-read pulls in are discarded by the `j < n` bound, so no per-lane
/// validity mask is needed.
pub