static_embeddings 0.1.3 → 0.1.5

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.
@@ -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,19 @@ 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_RESERVE 512
92
+ #define SE_SCRATCH_IDS_RETAIN_MAX 8192
93
+ #define SE_SCRATCH_BYTES_KEEP 1024
94
+
78
95
  int se_scratch_reserve(se_scratch_t *s, uint32_t dim) {
79
- if (!grow_u32(&s->cps, &s->cps_cap, 256))
96
+ if (!grow_u32(&s->cps, &s->cps_cap, SE_SCRATCH_CPS_KEEP))
80
97
  return 0;
81
- if (!grow_u32(&s->cps2, &s->cps2_cap, 256))
98
+ if (!grow_u32(&s->cps2, &s->cps2_cap, SE_SCRATCH_CPS_KEEP))
82
99
  return 0;
83
- if (!grow_u32(&s->ids, &s->ids_cap, 256))
100
+ if (!grow_u32(&s->ids, &s->ids_cap, SE_SCRATCH_IDS_RESERVE))
84
101
  return 0;
85
- if (!grow_bytes(&s->bytes, &s->bytes_cap, 256))
102
+ if (!grow_bytes(&s->bytes, &s->bytes_cap, SE_SCRATCH_BYTES_KEEP))
86
103
  return 0;
87
104
  if (!grow_float(&s->acc, &s->acc_cap, dim))
88
105
  return 0;
@@ -90,21 +107,224 @@ int se_scratch_reserve(se_scratch_t *s, uint32_t dim) {
90
107
  return 1;
91
108
  }
92
109
 
110
+ static int shrink_u32(uint32_t **buf, size_t *cap, size_t keep) {
111
+ size_t bytes = 0;
112
+ void *p;
113
+
114
+ if (*cap <= keep)
115
+ return 1;
116
+ if (!*buf) {
117
+ *cap = 0;
118
+ return 1;
119
+ }
120
+ if (!se_array_bytes(keep, sizeof(uint32_t), &bytes))
121
+ return 0;
122
+ p = se_realloc(SE_ALLOC_SCRATCH, *buf, bytes);
123
+ if (!p)
124
+ return 0;
125
+ *buf = (uint32_t *)p;
126
+ *cap = keep;
127
+ return 1;
128
+ }
129
+
130
+ static int shrink_bytes(uint8_t **buf, size_t *cap, size_t keep) {
131
+ size_t bytes = 0;
132
+ void *p;
133
+
134
+ if (*cap <= keep)
135
+ return 1;
136
+ if (!*buf) {
137
+ *cap = 0;
138
+ return 1;
139
+ }
140
+ if (!se_array_bytes(keep, sizeof(uint8_t), &bytes))
141
+ return 0;
142
+ p = se_realloc(SE_ALLOC_SCRATCH, *buf, bytes);
143
+ if (!p)
144
+ return 0;
145
+ *buf = (uint8_t *)p;
146
+ *cap = keep;
147
+ return 1;
148
+ }
149
+
150
+ static void se_scratch_trim(se_scratch_t *s) {
151
+ (void)shrink_u32(&s->cps, &s->cps_cap, SE_SCRATCH_CPS_KEEP);
152
+ (void)shrink_u32(&s->cps2, &s->cps2_cap, SE_SCRATCH_CPS_KEEP);
153
+ if (s->ids_cap > SE_SCRATCH_IDS_RETAIN_MAX)
154
+ (void)shrink_u32(&s->ids, &s->ids_cap, SE_SCRATCH_IDS_RETAIN_MAX);
155
+ (void)shrink_bytes(&s->bytes, &s->bytes_cap, SE_SCRATCH_BYTES_KEEP);
156
+ }
157
+
158
+ typedef struct {
159
+ se_scratch_t scratch;
160
+ int in_use;
161
+ } se_tls_scratch_t;
162
+
163
+ static void se_scratch_tls_dtor(void *p) {
164
+ se_tls_scratch_t *tls = (se_tls_scratch_t *)p;
165
+ if (!tls)
166
+ return;
167
+ se_scratch_free(&tls->scratch);
168
+ se_free(tls);
169
+ }
170
+
171
+ #ifndef _WIN32
172
+ static pthread_key_t se_scratch_key;
173
+ static pthread_once_t se_scratch_once = PTHREAD_ONCE_INIT;
174
+
175
+ static void se_scratch_key_init(void) {
176
+ (void)pthread_key_create(&se_scratch_key, se_scratch_tls_dtor);
177
+ }
178
+
179
+ static se_tls_scratch_t *se_scratch_tls_get(void) {
180
+ (void)pthread_once(&se_scratch_once, se_scratch_key_init);
181
+ return (se_tls_scratch_t *)pthread_getspecific(se_scratch_key);
182
+ }
183
+
184
+ static se_tls_scratch_t *se_scratch_tls_slot(void) {
185
+ se_tls_scratch_t *tls = se_scratch_tls_get();
186
+ if (tls)
187
+ return tls;
188
+
189
+ tls = (se_tls_scratch_t *)se_malloc(SE_ALLOC_SCRATCH, sizeof(*tls));
190
+ if (!tls)
191
+ return NULL;
192
+ memset(tls, 0, sizeof(*tls));
193
+ se_scratch_init(&tls->scratch);
194
+ if (pthread_setspecific(se_scratch_key, tls) != 0) {
195
+ se_free(tls);
196
+ return NULL;
197
+ }
198
+ return tls;
199
+ }
200
+
201
+ static void se_scratch_tls_clear(void) {
202
+ se_tls_scratch_t *tls = se_scratch_tls_get();
203
+ if (!tls)
204
+ return;
205
+ (void)pthread_setspecific(se_scratch_key, NULL);
206
+ se_scratch_tls_dtor(tls);
207
+ }
208
+ #else
209
+ static DWORD se_fls_index = FLS_OUT_OF_INDEXES;
210
+ static INIT_ONCE se_fls_once = INIT_ONCE_STATIC_INIT;
211
+
212
+ static VOID WINAPI se_scratch_fls_dtor(PVOID p) {
213
+ se_scratch_tls_dtor(p);
214
+ }
215
+
216
+ static BOOL CALLBACK se_scratch_fls_init(PINIT_ONCE once, PVOID param, PVOID *ctx) {
217
+ (void)once;
218
+ (void)param;
219
+ (void)ctx;
220
+ se_fls_index = FlsAlloc(se_scratch_fls_dtor);
221
+ return se_fls_index != FLS_OUT_OF_INDEXES;
222
+ }
223
+
224
+ static se_tls_scratch_t *se_scratch_tls_get(void) {
225
+ if (se_fls_index == FLS_OUT_OF_INDEXES)
226
+ return NULL;
227
+ return (se_tls_scratch_t *)FlsGetValue(se_fls_index);
228
+ }
229
+
230
+ static se_tls_scratch_t *se_scratch_tls_slot(void) {
231
+ if (!InitOnceExecuteOnce(&se_fls_once, se_scratch_fls_init, NULL, NULL) ||
232
+ se_fls_index == FLS_OUT_OF_INDEXES)
233
+ return NULL;
234
+
235
+ se_tls_scratch_t *tls = se_scratch_tls_get();
236
+ if (tls)
237
+ return tls;
238
+
239
+ tls = (se_tls_scratch_t *)se_malloc(SE_ALLOC_SCRATCH, sizeof(*tls));
240
+ if (!tls)
241
+ return NULL;
242
+ memset(tls, 0, sizeof(*tls));
243
+ se_scratch_init(&tls->scratch);
244
+ if (!FlsSetValue(se_fls_index, tls)) {
245
+ se_free(tls);
246
+ return NULL;
247
+ }
248
+ return tls;
249
+ }
250
+
251
+ static void se_scratch_tls_clear(void) {
252
+ se_tls_scratch_t *tls = se_scratch_tls_get();
253
+ if (!tls)
254
+ return;
255
+ (void)FlsSetValue(se_fls_index, NULL);
256
+ se_scratch_tls_dtor(tls);
257
+ }
258
+ #endif
259
+
260
+ se_scratch_t *se_scratch_acquire(uint32_t dim) {
261
+ se_tls_scratch_t *tls = se_scratch_tls_slot();
262
+ if (!tls)
263
+ return NULL;
264
+
265
+ if (!tls->in_use) {
266
+ if (!se_scratch_reserve(&tls->scratch, dim))
267
+ return NULL;
268
+ tls->in_use = 1;
269
+ return &tls->scratch;
270
+ }
271
+
272
+ se_scratch_t *heap = (se_scratch_t *)se_malloc(SE_ALLOC_SCRATCH, sizeof(*heap));
273
+ if (!heap)
274
+ return NULL;
275
+ se_scratch_init(heap);
276
+ if (!se_scratch_reserve(heap, dim)) {
277
+ se_scratch_free(heap);
278
+ se_free(heap);
279
+ return NULL;
280
+ }
281
+ return heap;
282
+ }
283
+
284
+ void se_scratch_release(se_scratch_t *s) {
285
+ se_tls_scratch_t *tls;
286
+
287
+ if (!s)
288
+ return;
289
+
290
+ tls = se_scratch_tls_get();
291
+ if (tls && s == &tls->scratch) {
292
+ tls->in_use = 0;
293
+ se_scratch_trim(&tls->scratch);
294
+ return;
295
+ }
296
+ se_scratch_free(s);
297
+ se_free(s);
298
+ }
299
+
300
+ void se_scratch_drop_thread(void) {
301
+ se_tls_scratch_t *tls = se_scratch_tls_get();
302
+ if (tls && tls->in_use)
303
+ tls->in_use = 0;
304
+ se_scratch_tls_clear();
305
+ }
306
+
93
307
  static int is_whitespace(const se_model_t *m, uint32_t cp) {
94
308
  if (cp < 0x80)
95
309
  return se_is_ascii_whitespace(cp);
310
+ if (cp < 256)
311
+ return m->norm.whitespace256[cp];
96
312
  return se_range_contains(m->norm.whitespace, m->norm.whitespace_count, cp);
97
313
  }
98
314
 
99
315
  static int is_control(const se_model_t *m, uint32_t cp) {
100
316
  if (cp < 0x80)
101
317
  return (cp < 0x20 || cp == 0x7f) && cp != '\t' && cp != '\n' && cp != '\r';
318
+ if (cp < 256)
319
+ return m->norm.control256[cp];
102
320
  return se_range_contains(m->norm.control, m->norm.control_count, cp);
103
321
  }
104
322
 
105
323
  static int is_punct(const se_model_t *m, uint32_t cp) {
106
324
  if (cp < 0x80)
107
325
  return se_is_ascii_punct(cp);
326
+ if (cp < 256)
327
+ return m->norm.punct256[cp];
108
328
  return se_range_contains(m->norm.punct, m->norm.punct_count, cp);
109
329
  }
110
330
 
@@ -154,12 +374,18 @@ static int decode_one(const uint8_t *src, size_t len, size_t *i, uint32_t *cp_ou
154
374
  static int normalization_stable(const se_model_t *m, uint32_t cp) {
155
375
  if (cp < 0x80)
156
376
  return 1;
157
- if (m->meta.do_lower_case && se_map_lookup(m->norm.lower, m->norm.lower_count, cp))
158
- return 0;
377
+ if (m->meta.do_lower_case) {
378
+ const se_map_entry_t *lower =
379
+ cp < 256 ? m->norm.lower256[cp] : se_map_lookup(m->norm.lower, m->norm.lower_count, cp);
380
+ if (lower)
381
+ return 0;
382
+ }
159
383
  if (m->meta.strip_accents) {
160
- if (se_map_lookup(m->norm.nfd, m->norm.nfd_count, cp))
384
+ const se_map_entry_t *nfd =
385
+ cp < 256 ? m->norm.nfd256[cp] : se_map_lookup(m->norm.nfd, m->norm.nfd_count, cp);
386
+ if (nfd)
161
387
  return 0;
162
- if (se_range_contains(m->norm.mn, m->norm.mn_count, cp))
388
+ if (cp < 256 ? m->norm.mn256[cp] : se_range_contains(m->norm.mn, m->norm.mn_count, cp))
163
389
  return 0;
164
390
  }
165
391
  return 1;
@@ -169,6 +395,37 @@ static int cp_is_cjk_segment(const se_model_t *m, uint32_t cp) {
169
395
  return m->meta.handle_chinese_chars && cp >= 0x3400 && se_is_cjk(cp);
170
396
  }
171
397
 
398
+ typedef struct {
399
+ const char *text;
400
+ uint32_t len;
401
+ uint32_t bit;
402
+ } se_added_token_spec_t;
403
+
404
+ static const se_added_token_spec_t SE_ADDED_TOKENS[] = {
405
+ {"[MASK]", 6u, SE_ADDED_MASK}, {"[PAD]", 5u, SE_ADDED_PAD}, {"[UNK]", 5u, SE_ADDED_UNK},
406
+ {"[CLS]", 5u, SE_ADDED_CLS}, {"[SEP]", 5u, SE_ADDED_SEP},
407
+ };
408
+
409
+ static int boundary_splits_added_token(const se_model_t *model, const uint8_t *input,
410
+ size_t input_len, size_t boundary) {
411
+ if (model->meta.added_token_mask == 0 || boundary == 0 || boundary >= input_len)
412
+ return 0;
413
+
414
+ for (size_t k = 0; k < SE_ARRAY_LEN(SE_ADDED_TOKENS); k++) {
415
+ const se_added_token_spec_t *token = &SE_ADDED_TOKENS[k];
416
+ if ((model->meta.added_token_mask & token->bit) == 0)
417
+ continue;
418
+ for (size_t back = 1; back < token->len && back <= boundary; back++) {
419
+ size_t start = boundary - back;
420
+ if (start + token->len > input_len || input[start] != '[')
421
+ continue;
422
+ if (memcmp(input + start, token->text, token->len) == 0)
423
+ return 1;
424
+ }
425
+ }
426
+ return 0;
427
+ }
428
+
172
429
  size_t se_prefix_boundary_len(const se_model_t *model, const uint8_t *input, size_t input_len,
173
430
  size_t target, size_t backscan) {
174
431
  if (target >= input_len)
@@ -196,14 +453,15 @@ size_t se_prefix_boundary_len(const se_model_t *model, const uint8_t *input, siz
196
453
  continue;
197
454
 
198
455
  if (cp_is_cjk_segment(model, cp)) {
199
- if (after <= target)
456
+ if (after <= target && !boundary_splits_added_token(model, input, input_len, after))
200
457
  return after;
201
- if (pos > 0)
458
+ if (pos > 0 && !boundary_splits_added_token(model, input, input_len, pos))
202
459
  return pos;
203
- return 0;
460
+ continue;
204
461
  }
205
462
 
206
- if ((is_whitespace(model, cp) || is_punct(model, cp)) && after <= target)
463
+ if ((is_whitespace(model, cp) || is_punct(model, cp)) && after <= target &&
464
+ !boundary_splits_added_token(model, input, input_len, after))
207
465
  return after;
208
466
  }
209
467
 
@@ -230,9 +488,11 @@ typedef struct {
230
488
  const se_model_t *model;
231
489
  se_scratch_t *scratch;
232
490
  uint32_t max_tokens;
491
+ se_token_limit_t limit_mode;
233
492
  size_t n_ids;
234
493
  size_t n_unk;
235
494
  size_t segment_len;
495
+ int segment_ascii;
236
496
  se_token_stats_t *stats;
237
497
  se_error_t *err;
238
498
  volatile sig_atomic_t *cancelled;
@@ -248,23 +508,52 @@ static se_status_t oom(token_state_t *st, const char *where) {
248
508
  }
249
509
 
250
510
  static int append_segment_cp(token_state_t *st, uint32_t cp) {
511
+ if (cp >= 0x80)
512
+ st->segment_ascii = 0;
251
513
  if (!grow_u32(&st->scratch->cps, &st->scratch->cps_cap, st->segment_len + 1))
252
514
  return 0;
253
515
  st->scratch->cps[st->segment_len++] = cp;
254
516
  return 1;
255
517
  }
256
518
 
519
+ static size_t limited_token_count(const token_state_t *st) {
520
+ if (st->limit_mode == SE_TOKEN_LIMIT_USABLE && st->model->meta.unk_policy == SE_UNK_DROP)
521
+ return st->n_ids - st->n_unk;
522
+ return st->n_ids;
523
+ }
524
+
257
525
  static int cap_after_append(token_state_t *st) {
258
- if (st->max_tokens == 0 || st->n_ids <= (size_t)st->max_tokens)
526
+ if (st->max_tokens == 0 || limited_token_count(st) <= (size_t)st->max_tokens)
259
527
  return 0;
260
528
 
261
- size_t dropped_unk = 0;
262
- for (size_t k = st->max_tokens; k < st->n_ids; k++) {
263
- if (st->scratch->ids[k] == st->model->meta.unk_id)
264
- dropped_unk++;
529
+ if (st->limit_mode == SE_TOKEN_LIMIT_RAW || st->model->meta.unk_policy != SE_UNK_DROP) {
530
+ size_t dropped_unk = 0;
531
+ for (size_t k = st->max_tokens; k < st->n_ids; k++) {
532
+ if (st->scratch->ids[k] == st->model->meta.unk_id)
533
+ dropped_unk++;
534
+ }
535
+ st->n_unk -= dropped_unk;
536
+ st->n_ids = st->max_tokens;
537
+ } else {
538
+ size_t usable = 0;
539
+ size_t kept_unk = 0;
540
+ size_t keep = 0;
541
+ for (size_t k = 0; k < st->n_ids; k++) {
542
+ uint32_t id = st->scratch->ids[k];
543
+ if (id == st->model->meta.unk_id) {
544
+ kept_unk++;
545
+ continue;
546
+ }
547
+ usable++;
548
+ if (usable == (size_t)st->max_tokens) {
549
+ keep = k + 1;
550
+ break;
551
+ }
552
+ }
553
+ st->n_ids = keep;
554
+ st->n_unk = kept_unk;
265
555
  }
266
- st->n_unk -= dropped_unk;
267
- st->n_ids = st->max_tokens;
556
+
268
557
  st->stats->truncated = 1;
269
558
  return 1;
270
559
  }
@@ -272,7 +561,8 @@ static int cap_after_append(token_state_t *st) {
272
561
  typedef enum { WORDPIECE_OK = 1, WORDPIECE_OOM = 0, WORDPIECE_INVALID = -1 } wordpiece_status_t;
273
562
 
274
563
  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) {
564
+ size_t word_len, size_t *n_ids, size_t *n_unk,
565
+ int known_ascii) {
276
566
  const se_meta_t *meta = &m->meta;
277
567
 
278
568
  if (word_len == 0)
@@ -285,30 +575,49 @@ static wordpiece_status_t wordpiece(const se_model_t *m, se_scratch_t *sc, const
285
575
  return 1;
286
576
  }
287
577
 
288
- size_t bytes_need = 0;
289
- if (!se_checked_mul_size(word_len, 4, &bytes_need) ||
290
- !se_checked_add_size(bytes_need, 4, &bytes_need))
291
- return 0;
292
- if (!grow_bytes(&sc->bytes, &sc->bytes_cap, bytes_need))
293
- return 0;
294
- if (!grow_u32(&sc->cps2, &sc->cps2_cap, word_len + 1))
295
- return 0;
578
+ int ascii_identity = known_ascii;
579
+ if (!ascii_identity) {
580
+ ascii_identity = 1;
581
+ for (size_t k = 0; k < word_len; k++) {
582
+ if (word[k] >= 0x80) {
583
+ ascii_identity = 0;
584
+ break;
585
+ }
586
+ }
587
+ }
296
588
 
297
589
  size_t blen = 0;
298
- for (size_t k = 0; k < word_len; k++) {
299
- if (blen > UINT32_MAX)
590
+ if (ascii_identity) {
591
+ if (!grow_bytes(&sc->bytes, &sc->bytes_cap, word_len))
592
+ return 0;
593
+ if (!grow_u32(&sc->cps2, &sc->cps2_cap, word_len + 1))
300
594
  return 0;
301
- sc->cps2[k] = (uint32_t)blen;
302
- uint32_t cp = word[k];
303
- if (cp < 0x80) {
304
- sc->bytes[blen++] = (uint8_t)cp;
305
- } else {
306
- blen += se_utf8_encode(cp, sc->bytes + blen);
595
+ for (size_t k = 0; k < word_len; k++) {
596
+ sc->bytes[k] = (uint8_t)word[k];
597
+ sc->cps2[k] = (uint32_t)k;
598
+ }
599
+ blen = word_len;
600
+ sc->cps2[word_len] = (uint32_t)word_len;
601
+ } else {
602
+ size_t bytes_need = 0;
603
+ if (!se_checked_mul_size(word_len, 4, &bytes_need) ||
604
+ !se_checked_add_size(bytes_need, 4, &bytes_need))
605
+ return 0;
606
+ if (!grow_bytes(&sc->bytes, &sc->bytes_cap, bytes_need))
607
+ return 0;
608
+ if (!grow_u32(&sc->cps2, &sc->cps2_cap, word_len + 1))
609
+ return 0;
610
+
611
+ for (size_t k = 0; k < word_len; k++) {
612
+ if (blen > UINT32_MAX)
613
+ return 0;
614
+ sc->cps2[k] = (uint32_t)blen;
615
+ blen += se_utf8_encode(word[k], sc->bytes + blen);
307
616
  }
617
+ if (blen > UINT32_MAX)
618
+ return 0;
619
+ sc->cps2[word_len] = (uint32_t)blen;
308
620
  }
309
- if (blen > UINT32_MAX)
310
- return 0;
311
- sc->cps2[word_len] = (uint32_t)blen;
312
621
 
313
622
  if (word_len <= meta->max_token_chars) {
314
623
  uint32_t exact_id = 0;
@@ -355,10 +664,59 @@ static wordpiece_status_t wordpiece(const se_model_t *m, se_scratch_t *sc, const
355
664
  return 1;
356
665
  }
357
666
 
667
+ static uint32_t added_token_id(const se_model_t *model, uint32_t bit) {
668
+ switch (bit) {
669
+ case SE_ADDED_PAD:
670
+ return model->meta.pad_id;
671
+ case SE_ADDED_UNK:
672
+ return model->meta.unk_id;
673
+ case SE_ADDED_CLS:
674
+ return model->meta.cls_id;
675
+ case SE_ADDED_SEP:
676
+ return model->meta.sep_id;
677
+ case SE_ADDED_MASK:
678
+ return model->meta.mask_id;
679
+ default:
680
+ return SE_SLOT_EMPTY;
681
+ }
682
+ }
683
+
684
+ static int match_added_token(const se_model_t *model, const uint8_t *input, size_t input_len,
685
+ size_t pos, uint32_t *id_out, size_t *len_out) {
686
+ if (model->meta.added_token_mask == 0 || pos >= input_len || input[pos] != '[')
687
+ return 0;
688
+
689
+ for (size_t k = 0; k < SE_ARRAY_LEN(SE_ADDED_TOKENS); k++) {
690
+ const se_added_token_spec_t *token = &SE_ADDED_TOKENS[k];
691
+ if ((model->meta.added_token_mask & token->bit) == 0)
692
+ continue;
693
+ if (token->len > input_len - pos)
694
+ continue;
695
+ if (memcmp(input + pos, token->text, token->len) != 0)
696
+ continue;
697
+
698
+ *id_out = added_token_id(model, token->bit);
699
+ *len_out = token->len;
700
+ return 1;
701
+ }
702
+ return 0;
703
+ }
704
+
705
+ static se_status_t append_direct_id(token_state_t *st, uint32_t id, int *stop) {
706
+ if (!push_id(st->scratch, &st->n_ids, id))
707
+ return oom(st, "adding a special token");
708
+ if (id == st->model->meta.unk_id)
709
+ st->n_unk++;
710
+ if (cap_after_append(st))
711
+ *stop = 1;
712
+ return SE_OK;
713
+ }
714
+
358
715
  static se_status_t append_wordpiece(token_state_t *st, const uint32_t *word, size_t word_len,
359
716
  int *stop) {
360
717
  wordpiece_status_t wp =
361
- wordpiece(st->model, st->scratch, word, word_len, &st->n_ids, &st->n_unk);
718
+ wordpiece(st->model, st->scratch, word, word_len, &st->n_ids, &st->n_unk,
719
+ word_len == 1 ? (word[0] < 0x80) : st->segment_ascii);
362
720
  if (wp == WORDPIECE_OOM)
363
721
  return oom(st, "tokenizing");
364
722
  if (wp == WORDPIECE_INVALID) {
@@ -375,6 +733,7 @@ static se_status_t flush_segment(token_state_t *st, int *stop) {
375
733
  return SE_OK;
376
734
  se_status_t rc = append_wordpiece(st, st->scratch->cps, st->segment_len, stop);
377
735
  st->segment_len = 0;
736
+ st->segment_ascii = 1;
378
737
  return rc;
379
738
  }
380
739
 
@@ -394,13 +753,30 @@ static se_status_t feed_token_cp(token_state_t *st, uint32_t cp, int *stop) {
394
753
  return SE_OK;
395
754
  }
396
755
 
756
+ static const se_map_entry_t *lower_entry(const se_model_t *m, uint32_t cp) {
757
+ if (cp < 256)
758
+ return m->norm.lower256[cp];
759
+ return se_map_lookup(m->norm.lower, m->norm.lower_count, cp);
760
+ }
761
+
762
+ static const se_map_entry_t *nfd_entry(const se_model_t *m, uint32_t cp) {
763
+ if (cp < 256)
764
+ return m->norm.nfd256[cp];
765
+ return se_map_lookup(m->norm.nfd, m->norm.nfd_count, cp);
766
+ }
767
+
768
+ static int is_mn(const se_model_t *m, uint32_t cp) {
769
+ if (cp < 256)
770
+ return m->norm.mn256[cp];
771
+ return se_range_contains(m->norm.mn, m->norm.mn_count, cp);
772
+ }
773
+
397
774
  static se_status_t emit_lowered(token_state_t *st, uint32_t cp, int *stop) {
398
775
  if (st->model->meta.do_lower_case) {
399
776
  if (cp >= 'A' && cp <= 'Z')
400
777
  cp += 32;
401
778
  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);
779
+ const se_map_entry_t *e = lower_entry(st->model, cp);
404
780
  if (e) {
405
781
  for (uint32_t k = 0; k < e->len; k++) {
406
782
  se_status_t rc = feed_token_cp(st, e->out[k], stop);
@@ -418,16 +794,16 @@ static se_status_t emit_stripped(token_state_t *st, uint32_t cp, int *stop) {
418
794
  if (!st->model->meta.strip_accents || cp < 0x80)
419
795
  return emit_lowered(st, cp, stop);
420
796
 
421
- const se_map_entry_t *e = se_map_lookup(st->model->norm.nfd, st->model->norm.nfd_count, cp);
797
+ const se_map_entry_t *e = nfd_entry(st->model, cp);
422
798
  if (!e) {
423
- if (se_range_contains(st->model->norm.mn, st->model->norm.mn_count, cp))
799
+ if (is_mn(st->model, cp))
424
800
  return SE_OK;
425
801
  return emit_lowered(st, cp, stop);
426
802
  }
427
803
 
428
804
  for (uint32_t k = 0; k < e->len; k++) {
429
805
  uint32_t d = e->out[k];
430
- if (se_range_contains(st->model->norm.mn, st->model->norm.mn_count, d))
806
+ if (is_mn(st->model, d))
431
807
  continue;
432
808
  se_status_t rc = emit_lowered(st, d, stop);
433
809
  if (rc != SE_OK || *stop)
@@ -486,6 +862,31 @@ static se_status_t tokenize_ascii_run(token_state_t *st, const uint8_t *input, s
486
862
  if (b >= 0x80)
487
863
  break;
488
864
 
865
+ if (b == '[' && st->model->meta.added_token_mask != 0) {
866
+ uint32_t added_id = 0;
867
+ size_t added_len = 0;
868
+ if (match_added_token(st->model, input, input_len, i, &added_id, &added_len)) {
869
+ se_status_t rc = flush_segment(st, stop);
870
+ if (rc != SE_OK) {
871
+ *ip = i;
872
+ return rc;
873
+ }
874
+ if (*stop) {
875
+ *ip = i;
876
+ return SE_OK;
877
+ }
878
+ rc = append_direct_id(st, added_id, stop);
879
+ if (rc != SE_OK) {
880
+ *ip = i;
881
+ return rc;
882
+ }
883
+ i += added_len;
884
+ if (*stop)
885
+ break;
886
+ continue;
887
+ }
888
+ }
889
+
489
890
  if (i >= next_cancel_check) {
490
891
  if (token_cancelled(st)) {
491
892
  *ip = i;
@@ -545,8 +946,9 @@ static se_status_t tokenize_ascii_run(token_state_t *st, const uint8_t *input, s
545
946
  }
546
947
 
547
948
  se_status_t se_tokenize(const se_model_t *model, se_scratch_t *sc, const uint8_t *input,
548
- size_t input_len, uint32_t max_tokens, se_token_stats_t *stats,
549
- se_error_t *err, volatile sig_atomic_t *cancelled) {
949
+ size_t input_len, uint32_t max_tokens, se_token_limit_t limit_mode,
950
+ se_token_stats_t *stats, se_error_t *err,
951
+ volatile sig_atomic_t *cancelled) {
550
952
  memset(stats, 0, sizeof(*stats));
551
953
 
552
954
  token_state_t st;
@@ -554,9 +956,11 @@ se_status_t se_tokenize(const se_model_t *model, se_scratch_t *sc, const uint8_t
554
956
  st.model = model;
555
957
  st.scratch = sc;
556
958
  st.max_tokens = max_tokens;
959
+ st.limit_mode = limit_mode;
557
960
  st.stats = stats;
558
961
  st.err = err;
559
962
  st.cancelled = cancelled;
963
+ st.segment_ascii = 1;
560
964
 
561
965
  size_t i = 0;
562
966
  size_t iterations = 0;
@@ -115,6 +115,6 @@ const se_map_entry_t *se_map_lookup(const se_map_entry_t *entries, uint32_t coun
115
115
  int se_is_cjk(uint32_t cp) {
116
116
  return (cp >= 0x4E00 && cp <= 0x9FFF) || (cp >= 0x3400 && cp <= 0x4DBF) ||
117
117
  (cp >= 0x20000 && cp <= 0x2A6DF) || (cp >= 0x2A700 && cp <= 0x2B73F) ||
118
- (cp >= 0x2B740 && cp <= 0x2B81F) || (cp >= 0x2B820 && cp <= 0x2CEAF) ||
118
+ (cp >= 0x2B740 && cp <= 0x2B81F) || (cp >= 0x2B920 && cp <= 0x2CEAF) ||
119
119
  (cp >= 0xF900 && cp <= 0xFAFF) || (cp >= 0x2F800 && cp <= 0x2FA1F);
120
120
  }