← Back to C-Kernel-Engine Docs Doxygen Source Documentation
 
Loading...
Searching...
No Matches
tokenizer.c File Reference
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <ctype.h>
#include "tokenizer/tokenizer.h"
#include "tokenizer/murmurhash3.h"
#include "tokenizer/hash_table.h"

Go to the source code of this file.

Functions

int ck_tokenizer_add_merge (CKTokenizer *tok, int32_t left, int32_t right, int32_t merged, int32_t priority)
 
int ck_tokenizer_add_special_token (CKTokenizer *tok, const char *name, int32_t id)
 
int ck_tokenizer_add_token (CKTokenizer *tok, const char *token, int32_t id, float score)
 
CKTokenizerck_tokenizer_create (CKTokenizerType type)
 
int ck_tokenizer_decode (const CKTokenizer *tok, const int32_t *ids, int num_ids, char *text, int max_len)
 
CKSpacePrefixStyle ck_tokenizer_detect_space_prefix_style (CKTokenizer *tok)
 
int ck_tokenizer_encode (const CKTokenizer *tok, const char *text, int text_len, int32_t *ids, int max_ids)
 
int ck_tokenizer_encode_spm_dispatch (const CKTokenizer *tok, const char *text, int text_len, int32_t *ids, int max_ids)
 
void ck_tokenizer_free (CKTokenizer *tok)
 
const char * ck_tokenizer_id_to_token (const CKTokenizer *tok, int32_t id)
 
int ck_tokenizer_load_binary (CKTokenizer *tok, int vocab_size, const int32_t *offsets, const char *strings, int num_merges, const int32_t *merges)
 
int ck_tokenizer_load_gguf (CKTokenizer *tok, const char *path)
 
int ck_tokenizer_load_json (CKTokenizer *tok, const char *path)
 
int ck_tokenizer_load_merges (CKTokenizer *tok, const char *path)
 
int ck_tokenizer_load_text (CKTokenizer *tok, const char *path)
 
int32_t ck_tokenizer_lookup (const CKTokenizer *tok, const char *token)
 
void ck_tokenizer_reset (CKTokenizer *tok)
 
void ck_tokenizer_set_add_bos_eos (CKTokenizer *tok, bool add_bos, bool add_eos)
 
void ck_tokenizer_set_add_space_prefix (CKTokenizer *tok, bool add_space_prefix)
 
void ck_tokenizer_set_space_prefix_style (CKTokenizer *tok, CKSpacePrefixStyle style)
 
void ck_tokenizer_set_special_ids (CKTokenizer *tok, int32_t unk, int32_t bos, int32_t eos, int32_t pad, int32_t mask)
 
void ck_tokenizer_set_spm_mode (CKTokenizer *tok, CKSpmMode spm_mode)
 
void ck_tokenizer_set_use_trie (CKTokenizer *tok, bool use_trie)
 
static int32_t find_longest_match (const CKTokenizer *tok, const char *text, size_t text_len, size_t pos, size_t *match_len)
 
static int32_t find_longest_match_hash (const CKTokenizer *tok, const char *text, size_t text_len, size_t pos, size_t *match_len)
 
static int32_t find_longest_match_trie (const CKTokenizer *tok, const char *text, size_t text_len, size_t pos, size_t *match_len)
 
static int preprocess_bpe_spaces (const char *text, int text_len, char *out, int out_max, CKSpacePrefixStyle style)
 

Function Documentation

◆ ck_tokenizer_add_merge()

int ck_tokenizer_add_merge ( CKTokenizer tok,
int32_t  left_id,
int32_t  right_id,
int32_t  merged_id,
int32_t  priority 
)

Add a BPE merge rule.

Parameters
tokTokenizer
left_idLeft token ID
right_idRight token ID
merged_idMerged token ID
priorityLower = higher priority (applied first)
Returns
0 on success, -1 on error

Definition at line 560 of file tokenizer.c.

560 {
561 (void)tok; (void)left; (void)right; (void)merged; (void)priority; return 0;
562}
int32_t int32_t int32_t int32_t priority
Definition true_bpe.h:123
const char * left
Definition true_bpe.h:138
const char const char * right
Definition true_bpe.h:139

References left, priority, and right.

◆ ck_tokenizer_add_special_token()

int ck_tokenizer_add_special_token ( CKTokenizer tok,
const char *  name,
int32_t  id 
)

Add special token (UNK, BOS, EOS, PAD, MASK).

Parameters
tokTokenizer
nameSpecial token name ("unk", "bos", "eos", "pad", "mask")
idToken ID
Returns
0 on success, -1 on error

Definition at line 218 of file tokenizer.c.

