10#if defined(__SSE__) || defined(__SSE2__) || defined(__SSE3__) || defined(__SSSE3__) || \
11 defined(__SSE4_1__) || defined(__SSE4_2__) || defined(__AVX__) || defined(__AVX2__) || \
20#define CK_TOKENIZER_HASH_SEED 0x9747b28c
32static inline int simd_strcmp(
const char *s1,
const char *s2) {
33 size_t len1 = strlen(s1);
34 size_t len2 = strlen(s2);
37 if (len1 < 64 || len2 < 64) {
38 return strcmp(s1, s2);
41#if defined(__AVX512F__) && defined(__AVX512BW__) && defined(__AVX512DQ__)
45 __m512i chunk1 = _mm512_loadu_si512((
const __m512i *)s1);
46 __m512i chunk2 = _mm512_loadu_si512((
const __m512i *)s2);
49 __mmask64 cmp_mask = _mm512_cmpeq_epu8_mask(chunk1, chunk2);
52 if (cmp_mask != 0xFFFFFFFFFFFFFFFF) {
54 int first_diff = __builtin_ctzll(~cmp_mask);
55 return (
unsigned char)s1[first_diff] - (
unsigned char)s2[first_diff];
59 __mmask64 null_mask1 = _mm512_test_epi8_mask(chunk1, _mm512_set1_epi8(
'\0'));
60 __mmask64 null_mask2 = _mm512_test_epi8_mask(chunk2, _mm512_set1_epi8(
'\0'));
62 if (null_mask1 || null_mask2) {
66 return (len1 < len2) ? -1 : 1;
80 return strcmp(s1, s2);
85 if (bucket_count == 0) {
100 table->
size = bucket_count;
113 entry->
key = strdup(key);
120 entry->
value = malloc(value_size);
126 memcpy(entry->
value, value, value_size);
138 if (free_value && entry->
value) {
149 for (
size_t i = 0; i < table->
size; i++) {
165 if (!table || !key) {
174 if (strcmp(entry->
key, key) == 0) {
176 entry->
value = value;
188 new_entry->
key = strdup(key);
189 if (!new_entry->
key) {
194 new_entry->
value = value;
196 table->
entries[bucket] = new_entry;
203 if (!table || !key) {
211 if (strcmp(entry->
key, key) == 0) {
222 if (!table || !key) {
242 if (!table || !key) {
251 if (strcmp(entry->
key, key) == 0) {
269 return table ? table->
count : 0;
279 if (!table || !callback) {
283 for (
size_t i = 0; i < table->
size; i++) {
286 int ret = callback(entry->
key, entry->
value, user_data);
298 const char **out_keys,
300 if (!table || !out_keys) {
305 for (
size_t i = 0; i < table->
size && written < max_keys; i++) {
307 while (entry && written < max_keys) {
308 out_keys[written++] = entry->
key;
321 for (
size_t i = 0; i < table->
size; i++) {
bool ck_tokenizer_hash_table_contains(CKTokenizerHashTable *table, const char *key)
#define CK_TOKENIZER_HASH_SEED
size_t ck_tokenizer_hash_table_count(CKTokenizerHashTable *table)
size_t ck_tokenizer_hash_table_keys(CKTokenizerHashTable *table, const char **out_keys, size_t max_keys)
void ck_tokenizer_hash_table_free(CKTokenizerHashTable *table, bool free_values)
static CKTokenizerHashEntry * create_entry(const char *key, const void *value, size_t value_size)
static void free_entry(CKTokenizerHashEntry *entry, bool free_value)
int ck_tokenizer_hash_table_iterate(CKTokenizerHashTable *table, CKTokenizerHashCallback callback, void *user_data)
int ck_tokenizer_hash_table_insert(CKTokenizerHashTable *table, const char *key, void *value)
void * ck_tokenizer_hash_table_lookup_avx(CKTokenizerHashTable *table, const char *key)
uint32_t ck_tokenizer_hash(const char *key, size_t len)
uint32_t ck_tokenizer_hash_str(const char *key)
CKTokenizerHashTable * ck_tokenizer_hash_table_create(size_t bucket_count)
static int simd_strcmp(const char *s1, const char *s2)
void * ck_tokenizer_hash_table_lookup(CKTokenizerHashTable *table, const char *key)
int ck_tokenizer_hash_table_delete(CKTokenizerHashTable *table, const char *key, bool free_value)
void ck_tokenizer_hash_table_clear(CKTokenizerHashTable *table, bool free_values)
int(* CKTokenizerHashCallback)(const char *key, void *value, void *user_data)
#define CK_TOKENIZER_HT_BUCKETS_SMALL
uint32_t ck_murmurhash3(const char *key, uint32_t len, uint32_t seed)
static uint32_t ck_murmurhash3_str(const char *str, uint32_t seed)
struct CKTokenizerHashEntry * next
CKTokenizerHashEntry ** entries