static_embeddings 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +161 -0
- data/README.md +13 -6
- data/Rakefile +95 -0
- data/benchmark/_support.rb +196 -0
- data/benchmark/core_paths.rb +57 -0
- data/benchmark/gvl_threshold.rb +48 -0
- data/docs/ARCHITECTURE.md +12 -4
- data/docs/BENCHMARKING.md +87 -0
- data/docs/LIMITATIONS.md +93 -0
- data/docs/MODEL_AUDIT.md +27 -13
- data/docs/PERFORMANCE.md +36 -19
- data/ext/static_embeddings/se_embed.c +46 -7
- data/ext/static_embeddings/se_f16.c +43 -7
- data/ext/static_embeddings/se_format.c +83 -5
- data/ext/static_embeddings/se_internal.h +9 -0
- data/ext/static_embeddings/se_tokenizer.c +301 -34
- data/ext/static_embeddings/static_embeddings.c +157 -47
- data/lib/static_embeddings/version.rb +1 -1
- data/static_embeddings.gemspec +2 -0
- metadata +7 -1
|
@@ -4,6 +4,18 @@
|
|
|
4
4
|
#include <stdlib.h>
|
|
5
5
|
#include <string.h>
|
|
6
6
|
|
|
7
|
+
#ifndef _WIN32
|
|
8
|
+
#include <pthread.h>
|
|
9
|
+
#else
|
|
10
|
+
#ifndef WIN32_LEAN_AND_MEAN
|
|
11
|
+
#define WIN32_LEAN_AND_MEAN
|
|
12
|
+
#endif
|
|
13
|
+
#ifndef _WIN32_WINNT
|
|
14
|
+
#define _WIN32_WINNT 0x0600
|
|
15
|
+
#endif
|
|
16
|
+
#include <windows.h>
|
|
17
|
+
#endif
|
|
18
|
+
|
|
7
19
|
#define SE_CANCEL_CHECK_MASK 0x3ffu
|
|
8
20
|
|
|
9
21
|
void se_scratch_init(se_scratch_t *s) {
|
|
@@ -75,14 +87,18 @@ static int push_id(se_scratch_t *sc, size_t *n_ids, uint32_t id) {
|
|
|
75
87
|
return 1;
|
|
76
88
|
}
|
|
77
89
|
|
|
90
|
+
#define SE_SCRATCH_CPS_KEEP 256
|
|
91
|
+
#define SE_SCRATCH_IDS_KEEP 512
|
|
92
|
+
#define SE_SCRATCH_BYTES_KEEP 1024
|
|
93
|
+
|
|
78
94
|
int se_scratch_reserve(se_scratch_t *s, uint32_t dim) {
|
|
79
|
-
if (!grow_u32(&s->cps, &s->cps_cap,
|
|
95
|
+
if (!grow_u32(&s->cps, &s->cps_cap, SE_SCRATCH_CPS_KEEP))
|
|
80
96
|
return 0;
|
|
81
|
-
if (!grow_u32(&s->cps2, &s->cps2_cap,
|
|
97
|
+
if (!grow_u32(&s->cps2, &s->cps2_cap, SE_SCRATCH_CPS_KEEP))
|
|
82
98
|
return 0;
|
|
83
|
-
if (!grow_u32(&s->ids, &s->ids_cap,
|
|
99
|
+
if (!grow_u32(&s->ids, &s->ids_cap, SE_SCRATCH_IDS_KEEP))
|
|
84
100
|
return 0;
|
|
85
|
-
if (!grow_bytes(&s->bytes, &s->bytes_cap,
|
|
101
|
+
if (!grow_bytes(&s->bytes, &s->bytes_cap, SE_SCRATCH_BYTES_KEEP))
|
|
86
102
|
return 0;
|
|
87
103
|
if (!grow_float(&s->acc, &s->acc_cap, dim))
|
|
88
104
|
return 0;
|
|
@@ -90,21 +106,223 @@ int se_scratch_reserve(se_scratch_t *s, uint32_t dim) {
|
|
|
90
106
|
return 1;
|
|
91
107
|
}
|
|
92
108
|
|
|
109
|
+
static int shrink_u32(uint32_t **buf, size_t *cap, size_t keep) {
|
|
110
|
+
size_t bytes = 0;
|
|
111
|
+
void *p;
|
|
112
|
+
|
|
113
|
+
if (*cap <= keep)
|
|
114
|
+
return 1;
|
|
115
|
+
if (!*buf) {
|
|
116
|
+
*cap = 0;
|
|
117
|
+
return 1;
|
|
118
|
+
}
|
|
119
|
+
if (!se_array_bytes(keep, sizeof(uint32_t), &bytes))
|
|
120
|
+
return 0;
|
|
121
|
+
p = se_realloc(SE_ALLOC_SCRATCH, *buf, bytes);
|
|
122
|
+
if (!p)
|
|
123
|
+
return 0;
|
|
124
|
+
*buf = (uint32_t *)p;
|
|
125
|
+
*cap = keep;
|
|
126
|
+
return 1;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
static int shrink_bytes(uint8_t **buf, size_t *cap, size_t keep) {
|
|
130
|
+
size_t bytes = 0;
|
|
131
|
+
void *p;
|
|
132
|
+
|
|
133
|
+
if (*cap <= keep)
|
|
134
|
+
return 1;
|
|
135
|
+
if (!*buf) {
|
|
136
|
+
*cap = 0;
|
|
137
|
+
return 1;
|
|
138
|
+
}
|
|
139
|
+
if (!se_array_bytes(keep, sizeof(uint8_t), &bytes))
|
|
140
|
+
return 0;
|
|
141
|
+
p = se_realloc(SE_ALLOC_SCRATCH, *buf, bytes);
|
|
142
|
+
if (!p)
|
|
143
|
+
return 0;
|
|
144
|
+
*buf = (uint8_t *)p;
|
|
145
|
+
*cap = keep;
|
|
146
|
+
return 1;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
static void se_scratch_trim(se_scratch_t *s) {
|
|
150
|
+
(void)shrink_u32(&s->cps, &s->cps_cap, SE_SCRATCH_CPS_KEEP);
|
|
151
|
+
(void)shrink_u32(&s->cps2, &s->cps2_cap, SE_SCRATCH_CPS_KEEP);
|
|
152
|
+
(void)shrink_u32(&s->ids, &s->ids_cap, SE_SCRATCH_IDS_KEEP);
|
|
153
|
+
(void)shrink_bytes(&s->bytes, &s->bytes_cap, SE_SCRATCH_BYTES_KEEP);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
typedef struct {
|
|
157
|
+
se_scratch_t scratch;
|
|
158
|
+
int in_use;
|
|
159
|
+
} se_tls_scratch_t;
|
|
160
|
+
|
|
161
|
+
static void se_scratch_tls_dtor(void *p) {
|
|
162
|
+
se_tls_scratch_t *tls = (se_tls_scratch_t *)p;
|
|
163
|
+
if (!tls)
|
|
164
|
+
return;
|
|
165
|
+
se_scratch_free(&tls->scratch);
|
|
166
|
+
se_free(tls);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
#ifndef _WIN32
|
|
170
|
+
static pthread_key_t se_scratch_key;
|
|
171
|
+
static pthread_once_t se_scratch_once = PTHREAD_ONCE_INIT;
|
|
172
|
+
|
|
173
|
+
static void se_scratch_key_init(void) {
|
|
174
|
+
(void)pthread_key_create(&se_scratch_key, se_scratch_tls_dtor);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
static se_tls_scratch_t *se_scratch_tls_get(void) {
|
|
178
|
+
(void)pthread_once(&se_scratch_once, se_scratch_key_init);
|
|
179
|
+
return (se_tls_scratch_t *)pthread_getspecific(se_scratch_key);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
static se_tls_scratch_t *se_scratch_tls_slot(void) {
|
|
183
|
+
se_tls_scratch_t *tls = se_scratch_tls_get();
|
|
184
|
+
if (tls)
|
|
185
|
+
return tls;
|
|
186
|
+
|
|
187
|
+
tls = (se_tls_scratch_t *)se_malloc(SE_ALLOC_SCRATCH, sizeof(*tls));
|
|
188
|
+
if (!tls)
|
|
189
|
+
return NULL;
|
|
190
|
+
memset(tls, 0, sizeof(*tls));
|
|
191
|
+
se_scratch_init(&tls->scratch);
|
|
192
|
+
if (pthread_setspecific(se_scratch_key, tls) != 0) {
|
|
193
|
+
se_free(tls);
|
|
194
|
+
return NULL;
|
|
195
|
+
}
|
|
196
|
+
return tls;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
static void se_scratch_tls_clear(void) {
|
|
200
|
+
se_tls_scratch_t *tls = se_scratch_tls_get();
|
|
201
|
+
if (!tls)
|
|
202
|
+
return;
|
|
203
|
+
(void)pthread_setspecific(se_scratch_key, NULL);
|
|
204
|
+
se_scratch_tls_dtor(tls);
|
|
205
|
+
}
|
|
206
|
+
#else
|
|
207
|
+
static DWORD se_fls_index = FLS_OUT_OF_INDEXES;
|
|
208
|
+
static INIT_ONCE se_fls_once = INIT_ONCE_STATIC_INIT;
|
|
209
|
+
|
|
210
|
+
static VOID WINAPI se_scratch_fls_dtor(PVOID p) {
|
|
211
|
+
se_scratch_tls_dtor(p);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
static BOOL CALLBACK se_scratch_fls_init(PINIT_ONCE once, PVOID param, PVOID *ctx) {
|
|
215
|
+
(void)once;
|
|
216
|
+
(void)param;
|
|
217
|
+
(void)ctx;
|
|
218
|
+
se_fls_index = FlsAlloc(se_scratch_fls_dtor);
|
|
219
|
+
return se_fls_index != FLS_OUT_OF_INDEXES;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
static se_tls_scratch_t *se_scratch_tls_get(void) {
|
|
223
|
+
if (se_fls_index == FLS_OUT_OF_INDEXES)
|
|
224
|
+
return NULL;
|
|
225
|
+
return (se_tls_scratch_t *)FlsGetValue(se_fls_index);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
static se_tls_scratch_t *se_scratch_tls_slot(void) {
|
|
229
|
+
if (!InitOnceExecuteOnce(&se_fls_once, se_scratch_fls_init, NULL, NULL) ||
|
|
230
|
+
se_fls_index == FLS_OUT_OF_INDEXES)
|
|
231
|
+
return NULL;
|
|
232
|
+
|
|
233
|
+
se_tls_scratch_t *tls = se_scratch_tls_get();
|
|
234
|
+
if (tls)
|
|
235
|
+
return tls;
|
|
236
|
+
|
|
237
|
+
tls = (se_tls_scratch_t *)se_malloc(SE_ALLOC_SCRATCH, sizeof(*tls));
|
|
238
|
+
if (!tls)
|
|
239
|
+
return NULL;
|
|
240
|
+
memset(tls, 0, sizeof(*tls));
|
|
241
|
+
se_scratch_init(&tls->scratch);
|
|
242
|
+
if (!FlsSetValue(se_fls_index, tls)) {
|
|
243
|
+
se_free(tls);
|
|
244
|
+
return NULL;
|
|
245
|
+
}
|
|
246
|
+
return tls;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
static void se_scratch_tls_clear(void) {
|
|
250
|
+
se_tls_scratch_t *tls = se_scratch_tls_get();
|
|
251
|
+
if (!tls)
|
|
252
|
+
return;
|
|
253
|
+
(void)FlsSetValue(se_fls_index, NULL);
|
|
254
|
+
se_scratch_tls_dtor(tls);
|
|
255
|
+
}
|
|
256
|
+
#endif
|
|
257
|
+
|
|
258
|
+
se_scratch_t *se_scratch_acquire(uint32_t dim) {
|
|
259
|
+
se_tls_scratch_t *tls = se_scratch_tls_slot();
|
|
260
|
+
if (!tls)
|
|
261
|
+
return NULL;
|
|
262
|
+
|
|
263
|
+
if (!tls->in_use) {
|
|
264
|
+
if (!se_scratch_reserve(&tls->scratch, dim))
|
|
265
|
+
return NULL;
|
|
266
|
+
tls->in_use = 1;
|
|
267
|
+
return &tls->scratch;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
se_scratch_t *heap = (se_scratch_t *)se_malloc(SE_ALLOC_SCRATCH, sizeof(*heap));
|
|
271
|
+
if (!heap)
|
|
272
|
+
return NULL;
|
|
273
|
+
se_scratch_init(heap);
|
|
274
|
+
if (!se_scratch_reserve(heap, dim)) {
|
|
275
|
+
se_scratch_free(heap);
|
|
276
|
+
se_free(heap);
|
|
277
|
+
return NULL;
|
|
278
|
+
}
|
|
279
|
+
return heap;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
void se_scratch_release(se_scratch_t *s) {
|
|
283
|
+
se_tls_scratch_t *tls;
|
|
284
|
+
|
|
285
|
+
if (!s)
|
|
286
|
+
return;
|
|
287
|
+
|
|
288
|
+
tls = se_scratch_tls_get();
|
|
289
|
+
if (tls && s == &tls->scratch) {
|
|
290
|
+
tls->in_use = 0;
|
|
291
|
+
se_scratch_trim(&tls->scratch);
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
se_scratch_free(s);
|
|
295
|
+
se_free(s);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
void se_scratch_drop_thread(void) {
|
|
299
|
+
se_tls_scratch_t *tls = se_scratch_tls_get();
|
|
300
|
+
if (tls && tls->in_use)
|
|
301
|
+
tls->in_use = 0;
|
|
302
|
+
se_scratch_tls_clear();
|
|
303
|
+
}
|
|
304
|
+
|
|
93
305
|
static int is_whitespace(const se_model_t *m, uint32_t cp) {
|
|
94
306
|
if (cp < 0x80)
|
|
95
307
|
return se_is_ascii_whitespace(cp);
|
|
308
|
+
if (cp < 256)
|
|
309
|
+
return m->norm.whitespace256[cp];
|
|
96
310
|
return se_range_contains(m->norm.whitespace, m->norm.whitespace_count, cp);
|
|
97
311
|
}
|
|
98
312
|
|
|
99
313
|
static int is_control(const se_model_t *m, uint32_t cp) {
|
|
100
314
|
if (cp < 0x80)
|
|
101
315
|
return (cp < 0x20 || cp == 0x7f) && cp != '\t' && cp != '\n' && cp != '\r';
|
|
316
|
+
if (cp < 256)
|
|
317
|
+
return m->norm.control256[cp];
|
|
102
318
|
return se_range_contains(m->norm.control, m->norm.control_count, cp);
|
|
103
319
|
}
|
|
104
320
|
|
|
105
321
|
static int is_punct(const se_model_t *m, uint32_t cp) {
|
|
106
322
|
if (cp < 0x80)
|
|
107
323
|
return se_is_ascii_punct(cp);
|
|
324
|
+
if (cp < 256)
|
|
325
|
+
return m->norm.punct256[cp];
|
|
108
326
|
return se_range_contains(m->norm.punct, m->norm.punct_count, cp);
|
|
109
327
|
}
|
|
110
328
|
|
|
@@ -154,12 +372,18 @@ static int decode_one(const uint8_t *src, size_t len, size_t *i, uint32_t *cp_ou
|
|
|
154
372
|
static int normalization_stable(const se_model_t *m, uint32_t cp) {
|
|
155
373
|
if (cp < 0x80)
|
|
156
374
|
return 1;
|
|
157
|
-
if (m->meta.do_lower_case
|
|
158
|
-
|
|
375
|
+
if (m->meta.do_lower_case) {
|
|
376
|
+
const se_map_entry_t *lower =
|
|
377
|
+
cp < 256 ? m->norm.lower256[cp] : se_map_lookup(m->norm.lower, m->norm.lower_count, cp);
|
|
378
|
+
if (lower)
|
|
379
|
+
return 0;
|
|
380
|
+
}
|
|
159
381
|
if (m->meta.strip_accents) {
|
|
160
|
-
|
|
382
|
+
const se_map_entry_t *nfd =
|
|
383
|
+
cp < 256 ? m->norm.nfd256[cp] : se_map_lookup(m->norm.nfd, m->norm.nfd_count, cp);
|
|
384
|
+
if (nfd)
|
|
161
385
|
return 0;
|
|
162
|
-
if (se_range_contains(m->norm.mn, m->norm.mn_count, cp))
|
|
386
|
+
if (cp < 256 ? m->norm.mn256[cp] : se_range_contains(m->norm.mn, m->norm.mn_count, cp))
|
|
163
387
|
return 0;
|
|
164
388
|
}
|
|
165
389
|
return 1;
|
|
@@ -233,6 +457,7 @@ typedef struct {
|
|
|
233
457
|
size_t n_ids;
|
|
234
458
|
size_t n_unk;
|
|
235
459
|
size_t segment_len;
|
|
460
|
+
int segment_ascii;
|
|
236
461
|
se_token_stats_t *stats;
|
|
237
462
|
se_error_t *err;
|
|
238
463
|
volatile sig_atomic_t *cancelled;
|
|
@@ -248,6 +473,8 @@ static se_status_t oom(token_state_t *st, const char *where) {
|
|
|
248
473
|
}
|
|
249
474
|
|
|
250
475
|
static int append_segment_cp(token_state_t *st, uint32_t cp) {
|
|
476
|
+
if (cp >= 0x80)
|
|
477
|
+
st->segment_ascii = 0;
|
|
251
478
|
if (!grow_u32(&st->scratch->cps, &st->scratch->cps_cap, st->segment_len + 1))
|
|
252
479
|
return 0;
|
|
253
480
|
st->scratch->cps[st->segment_len++] = cp;
|
|
@@ -272,7 +499,8 @@ static int cap_after_append(token_state_t *st) {
|
|
|
272
499
|
typedef enum { WORDPIECE_OK = 1, WORDPIECE_OOM = 0, WORDPIECE_INVALID = -1 } wordpiece_status_t;
|
|
273
500
|
|
|
274
501
|
static wordpiece_status_t wordpiece(const se_model_t *m, se_scratch_t *sc, const uint32_t *word,
|
|
275
|
-
size_t word_len, size_t *n_ids, size_t *n_unk
|
|
502
|
+
size_t word_len, size_t *n_ids, size_t *n_unk,
|
|
503
|
+
int known_ascii) {
|
|
276
504
|
const se_meta_t *meta = &m->meta;
|
|
277
505
|
|
|
278
506
|
if (word_len == 0)
|
|
@@ -285,30 +513,49 @@ static wordpiece_status_t wordpiece(const se_model_t *m, se_scratch_t *sc, const
|
|
|
285
513
|
return 1;
|
|
286
514
|
}
|
|
287
515
|
|
|
288
|
-
|
|
289
|
-
if (!
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
516
|
+
int ascii_identity = known_ascii;
|
|
517
|
+
if (!ascii_identity) {
|
|
518
|
+
ascii_identity = 1;
|
|
519
|
+
for (size_t k = 0; k < word_len; k++) {
|
|
520
|
+
if (word[k] >= 0x80) {
|
|
521
|
+
ascii_identity = 0;
|
|
522
|
+
break;
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
}
|
|
296
526
|
|
|
297
527
|
size_t blen = 0;
|
|
298
|
-
|
|
299
|
-
if (
|
|
528
|
+
if (ascii_identity) {
|
|
529
|
+
if (!grow_bytes(&sc->bytes, &sc->bytes_cap, word_len))
|
|
530
|
+
return 0;
|
|
531
|
+
if (!grow_u32(&sc->cps2, &sc->cps2_cap, word_len + 1))
|
|
300
532
|
return 0;
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
sc->bytes[blen++] = (uint8_t)cp;
|
|
305
|
-
} else {
|
|
306
|
-
blen += se_utf8_encode(cp, sc->bytes + blen);
|
|
533
|
+
for (size_t k = 0; k < word_len; k++) {
|
|
534
|
+
sc->bytes[k] = (uint8_t)word[k];
|
|
535
|
+
sc->cps2[k] = (uint32_t)k;
|
|
307
536
|
}
|
|
537
|
+
blen = word_len;
|
|
538
|
+
sc->cps2[word_len] = (uint32_t)word_len;
|
|
539
|
+
} else {
|
|
540
|
+
size_t bytes_need = 0;
|
|
541
|
+
if (!se_checked_mul_size(word_len, 4, &bytes_need) ||
|
|
542
|
+
!se_checked_add_size(bytes_need, 4, &bytes_need))
|
|
543
|
+
return 0;
|
|
544
|
+
if (!grow_bytes(&sc->bytes, &sc->bytes_cap, bytes_need))
|
|
545
|
+
return 0;
|
|
546
|
+
if (!grow_u32(&sc->cps2, &sc->cps2_cap, word_len + 1))
|
|
547
|
+
return 0;
|
|
548
|
+
|
|
549
|
+
for (size_t k = 0; k < word_len; k++) {
|
|
550
|
+
if (blen > UINT32_MAX)
|
|
551
|
+
return 0;
|
|
552
|
+
sc->cps2[k] = (uint32_t)blen;
|
|
553
|
+
blen += se_utf8_encode(word[k], sc->bytes + blen);
|
|
554
|
+
}
|
|
555
|
+
if (blen > UINT32_MAX)
|
|
556
|
+
return 0;
|
|
557
|
+
sc->cps2[word_len] = (uint32_t)blen;
|
|
308
558
|
}
|
|
309
|
-
if (blen > UINT32_MAX)
|
|
310
|
-
return 0;
|
|
311
|
-
sc->cps2[word_len] = (uint32_t)blen;
|
|
312
559
|
|
|
313
560
|
if (word_len <= meta->max_token_chars) {
|
|
314
561
|
uint32_t exact_id = 0;
|
|
@@ -358,7 +605,8 @@ static wordpiece_status_t wordpiece(const se_model_t *m, se_scratch_t *sc, const
|
|
|
358
605
|
static se_status_t append_wordpiece(token_state_t *st, const uint32_t *word, size_t word_len,
|
|
359
606
|
int *stop) {
|
|
360
607
|
wordpiece_status_t wp =
|
|
361
|
-
wordpiece(st->model, st->scratch, word, word_len, &st->n_ids, &st->n_unk
|
|
608
|
+
wordpiece(st->model, st->scratch, word, word_len, &st->n_ids, &st->n_unk,
|
|
609
|
+
word_len == 1 ? (word[0] < 0x80) : st->segment_ascii);
|
|
362
610
|
if (wp == WORDPIECE_OOM)
|
|
363
611
|
return oom(st, "tokenizing");
|
|
364
612
|
if (wp == WORDPIECE_INVALID) {
|
|
@@ -375,6 +623,7 @@ static se_status_t flush_segment(token_state_t *st, int *stop) {
|
|
|
375
623
|
return SE_OK;
|
|
376
624
|
se_status_t rc = append_wordpiece(st, st->scratch->cps, st->segment_len, stop);
|
|
377
625
|
st->segment_len = 0;
|
|
626
|
+
st->segment_ascii = 1;
|
|
378
627
|
return rc;
|
|
379
628
|
}
|
|
380
629
|
|
|
@@ -394,13 +643,30 @@ static se_status_t feed_token_cp(token_state_t *st, uint32_t cp, int *stop) {
|
|
|
394
643
|
return SE_OK;
|
|
395
644
|
}
|
|
396
645
|
|
|
646
|
+
static const se_map_entry_t *lower_entry(const se_model_t *m, uint32_t cp) {
|
|
647
|
+
if (cp < 256)
|
|
648
|
+
return m->norm.lower256[cp];
|
|
649
|
+
return se_map_lookup(m->norm.lower, m->norm.lower_count, cp);
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
static const se_map_entry_t *nfd_entry(const se_model_t *m, uint32_t cp) {
|
|
653
|
+
if (cp < 256)
|
|
654
|
+
return m->norm.nfd256[cp];
|
|
655
|
+
return se_map_lookup(m->norm.nfd, m->norm.nfd_count, cp);
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
static int is_mn(const se_model_t *m, uint32_t cp) {
|
|
659
|
+
if (cp < 256)
|
|
660
|
+
return m->norm.mn256[cp];
|
|
661
|
+
return se_range_contains(m->norm.mn, m->norm.mn_count, cp);
|
|
662
|
+
}
|
|
663
|
+
|
|
397
664
|
static se_status_t emit_lowered(token_state_t *st, uint32_t cp, int *stop) {
|
|
398
665
|
if (st->model->meta.do_lower_case) {
|
|
399
666
|
if (cp >= 'A' && cp <= 'Z')
|
|
400
667
|
cp += 32;
|
|
401
668
|
else if (cp >= 0x80) {
|
|
402
|
-
const se_map_entry_t *e =
|
|
403
|
-
se_map_lookup(st->model->norm.lower, st->model->norm.lower_count, cp);
|
|
669
|
+
const se_map_entry_t *e = lower_entry(st->model, cp);
|
|
404
670
|
if (e) {
|
|
405
671
|
for (uint32_t k = 0; k < e->len; k++) {
|
|
406
672
|
se_status_t rc = feed_token_cp(st, e->out[k], stop);
|
|
@@ -418,16 +684,16 @@ static se_status_t emit_stripped(token_state_t *st, uint32_t cp, int *stop) {
|
|
|
418
684
|
if (!st->model->meta.strip_accents || cp < 0x80)
|
|
419
685
|
return emit_lowered(st, cp, stop);
|
|
420
686
|
|
|
421
|
-
const se_map_entry_t *e =
|
|
687
|
+
const se_map_entry_t *e = nfd_entry(st->model, cp);
|
|
422
688
|
if (!e) {
|
|
423
|
-
if (
|
|
689
|
+
if (is_mn(st->model, cp))
|
|
424
690
|
return SE_OK;
|
|
425
691
|
return emit_lowered(st, cp, stop);
|
|
426
692
|
}
|
|
427
693
|
|
|
428
694
|
for (uint32_t k = 0; k < e->len; k++) {
|
|
429
695
|
uint32_t d = e->out[k];
|
|
430
|
-
if (
|
|
696
|
+
if (is_mn(st->model, d))
|
|
431
697
|
continue;
|
|
432
698
|
se_status_t rc = emit_lowered(st, d, stop);
|
|
433
699
|
if (rc != SE_OK || *stop)
|
|
@@ -557,6 +823,7 @@ se_status_t se_tokenize(const se_model_t *model, se_scratch_t *sc, const uint8_t
|
|
|
557
823
|
st.stats = stats;
|
|
558
824
|
st.err = err;
|
|
559
825
|
st.cancelled = cancelled;
|
|
826
|
+
st.segment_ascii = 1;
|
|
560
827
|
|
|
561
828
|
size_t i = 0;
|
|
562
829
|
size_t iterations = 0;
|