218 {
219 if (!tok || !name) return -1;
220 if (ck_tokenizer_add_token(tok, name, id, -1e10f) != 0) return -1;
221
222 TokenInfo *info = (TokenInfo *)ck_tokenizer_hash_table_lookup(tok->vocab, name);
223 if (info) info->is_special = true;
224
225 /* Also add to trie as special */
226 if (tok->vocab_trie) {
227 ck_trie_insert(tok->vocab_trie, name, id, true, 0);
228 }
229
230 if (strcmp(name, "<unk>") == 0 || strcmp(name, "[UNK]") == 0) tok->unk_id = id;
231 else if (strcmp(name, "<s>") == 0 || strcmp(name, "<bos>") == 0 || strcmp(name, "[BOS]") == 0) tok->bos_id = id;
232 else if (strcmp(name, "</s>") == 0 || strcmp(name, "<eos>") == 0 || strcmp(name, "[EOS]") == 0) tok->eos_id = id;
233 else if (strcmp(name, "<pad>") == 0 || strcmp(name, "[PAD]") == 0) tok->pad_id = id;
234
235 return 0;
236}
void * ck_tokenizer_hash_table_lookup(CKTokenizerHashTable *table, const char *key)
Definition hash_table.c:202
int ck_trie_insert(CKTrie *trie, const char *token, int32_t token_id, bool is_special, int32_t priority)
Definition trie.c:110
int32_t bos_id
int32_t unk_id
CKTrie * vocab_trie
Definition tokenizer.h:104
int32_t eos_id
CKTokenizerHashTable * vocab
Definition tokenizer.h:101
int32_t pad_id
int ck_tokenizer_add_token(CKTokenizer *tok, const char *token, int32_t id, float score)
Definition tokenizer.c:162
int32_t id
Definition tokenizer.h:316

References CKTokenizer::bos_id, ck_tokenizer_add_token(), ck_tokenizer_hash_table_lookup(), ck_trie_insert(), CKTokenizer::eos_id, id, CKTokenizer::pad_id, CKTokenizer::unk_id, CKTokenizer::vocab, and CKTokenizer::vocab_trie.

Referenced by main().

◆ ck_tokenizer_add_token()

int ck_tokenizer_add_token ( CKTokenizer tok,
const char *  token,
int32_t  id,
float  score 
)

Add a token to vocabulary.

Parameters
tokTokenizer
tokenToken string
idToken ID
scoreToken score (for SPM)
Returns
0 on success, -1 on error

Definition at line 162 of file tokenizer.c.

162 {
163 if (!tok || !token) {
164 return -1;
165 }
166
167 /* Ensure we have space in reverse vocab */
168 if (id >= (int32_t)tok->vocab_capacity) {
169 size_t new_cap = tok->vocab_capacity * 2;
170 while (new_cap <= (size_t)id) {
171 new_cap *= 2;
172 }
173 char **new_array = (char **)realloc(tok->id_to_token, new_cap * sizeof(char *));
174 if (!new_array) {
175 return -1;
176 }
177 memset(new_array + tok->vocab_capacity, 0, (new_cap - tok->vocab_capacity) * sizeof(char *));
178 tok->id_to_token = new_array;
179 tok->vocab_capacity = new_cap;
180 }
181
182 /* Check if token already exists */
183 TokenInfo *existing = (TokenInfo *)ck_tokenizer_hash_table_lookup(tok->vocab, token);
184 if (existing) {
185 existing->id = id;
186 existing->score = score;
187 if (id >= (int32_t)tok->vocab_size) tok->vocab_size = id + 1;
188 if (tok->id_to_token[id]) free(tok->id_to_token[id]);
189 tok->id_to_token[id] = strdup(token);
190 return 0;
191 }
192
193 /* Create new token info */
194 TokenInfo *info = (TokenInfo *)malloc(sizeof(TokenInfo));
195 if (!info) return -1;
196 info->id = id;
197 info->score = score;
198 info->is_special = false;
199
200 if (ck_tokenizer_hash_table_insert(tok->vocab, token, info) != 0) {
201 free(info);
202 return -1;
203 }
204
205 /* Also add to trie for fast longest-match lookups */
206 if (tok->vocab_trie) {
207 ck_trie_insert(tok->vocab_trie, token, id, false, 0);
208 }
209
210 if (id >= (int32_t)tok->vocab_size) tok->vocab_size = id + 1;
211 if (tok->id_to_token[id]) free(tok->id_to_token[id]);
212 tok->id_to_token[id] = strdup(token);
213
214 return 0;
215}
int ck_tokenizer_hash_table_insert(CKTokenizerHashTable *table, const char *key, void *value)
Definition hash_table.c:162
size_t vocab_capacity
Definition tokenizer.h:109
char ** id_to_token
const char * token
Definition tokenizer.h:307
int32_t float * score
Definition tokenizer.h:328

References ck_tokenizer_hash_table_insert(), ck_tokenizer_hash_table_lookup(), ck_trie_insert(), id, CKTokenizer::id_to_token, score, token, CKTokenizer::vocab, CKTokenizer::vocab_capacity, CKTokenizer::vocab_size, and CKTokenizer::vocab_trie.

Referenced by ck_tokenizer_add_special_token().

◆ ck_tokenizer_create()

CKTokenizer * ck_tokenizer_create ( CKTokenizerType  type)

Definition at line 39 of file tokenizer.c.

