├── .gitignore ├── Makefile ├── LICENSE ├── ltable.h ├── test.c ├── README.md └── ltable.c /.gitignore: -------------------------------------------------------------------------------- 1 | test 2 | 3 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all test 2 | 3 | all: test 4 | 5 | test: test.c ltable.c 6 | gcc -g ltable.c test.c -o test 7 | 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 王泓钦 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /ltable.h: -------------------------------------------------------------------------------- 1 | #ifndef LTABLE_H 2 | #define LTABLE_H 3 | 4 | #include 5 | 6 | #define LTABLE_SEED 7 | 8 | #define LTABLE_KEYNUM 1 9 | #define LTABLE_KEYINT 2 10 | #define LTABLE_KEYSTR 3 11 | #define LTABLE_KEYOBJ 4 12 | 13 | #define ltable_keytype(key) ((key)->type) 14 | #define ltable_keyval(key) ((key)->v) 15 | 16 | struct ltable_key { 17 | int type; 18 | union { 19 | double f; 20 | long int i; 21 | const void * p; 22 | const char* s; 23 | } v; 24 | }; 25 | 26 | 27 | struct ltable; 28 | 29 | struct ltable* ltable_create(size_t vmemsz, unsigned int seed); 30 | void ltable_release(struct ltable *); 31 | void ltable_resize(struct ltable *t, int nasize, int nhsize); 32 | void* ltable_next(struct ltable *t, unsigned int *ip, struct ltable_key *key); 33 | 34 | void* ltable_get(struct ltable* t, const struct ltable_key* key); 35 | void* ltable_set(struct ltable* t, const struct ltable_key* key); 36 | void* ltable_getn(struct ltable* t, int i); 37 | void ltable_del(struct ltable* t, const struct ltable_key* key); 38 | 39 | struct ltable_key* ltable_numkey(struct ltable_key *key, double k); 40 | struct ltable_key* ltable_strkey(struct ltable_key *key, const char* k); 41 | struct ltable_key* ltable_intkey(struct ltable_key *key, long int k); 42 | struct ltable_key* ltable_objkey(struct ltable_key *key, const void *p); 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "ltable.h" 3 | 4 | static void 5 | _dumparray(struct ltable *t) { 6 | unsigned int i = 0; 7 | int *p; 8 | printf("iter array:\n"); 9 | while (p = ltable_getn(t, i)) { 10 | printf("\t%d: %d\n", i, *p); 11 | i++; 12 | } 13 | } 14 | 15 | static void 16 | _dump(struct ltable *t) { 17 | unsigned int i = 0; 18 | int *p; 19 | struct ltable_key kp; 20 | 21 | printf("iter table:\n"); 22 | i = 0; 23 | while (p = ltable_next(t, &i, &kp)) { 24 | switch (kp.type) { 25 | case LTABLE_KEYNUM: 26 | printf("\tkey=%.3f, val=%d\n", kp.v.f, *p); 27 | break; 28 | case LTABLE_KEYINT: 29 | printf("\tkey=%d, val=%d\n", kp.v.i, *p); 30 | break; 31 | case LTABLE_KEYSTR: 32 | printf("\tkey=['%s'], val=%d\n", kp.v.s, *p); 33 | break; 34 | case LTABLE_KEYOBJ: 35 | printf("\tkey=[%p], val=%d\n", kp.v.p, *p); 36 | break; 37 | default : 38 | printf("\terror type %d\n", kp.type); 39 | } 40 | } 41 | } 42 | 43 | int 44 | main() { 45 | struct ltable_key key; 46 | struct ltable* t; 47 | int *p; 48 | 49 | /*****************************/ 50 | /* construct a simple table*/ 51 | /*****************************/ 52 | 53 | t = ltable_create(sizeof(int), 0); 54 | /* t["foo"] = 12 */ 55 | p = ltable_set(t, ltable_strkey(&key, "foo")); 56 | *p = 12; 57 | 58 | /* t[3.5] = 13 */ 59 | p = ltable_set(t, ltable_numkey(&key, 3.5)); 60 | *p = 13; 61 | 62 | /* t[&obj] = 20 */ 63 | int obj = 0; 64 | p = ltable_set(t, ltable_objkey(&key, &obj)); 65 | *p = 20; 66 | 67 | int i; 68 | for(i=0;i<10;i++) { 69 | p = ltable_set(t, ltable_intkey(&key, i)); 70 | *p = i+1; 71 | } 72 | 73 | _dumparray(t); 74 | 75 | for(i=9;i>=0;i--){ 76 | ltable_del(t, ltable_intkey(&key, i)); 77 | } 78 | 79 | p = ltable_set(t, ltable_strkey(&key, "bar")); 80 | *p = 99; 81 | p = ltable_set(t, ltable_strkey(&key, "hello,world")); 82 | *p = 100; 83 | p = ltable_set(t, ltable_strkey(&key, "hqwrong.github.io")); 84 | *p = 101; 85 | 86 | _dump(t); 87 | 88 | ltable_release(t); 89 | } 90 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | C hash lib inspired by Lua's Table 2 | ===================================== 3 | 4 | ## APIS 5 | ### Create 6 | ``` 7 | struct ltable* ltable_create(size_t vmemsz, unsigned int seed); 8 | ``` 9 | create a table instance. 10 | 11 | `seed` is used to gen hash value, `LTABLE_SEED` is used when 0 supplied. 12 | 13 | 14 | `vmemsz` is the maximum memory size a single table value can occupy. If you have multiple types of table value, I recommend you to use a tag union to group them, for example: 15 | 16 | ``` 17 | struct TLValue { 18 | int type; 19 | union { 20 | double f; 21 | char * s[128]; 22 | void *p; 23 | } u; 24 | }; 25 | 26 | struct ltable* t = ltable_create(sizeof(struct TLValue), 0); 27 | ``` 28 | 29 | ### Key 30 | 4 types of key are supported 31 | 32 | ``` 33 | LTABLE_KEYNUM 1 34 | LTABLE_KEYINT 2 35 | LTABLE_KEYSTR 3 36 | LTABLE_KEYOBJ 4 37 | 38 | ``` 39 | Use corresponding function to create them, like `ltable_intkey` to gen int-type key, `ltable_numkey` for double-type key, e.t.c. 40 | 41 | ### Get, Set and Del 42 | 43 | ``` 44 | void* ltable_get(struct ltable* t, const struct ltable_key* key); 45 | void* ltable_set(struct ltable* t, const struct ltable_key* key); 46 | void ltable_del(struct ltable* t, const struct ltable_key* key); 47 | ``` 48 | 49 | `ltable_get` will return the addr of value if it finds any, otherwise `NULL` returned. 50 | 51 | `ltable_set` returns the same with `ltable_get` when the key is found, but it will create a new one otherwise. 52 | 53 | 54 | ### Iter 55 | use `ltable_next` to iter among table. 56 | ``` 57 | void* ltable_next(struct ltable *t, unsigned int *ip, struct ltable_key *key); 58 | ``` 59 | returns the value addr, or `NULL` when no more item to be iterated. 60 | 61 | `ip` is the iter handle, which must initialize to 0 at beginning of iteration. 62 | 63 | `key` will be filled with corresponding key. set it to `NULL` if you don't need it. 64 | 65 | ### Array 66 | ltable's array is 0-based, which is different from Lua's 1-based array. 67 | For your convenience, ltable offered an auxiliary function to fetch array item, insead of `ltable_get`: 68 | ``` 69 | void* ltable_getn(struct ltable* t, int i); 70 | ``` 71 | To iter on array is easy: 72 | ``` 73 | int i = 0; 74 | while (p = ltable_getn(t, i++)) {...} 75 | ``` 76 | 77 | ## EXAMPLES 78 | see `test.c` 79 | 80 | 81 | -------------------------------------------------------------------------------- /ltable.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "ltable.h" 9 | 10 | #define SHORTSTR_LEN 128 11 | 12 | struct pool_node { 13 | size_t nodesz; 14 | struct pool_node *next; 15 | }; 16 | 17 | struct pool { 18 | struct pool_node *node; 19 | struct pool_node *freenode; 20 | }; 21 | 22 | #define MAXBITS 30 23 | #define MAXASIZE (1 << MAXBITS) 24 | 25 | /* use at most ~(2^LUAI_HASHLIMIT) bytes from a string to compute its hash*/ 26 | #define STR_HASHLIMIT 5 27 | 28 | union ltable_Hash { 29 | double f; 30 | const void *p; 31 | long int i; 32 | uint8_t l_p[4]; 33 | }; 34 | 35 | struct ltable_value { 36 | bool setted; 37 | }; 38 | 39 | struct ltable_node { 40 | struct ltable_node *next; 41 | struct ltable_key key; 42 | struct ltable_value value; 43 | /* follow vmemsz space*/ 44 | }; 45 | 46 | struct ltable { 47 | size_t vmemsz; 48 | struct ltable_value *array; 49 | struct ltable_node *node; 50 | int sizearray; 51 | uint8_t lsizenode; /* log2 of size of `node' array */ 52 | struct pool pool; 53 | unsigned int seed; 54 | int lastfree; 55 | }; 56 | 57 | 58 | /* 59 | ** `module' operation for hashing (size is always a power of 2) 60 | */ 61 | #define lmod(s,size) ((int)((s) & ((size)-1))) 62 | 63 | #define twoto(i) (1<<(i)) 64 | #define gnext(n) ((n)->next) 65 | #define sizenode(t) (1 << ((t)->lsizenode)) 66 | #define inarray(t, idx) ((idx)>=0 && (idx) < (t)->sizearray) 67 | #define nodememsz(t) (t->vmemsz + sizeof(struct ltable_node)) 68 | #define valmemsz(t) (t->vmemsz + sizeof(struct ltable_value)) 69 | 70 | /* 71 | ** {============================================================= 72 | ** Pool 73 | ** ============================================================== 74 | */ 75 | 76 | static void 77 | pool_init(struct pool *p) { 78 | p->node = NULL; 79 | p->freenode = NULL; 80 | } 81 | 82 | static void* 83 | pool_alloc(struct pool *p, size_t sz) { 84 | struct pool_node **np = &p->freenode; 85 | struct pool_node *n = NULL; 86 | while (*np) { 87 | if ((*np)->nodesz >= sz) { 88 | n = *np; 89 | *np = (*np)->next; 90 | break; 91 | } 92 | np = &(*np)->next; 93 | } 94 | if (!n) { 95 | if (sz < SHORTSTR_LEN) sz = SHORTSTR_LEN; 96 | n = (struct pool_node*)malloc(sz + sizeof(struct pool_node)); 97 | n->nodesz = sz; 98 | } 99 | n->next = p->node; 100 | p->node = n; 101 | return n+1; 102 | } 103 | 104 | static void 105 | pool_free(struct pool *p, struct pool_node *node) { 106 | struct pool_node **np = &p->node; 107 | node--; 108 | 109 | while(*np) { 110 | if (*np == node) { 111 | *np = (*np)->next; 112 | break; 113 | } 114 | np = &(*np)->next; 115 | } 116 | 117 | node->next = p->freenode; 118 | p->freenode = node; 119 | } 120 | 121 | static void 122 | pool_release(struct pool *p) { 123 | struct pool_node *nextn; 124 | struct pool_node *n = p->node; 125 | while(n) { 126 | nextn = n->next; 127 | free(n); 128 | n = nextn; 129 | } 130 | n = p->freenode; 131 | while(n) { 132 | nextn = n->next; 133 | free(n); 134 | n = nextn; 135 | } 136 | } 137 | 138 | 139 | /* 140 | ** }============================================================= 141 | */ 142 | 143 | static inline bool 144 | isnil(const struct ltable_value *v) { 145 | return !v->setted; 146 | } 147 | 148 | static inline bool 149 | isnilnode(const struct ltable_node *n) { 150 | return isnil(&n->value); 151 | } 152 | 153 | static inline struct ltable_value* 154 | _garray(const struct ltable* t, int idx) { 155 | return (struct ltable_value*)(((char*)t->array) + valmemsz(t)*idx); 156 | } 157 | 158 | static inline struct ltable_node* 159 | _gnode(const struct ltable* t, int idx) { 160 | return (struct ltable_node*)(((char*)t->node) + nodememsz(t)*idx); 161 | } 162 | 163 | static inline struct ltable_node* 164 | _gnodex(const struct ltable*t, int idx, void* n) { 165 | return (struct ltable_node*)(((char*)n) + nodememsz(t)*idx); 166 | } 167 | 168 | static inline void 169 | _cpyval(struct ltable *t, struct ltable_value *dest, const struct ltable_value *src) { 170 | memcpy(dest, src, valmemsz(t)); 171 | } 172 | 173 | static inline void 174 | _cpynode(struct ltable *t, struct ltable_node *dest, const struct ltable_node *src) { 175 | memcpy(dest, src, nodememsz(t)); 176 | } 177 | 178 | static inline void* 179 | _gud(struct ltable_value* v) { 180 | if (v == NULL || isnil(v)) 181 | return NULL; 182 | else 183 | return v+1; 184 | } 185 | 186 | static struct ltable_node* 187 | _hashnode(struct ltable *t, unsigned int h) { 188 | return _gnode(t, h & (sizenode(t)-1)); 189 | } 190 | 191 | static void 192 | _rehash(struct ltable* t, const struct ltable_key *ek); 193 | 194 | static struct ltable_value * 195 | _set(struct ltable* t, const struct ltable_key *key); 196 | 197 | 198 | int 199 | _floorlog2 (unsigned int x) { 200 | static const unsigned char log_2[256] = { 201 | 0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 202 | 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 203 | 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 204 | 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 205 | 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 206 | 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 207 | 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 208 | 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 209 | }; 210 | int l = 0; 211 | while (x >= 256) { l += 8; x >>= 8; } 212 | return l + log_2[x]; 213 | } 214 | 215 | int 216 | _ceillog2 (unsigned int x) { 217 | static const unsigned char log_2[256] = { 218 | 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 219 | 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 220 | 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 221 | 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 222 | 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 223 | 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 224 | 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 225 | 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8 226 | }; 227 | int l = 0; 228 | x--; 229 | while (x >= 256) { l += 8; x >>= 8; } 230 | return l + log_2[x]; 231 | } 232 | 233 | void 234 | _cpykey(struct ltable *t, struct ltable_key *dest, const struct ltable_key *src) { 235 | *dest = *src; 236 | if (dest->type == LTABLE_KEYSTR) { 237 | size_t l = strlen(src->v.s)+1; 238 | char *sp = pool_alloc(&t->pool, l); 239 | memcpy(sp, src->v.s, l); 240 | dest->v.s = sp; 241 | } 242 | } 243 | 244 | bool 245 | _eqkey(const struct ltable_key *key, const struct ltable_key *nkey) { 246 | if (key->type != nkey->type) 247 | return false; 248 | 249 | switch (key->type) { 250 | case LTABLE_KEYSTR: 251 | return !strcmp(key->v.s, nkey->v.s); 252 | case LTABLE_KEYINT: 253 | return key->v.i == nkey->v.i; 254 | case LTABLE_KEYNUM: 255 | return key->v.f == nkey->v.f; 256 | default: /* keyobj */ 257 | return key->v.p == nkey->v.p; 258 | } 259 | } 260 | 261 | unsigned int 262 | _strhash (const char *str, unsigned int seed) { 263 | size_t l = strlen(str); 264 | unsigned int h = seed ^ ((unsigned int)l); 265 | size_t l1; 266 | size_t step = (l >> STR_HASHLIMIT) + 1; 267 | for (l1 = l; l1 >= step; l1 -= step) 268 | h = h ^ ((h<<5) + (h>>2) + ((uint8_t)(str[l1 - 1]))); 269 | return h; 270 | } 271 | 272 | unsigned int 273 | _numhash (union ltable_Hash *u) { 274 | int i = u->l_p[0] + u->l_p[1] + u->l_p[2] + u->l_p[3]; 275 | 276 | if (i < 0) { 277 | if (((unsigned int)i) == 0u - i) /* use unsigned to avoid overflows */ 278 | i = 0; /* handle INT_MIN */ 279 | i = -i; /* must be a positive value */ 280 | } 281 | return i; 282 | } 283 | 284 | /* 285 | ** returns the index for `key' if `key' is an appropriate key to live in 286 | ** the array part of the table, -1 otherwise. 287 | */ 288 | static int 289 | arrayindex (const struct ltable_key *key) { 290 | if (key->type == LTABLE_KEYINT) { 291 | return key->v.i; 292 | } 293 | return -1; /* `key' did not match some condition */ 294 | } 295 | 296 | static struct ltable_node * 297 | mainposition(struct ltable* t, const struct ltable_key* key) { 298 | unsigned int h; 299 | if (key->type == LTABLE_KEYSTR) 300 | h = _strhash(key->v.s, t->seed); 301 | else { 302 | union ltable_Hash u; 303 | memset(&u, 0, sizeof(u)); 304 | 305 | switch(key->type) { 306 | case LTABLE_KEYNUM: 307 | u.f = key->v.f; break; 308 | case LTABLE_KEYINT: 309 | u.i = key->v.i; break; 310 | default: /* LTABLE_KEYOBJ */ 311 | u.p = key->v.p; break; 312 | } 313 | 314 | h = _numhash(&u); 315 | } 316 | return _hashnode(t, h); 317 | } 318 | 319 | static struct ltable_node* 320 | _getfreepos(struct ltable* t) { 321 | while (t->lastfree > 0) { 322 | t->lastfree--; 323 | if (isnilnode(_gnode(t, t->lastfree))) 324 | return _gnode(t, t->lastfree); 325 | } 326 | return NULL; /* could not find a free place */ 327 | } 328 | 329 | static struct ltable_node * 330 | _hashget(struct ltable* t, const struct ltable_key * key) { 331 | struct ltable_node *node = mainposition(t, key); 332 | while (node) { 333 | if (!isnilnode(node) && _eqkey(&node->key, key)) 334 | break; 335 | else 336 | node = gnext(node); 337 | } 338 | return node; 339 | } 340 | 341 | static struct ltable_value * 342 | _get(struct ltable* t, const struct ltable_key * key) { 343 | int idx = arrayindex(key); 344 | if (inarray(t, idx)) { /* in array part? */ 345 | struct ltable_value* val = _garray(t, idx); 346 | return isnil(val) ? NULL : val; 347 | } 348 | 349 | struct ltable_node *node = _hashget(t, key); 350 | return node ? &node->value : NULL; 351 | } 352 | 353 | static struct ltable_value * 354 | _hashset(struct ltable* t, const struct ltable_key *key) { 355 | struct ltable_node *mp = mainposition(t, key); 356 | if (!isnilnode(mp)){ /* main position is taken? */ 357 | struct ltable_node *othern; 358 | struct ltable_node *freen = _getfreepos(t); 359 | if (!freen) { 360 | _rehash(t, key); 361 | return _set(t, key); 362 | } 363 | othern = mainposition(t, &mp->key); 364 | if (othern != mp) { /* is colliding node out of its main position? */ 365 | /* yes; move colliding node into free position */ 366 | while (gnext(othern) != mp) 367 | othern = gnext(othern); /* find previous */ 368 | gnext(othern) = freen; 369 | _cpynode(t, freen, mp); /* copy colliding node into free pos. (mp->next also goes) */ 370 | gnext(mp) = NULL; 371 | } 372 | else { /* colliding node is in its own main position */ 373 | /* new node will go into free position */ 374 | gnext(freen) = gnext(mp); 375 | gnext(mp) = freen; 376 | mp = freen; 377 | } 378 | } 379 | _cpykey(t, &mp->key, key); 380 | mp->value.setted = true; 381 | return &mp->value; 382 | } 383 | 384 | static struct ltable_value * 385 | _set(struct ltable* t, const struct ltable_key *key) { 386 | int idx = arrayindex(key); 387 | if (inarray(t, idx)) { /* in array part? */ 388 | struct ltable_value * val = _garray(t, idx); 389 | val->setted = true; 390 | return val; 391 | } else { 392 | return _hashset(t, key); 393 | } 394 | } 395 | 396 | /* 397 | ** {============================================================= 398 | ** Rehash 399 | ** ============================================================== 400 | */ 401 | static int 402 | computesizes (int nums[], int *narray) { 403 | int i; 404 | int twotoi; /* 2^i */ 405 | int a = 0; /* number of elements smaller than 2^i */ 406 | int na = 0; /* number of elements to go to array part */ 407 | int n = 0; /* optimal size for array part */ 408 | for (i = 0, twotoi = 1;i<=MAXBITS; i++, twotoi *= 2) { 409 | a += nums[i]; 410 | if (a && a >= twotoi/2) { /* at least half elements present? */ 411 | n = twotoi; /* optimal size (till now) */ 412 | na = a; /* all elements smaller than n will go to array part */ 413 | } 414 | if (*narray == a) break; 415 | } 416 | *narray = n; 417 | return na; 418 | } 419 | 420 | static int 421 | countint (const struct ltable_key *key, int *nums) { 422 | int k = arrayindex(key); 423 | if (k<0 || k > MAXASIZE) 424 | return 0; 425 | 426 | if (k==0) 427 | nums[0]++; 428 | else 429 | nums[_floorlog2(k)+1]++; 430 | return 1; 431 | } 432 | 433 | static int 434 | numusearray (const struct ltable *t, int *nums) { 435 | int lg; 436 | int ause = 0; /* summation of `nums' */ 437 | int i = 0; /* count to traverse all array keys. */ 438 | for (lg=0; lg<=MAXBITS; lg++) { /* for each slice */ 439 | int lc = 0; /* counter */ 440 | int lim = twoto(lg); 441 | if (lim > t->sizearray) { 442 | lim = t->sizearray; /* adjust upper limit */ 443 | if (i >= lim) break; /* no more elements to count */ 444 | } 445 | /* count elements in range [2^(lg-1), 2^lg) */ 446 | for (; i < lim; i++) { 447 | if (!isnil(_garray(t, i))) lc++; 448 | } 449 | nums[lg] += lc; 450 | ause += lc; 451 | } 452 | return ause; 453 | } 454 | 455 | static int 456 | numusehash (const struct ltable *t, int *nums, int *pnasize) { 457 | int totaluse = 0; /* total number of elements */ 458 | int ause = 0; /* summation of `nums' */ 459 | int i; 460 | for (i=0;ikey, nums); 464 | totaluse++; 465 | } 466 | } 467 | *pnasize += ause; 468 | return totaluse; 469 | } 470 | 471 | 472 | void 473 | _resize_node(struct ltable *t, int size) { 474 | int lsize = size > 0 ? _ceillog2(size) : 0; /* at least one node */ 475 | if (lsize > MAXBITS) 476 | assert(0); 477 | size = twoto(lsize); 478 | int memsz = nodememsz(t)*size; 479 | t->node = malloc(memsz); 480 | memset(t->node, 0, memsz); 481 | t->lsizenode = (uint8_t)lsize; 482 | t->lastfree = size; /* all positions are free */ 483 | } 484 | 485 | void 486 | _resize_array(struct ltable *t, int nasize) { 487 | int oldasize = t->sizearray; 488 | t->sizearray = nasize; 489 | t->array = realloc(t->array, valmemsz(t) * nasize); 490 | if(nasize > oldasize) /* set growed part to zero */ 491 | memset(_garray(t, oldasize), 0, valmemsz(t) * (nasize-oldasize)); 492 | } 493 | 494 | void 495 | _resize(struct ltable *t, int nasize, int nhsize) { 496 | int i; 497 | int oldasize = t->sizearray; 498 | int oldhsize = t->lsizenode; 499 | 500 | struct ltable_node *nold = t->node; /* save old hash ... */ 501 | 502 | /* resize hash part */ 503 | _resize_node(t, nhsize); 504 | 505 | /* resize array part */ 506 | if (nasize < oldasize) { /* array part must shrink? */ 507 | /* re-insert elements from vanishing slice */ 508 | for (i=nasize; i= 0; i--) { 523 | struct ltable_node *old = _gnodex(t, i, nold); 524 | if (!isnilnode(old)) { 525 | struct ltable_value *val = _set(t, &old->key); 526 | _cpyval(t, val, &old->value); 527 | } 528 | } 529 | /* free old hash part */ 530 | free(nold); 531 | } 532 | } 533 | 534 | 535 | static void 536 | _rehash(struct ltable* t, const struct ltable_key *ek) { 537 | int nasize, na; 538 | int nums[MAXBITS+1]; /* nums[i] = number of keys with 2^(i-1) <= k < 2^i */ 539 | int i; 540 | int totaluse; 541 | for (i=0; i<=MAXBITS; i++) nums[i] = 0; /* reset counts */ 542 | nasize = numusearray(t, nums); /* count keys in array part */ 543 | totaluse = nasize; /* all those keys are integer keys */ 544 | totaluse += numusehash(t, nums, &nasize); /* count keys in hash part */ 545 | /* count extra key */ 546 | nasize += countint(ek, nums); 547 | totaluse++; 548 | /* compute new size for array part */ 549 | na = computesizes(nums, &nasize); 550 | /* resize the table to new computed sizes */ 551 | _resize(t, nasize, totaluse - na); 552 | } 553 | 554 | /* 555 | ** }============================================================= 556 | */ 557 | 558 | 559 | struct ltable* 560 | ltable_create(size_t vmemsz, unsigned int seed) { 561 | struct ltable* t = malloc(sizeof(struct ltable)); 562 | 563 | t->vmemsz = vmemsz; 564 | t->array = NULL; 565 | t->node = NULL; 566 | t->lastfree = -1; 567 | t->sizearray = 0; 568 | t->lsizenode = 0; /* log2 of size of `node' array */ 569 | t->seed = seed == 0 ? LTABLE_SEED : seed; 570 | pool_init(&t->pool); 571 | 572 | _resize(t, 0, 1); 573 | return t; 574 | } 575 | 576 | void 577 | ltable_release(struct ltable *t) { 578 | free(t->node); 579 | free(t->array); 580 | pool_release(&t->pool); 581 | } 582 | 583 | void 584 | ltable_resize(struct ltable *t, int nasize, int nhsize) { 585 | _resize(t, nasize, nhsize); 586 | } 587 | 588 | void* 589 | ltable_get(struct ltable *t, const struct ltable_key* key) { 590 | struct ltable_value *val = _get(t, key); 591 | return _gud(val); 592 | } 593 | 594 | void* 595 | ltable_set(struct ltable* t, const struct ltable_key* key) { 596 | struct ltable_value *val = _get(t, key); 597 | if (!val) val = _set(t, key); 598 | return _gud(val); 599 | } 600 | 601 | void* 602 | ltable_getn(struct ltable* t, int i) { 603 | if (inarray(t, i)) { 604 | struct ltable_value *val = _garray(t, i); 605 | return _gud(val); 606 | } 607 | 608 | struct ltable_key k; 609 | ltable_intkey(&k, i); 610 | struct ltable_node *node = _hashget(t, &k); 611 | if (node) 612 | return _gud(&node->value); 613 | return NULL; 614 | } 615 | 616 | void 617 | ltable_del(struct ltable* t, const struct ltable_key* key) { 618 | if (key->type == LTABLE_KEYSTR) { 619 | struct ltable_node *node = _hashget(t, key); 620 | if (node) { 621 | node->value.setted = false; 622 | /* free string key */ 623 | pool_free(&t->pool, (struct pool_node*)node->key.v.s); 624 | node->key.v.s = NULL; 625 | } 626 | } else { 627 | struct ltable_value *val = _get(t, key); 628 | if (val) val->setted = false; 629 | } 630 | } 631 | 632 | void * 633 | ltable_next(struct ltable *t, unsigned int *ip, struct ltable_key *key) { 634 | assert(*ip >= 0); 635 | int nsz = sizenode(t); 636 | struct ltable_value * val = NULL; 637 | 638 | int i = *ip; 639 | for (;i < t->sizearray; i++) { /* search array part */ 640 | val = _garray(t, i); 641 | if (!isnil(val)) { 642 | if (key) { 643 | key->type = LTABLE_KEYINT; 644 | key->v.i = i; 645 | } 646 | break; 647 | } 648 | } 649 | if (i >= t->sizearray) 650 | for (;i < nsz + t->sizearray; i++) { /* search hash part */ 651 | struct ltable_node * node = _gnode(t, i - t->sizearray); 652 | if (!isnilnode(node)) { 653 | if (key) *key = node->key; 654 | val = &node->value; 655 | break; 656 | } 657 | } 658 | 659 | *ip = i+1; 660 | return _gud(val); 661 | } 662 | 663 | inline struct ltable_key* 664 | ltable_numkey(struct ltable_key *key, double k) { 665 | key->type = LTABLE_KEYNUM; 666 | key->v.f = k; 667 | 668 | return key; 669 | } 670 | 671 | inline struct ltable_key* 672 | ltable_strkey(struct ltable_key *key, const char* k) { 673 | key->type = LTABLE_KEYSTR; 674 | key->v.s = k; 675 | 676 | return key; 677 | } 678 | 679 | inline struct ltable_key* 680 | ltable_intkey(struct ltable_key *key, long int k) { 681 | key->type = LTABLE_KEYINT; 682 | key->v.i = k; 683 | return key; 684 | } 685 | 686 | inline struct ltable_key* 687 | ltable_objkey(struct ltable_key *key, const void *p) { 688 | key->type = LTABLE_KEYOBJ; 689 | key->v.p = p; 690 | return key; 691 | } 692 | 693 | /* end of ltable.c */ 694 | --------------------------------------------------------------------------------