← Back to C-Kernel-Engine Docs Doxygen Source Documentation
 
Loading...
Searching...
No Matches
tokenizer.h
Go to the documentation of this file.
1/*
2 * C-Kernel-Engine Tokenizer
3 *
4 * High-performance tokenizer supporting:
5 * - BPE (Byte-Pair Encoding): GPT-2, LLaMA, Qwen
6 * - WordPiece: BERT, RoBERTa
7 * - SentencePiece (unigram): LLaMA, T5
8 *
9 * Features:
10 * - MurmurHash3 hashing
11 * - AVX-512 optimized string comparison
12 * - Greedy longest-match encoding
13 * - Full UTF-8 support
14 * - GGUF vocab loading
15 *
16 * By Anthony Shivakumar
17 */
18
19#ifndef CK_TOKENIZER_H
20#define CK_TOKENIZER_H
21
22#include <stddef.h>
23#include <stdint.h>
24#include <stdbool.h>
25
29#include "tokenizer/utf8.h"
30#include "data_structures/tries/trie.h"
31
32#ifdef __cplusplus
33extern "C" {
34#endif
35
36/* Export macro */
37#ifdef _WIN32
38#define CK_TOKENIZER_API __declspec(dllexport)
39#else
40#define CK_TOKENIZER_API __attribute__((visibility("default")))
41#endif
42
43/* Maximum token length */
44#define CK_TOKENIZER_MAX_TOKEN_LEN 256
45
46/* Maximum vocabulary size */
47#define CK_TOKENIZER_MAX_VOCAB_SIZE 256000
48
49/* Default hash table size */
50#define CK_TOKENIZER_DEFAULT_HT_SIZE 65536
51
52/* Tokenizer model type */
53typedef enum {
54 CK_TOKENIZER_BPE = 0, /* Byte-Pair Encoding (GPT-2, LLaMA, Qwen) */
55 CK_TOKENIZER_WORDPIECE = 1, /* WordPiece (BERT, RoBERTa) */
56 CK_TOKENIZER_SPM = 2 /* SentencePiece (unigram) */
58
59/* Space prefix style for BPE tokenizers */
60typedef enum {
61 CK_SPACE_PREFIX_AUTO = 0, /* Auto-detect from vocabulary */
62 CK_SPACE_PREFIX_GPT2 = 1, /* GPT-2 style: Ġ (U+0120, bytes 0xC4 0xA0) */
63 CK_SPACE_PREFIX_SPM = 2, /* SentencePiece style: ▁ (U+2581, bytes 0xE2 0x96 0x81) */
64 CK_SPACE_PREFIX_ASCII = 3 /* ASCII identity mode: no UTF-8/byte remap */
66
67/* SentencePiece mode */
68typedef enum {
69 CK_SPM_MODE_UNIGRAM = 0, /* SentencePiece unigram/Viterbi */
70 CK_SPM_MODE_LLAMA = 1 /* llama.cpp merge-style SPM */
72
73/* Tokenizer configuration */
74typedef struct {
75 CKTokenizerType type; /* Tokenization algorithm */
76 bool add_bos; /* Add beginning-of-sequence token */
77 bool add_eos; /* Add end-of-sequence token */
78 bool add_space_prefix; /* For SPM: add ▁ at start (SentencePiece) */
79 bool lowercase; /* Convert text to lowercase before tokenizing */
80 bool treat_whitespace_as_suffix; /* For SentencePiece */
81 float unk_score; /* Unknown token score (for SPM) */
82 bool use_trie; /* Use trie for lookups (faster), false = use hash table */
83 CKSpacePrefixStyle space_prefix_style; /* Space prefix style (GPT-2 Ġ vs SentencePiece ▁) */
84 bool space_prefix_detected; /* True if auto-detection has run */
85 CKSpmMode spm_mode; /* SPM mode: unigram or llama-style */
87
88/* Vocabulary entry */
89typedef struct {
90 int32_t id; /* Token ID */
91 float score; /* Score (for SPM) */
92 bool is_special; /* Is special token */
94
95/* Main tokenizer structure */
96typedef struct CKTokenizer {
97 /* Configuration */
99
100 /* Vocabulary: token string -> token info */
102
103 /* Trie for fast longest-match lookups (O(k) instead of O(n*k)) */
105
106 /* Reverse vocabulary: ID -> token string */
107 char **id_to_token;
110
111 /* Token scores for SPM (Viterbi/DP encoding) */
112 float *scores;
113 size_t scores_size; /* Allocated size for scores array */
114 uint8_t *types; /* Token type (GGUF: 1=normal, 2=unknown, 3=control, 4=user_defined, 6=byte) */
115 size_t types_size; /* Allocated size for types array */
116
117 /* Byte token lookup table for SPM (built during load) */
118 int32_t *byte_token_id; /* Map byte value (0-255) to token ID, -1 = not found */
119
120 /* Special token IDs */
121 int32_t unk_id;
122 int32_t bos_id;
123 int32_t eos_id;
124 int32_t pad_id;
125 int32_t mask_id;
126
127 /* Memory pool for allocations */
129
130 /* For BPE: merge rules */
131 int32_t *merge_pairs; /* left_id * vocab_size + right_id -> merge priority */
133 int32_t *merge_result; /* merge priority -> merged token ID */
135 int32_t num_merges;
136
137 /* Cache for encoding */
141
142/* ============================================================================
143 * Initialization and Cleanup
144 * ============================================================================ */
145
146/**
147 * Create a new tokenizer.
148 *
149 * @param type Tokenizer type (BPE, WordPiece, SPM)
150 * @return Newly allocated tokenizer, or NULL on error
151 */
153
154/**
155 * Create tokenizer with default BPE config.
156 */
160
161/**
162 * Create tokenizer with default WordPiece config.
163 */
167
168/**
169 * Create tokenizer with default SPM config.
170 */
174
175/**
176 * Free a tokenizer.
177 *
178 * @param tok Tokenizer to free
179 */
181
182/**
183 * Reset tokenizer state (clear vocab but keep config).
184 *
185 * @param tok Tokenizer to reset
186 */
188
189/* ============================================================================
190 * Vocabulary Management
191 * ============================================================================ */
192
193/**
194 * Add a token to vocabulary.
195 *
196 * @param tok Tokenizer
197 * @param token Token string
198 * @param id Token ID
199 * @param score Token score (for SPM)
200 * @return 0 on success, -1 on error
201 */
203 const char *token,
204 int32_t id,
205 float score);
206
207/**
208 * Add special token (UNK, BOS, EOS, PAD, MASK).
209 *
210 * @param tok Tokenizer
211 * @param name Special token name ("unk", "bos", "eos", "pad", "mask")
212 * @param id Token ID
213 * @return 0 on success, -1 on error
214 */
216 const char *name,
217 int32_t id);
218
219/**
220 * Set special token IDs.
221 *
222 * @param tok Tokenizer
223 * @param unk Unknown token ID
224 * @param bos Beginning-of-sequence token ID
225 * @param eos End-of-sequence token ID
226 * @param pad Padding token ID
227 * @param mask Mask token ID
228 */
230 int32_t unk,
231 int32_t bos,
232 int32_t eos,
233 int32_t pad,
234 int32_t mask);
235
236/**
237 * Set whether to add BOS/EOS tokens during encoding.
238 *
239 * @param tok Tokenizer
240 * @param add_bos If true, prepend BOS token (if available)
241 * @param add_eos If true, append EOS token (if available)
242 */
244
245/**
246 * Set whether to add the SentencePiece space prefix (▁) at the start.
247 *
248 * This mirrors SentencePiece's add_dummy_prefix behavior.
249 *
250 * @param tok Tokenizer
251 * @param add_space_prefix If true, add leading ▁ when appropriate
252 */
254
255/**
256 * Set SentencePiece mode.
257 *
258 * @param tok Tokenizer
259 * @param spm_mode SPM mode (unigram or llama-style)
260 */
262
263/**
264 * Set whether to lowercase input text before tokenizing.
265 *
266 * @param tok Tokenizer
267 * @param lowercase If true, convert text to lowercase
268 */
269CK_TOKENIZER_API void ck_tokenizer_set_lowercase(CKTokenizer *tok, bool lowercase);
270
271/**
272 * Set lookup method (trie vs hash table).
273 *
274 * @param tok Tokenizer
275 * @param use_trie If true, use trie (faster for longest-match), false = hash table
276 */
278
279/**
280 * Set space prefix style for BPE tokenizers.
281 *
282 * GPT-2/Qwen use Ġ (U+0120), LLaMA/SentencePiece use ▁ (U+2581).
283 * Default is AUTO which auto-detects from vocabulary.
284 *
285 * @param tok Tokenizer
286 * @param style Space prefix style (AUTO, GPT2, or SPM)
287 */
289
290/**
291 * Auto-detect space prefix style from vocabulary.
292 *
293 * Checks for presence of tokens starting with Ġ vs ▁ to determine style.
294 *
295 * @param tok Tokenizer
296 * @return Detected style (GPT2 or SPM)
297 */
299
300/**
301 * Look up token ID by string.
302 *
303 * @param tok Tokenizer
304 * @param token Token string
305 * @return Token ID, or unk_id if not found
306 */
307CK_TOKENIZER_API int32_t ck_tokenizer_lookup(const CKTokenizer *tok, const char *token);
308
309/**
310 * Get token string by ID.
311 *
312 * @param tok Tokenizer
313 * @param id Token ID
314 * @return Token string, or NULL if invalid
315 */
316CK_TOKENIZER_API const char *ck_tokenizer_id_to_token(const CKTokenizer *tok, int32_t id);
317
318/**
319 * Get token info by ID.
320 *
321 * @param tok Tokenizer
322 * @param id Token ID
323 * @param score Output: token score
324 * @return Token string, or NULL if invalid
325 */
326CK_TOKENIZER_API const char *ck_tokenizer_id_to_token_info(const CKTokenizer *tok,
327 int32_t id,
328 float *score);
329
330/**
331 * Get vocabulary size.
332 */
333static inline size_t ck_tokenizer_vocab_size(const CKTokenizer *tok) {
334 return tok ? tok->vocab_size : 0;
335}
336
337/* ============================================================================
338 * BPE Merge Rules
339 * ============================================================================ */
340
341/**
342 * Add a BPE merge rule.
343 *
344 * @param tok Tokenizer
345 * @param left_id Left token ID
346 * @param right_id Right token ID
347 * @param merged_id Merged token ID
348 * @param priority Lower = higher priority (applied first)
349 * @return 0 on success, -1 on error
350 */
352 int32_t left_id,
353 int32_t right_id,
354 int32_t merged_id,
355 int32_t priority);
356
357/* ============================================================================
358 * Encoding (Text -> Token IDs)
359 * ============================================================================ */
360
361/**
362 * Encode text to token IDs using greedy longest-match.
363 *
364 * For BPE: applies merge rules iteratively.
365 * For WordPiece/SPM: greedy longest-match from vocabulary.
366 *
367 * @param tok Tokenizer
368 * @param text Input text
369 * @param text_len Text length, or -1 for null-terminated
370 * @param ids Output token IDs
371 * @param max_ids Maximum IDs to write
372 * @return Number of tokens written
373 */
374int ck_tokenizer_encode(const CKTokenizer *tok,
375 const char *text,
376 int text_len,
377 int32_t *ids,
378 int max_ids);
379
380/**
381 * Encode with special token handling.
382 *
383 * @param tok Tokenizer
384 * @param text Input text
385 * @param text_len Text length, or -1 for null-terminated
386 * @param ids Output token IDs
387 * @param max_ids Maximum IDs to write
388 * @param add_special Add BOS/EOS tokens
389 * @return Number of tokens written
390 */
392 const char *text,
393 int text_len,
394 int32_t *ids,
395 int max_ids,
396 bool add_special);
397
398/**
399 * Encode and return tokens as array of strings.
400 *
401 * @param tok Tokenizer
402 * @param text Input text
403 * @param text_len Text length
404 * @param out_tokens Output token strings (caller must free each)
405 * @param max_tokens Maximum tokens
406 * @return Number of tokens written
407 */
409 const char *text,
410 int text_len,
411 const char **out_tokens,
412 int max_tokens);
413
414/* ============================================================================
415 * Decoding (Token IDs -> Text)
416 * ============================================================================ */
417
418/**
419 * Decode token IDs to text.
420 *
421 * @param tok Tokenizer
422 * @param ids Input token IDs
423 * @param num_ids Number of IDs
424 * @param text Output text buffer
425 * @param max_len Maximum text length
426 * @return Number of bytes written
427 */
428int ck_tokenizer_decode(const CKTokenizer *tok,
429 const int32_t *ids,
430 int num_ids,
431 char *text,
432 int max_len);
433
434/**
435 * Decode to buffer allocated by caller.
436 *
437 * @param tok Tokenizer
438 * @param ids Input token IDs
439 * @param num_ids Number of IDs
440 * @param out_len Output: length of decoded string
441 * @return Newly allocated string, or NULL on error
442 */
443CK_TOKENIZER_API char *ck_tokenizer_decode_alloc(const CKTokenizer *tok,
444 const int32_t *ids,
446 int *out_len);
447
448/* ============================================================================
449 * File Loading
450 * ============================================================================ */
451
452/**
453 * Load vocabulary from memory-mapped binary data.
454 *
455 * @param tok Tokenizer
456 * @param vocab_size Number of tokens
457 * @param offsets Array of offsets into strings pool
458 * @param strings String pool containing null-terminated tokens
459 * @param num_merges Number of BPE merges
460 * @param merges Merge rules as (left, right, merged) triplets
461 * @return 0 on success, -1 on error
462 */
464 int vocab_size,
465 const int32_t *offsets,
466 const char *strings,
467 int num_merges,
468 const int32_t *merges);
469
470/**
471 * Load vocabulary from memory-mapped binary data with scores and types.
472 *
473 * This extended version supports SPM (SentencePiece) tokenizers which require
474 * token scores for Viterbi/DP encoding.
475 *
476 * @param tok Tokenizer
477 * @param vocab_size Number of tokens
478 * @param offsets Array of offsets into strings pool
479 * @param strings String pool containing null-terminated tokens
480 * @param scores Array of token scores (float32), can be NULL
481 * @param types Array of token types (uint8), can be NULL
482 * @param num_merges Number of BPE merges
483 * @param merges Merge rules as (left, right, merged) triplets
484 * @return 0 on success, -1 on error
485 */
487 int vocab_size,
488 const int32_t *offsets,
489 const char *strings,
490 const float *scores,
491 const uint8_t *types,
492 int num_merges,
493 const int32_t *merges);
494
495/**
496 * Load vocabulary from GGUF file.
497 *
498 * @param tok Tokenizer
499 * @param path Path to GGUF file
500 * @return 0 on success, -1 on error
501 */
502int ck_tokenizer_load_gguf(CKTokenizer *tok, const char *path);
503
504/**
505 * Load vocabulary from JSON file (HuggingFace format).
506 *
507 * @param tok Tokenizer
508 * @param path Path to vocab.json or tokenizer.json
509 * @return 0 on success, -1 on error
510 */
511int ck_tokenizer_load_json(CKTokenizer *tok, const char *path);
512
513/**
514 * Load vocabulary from text file (one token per line).
515 *
516 * Format: token_string [id] [score]
517 * Lines starting with # are comments.
518 *
519 * @param tok Tokenizer
520 * @param path Path to vocabulary file
521 * @return 0 on success, -1 on error
522 */
523int ck_tokenizer_load_text(CKTokenizer *tok, const char *path);
524
525/**
526 * Load BPE merges from text file.
527 *
528 * Format: token1 token2 (one merge per line)
529 *
530 * @param tok Tokenizer
531 * @param path Path to merges.txt
532 * @return 0 on success, -1 on error
533 */
534int ck_tokenizer_load_merges(CKTokenizer *tok, const char *path);
535
536/* ============================================================================
537 * Utility Functions
538 * ============================================================================ */
539
540/**
541 * Get the tokenizer type name.
542 *
543 * @param tok Tokenizer
544 * @return Type name string
545 */
546CK_TOKENIZER_API const char *ck_tokenizer_type_name(const CKTokenizer *tok);
547
548/**
549 * Check if token is special.
550 *
551 * @param tok Tokenizer
552 * @param id Token ID
553 * @return true if special token
554 */
555CK_TOKENIZER_API bool ck_tokenizer_is_special(const CKTokenizer *tok, int32_t id);
556
557/**
558 * Estimate encoded token count.
559 *
560 * @param tok Tokenizer
561 * @param text Input text
562 * @return Estimated number of tokens
563 */
564CK_TOKENIZER_API size_t ck_tokenizer_estimate_tokens(const CKTokenizer *tok, const char *text);
565
566/**
567 * Get last error message.
568 *
569 * @return Last error message, or NULL if no error
570 */
571CK_TOKENIZER_API const char *ck_tokenizer_last_error(void);
572
573#ifdef __cplusplus
574}
575#endif
576
577#endif /* CK_TOKENIZER_H */
int32_t ck_tokenizer_lookup(const CKTokenizer *tok, const char *token, int len)
void ck_tokenizer_free(CKTokenizer *tok)
const char * ck_tokenizer_id_to_token(const CKTokenizer *tok, int32_t id)
bool treat_whitespace_as_suffix
Definition tokenizer.h:80
CKTokenizerType type
Definition tokenizer.h:75
CKSpmMode spm_mode
Definition tokenizer.h:85
bool space_prefix_detected
Definition tokenizer.h:84
CKSpacePrefixStyle space_prefix_style
Definition tokenizer.h:83
int32_t bos_id
float * scores
Definition tokenizer.h:112
size_t types_size
Definition tokenizer.h:115
int32_t * merge_result
Definition tokenizer.h:133
size_t vocab_size
Definition tokenizer.h:108
int32_t * byte_token_id
Definition tokenizer.h:118
CKTokenizerMemPool pool
Definition tokenizer.h:128
int32_t unk_id
int32_t num_merges
Definition tokenizer.h:135
CKTrie * vocab_trie
Definition tokenizer.h:104
int32_t eos_id
size_t merge_pairs_size
Definition tokenizer.h:132
size_t merge_result_size
Definition tokenizer.h:134
char * encode_buffer
Definition tokenizer.h:138
int32_t * merge_pairs
Definition tokenizer.h:131
size_t encode_buffer_size
Definition tokenizer.h:139
CKTokenizerHashTable * vocab
Definition tokenizer.h:101
uint8_t * types
Definition tokenizer.h:114
size_t vocab_capacity
Definition tokenizer.h:109
size_t scores_size
Definition tokenizer.h:113
char ** id_to_token
int32_t mask_id
Definition tokenizer.h:125
CKTokenizerConfig config
Definition tokenizer.h:98
int32_t pad_id
void ck_tokenizer_set_add_bos_eos(CKTokenizer *tok, bool add_bos, bool add_eos)
Definition tokenizer.c:248
CKSpacePrefixStyle ck_tokenizer_detect_space_prefix_style(CKTokenizer *tok)
Definition tokenizer.c:281
void ck_tokenizer_set_spm_mode(CKTokenizer *tok, CKSpmMode spm_mode)
Definition tokenizer.c:259
CKTokenizer * ck_tokenizer_create(CKTokenizerType type)
Definition tokenizer.c:39
void ck_tokenizer_set_special_ids(CKTokenizer *tok, int32_t unk, int32_t bos, int32_t eos, int32_t pad, int32_t mask)
Definition tokenizer.c:239
void ck_tokenizer_reset(CKTokenizer *tok)
Definition tokenizer.c:130
void ck_tokenizer_set_use_trie(CKTokenizer *tok, bool use_trie)
Definition tokenizer.c:265
void ck_tokenizer_set_add_space_prefix(CKTokenizer *tok, bool add_space_prefix)
Definition tokenizer.c:254
void ck_tokenizer_set_space_prefix_style(CKTokenizer *tok, CKSpacePrefixStyle style)
Definition tokenizer.c:271
int32_t int32_t int32_t int32_t int32_t mask
Definition tokenizer.h:234
const int32_t * ids
Definition tokenizer.h:444
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 ck_tokenizer_decode(const CKTokenizer *tok, const int32_t *ids, int num_ids, char *text, int max_len)
int ck_tokenizer_add_token(CKTokenizer *tok, const char *token, int32_t id, float score)
Definition tokenizer.c:162
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
const int32_t int num_ids
Definition tokenizer.h:445
CKTokenizerType
Definition tokenizer.h:53
@ CK_TOKENIZER_BPE
Definition tokenizer.h:54
@ CK_TOKENIZER_SPM
Definition tokenizer.h:56
@ CK_TOKENIZER_WORDPIECE
Definition tokenizer.h:55
static CKTokenizer * ck_tokenizer_create_wordpiece(void)
Definition tokenizer.h:164
int ck_tokenizer_load_text(CKTokenizer *tok, const char *path)
Definition tokenizer.c:558
int ck_tokenizer_load_gguf(CKTokenizer *tok, const char *path)
Definition tokenizer.c:556
int ck_tokenizer_load_json(CKTokenizer *tok, const char *path)
Definition tokenizer.c:557
const char * text
Definition tokenizer.h:564
bool bool add_eos
Definition tokenizer.h:243
bool add_space_prefix
Definition tokenizer.h:253
int ck_tokenizer_load_binary(CKTokenizer *tok, int vocab_size, const int32_t *offsets, const char *strings, int num_merges, const int32_t *merges)
bool lowercase
Definition tokenizer.h:269
CKSpmMode spm_mode
Definition tokenizer.h:261
static size_t ck_tokenizer_vocab_size(const CKTokenizer *tok)
Definition tokenizer.h:333
bool add_bos
Definition tokenizer.h:243
const char * token
Definition tokenizer.h:307
int32_t float * score
Definition tokenizer.h:328
CKSpmMode
Definition tokenizer.h:68
@ CK_SPM_MODE_UNIGRAM
Definition tokenizer.h:69
@ CK_SPM_MODE_LLAMA
Definition tokenizer.h:70
int32_t unk
Definition tokenizer.h:230
int ck_tokenizer_encode(const CKTokenizer *tok, const char *text, int text_len, int32_t *ids, int max_ids)
int ck_tokenizer_encode_tokens(const CKTokenizer *tok, const char *text, int text_len, const char **out_tokens, int max_tokens)
bool use_trie
Definition tokenizer.h:277
static CKTokenizer * ck_tokenizer_create_spm(void)
Definition tokenizer.h:171
int ck_tokenizer_add_merge(CKTokenizer *tok, int32_t left_id, int32_t right_id, int32_t merged_id, int32_t priority)
Definition tokenizer.c:560
static CKTokenizer * ck_tokenizer_create_bpe(void)
Definition tokenizer.h:157
int ck_tokenizer_encode_with_special(CKTokenizer *tok, const char *text, int text_len, int32_t *ids, int max_ids, bool add_special)
int ck_tokenizer_add_special_token(CKTokenizer *tok, const char *name, int32_t id)
Definition tokenizer.c:218
int ck_tokenizer_load_merges(CKTokenizer *tok, const char *path)
Definition tokenizer.c:559
int32_t int32_t int32_t eos
Definition tokenizer.h:232
#define CK_TOKENIZER_API
Definition tokenizer.h:40
int32_t int32_t int32_t int32_t pad
Definition tokenizer.h:233
CKSpacePrefixStyle style
Definition tokenizer.h:288
int32_t int32_t bos
Definition tokenizer.h:231
const int32_t int int * out_len
Definition tokenizer.h:446
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
int32_t int32_t int32_t int32_t priority
Definition true_bpe.h:123
const int32_t int char int max_len
Definition true_bpe.h:288
int32_t left_id
Definition true_bpe.h:120
const char int text_len
Definition true_bpe.h:270
int vocab_size
Definition true_bpe.h:193
int32_t int32_t right_id
Definition true_bpe.h:121
int const int32_t * offsets
Definition true_bpe.h:194
int32_t int32_t int32_t merged_id
Definition true_bpe.h:122
const char int int32_t int max_ids
Definition true_bpe.h:272