39 {
40 CKTokenizer *tok = (CKTokenizer *)malloc(sizeof(CKTokenizer));
41 if (!tok) {
42 return NULL;
43 }
44
45 memset(tok, 0, sizeof(*tok));
46
47 /* Create hash table for vocabulary */
49 if (!tok->vocab) {
50 free(tok);
51 return NULL;
52 }
53
54 /* Create trie for fast lookups (1M nodes for ~50k vocab) */
55 tok->vocab_trie = ck_trie_create(1000000);
56 if (!tok->vocab_trie) {
58 free(tok);
59 return NULL;
60 }
61
62 /* Initialize reverse vocab */
63 tok->vocab_capacity = 4096;
64 tok->id_to_token = (char **)calloc(tok->vocab_capacity, sizeof(char *));
65 if (!tok->id_to_token) {
67 free(tok);
68 return NULL;
69 }
70
71 /* Set default special tokens */
72 tok->unk_id = 0;
73 tok->bos_id = 1;
74 tok->eos_id = 2;
75 tok->pad_id = -1;
76 tok->mask_id = -1;
77
78 /* Initialize scores and types for SPM */
79 tok->scores = NULL;
80 tok->types = NULL;
81
82 /* Set config */
83 tok->config.type = type;
84 tok->config.add_bos = false;
85 tok->config.add_eos = false;
86 tok->config.add_space_prefix = true;
87 tok->config.unk_score = -1e10f;
89
90 ck_tokenizer_mempool_init(&tok->pool, 1024 * 1024);
91
92 return tok;
93}
#define CK_TOKENIZER_HT_BUCKETS_LARGE
Definition hash_table.h:142
void ck_tokenizer_hash_table_free(CKTokenizerHashTable *table, bool free_values)
Definition hash_table.c:144
CKTokenizerHashTable * ck_tokenizer_hash_table_create(size_t bucket_count)
Definition hash_table.c:84
CKTrie * ck_trie_create(size_t max_nodes)
Definition trie.c:29
int ck_tokenizer_mempool_init(CKTokenizerMemPool *pool, size_t size)
Definition memory_pool.c:11
CKTokenizerType type
Definition tokenizer.h:75
CKSpmMode spm_mode
Definition tokenizer.h:85
float * scores
Definition tokenizer.h:112
CKMemPool pool
uint8_t * types
Definition tokenizer.h:114
int32_t mask_id
Definition tokenizer.h:125
CKTokenizerConfig config
Definition tokenizer.h:98
@ CK_SPM_MODE_UNIGRAM
Definition tokenizer.h:69

References CKTokenizerConfig::add_bos, CKTokenizerConfig::add_eos, CKTokenizerConfig::add_space_prefix, CKTokenizer::bos_id, CK_SPM_MODE_UNIGRAM, ck_tokenizer_hash_table_create(), ck_tokenizer_hash_table_free(), CK_TOKENIZER_HT_BUCKETS_LARGE, ck_tokenizer_mempool_init(), ck_trie_create(), CKTokenizer::config, CKTokenizer::eos_id, CKTokenizer::id_to_token, CKTokenizer::mask_id, CKTokenizer::pad_id, CKTokenizer::pool, CKTokenizer::scores, CKTokenizerConfig::spm_mode, CKTokenizerConfig::type, CKTokenizer::types, CKTokenizer::unk_id, CKTokenizerConfig::unk_score, CKTokenizer::vocab, CKTokenizer::vocab_capacity, and CKTokenizer::vocab_trie.

Referenced by ck_tokenizer_create_bpe(), ck_tokenizer_create_spm(), ck_tokenizer_create_wordpiece(), and main().

◆ ck_tokenizer_decode()

int ck_tokenizer_decode ( const CKTokenizer tok,
const int32_t *  ids,
int  num_ids,
char *  text,
int  max_len 
)

Decode token IDs to text.

Parameters
tokTokenizer
idsInput token IDs
num_idsNumber of IDs
textOutput text buffer
max_lenMaximum text length
Returns
Number of bytes written

Definition at line 494 of file tokenizer.c.

494 {
495 if (!tok || !ids || !text || max_len <= 0) return 0;
496 int len = 0;
497 for (int i = 0; i < num_ids; i++) {
498 int32_t id = ids[i];
499 if (id < 0) continue;
500 const char *token = ck_tokenizer_id_to_token(tok, id);
501 if (!token) continue;
502 int token_len = (int)strlen(token);
503
504 /* Check for space prefix markers and convert to ASCII space */
505 unsigned char c0 = (unsigned char)token[0];
506 unsigned char c1 = (unsigned char)token[1];
507
508 if (c0 == 0xC4 && c1 == 0xA0) {
509 /* Ġ (U+0120) is 2 bytes - convert to space */
510 if (len < max_len - 1) text[len++] = ' ';
511 token += 2; token_len -= 2;
512 } else if (c0 == 0xE2 && c1 == 0x96 && (unsigned char)token[2] == 0x81) {
513 /* ▁ (U+2581) is 3 bytes - convert to space */
514 if (len < max_len - 1) text[len++] = ' ';
515 token += 3; token_len -= 3;
516 }
517
518 /* SentencePiece byte tokens should decode back to the raw byte rather
519 * than printing the literal vocabulary piece "<0xXX>". */
520 if (token_len == 6 && token[0] == '<' && token[1] == '0' &&
521 token[2] == 'x' && token[5] == '>') {
522 unsigned int byte_val = 0;
523 if (sscanf(token, "<0x%02X>", &byte_val) == 1 && byte_val < 256) {
524 if (len < max_len - 1) text[len++] = (char)byte_val;
525 continue;
526 }
527 }
528
529 for (int j = 0; j < token_len && len < max_len - 1; ) {
530 if (j + 2 < token_len &&
531 (unsigned char)token[j] == 0xE2 &&
532 (unsigned char)token[j + 1] == 0x96 &&
533 (unsigned char)token[j + 2] == 0x81) {
534 text[len++] = ' ';
535 j += 3;
536 continue;
537 }
538 text[len++] = token[j++];
539 }
540 }
541 text[len] = '\0';
542 return len;
543}
const char * ck_tokenizer_id_to_token(const CKTokenizer *tok, int32_t id)
Definition tokenizer.c:337
const int32_t * ids
Definition tokenizer.h:444
const int32_t int num_ids
Definition tokenizer.h:445
const char * text
Definition tokenizer.h:564
const int32_t int char int max_len
Definition true_bpe.h:288

References CKTokenizer::bos_id, ck_tokenizer_id_to_token(), CKTokenizer::eos_id, ids, max_len, num_ids, CKTokenizer::pad_id, text, and token.

Referenced by main().

◆ ck_tokenizer_detect_space_prefix_style()

CKSpacePrefixStyle ck_tokenizer_detect_space_prefix_style ( CKTokenizer tok)

Definition at line 281 of file tokenizer.c.

281 {
282 if (!tok) return CK_SPACE_PREFIX_GPT2;
283
284 /* Already detected? */
286 return tok->config.space_prefix_style;
287 }
288
289 /* Count tokens starting with each style:
290 * Ġ (U+0120) = bytes 0xC4 0xA0
291 * ▁ (U+2581) = bytes 0xE2 0x96 0x81
292 */
293 int gpt2_count = 0;
294 int spm_count = 0;
295
296 for (size_t i = 0; i < tok->vocab_size; i++) {
297 const char *token = tok->id_to_token[i];
298 if (!token) continue;
299
300 unsigned char c0 = (unsigned char)token[0];
301 unsigned char c1 = (unsigned char)token[1];
302
303 /* Check for Ġ (0xC4 0xA0) */
304 if (c0 == 0xC4 && c1 == 0xA0) {
305 gpt2_count++;
306 }
307 /* Check for ▁ (0xE2 0x96 0x81) */
308 else if (c0 == 0xE2 && c1 == 0x96 && (unsigned char)token[2] == 0x81) {
309 spm_count++;
310 }
311 }
312
313 /* Determine style based on counts */
314 CKSpacePrefixStyle detected;
315 if (spm_count > gpt2_count * 2 && spm_count > 0) {
316 detected = CK_SPACE_PREFIX_SPM;
317 } else if (gpt2_count > 0) {
318 detected = CK_SPACE_PREFIX_GPT2;
319 } else {
320 detected = CK_SPACE_PREFIX_ASCII;
321 }
322
323 tok->config.space_prefix_style = detected;
324 tok->config.space_prefix_detected = true;
325
326 return detected;
327}
bool space_prefix_detected
Definition tokenizer.h:84
CKSpacePrefixStyle space_prefix_style
Definition tokenizer.h:83
CKSpacePrefixStyle
Definition tokenizer.h:60
@ CK_SPACE_PREFIX_AUTO
Definition tokenizer.h:61
@ CK_SPACE_PREFIX_SPM
Definition tokenizer.h:63
@ CK_SPACE_PREFIX_GPT2
Definition tokenizer.h:62
@ CK_SPACE_PREFIX_ASCII
Definition tokenizer.h:64

References CK_SPACE_PREFIX_ASCII, CK_SPACE_PREFIX_AUTO, CK_SPACE_PREFIX_GPT2, CK_SPACE_PREFIX_SPM, CKTokenizer::config, CKTokenizer::id_to_token, CKTokenizerConfig::space_prefix_detected, CKTokenizerConfig::space_prefix_style, token, and CKTokenizer::vocab_size.

Referenced by ck_tokenizer_encode().

◆ ck_tokenizer_encode()

int ck_tokenizer_encode ( const CKTokenizer tok,
const char *  text,
int  text_len,
int32_t *  ids,
int  max_ids 
)

Encode text to token IDs using greedy longest-match.

For BPE: applies merge rules iteratively. For WordPiece/SPM: greedy longest-match from vocabulary.

Parameters
tokTokenizer
textInput text
text_lenText length, or -1 for null-terminated
idsOutput token IDs
max_idsMaximum IDs to write
Returns
Number of tokens written

Definition at line 436 of file tokenizer.c.

436 {
437 if (!tok || !text || !ids || max_ids <= 0) return 0;
438 if (text_len < 0) text_len = (int)strlen(text);
439
440 /* SentencePiece implementation lives in tokenizer_spm.c */
441 if (tok->config.type == CK_TOKENIZER_SPM) {
443 }
444
445 /* For BPE tokenizers, convert spaces to appropriate prefix marker.
446 * Auto-detect style from vocabulary if not already set. */
447 char preprocessed[8192];
448 const char *input = text;
449 int input_len = text_len;
450
451 if (tok->config.type == CK_TOKENIZER_BPE) {
452 /* Get or detect space prefix style */
453 CKSpacePrefixStyle style = ((CKTokenizer *)tok)->config.space_prefix_style;
454 if (!((CKTokenizer *)tok)->config.space_prefix_detected) {
456 }
457
458 int pp_len = preprocess_bpe_spaces(text, text_len, preprocessed, sizeof(preprocessed) - 1, style);
459 if (pp_len > 0) {
460 preprocessed[pp_len] = '\0';
461 input = preprocessed;
462 input_len = pp_len;
463 }
464 }
465
466 int out_idx = 0;
467 if (tok->config.add_bos && tok->bos_id >= 0 && out_idx < max_ids) {
468 ids[out_idx++] = tok->bos_id;
469 }
470
471 size_t pos = 0;
472 while (pos < (size_t)input_len && out_idx < max_ids) {
473 size_t match_len = 0;
474 int32_t id = find_longest_match(tok, input, input_len, pos, &match_len);
475
476 if (match_len == 0) {
477 /* Emit UNK for unknown characters */
478 if (tok->unk_id >= 0) ids[out_idx++] = tok->unk_id;
479 pos++;
480 } else {
481 ids[out_idx++] = id;
482 pos += match_len;
483 }
484 }
485
486 if (tok->config.add_eos && tok->eos_id >= 0 && out_idx < max_ids) {
487 ids[out_idx++] = tok->eos_id;
488 }
489
490 return out_idx;
491}
CKSpacePrefixStyle ck_tokenizer_detect_space_prefix_style(CKTokenizer *tok)
Definition tokenizer.c:281
static int32_t find_longest_match(const CKTokenizer *tok, const char *text, size_t text_len, size_t pos, size_t *match_len)
Definition tokenizer.c:384
int ck_tokenizer_encode_spm_dispatch(const CKTokenizer *tok, const char *text, int text_len, int32_t *ids, int max_ids)
static int preprocess_bpe_spaces(const char *text, int text_len, char *out, int out_max, CKSpacePrefixStyle style)
Definition tokenizer.c:396
@ CK_TOKENIZER_BPE
Definition tokenizer.h:54
@ CK_TOKENIZER_SPM
Definition tokenizer.h:56
CKSpacePrefixStyle style
Definition tokenizer.h:288
const CKBPEConfig * config
Definition true_bpe.h:179
const char int text_len
Definition true_bpe.h:270
const char int int32_t int max_ids
Definition true_bpe.h:272

References CKTokenizer::add_bos, CKTokenizerConfig::add_bos, CKTokenizer::add_eos, CKTokenizerConfig::add_eos, CKTokenizer::bos_id, CK_TOKENIZER_BPE, ck_tokenizer_detect_space_prefix_style(), ck_tokenizer_encode_spm_dispatch(), ck_tokenizer_lookup(), ck_tokenizer_lookup_merge(), CK_TOKENIZER_SPM, CKTokenizer::config, config, CKTokenizer::eos_id, find_longest_match(), id, ids, max_ids, CKMergeRule::merged, CKTokenizer::merges, CKTokenizer::num_merges, out_len, preprocess_bpe_spaces(), CKMergeRule::priority, style, text, text_len, CKTokenizerConfig::type, CKTokenizer::unk_id, and utf8_len().

Referenced by main(), and run_inference().

◆ ck_tokenizer_encode_spm_dispatch()

int ck_tokenizer_encode_spm_dispatch ( const CKTokenizer tok,
const char *  text,
int  text_len,
int32_t *  ids,
int  max_ids 
)

Definition at line 792 of file tokenizer_spm.c.

796 {
797 if (!tok || !text || !ids || max_ids <= 0) return 0;
798 if (text_len < 0) text_len = (int)strlen(text);
799
800 int out_idx = 0;
801 if (tok->config.add_bos && tok->bos_id >= 0 && out_idx < max_ids) {
802 ids[out_idx++] = tok->bos_id;
803 }
804 if (text_len == 0) {
805 if (tok->config.add_eos && tok->eos_id >= 0 && out_idx < max_ids) {
806 ids[out_idx++] = tok->eos_id;
807 }
808 return out_idx;
809 }
810
811 int segment_start = 0;
812 for (int pos = 0; pos < text_len && out_idx < max_ids;) {
813 size_t special_len = 0;
814 int32_t special_id = spm_find_special_token_at_pos(tok, text, text_len, (size_t)pos, &special_len);
815 if (special_id < 0 || special_len == 0) {
816 pos++;
817 continue;
818 }
819
820 if (segment_start < pos) {
822 tok,
823 text + segment_start,
824 pos - segment_start,
825 ids + out_idx,
826 max_ids - out_idx
827 );
828 if (n <= 0) return n;
829 out_idx += n;
830 if (out_idx >= max_ids) break;
831 }
832
833 ids[out_idx++] = special_id;
834 pos += (int)special_len;
835 segment_start = pos;
836 }
837
838 if (segment_start < text_len && out_idx < max_ids) {
840 tok,
841 text + segment_start,
842 text_len - segment_start,
843 ids + out_idx,
844 max_ids - out_idx
845 );
846 if (n <= 0) return n;
847 out_idx += n;
848 }
849
850 if (tok->config.add_eos && tok->eos_id >= 0 && out_idx < max_ids) {
851 ids[out_idx++] = tok->eos_id;
852 }
853
854 return out_idx;
855}
static int32_t spm_find_special_token_at_pos(const CKTokenizer *tok, const char *text, int text_len, size_t pos, size_t *match_len)
static int ck_tokenizer_encode_spm_plain_segment(const CKTokenizer *tok, const char *text, int text_len, int32_t *ids, int max_ids)

References CKTokenizerConfig::add_bos, CKTokenizerConfig::add_eos, CKTokenizer::bos_id, ck_tokenizer_encode_spm_plain_segment(), CKTokenizer::config, CKTokenizer::eos_id, ids, max_ids, spm_find_special_token_at_pos(), text, and text_len.

Referenced by ck_tokenizer_encode().

◆ ck_tokenizer_free()

void ck_tokenizer_free ( CKTokenizer tok)

Definition at line 96 of file tokenizer.c.

96 {
97 if (!tok) return;
98
99 /* Free vocabulary entries */
100 if (tok->vocab) {
102 }
103
104 /* Free trie */
105 if (tok->vocab_trie) {
107 }
108
109 /* Free reverse vocab strings */
110 if (tok->id_to_token) {
111 /* Note: strings were strdup'd in add_token */
112 for (size_t i = 0; i < tok->vocab_size; i++) {
113 if (tok->id_to_token[i]) {
114 free(tok->id_to_token[i]);
115 }
116 }
117 free(tok->id_to_token);
118 }
119
120 /* Free SPM-related arrays */
121 if (tok->scores) free(tok->scores);
122 if (tok->types) free(tok->types);
123 if (tok->byte_token_id) free(tok->byte_token_id);
124
126 free(tok);
127}
void ck_trie_free(CKTrie *trie)
Definition trie.c:51
void ck_tokenizer_mempool_free(CKTokenizerMemPool *pool)
Definition memory_pool.c:28
int32_t * byte_token_id
Definition tokenizer.h:118

References CKTokenizer::byte_token_id, ck_pool_free(), ck_tokenizer_hash_table_free(), ck_tokenizer_mempool_free(), ck_trie_free(), CKTokenizer::id_to_token, CKTokenizer::merge_hash, CKTokenizer::merges, CKTokenizer::pool, CKTokenizer::scores, CKTokenizer::types, CKTokenizer::vocab, CKTokenizer::vocab_hash, CKTokenizer::vocab_size, and CKTokenizer::vocab_trie.

Referenced by main(), run_inference(), run_inference(), and run_inference().

◆ ck_tokenizer_id_to_token()

const char * ck_tokenizer_id_to_token ( const CKTokenizer tok,
int32_t  id 
)

Definition at line 337 of file tokenizer.c.

337 {
338 if (!tok || id < 0 || id >= (int32_t)tok->vocab_size) return NULL;
339 return tok->id_to_token[id];
340}

References id, CKTokenizer::id_to_token, and CKTokenizer::vocab_size.

Referenced by ck_tokenizer_decode(), ck_tokenizer_encode_spm_impl(), main(), and run_inference().

◆ ck_tokenizer_load_binary()

int ck_tokenizer_load_binary ( CKTokenizer tok,
int  vocab_size,
const int32_t *  offsets,
const char *  strings,
int  num_merges,
const int32_t *  merges 
)

Load vocabulary from memory-mapped binary data.

Parameters
tokTokenizer
vocab_sizeNumber of tokens
offsetsArray of offsets into strings pool
stringsString pool containing null-terminated tokens
num_mergesNumber of BPE merges
mergesMerge rules as (left, right, merged) triplets
Returns
0 on success, -1 on error

Definition at line 546 of file tokenizer.c.

551 {
553}
int ck_tokenizer_load_binary_with_scores(CKTokenizer *tok, int vocab_size, const int32_t *offsets, const char *strings, const float *scores, const uint8_t *types, int num_merges, const int32_t *merges)
int const int32_t const char int num_merges
Definition true_bpe.h:196
int const int32_t const char * strings
Definition true_bpe.h:195
int const int32_t const char int const int32_t * merges
Definition true_bpe.h:197
int vocab_size
Definition true_bpe.h:193
int const int32_t * offsets
Definition true_bpe.h:194

References ck_tokenizer_load_binary_with_scores(), merges, num_merges, offsets, strings, and vocab_size.

◆ ck_tokenizer_load_gguf()

int ck_tokenizer_load_gguf ( CKTokenizer tok,
const char *  path 
)

Load vocabulary from GGUF file.

Parameters
tokTokenizer
pathPath to GGUF file
Returns
0 on success, -1 on error

Definition at line 556 of file tokenizer.c.

556{ (void)tok; (void)path; return -1; }

◆ ck_tokenizer_load_json()

int ck_tokenizer_load_json ( CKTokenizer tok,
const char *  path 
)

Load vocabulary from JSON file (HuggingFace format).

Parameters
tokTokenizer
pathPath to vocab.json or tokenizer.json
Returns
0 on success, -1 on error

Definition at line 557 of file tokenizer.c.

557{ (void)tok; (void)path; return -1; }

◆ ck_tokenizer_load_merges()

int ck_tokenizer_load_merges ( CKTokenizer tok,
const char *  path 
)

Load BPE merges from text file.

Format: token1 token2 (one merge per line)

Parameters
tokTokenizer
pathPath to merges.txt
Returns
0 on success, -1 on error

Definition at line 559 of file tokenizer.c.

559{ (void)tok; (void)path; return -1; }

◆ ck_tokenizer_load_text()

int ck_tokenizer_load_text ( CKTokenizer tok,
const char *  path 
)

Load vocabulary from text file (one token per line).

Format: token_string [id] [score] Lines starting with # are comments.

Parameters
tokTokenizer
pathPath to vocabulary file
Returns
0 on success, -1 on error

Definition at line 558 of file tokenizer.c.

558{ (void)tok; (void)path; return -1; }

◆ ck_tokenizer_lookup()

int32_t ck_tokenizer_lookup ( const CKTokenizer tok,
const char *  token 
)

Definition at line 330 of file tokenizer.c.

330 {
331 if (!tok || !token) return -1;
332 TokenInfo *info = (TokenInfo *)ck_tokenizer_hash_table_lookup(tok->vocab, token);
333 return info ? info->id : tok->unk_id;
334}

References ck_tokenizer_hash_table_lookup(), token, CKTokenizer::unk_id, and CKTokenizer::vocab.

◆ ck_tokenizer_reset()

void ck_tokenizer_reset ( CKTokenizer tok)

Definition at line 130 of file tokenizer.c.

130 {
131 if (!tok) return;
132
134
135 if (tok->vocab_trie) {
137 }
138
139 for (size_t i = 0; i < tok->vocab_size; i++) {
140 if (tok->id_to_token[i]) {
141 free(tok->id_to_token[i]);
142 tok->id_to_token[i] = NULL;
143 }
144 }
145
146 tok->vocab_size = 0;
147
148 /* Reset SPM-related arrays using actual allocated sizes */
149 if (tok->scores && tok->scores_size > 0) {
150 memset(tok->scores, 0, tok->scores_size * sizeof(float));
151 }
152 if (tok->types && tok->types_size > 0) {
153 memset(tok->types, 0, tok->types_size * sizeof(uint8_t));
154 }
155 /* Clear byte lookup table */
156 if (tok->byte_token_id) {
157 memset(tok->byte_token_id, -1, 256 * sizeof(int32_t));
158 }
159}
void ck_tokenizer_hash_table_clear(CKTokenizerHashTable *table, bool free_values)
Definition hash_table.c:316
void ck_trie_clear(CKTrie *trie)
Definition trie.c:80
size_t types_size
Definition tokenizer.h:115
size_t scores_size
Definition tokenizer.h:113

References CKTokenizer::byte_token_id, ck_tokenizer_hash_table_clear(), ck_trie_clear(), CKTokenizer::id_to_token, CKTokenizer::scores, CKTokenizer::scores_size, CKTokenizer::types, CKTokenizer::types_size, CKTokenizer::vocab, CKTokenizer::vocab_size, and CKTokenizer::vocab_trie.

Referenced by ck_tokenizer_load_binary_with_scores().

◆ ck_tokenizer_set_add_bos_eos()

void ck_tokenizer_set_add_bos_eos ( CKTokenizer tok,
bool  add_bos,
bool  add_eos 
)

Definition at line 248 of file tokenizer.c.

248 {
249 if (!tok) return;
250 tok->config.add_bos = add_bos;
251 tok->config.add_eos = add_eos;
252}
bool bool add_eos
Definition tokenizer.h:243
bool add_bos
Definition tokenizer.h:243

References CKTokenizerConfig::add_bos, add_bos, CKTokenizerConfig::add_eos, add_eos, and CKTokenizer::config.

◆ ck_tokenizer_set_add_space_prefix()

void ck_tokenizer_set_add_space_prefix ( CKTokenizer tok,
bool  add_space_prefix 
)

Definition at line 254 of file tokenizer.c.

254 {
255 if (!tok) return;
257}
bool add_space_prefix
Definition tokenizer.h:253

References CKTokenizerConfig::add_space_prefix, add_space_prefix, and CKTokenizer::config.

◆ ck_tokenizer_set_space_prefix_style()

void ck_tokenizer_set_space_prefix_style ( CKTokenizer tok,
CKSpacePrefixStyle  style 
)

Definition at line 271 of file tokenizer.c.

271 {
272 if (!tok) return;
275 tok->config.space_prefix_detected = true;
276 }
277}

References CK_SPACE_PREFIX_AUTO, CKTokenizer::config, CKTokenizerConfig::space_prefix_detected, CKTokenizerConfig::space_prefix_style, and style.

◆ ck_tokenizer_set_special_ids()

void ck_tokenizer_set_special_ids ( CKTokenizer tok,
int32_t  unk,
int32_t  bos,
int32_t  eos,
int32_t  pad,
int32_t  mask 
)

Definition at line 239 of file tokenizer.c.

239 {
240 if (!tok) return;
241 tok->unk_id = unk;
242 tok->bos_id = bos;
243 tok->eos_id = eos;
244 tok->pad_id = pad;
245 tok->mask_id = mask;
246}
int32_t int32_t int32_t int32_t int32_t mask
Definition tokenizer.h:234
int32_t unk
Definition tokenizer.h:230
int32_t int32_t int32_t eos
Definition tokenizer.h:232
int32_t int32_t int32_t int32_t pad
Definition tokenizer.h:233
int32_t int32_t bos
Definition tokenizer.h:231

References bos, CKTokenizer::bos_id, eos, CKTokenizer::eos_id, mask, CKTokenizer::mask_id, pad, CKTokenizer::pad_id, unk, and CKTokenizer::unk_id.

◆ ck_tokenizer_set_spm_mode()

void ck_tokenizer_set_spm_mode ( CKTokenizer tok,
CKSpmMode  spm_mode 
)

Definition at line 259 of file tokenizer.c.

259 {
260 if (!tok) return;
261 tok->config.spm_mode = spm_mode;
262}
CKSpmMode spm_mode
Definition tokenizer.h:261

References CKTokenizer::config, CKTokenizerConfig::spm_mode, and spm_mode.

◆ ck_tokenizer_set_use_trie()

void ck_tokenizer_set_use_trie ( CKTokenizer tok,
bool  use_trie 
)

Definition at line 265 of file tokenizer.c.

265 {
266 if (!tok) return;
267 tok->config.use_trie = use_trie;
268}
bool use_trie
Definition tokenizer.h:277

References CKTokenizer::config, CKTokenizerConfig::use_trie, and use_trie.

◆ find_longest_match()

static int32_t find_longest_match ( const CKTokenizer tok,
const char *  text,
size_t  text_len,
size_t  pos,
size_t *  match_len 
)
static

Definition at line 384 of file tokenizer.c.

384 {
385 if (tok->config.use_trie) {
386 return find_longest_match_trie(tok, text, text_len, pos, match_len);
387 } else {
388 return find_longest_match_hash(tok, text, text_len, pos, match_len);
389 }
390}
static int32_t find_longest_match_trie(const CKTokenizer *tok, const char *text, size_t text_len, size_t pos, size_t *match_len)
Definition tokenizer.c:343
static int32_t find_longest_match_hash(const CKTokenizer *tok, const char *text, size_t text_len, size_t pos, size_t *match_len)
Definition tokenizer.c:354

References CKTokenizer::config, find_longest_match_hash(), find_longest_match_trie(), text, text_len, and CKTokenizerConfig::use_trie.

Referenced by ck_tokenizer_encode().

◆ find_longest_match_hash()

static int32_t find_longest_match_hash ( const CKTokenizer tok,
const char *  text,
size_t  text_len,
size_t  pos,
size_t *  match_len 
)
static

Definition at line 354 of file tokenizer.c.

354 {
355 if (!tok || !text || pos >= text_len) {
356 *match_len = 0;
357 return tok ? tok->unk_id : -1;
358 }
359
360 size_t max_len = 64;
361 if (pos + max_len > text_len) max_len = text_len - pos;
362
363 int32_t best_id = tok->unk_id;
364 size_t best_len = 0;
365
366 for (size_t len = max_len; len >= 1; len--) {
367 char tmp[65];
368 memcpy(tmp, text + pos, len);
369 tmp[len] = '\0';
370
371 TokenInfo *info = (TokenInfo *)ck_tokenizer_hash_table_lookup(tok->vocab, tmp);
372 if (info) {
373 best_id = info->id;
374 best_len = len;
375 break;
376 }
377 }
378
379 *match_len = best_len;
380 return best_id;
381}

References ck_tokenizer_hash_table_lookup(), max_len, text, text_len, CKTokenizer::unk_id, and CKTokenizer::vocab.

Referenced by find_longest_match().

◆ find_longest_match_trie()

static int32_t find_longest_match_trie ( const CKTokenizer tok,
const char *  text,
size_t  text_len,
size_t  pos,
size_t *  match_len 
)
static

Definition at line 343 of file tokenizer.c.

343 {
344 if (!tok || !tok->vocab_trie || !text || pos >= text_len) {
345 *match_len = 0;
346 return tok ? tok->unk_id : -1;
347 }
348
349 int32_t token_id = ck_trie_find_longest(tok->vocab_trie, text, text_len, pos, match_len);
350 return token_id >= 0 ? token_id : tok->unk_id;
351}
int32_t ck_trie_find_longest(const CKTrie *trie, const char *text, size_t text_len, size_t start_pos, size_t *match_len)
Definition trie.c:142

References ck_trie_find_longest(), text, text_len, CKTokenizer::unk_id, and CKTokenizer::vocab_trie.

Referenced by find_longest_match().

◆ preprocess_bpe_spaces()

static int preprocess_bpe_spaces ( const char *  text,
int  text_len,
char *  out,
int  out_max,
CKSpacePrefixStyle  style 
)
static

Definition at line 396 of file tokenizer.c.

396 {
397 int out_len = 0;
398
400 if (text_len > out_max) return -1;
401 memcpy(out, text, (size_t)text_len);
402 return text_len;
403 }
404
405 /* For SentencePiece, add ▁ at the start of text (unless text starts with space) */
406 if (style == CK_SPACE_PREFIX_SPM && text_len > 0 && text[0] != ' ') {
407 if (out_len + 3 > out_max) return -1;
408 out[out_len++] = (char)0xE2;
409 out[out_len++] = (char)0x96;
410 out[out_len++] = (char)0x81;
411 }
412
413 for (int i = 0; i < text_len; i++) {
414 if (text[i] == ' ') {
415 if (style == CK_SPACE_PREFIX_SPM) {
416 /* SentencePiece style: ▁ (3 bytes: 0xE2 0x96 0x81) */
417 if (out_len + 3 > out_max) return -1;
418 out[out_len++] = (char)0xE2;
419 out[out_len++] = (char)0x96;
420 out[out_len++] = (char)0x81;
421 } else {
422 /* GPT-2 style: Ġ (2 bytes: 0xC4 0xA0) */
423 if (out_len + 2 > out_max) return -1;
424 out[out_len++] = (char)0xC4;
425 out[out_len++] = (char)0xA0;
426 }
427 } else {
428 if (out_len + 1 > out_max) return -1;
429 out[out_len++] = text[i];
430 }
431 }
432 return out_len;
433}
const int32_t int int * out_len
Definition tokenizer.h:446

References CK_SPACE_PREFIX_ASCII, CK_SPACE_PREFIX_SPM, out_len, style, text, and text_len.

Referenced by ck_tokenizer_encode().