Ruby  2.4.2p198(2017-09-14revision59899)
id_table.c
Go to the documentation of this file.
1 /* This file is included by symbol.c */
2 
3 #include "id_table.h"
4 
5 #ifndef ID_TABLE_DEBUG
6 #define ID_TABLE_DEBUG 0
7 #endif
8 
9 #if ID_TABLE_DEBUG == 0
10 #define NDEBUG
11 #endif
12 #include "ruby_assert.h"
13 
14 /*
15  * st
16  * 0: using st with debug information.
17  * 1: using st.
18  * array
19  * 11: simple array. ids = [ID1, ID2, ...], values = [val1, val2, ...]
20  * 12: simple array, and use rb_id_serial_t instead of ID.
21  * 13: simple array, and use rb_id_serial_t instead of ID. Swap recent access.
22  * 14: sorted array, and use rb_id_serial_t instead of ID.
23  * 15: sorted array, and use rb_id_serial_t instead of ID, linear small part.
24  * hash
25  * 21: funny falcon's Coalesced Hashing implementation [Feature #6962]
26  * 22: simple open addressing with quadratic probing.
27  * mix (array + hash)
28  * 31: array(12) (capa <= 32) + hash(22)
29  * 32: array(14) (capa <= 32) + hash(22)
30  * 33: array(12) (capa <= 64) + hash(22)
31  * 34: array(14) (capa <= 64) + hash(22)
32  * 34: array(15) (capa <= 64) + hash(22)
33  */
34 
35 #ifndef ID_TABLE_IMPL
36 #define ID_TABLE_IMPL 34
37 #endif
38 
39 #if ID_TABLE_IMPL == 0
40 #define ID_TABLE_NAME st
41 #define ID_TABLE_IMPL_TYPE struct st_id_table
42 
43 #define ID_TABLE_USE_ST 1
44 #define ID_TABLE_USE_ST_DEBUG 1
45 
46 #elif ID_TABLE_IMPL == 1
47 #define ID_TABLE_NAME st
48 #define ID_TABLE_IMPL_TYPE struct st_id_table
49 
50 #define ID_TABLE_USE_ST 1
51 #define ID_TABLE_USE_ST_DEBUG 0
52 
53 #elif ID_TABLE_IMPL == 11
54 #define ID_TABLE_NAME list
55 #define ID_TABLE_IMPL_TYPE struct list_id_table
56 
57 #define ID_TABLE_USE_LIST 1
58 #define ID_TABLE_USE_CALC_VALUES 1
59 
60 #elif ID_TABLE_IMPL == 12
61 #define ID_TABLE_NAME list
62 #define ID_TABLE_IMPL_TYPE struct list_id_table
63 
64 #define ID_TABLE_USE_LIST 1
65 #define ID_TABLE_USE_CALC_VALUES 1
66 #define ID_TABLE_USE_ID_SERIAL 1
67 
68 #elif ID_TABLE_IMPL == 13
69 #define ID_TABLE_NAME list
70 #define ID_TABLE_IMPL_TYPE struct list_id_table
71 
72 #define ID_TABLE_USE_LIST 1
73 #define ID_TABLE_USE_CALC_VALUES 1
74 #define ID_TABLE_USE_ID_SERIAL 1
75 #define ID_TABLE_SWAP_RECENT_ACCESS 1
76 
77 #elif ID_TABLE_IMPL == 14
78 #define ID_TABLE_NAME list
79 #define ID_TABLE_IMPL_TYPE struct list_id_table
80 
81 #define ID_TABLE_USE_LIST 1
82 #define ID_TABLE_USE_CALC_VALUES 1
83 #define ID_TABLE_USE_ID_SERIAL 1
84 #define ID_TABLE_USE_LIST_SORTED 1
85 
86 #elif ID_TABLE_IMPL == 15
87 #define ID_TABLE_NAME list
88 #define ID_TABLE_IMPL_TYPE struct list_id_table
89 
90 #define ID_TABLE_USE_LIST 1
91 #define ID_TABLE_USE_CALC_VALUES 1
92 #define ID_TABLE_USE_ID_SERIAL 1
93 #define ID_TABLE_USE_LIST_SORTED 1
94 #define ID_TABLE_USE_LIST_SORTED_LINEAR_SMALL_RANGE 1
95 
96 #elif ID_TABLE_IMPL == 21
97 #define ID_TABLE_NAME hash
98 #define ID_TABLE_IMPL_TYPE sa_table
99 
100 #define ID_TABLE_USE_COALESCED_HASHING 1
101 #define ID_TABLE_USE_ID_SERIAL 1
102 
103 #elif ID_TABLE_IMPL == 22
104 #define ID_TABLE_NAME hash
105 #define ID_TABLE_IMPL_TYPE struct hash_id_table
106 
107 #define ID_TABLE_USE_SMALL_HASH 1
108 #define ID_TABLE_USE_ID_SERIAL 1
109 
110 #elif ID_TABLE_IMPL == 31
111 #define ID_TABLE_NAME mix
112 #define ID_TABLE_IMPL_TYPE struct mix_id_table
113 
114 #define ID_TABLE_USE_MIX 1
115 #define ID_TABLE_USE_MIX_LIST_MAX_CAPA 32
116 
117 #define ID_TABLE_USE_ID_SERIAL 1
118 
119 #define ID_TABLE_USE_LIST 1
120 #define ID_TABLE_USE_CALC_VALUES 1
121 #define ID_TABLE_USE_SMALL_HASH 1
122 
123 #elif ID_TABLE_IMPL == 32
124 #define ID_TABLE_NAME mix
125 #define ID_TABLE_IMPL_TYPE struct mix_id_table
126 
127 #define ID_TABLE_USE_MIX 1
128 #define ID_TABLE_USE_MIX_LIST_MAX_CAPA 32
129 
130 #define ID_TABLE_USE_ID_SERIAL 1
131 
132 #define ID_TABLE_USE_LIST 1
133 #define ID_TABLE_USE_CALC_VALUES 1
134 #define ID_TABLE_USE_LIST_SORTED 1
135 
136 #define ID_TABLE_USE_SMALL_HASH 1
137 
138 #elif ID_TABLE_IMPL == 33
139 #define ID_TABLE_NAME mix
140 #define ID_TABLE_IMPL_TYPE struct mix_id_table
141 
142 #define ID_TABLE_USE_MIX 1
143 #define ID_TABLE_USE_MIX_LIST_MAX_CAPA 64
144 
145 #define ID_TABLE_USE_ID_SERIAL 1
146 
147 #define ID_TABLE_USE_LIST 1
148 #define ID_TABLE_USE_CALC_VALUES 1
149 #define ID_TABLE_USE_SMALL_HASH 1
150 
151 #elif ID_TABLE_IMPL == 34
152 #define ID_TABLE_NAME mix
153 #define ID_TABLE_IMPL_TYPE struct mix_id_table
154 
155 #define ID_TABLE_USE_MIX 1
156 #define ID_TABLE_USE_MIX_LIST_MAX_CAPA 64
157 
158 #define ID_TABLE_USE_ID_SERIAL 1
159 
160 #define ID_TABLE_USE_LIST 1
161 #define ID_TABLE_USE_CALC_VALUES 1
162 #define ID_TABLE_USE_LIST_SORTED 1
163 
164 #define ID_TABLE_USE_SMALL_HASH 1
165 
166 #elif ID_TABLE_IMPL == 35
167 #define ID_TABLE_NAME mix
168 #define ID_TABLE_IMPL_TYPE struct mix_id_table
169 
170 #define ID_TABLE_USE_MIX 1
171 #define ID_TABLE_USE_MIX_LIST_MAX_CAPA 64
172 
173 #define ID_TABLE_USE_ID_SERIAL 1
174 
175 #define ID_TABLE_USE_LIST 1
176 #define ID_TABLE_USE_CALC_VALUES 1
177 #define ID_TABLE_USE_LIST_SORTED 1
178 #define ID_TABLE_USE_LIST_SORTED_LINEAR_SMALL_RANGE 1
179 
180 #define ID_TABLE_USE_SMALL_HASH 1
181 
182 #else
183 #error
184 #endif
185 
186 #if ID_TABLE_SWAP_RECENT_ACCESS && ID_TABLE_USE_LIST_SORTED
187 #error
188 #endif
189 
190 /* IMPL(create) will be "hash_id_table_create" and so on */
191 #define IMPL1(name, op) TOKEN_PASTE(name, _id##op) /* expand `name' */
192 #define IMPL(op) IMPL1(ID_TABLE_NAME, _table##op) /* but prevent `op' */
193 
194 #ifdef __GNUC__
195 # define UNUSED(func) static func __attribute__((unused))
196 #else
197 # define UNUSED(func) static func
198 #endif
199 
200 UNUSED(ID_TABLE_IMPL_TYPE *IMPL(_create)(size_t));
201 UNUSED(void IMPL(_free)(ID_TABLE_IMPL_TYPE *));
202 UNUSED(void IMPL(_clear)(ID_TABLE_IMPL_TYPE *));
203 UNUSED(size_t IMPL(_size)(const ID_TABLE_IMPL_TYPE *));
204 UNUSED(size_t IMPL(_memsize)(const ID_TABLE_IMPL_TYPE *));
205 UNUSED(int IMPL(_insert)(ID_TABLE_IMPL_TYPE *, ID, VALUE));
206 UNUSED(int IMPL(_lookup)(ID_TABLE_IMPL_TYPE *, ID, VALUE *));
207 UNUSED(int IMPL(_delete)(ID_TABLE_IMPL_TYPE *, ID));
208 UNUSED(void IMPL(_foreach)(ID_TABLE_IMPL_TYPE *, rb_id_table_foreach_func_t *, void *));
209 UNUSED(void IMPL(_foreach_values)(ID_TABLE_IMPL_TYPE *, rb_id_table_foreach_values_func_t *, void *));
210 
211 #if ID_TABLE_USE_ID_SERIAL
213 static inline ID
214 key2id(id_key_t key)
215 {
216  return rb_id_serial_to_id(key);
217 }
218 
219 static inline id_key_t
221 {
222  return rb_id_to_serial(id);
223 }
224 #else /* ID_TABLE_USE_ID_SERIAL */
225 
226 typedef ID id_key_t;
227 #define key2id(key) key
228 #define id2key(id) id
229 
230 #endif /* ID_TABLE_USE_ID_SERIAL */
231 
232 /***************************************************************
233  * 0: using st with debug information.
234  * 1: using st.
235  ***************************************************************/
236 #if ID_TABLE_USE_ST
237 #if ID_TABLE_USE_ST_DEBUG
238 #define ID_TABLE_MARK 0x12345678
239 
240 struct st_id_table {
241  struct st_table *st;
242  unsigned int check;
243 };
244 
245 static struct st_table *
246 tbl2st(struct st_id_table *tbl)
247 {
248  if (tbl->check != ID_TABLE_MARK) rb_bug("tbl2st: check error %x", tbl->check);
249  return tbl->st;
250 }
251 
252 static struct st_id_table *
253 st_id_table_create(size_t size)
254 {
255  struct st_id_table *tbl = ALLOC(struct st_id_table);
256  tbl->st = st_init_numtable_with_size(size);
257  tbl->check = ID_TABLE_MARK;
258  return tbl;
259 }
260 
261 static void
262 st_id_table_free(struct st_id_table *tbl)
263 {
264  st_free_table(tbl->st);
265  xfree(tbl);
266 }
267 
268 #else /* ID_TABLE_USE_ST_DEBUG */
269 
270 struct st_id_table {
271  struct st_table st;
272 };
273 
274 static struct st_table *
275 tbl2st(struct st_id_table *tbl)
276 {
277  return (struct st_table *)tbl;
278 }
279 
280 static struct st_id_table *
281 st_id_table_create(size_t size)
282 {
283  return (struct st_id_table *)st_init_numtable_with_size(size);
284 }
285 
286 static void
287 st_id_table_free(struct st_id_table *tbl)
288 {
289  st_free_table((struct st_table*)tbl);
290 }
291 
292 #endif /* ID_TABLE_USE_ST_DEBUG */
293 
294 static void
295 st_id_table_clear(struct st_id_table *tbl)
296 {
297  st_clear(tbl2st(tbl));
298 }
299 
300 static size_t
301 st_id_table_size(const struct st_id_table *tbl)
302 {
303  return tbl2st(tbl)->num_entries;
304 }
305 
306 static size_t
307 st_id_table_memsize(const struct st_id_table *tbl)
308 {
309  size_t header_size = ID_TABLE_USE_ST_DEBUG ? sizeof(struct st_id_table) : 0;
310  return header_size + st_memsize(tbl2st(tbl));
311 }
312 
313 static int
314 st_id_table_lookup(struct st_id_table *tbl, ID id, VALUE *val)
315 {
316  return st_lookup(tbl2st(tbl), (st_data_t)id, (st_data_t *)val);
317 }
318 
319 static int
320 st_id_table_insert(struct st_id_table *tbl, ID id, VALUE val)
321 {
322  return st_insert(tbl2st(tbl), id, val);
323 }
324 
325 static int
326 st_id_table_delete(struct st_id_table *tbl, ID id)
327 {
328  return st_delete(tbl2st(tbl), (st_data_t *)&id, NULL);
329 }
330 
331 static void
332 st_id_table_foreach(struct st_id_table *tbl, rb_id_table_foreach_func_t *func, void *data)
333 {
334  st_foreach(tbl2st(tbl), (int (*)(ANYARGS))func, (st_data_t)data);
335 }
336 
337 struct values_iter_data {
339  void *data;
340 };
341 
342 static int
343 each_values(st_data_t key, st_data_t val, st_data_t ptr)
344 {
345  struct values_iter_data *values_iter_data = (struct values_iter_data *)ptr;
346  return values_iter_data->values_i(val, values_iter_data->data);
347 }
348 
349 static void
350 st_id_table_foreach_values(struct st_id_table *tbl, rb_id_table_foreach_values_func_t *func, void *data)
351 {
352  struct values_iter_data values_iter_data;
353  values_iter_data.values_i = func;
354  values_iter_data.data = data;
355  st_foreach(tbl2st(tbl), each_values, (st_data_t)&values_iter_data);
356 }
357 #endif /* ID_TABLE_USE_ST */
358 
359 #if ID_TABLE_USE_LIST
360 
361 #define LIST_MIN_CAPA 4
362 
364  int capa;
365  int num;
366  id_key_t *keys;
367 #if ID_TABLE_USE_CALC_VALUES == 0
368  VALUE *values_;
369 #endif
370 };
371 
372 #if ID_TABLE_USE_CALC_VALUES
373 #define TABLE_VALUES(tbl) ((VALUE *)((tbl)->keys + (tbl)->capa))
374 #else
375 #define TABLE_VALUES(tbl) (tbl)->values_
376 #endif
377 
378 static struct list_id_table *
380 {
381  if (capa > 0) {
382 #if ID_TABLE_USE_CALC_VALUES && \
383  (UNALIGNED_WORD_ACCESS == 0) && (SIZEOF_VALUE == 8)
384  /* Workaround for 8-byte word alignment on 64-bit SPARC.
385  * This code assumes that sizeof(ID) == 4, sizeof(VALUE) == 8, and
386  * xmalloc() returns 8-byte aligned memory block.
387  */
388  if (capa & (size_t)1) capa += 1;
389 #endif
390  tbl->capa = (int)capa;
391 #if ID_TABLE_USE_CALC_VALUES
392  tbl->keys = (id_key_t *)xmalloc(sizeof(id_key_t) * capa + sizeof(VALUE) * capa);
393 #else
394  tbl->keys = ALLOC_N(id_key_t, capa);
395  tbl->values_ = ALLOC_N(VALUE, capa);
396 #endif
397  }
398  return tbl;
399 }
400 
401 #ifndef ID_TABLE_USE_MIX
402 static struct list_id_table *
403 list_id_table_create(size_t capa)
404 {
405  struct list_id_table *tbl = ZALLOC(struct list_id_table);
406  return list_id_table_init(tbl, capa);
407 }
408 #endif
409 
410 static void
412 {
413  xfree(tbl->keys);
414 #if ID_TABLE_USE_CALC_VALUES == 0
415  xfree(tbl->values_);
416 #endif
417  xfree(tbl);
418 }
419 
420 static void
422 {
423  tbl->num = 0;
424 }
425 
426 static size_t
428 {
429  return (size_t)tbl->num;
430 }
431 
432 static size_t
434 {
435  return (sizeof(id_key_t) + sizeof(VALUE)) * tbl->capa + sizeof(struct list_id_table);
436 }
437 
438 static void
440 {
441  if (tbl->capa == tbl->num) {
442  const int capa = tbl->capa == 0 ? LIST_MIN_CAPA : (tbl->capa * 2);
443 
444 #if ID_TABLE_USE_CALC_VALUES
445  {
446  VALUE *old_values, *new_values;
447  VALUE *debug_values = NULL;
448  const int num = tbl->num;
449  const int size = sizeof(id_key_t) * capa + sizeof(VALUE) * capa;
450  int i;
451 
452  if (num > 0) {
453  VALUE *orig_values = (VALUE *)(tbl->keys + num);
454  debug_values = ALLOC_N(VALUE, num);
455 
456  for (i=0; i<num; i++) {
457  debug_values[i] = orig_values[i];
458  }
459 
460  if (0)
461  for (i=0; i< 2 * num; i++) {
462  unsigned char *cs = (unsigned char *)&tbl->keys[i];
463  size_t j;
464  fprintf(stderr, ">> %3d | %p - ", i, cs);
465  for (j=0; j<sizeof(VALUE); j++) {
466  fprintf(stderr, "%x ", cs[j]);
467  }
468  fprintf(stderr, "\n");
469  }
470  }
471 
472  tbl->keys = (id_key_t *)xrealloc(tbl->keys, size);
473  old_values = (VALUE *)(tbl->keys + num);
474  new_values = (VALUE *)(tbl->keys + capa);
475 
476  /* [ keys (num) ] [ values (num) ]
477  * ^ old_values
478  * realloc =>
479  * [ keys (capa = num * 2) ] [ values (capa = num * 2) ]
480  * ^ new_values
481  */
482 
483  /* memmove */
484  if (0) {
485  fprintf(stderr, "memmove: %p -> %p (%d, capa: %d)\n",
486  old_values, new_values, num, capa);
487  }
488  assert(num < capa);
489  assert(num == 0 || old_values < new_values);
490 
491  for (i=num-1; i>=0; i--) {
492  new_values[i] = old_values[i];
493  }
494 
495  if (num > 0) {
496  for (i=0; i<num; i++) {
497  assert(debug_values[i] == new_values[i]);
498  }
499  xfree(debug_values);
500  }
501  }
502 
503  tbl->capa = capa;
504 #else
505  tbl->capa = capa;
506  tbl->keys = (id_key_t *)xrealloc(tbl->keys, sizeof(id_key_t) * capa);
507  tbl->values_ = (VALUE *)xrealloc(tbl->values_, sizeof(VALUE) * capa);
508 #endif
509  }
510 }
511 
512 #if ID_TABLE_DEBUG
513 static void
514 list_table_show(struct list_id_table *tbl)
515 {
516  const id_key_t *keys = tbl->keys;
517  const int num = tbl->num;
518  int i;
519 
520  fprintf(stderr, "tbl: %p (num: %d)\n", tbl, num);
521  for (i=0; i<num; i++) {
522  fprintf(stderr, " -> [%d] %s %d\n", i, rb_id2name(key2id(keys[i])), (int)keys[i]);
523  }
524 }
525 #endif
526 
527 static void
529 {
530 #if ID_TABLE_DEBUG
531 #if ID_TABLE_USE_LIST_SORTED
532  const id_key_t *keys = tbl->keys;
533  const int num = tbl->num;
534  int i;
535 
536  for (i=0; i<num-1; i++) {
537  if (keys[i] >= keys[i+1]) {
538  list_table_show(tbl);
539  rb_bug(": not sorted.");
540  }
541  }
542 #endif
543 #endif
544 }
545 
546 #if ID_TABLE_USE_LIST_SORTED
547 static int
548 list_ids_bsearch(const id_key_t *keys, id_key_t key, int num)
549 {
550  int p, min = 0, max = num;
551 
552 #if ID_TABLE_USE_LIST_SORTED_LINEAR_SMALL_RANGE
553  if (num <= 64) {
554  if (num > 32) {
555  if (keys[num/2] <= key) {
556  min = num/2;
557  } else {
558  max = num/2;
559  }
560  }
561  for (p = min; p<num && keys[p] < key; p++) {
562  assert(keys[p] != 0);
563  }
564  return (p<num && keys[p] == key) ? p : -p-1;
565  }
566 #endif /* ID_TABLE_USE_LIST_SORTED_LINEAR_SMALL_RANGE */
567 
568  while (1) {
569  p = min + (max - min) / 2;
570 
571  if (min >= max) {
572  break;
573  }
574  else {
575  id_key_t kp = keys[p];
576  assert(p < max);
577  assert(p >= min);
578 
579  if (kp > key) max = p;
580  else if (kp < key) min = p+1;
581  else {
582  assert(kp == key);
583  assert(p >= 0);
584  assert(p < num);
585  return p;
586  }
587  }
588  }
589 
590  assert(min == max);
591  assert(min == p);
592  return -p-1;
593 }
594 #endif /* ID_TABLE_USE_LIST_SORTED */
595 
596 static int
597 list_table_index(struct list_id_table *tbl, id_key_t key)
598 {
599  const int num = tbl->num;
600  const id_key_t *keys = tbl->keys;
601 
602 #if ID_TABLE_USE_LIST_SORTED
603  return list_ids_bsearch(keys, key, num);
604 #else /* ID_TABLE_USE_LIST_SORTED */
605  int i;
606 
607  for (i=0; i<num; i++) {
608  assert(keys[i] != 0);
609 
610  if (keys[i] == key) {
611  return (int)i;
612  }
613  }
614  return -1;
615 #endif
616 }
617 
618 static int
620 {
621  id_key_t key = id2key(id);
622  int index = list_table_index(tbl, key);
623 
624  if (index >= 0) {
625  *valp = TABLE_VALUES(tbl)[index];
626 
627 #if ID_TABLE_SWAP_RECENT_ACCESS
628  if (index > 0) {
629  VALUE *values = TABLE_VALUES(tbl);
630  id_key_t tk = tbl->keys[index-1];
631  VALUE tv = values[index-1];
632  tbl->keys[index-1] = tbl->keys[index];
633  tbl->keys[index] = tk;
634  values[index-1] = values[index];
635  values[index] = tv;
636  }
637 #endif /* ID_TABLE_SWAP_RECENT_ACCESS */
638  return TRUE;
639  }
640  else {
641  return FALSE;
642  }
643 }
644 
645 static int
647 {
648  const id_key_t key = id2key(id);
649  const int index = list_table_index(tbl, key);
650 
651  if (index >= 0) {
652  TABLE_VALUES(tbl)[index] = val;
653  }
654  else {
655  list_table_extend(tbl);
656  {
657  const int num = tbl->num++;
658 #if ID_TABLE_USE_LIST_SORTED
659  const int insert_index = -(index + 1);
660  id_key_t *keys = tbl->keys;
661  VALUE *values = TABLE_VALUES(tbl);
662  int i;
663 
664  if (0) fprintf(stderr, "insert: %d into %d on\n", (int)key, insert_index);
665 
666  for (i=num; i>insert_index; i--) {
667  keys[i] = keys[i-1];
668  values[i] = values[i-1];
669  }
670  keys[i] = key;
671  values[i] = val;
672 
673  tbl_assert(tbl);
674 #else
675  tbl->keys[num] = key;
676  TABLE_VALUES(tbl)[num] = val;
677 #endif
678  }
679  }
680 
681  return TRUE;
682 }
683 
684 static int
685 list_delete_index(struct list_id_table *tbl, id_key_t key, int index)
686 {
687  if (index >= 0) {
688  VALUE *values = TABLE_VALUES(tbl);
689 
690 #if ID_TABLE_USE_LIST_SORTED
691  int i;
692  const int num = tbl->num;
693  id_key_t *keys = tbl->keys;
694 
695  for (i=index+1; i<num; i++) { /* compaction */
696  keys[i-1] = keys[i];
697  values[i-1] = values[i];
698  }
699 #else
700  tbl->keys[index] = tbl->keys[tbl->num-1];
701  values[index] = values[tbl->num-1];
702 #endif
703  tbl->num--;
704  tbl_assert(tbl);
705 
706  return TRUE;
707  }
708  else {
709  return FALSE;
710  }
711 }
712 
713 static int
715 {
716  const id_key_t key = id2key(id);
717  int index = list_table_index(tbl, key);
718  return list_delete_index(tbl, key, index);
719 }
720 
721 #define FOREACH_LAST() do { \
722  switch (ret) { \
723  case ID_TABLE_ITERATOR_RESULT_END: \
724  case ID_TABLE_CONTINUE: \
725  case ID_TABLE_STOP: \
726  break; \
727  case ID_TABLE_DELETE: \
728  list_delete_index(tbl, key, i); \
729  values = TABLE_VALUES(tbl); \
730  num = tbl->num; \
731  i--; /* redo same index */ \
732  break; \
733  } \
734 } while (0)
735 
736 static void
738 {
739  int num = tbl->num;
740  int i;
741  const id_key_t *keys = tbl->keys;
742  const VALUE *values = TABLE_VALUES(tbl);
743 
744  for (i=0; i<num; i++) {
745  const id_key_t key = keys[i];
746  enum rb_id_table_iterator_result ret = (*func)(key2id(key), values[i], data);
747  assert(key != 0);
748 
749  FOREACH_LAST();
750  if (ret == ID_TABLE_STOP) return;
751  }
752 }
753 
754 static void
756 {
757  int num = tbl->num;
758  int i;
759  const id_key_t *keys = tbl->keys;
760  VALUE *values = TABLE_VALUES(tbl);
761 
762  for (i=0; i<num; i++) {
763  const id_key_t key = keys[i];
764  enum rb_id_table_iterator_result ret = (*func)(values[i], data);
765  assert(key != 0);
766 
767  FOREACH_LAST();
768  if (ret == ID_TABLE_STOP) return;
769  }
770 }
771 #endif /* ID_TABLE_USE_LIST */
772 
773 
774 #if ID_TABLE_USE_COALESCED_HASHING
775 /* implementation is based on
776  * https://bugs.ruby-lang.org/issues/6962 by funny_falcon
777  */
778 
779 typedef unsigned int sa_index_t;
780 
781 #define SA_EMPTY 0
782 #define SA_LAST 1
783 #define SA_OFFSET 2
784 #define SA_MIN_SIZE 4
785 
786 typedef struct sa_entry {
787  sa_index_t next;
788  id_key_t key;
789  VALUE value;
790 } sa_entry;
791 
792 typedef struct {
793  sa_index_t num_bins;
794  sa_index_t num_entries;
795  sa_index_t free_pos;
796  sa_entry *entries;
797 } sa_table;
798 
799 static void
800 sa_init_table(register sa_table *table, sa_index_t num_bins)
801 {
802  if (num_bins) {
803  table->num_entries = 0;
804  table->entries = ZALLOC_N(sa_entry, num_bins);
805  table->num_bins = num_bins;
806  table->free_pos = num_bins;
807  }
808 }
809 
810 static sa_table*
811 hash_id_table_create(size_t size)
812 {
813  sa_table* table = ZALLOC(sa_table);
814  sa_init_table(table, (sa_index_t)size);
815  return table;
816 }
817 
818 static void
819 hash_id_table_clear(sa_table *table)
820 {
821  xfree(table->entries);
822  memset(table, 0, sizeof(sa_table));
823 }
824 
825 static void
826 hash_id_table_free(sa_table *table)
827 {
828  xfree(table->entries);
829  xfree(table);
830 }
831 
832 static size_t
833 hash_id_table_memsize(const sa_table *table)
834 {
835  return sizeof(sa_table) + table->num_bins * sizeof (sa_entry);
836 }
837 
838 static inline sa_index_t
839 calc_pos(register sa_table* table, id_key_t key)
840 {
841  return key & (table->num_bins - 1);
842 }
843 
844 static void
845 fix_empty(register sa_table* table)
846 {
847  while (--table->free_pos &&
848  table->entries[table->free_pos-1].next != SA_EMPTY);
849 }
850 
851 #define FLOOR_TO_4 ((~((sa_index_t)0)) << 2)
852 static sa_index_t
853 find_empty(register sa_table* table, register sa_index_t pos)
854 {
855  sa_index_t new_pos = table->free_pos-1;
856  sa_entry *entry;
857  static const unsigned offsets[][3] = {
858  {1, 2, 3},
859  {2, 3, 0},
860  {3, 1, 0},
861  {2, 1, 0}
862  };
863  const unsigned *const check = offsets[pos&3];
864  pos &= FLOOR_TO_4;
865  entry = table->entries+pos;
866 
867  if (entry[check[0]].next == SA_EMPTY) { new_pos = pos + check[0]; goto check; }
868  if (entry[check[1]].next == SA_EMPTY) { new_pos = pos + check[1]; goto check; }
869  if (entry[check[2]].next == SA_EMPTY) { new_pos = pos + check[2]; goto check; }
870 
871  check:
872  if (new_pos+1 == table->free_pos) fix_empty(table);
873  return new_pos;
874 }
875 
876 static void resize(register sa_table* table);
877 static int insert_into_chain(register sa_table*, register id_key_t, st_data_t, sa_index_t pos);
878 static int insert_into_main(register sa_table*, id_key_t, st_data_t, sa_index_t pos, sa_index_t prev_pos);
879 
880 static int
881 sa_insert(register sa_table* table, id_key_t key, VALUE value)
882 {
883  register sa_entry *entry;
884  sa_index_t pos, main_pos;
885 
886  if (table->num_bins == 0) {
887  sa_init_table(table, SA_MIN_SIZE);
888  }
889 
890  pos = calc_pos(table, key);
891  entry = table->entries + pos;
892 
893  if (entry->next == SA_EMPTY) {
894  entry->next = SA_LAST;
895  entry->key = key;
896  entry->value = value;
897  table->num_entries++;
898  if (pos+1 == table->free_pos) fix_empty(table);
899  return 0;
900  }
901 
902  if (entry->key == key) {
903  entry->value = value;
904  return 1;
905  }
906 
907  if (table->num_entries + (table->num_entries >> 2) > table->num_bins) {
908  resize(table);
909  return sa_insert(table, key, value);
910  }
911 
912  main_pos = calc_pos(table, entry->key);
913  if (main_pos == pos) {
914  return insert_into_chain(table, key, value, pos);
915  }
916  else {
917  if (!table->free_pos) {
918  resize(table);
919  return sa_insert(table, key, value);
920  }
921  return insert_into_main(table, key, value, pos, main_pos);
922  }
923 }
924 
925 static int
926 hash_id_table_insert(register sa_table* table, ID id, VALUE value)
927 {
928  return sa_insert(table, id2key(id), value);
929 }
930 
931 static int
932 insert_into_chain(register sa_table* table, id_key_t key, st_data_t value, sa_index_t pos)
933 {
934  sa_entry *entry = table->entries + pos, *new_entry;
935  sa_index_t new_pos;
936 
937  while (entry->next != SA_LAST) {
938  pos = entry->next - SA_OFFSET;
939  entry = table->entries + pos;
940  if (entry->key == key) {
941  entry->value = value;
942  return 1;
943  }
944  }
945 
946  if (!table->free_pos) {
947  resize(table);
948  return sa_insert(table, key, value);
949  }
950 
951  new_pos = find_empty(table, pos);
952  new_entry = table->entries + new_pos;
953  entry->next = new_pos + SA_OFFSET;
954 
955  new_entry->next = SA_LAST;
956  new_entry->key = key;
957  new_entry->value = value;
958  table->num_entries++;
959  return 0;
960 }
961 
962 static int
963 insert_into_main(register sa_table* table, id_key_t key, st_data_t value, sa_index_t pos, sa_index_t prev_pos)
964 {
965  sa_entry *entry = table->entries + pos;
966  sa_index_t new_pos = find_empty(table, pos);
967  sa_entry *new_entry = table->entries + new_pos;
968  sa_index_t npos;
969 
970  *new_entry = *entry;
971 
972  while((npos = table->entries[prev_pos].next - SA_OFFSET) != pos) {
973  prev_pos = npos;
974  }
975  table->entries[prev_pos].next = new_pos + SA_OFFSET;
976 
977  entry->next = SA_LAST;
978  entry->key = key;
979  entry->value = value;
980  table->num_entries++;
981  return 0;
982 }
983 
984 static sa_index_t
985 new_size(sa_index_t num_entries)
986 {
987  sa_index_t size = num_entries >> 3;
988  size |= size >> 1;
989  size |= size >> 2;
990  size |= size >> 4;
991  size |= size >> 8;
992  size |= size >> 16;
993  return (size + 1) << 3;
994 }
995 
996 static void
997 resize(register sa_table *table)
998 {
999  sa_table tmp_table;
1000  sa_entry *entry;
1001  sa_index_t i;
1002 
1003  if (table->num_entries == 0) {
1004  xfree(table->entries);
1005  memset(table, 0, sizeof(sa_table));
1006  return;
1007  }
1008 
1009  sa_init_table(&tmp_table, new_size(table->num_entries + (table->num_entries >> 2)));
1010  entry = table->entries;
1011 
1012  for(i = 0; i < table->num_bins; i++, entry++) {
1013  if (entry->next != SA_EMPTY) {
1014  sa_insert(&tmp_table, entry->key, entry->value);
1015  }
1016  }
1017  xfree(table->entries);
1018  *table = tmp_table;
1019 }
1020 
1021 static int
1022 hash_id_table_lookup(register sa_table *table, ID id, VALUE *valuep)
1023 {
1024  register sa_entry *entry;
1025  id_key_t key = id2key(id);
1026 
1027  if (table->num_entries == 0) return 0;
1028 
1029  entry = table->entries + calc_pos(table, key);
1030  if (entry->next == SA_EMPTY) return 0;
1031 
1032  if (entry->key == key) goto found;
1033  if (entry->next == SA_LAST) return 0;
1034 
1035  entry = table->entries + (entry->next - SA_OFFSET);
1036  if (entry->key == key) goto found;
1037 
1038  while(entry->next != SA_LAST) {
1039  entry = table->entries + (entry->next - SA_OFFSET);
1040  if (entry->key == key) goto found;
1041  }
1042  return 0;
1043  found:
1044  if (valuep) *valuep = entry->value;
1045  return 1;
1046 }
1047 
1048 static size_t
1049 hash_id_table_size(const sa_table *table)
1050 {
1051  return table->num_entries;
1052 }
1053 
1054 static int
1055 hash_id_table_delete(sa_table *table, ID id)
1056 {
1057  sa_index_t pos, prev_pos = ~0;
1058  sa_entry *entry;
1059  id_key_t key = id2key(id);
1060 
1061  if (table->num_entries == 0) goto not_found;
1062 
1063  pos = calc_pos(table, key);
1064  entry = table->entries + pos;
1065 
1066  if (entry->next == SA_EMPTY) goto not_found;
1067 
1068  do {
1069  if (entry->key == key) {
1070  if (entry->next != SA_LAST) {
1071  sa_index_t npos = entry->next - SA_OFFSET;
1072  *entry = table->entries[npos];
1073  memset(table->entries + npos, 0, sizeof(sa_entry));
1074  }
1075  else {
1076  memset(table->entries + pos, 0, sizeof(sa_entry));
1077  if (~prev_pos) {
1078  table->entries[prev_pos].next = SA_LAST;
1079  }
1080  }
1081  table->num_entries--;
1082  if (table->num_entries < table->num_bins / 4) {
1083  resize(table);
1084  }
1085  return 1;
1086  }
1087  if (entry->next == SA_LAST) break;
1088  prev_pos = pos;
1089  pos = entry->next - SA_OFFSET;
1090  entry = table->entries + pos;
1091  } while(1);
1092 
1093  not_found:
1094  return 0;
1095 }
1096 
1097 enum foreach_type {
1098  foreach_key_values,
1099  foreach_values
1100 };
1101 
1102 static void
1103 hash_foreach(sa_table *table, enum rb_id_table_iterator_result (*func)(ANYARGS), void *arg, enum foreach_type type)
1104 {
1105  sa_index_t i;
1106 
1107  if (table->num_bins > 0) {
1108  for(i = 0; i < table->num_bins ; i++) {
1109  if (table->entries[i].next != SA_EMPTY) {
1110  id_key_t key = table->entries[i].key;
1111  st_data_t val = table->entries[i].value;
1112  enum rb_id_table_iterator_result ret;
1113 
1114  switch (type) {
1115  case foreach_key_values:
1116  ret = (*func)(key2id(key), val, arg);
1117  break;
1118  case foreach_values:
1119  ret = (*func)(val, arg);
1120  break;
1121  }
1122 
1123  switch (ret) {
1124  case ID_TABLE_DELETE:
1125  rb_warn("unsupported yet");
1126  break;
1127  default:
1128  break;
1129  }
1130  if (ret == ID_TABLE_STOP) break;
1131  }
1132  }
1133  }
1134 }
1135 
1136 static void
1137 hash_id_table_foreach(sa_table *table, enum rb_id_table_iterator_result (*func)(ID, VALUE, void *), void *arg)
1138 {
1139  hash_foreach(table, func, arg, foreach_key_values);
1140 }
1141 
1142 static void
1143 hash_id_table_foreach_values(sa_table *table, enum rb_id_table_iterator_result (*func)(VALUE, void *), void *arg)
1144 {
1145  hash_foreach(table, func, arg, foreach_values);
1146 }
1147 #endif /* ID_TABLE_USE_COALESCED_HASHING */
1148 
1149 #ifdef ID_TABLE_USE_SMALL_HASH
1150 /* simple open addressing with quadratic probing.
1151  uses mark-bit on collisions - need extra 1 bit,
1152  ID is strictly 3 bits larger than rb_id_serial_t */
1153 
1154 typedef struct rb_id_item {
1155  id_key_t key;
1156 #if SIZEOF_VALUE == 8
1157  int collision;
1158 #endif
1160 } item_t;
1161 
1163  int capa;
1164  int num;
1165  int used;
1167 };
1168 
1169 #if SIZEOF_VALUE == 8
1170 #define ITEM_GET_KEY(tbl, i) ((tbl)->items[i].key)
1171 #define ITEM_KEY_ISSET(tbl, i) ((tbl)->items[i].key)
1172 #define ITEM_COLLIDED(tbl, i) ((tbl)->items[i].collision)
1173 #define ITEM_SET_COLLIDED(tbl, i) ((tbl)->items[i].collision = 1)
1174 static inline void
1175 ITEM_SET_KEY(struct hash_id_table *tbl, int i, id_key_t key)
1176 {
1177  tbl->items[i].key = key;
1178 }
1179 #else
1180 #define ITEM_GET_KEY(tbl, i) ((tbl)->items[i].key >> 1)
1181 #define ITEM_KEY_ISSET(tbl, i) ((tbl)->items[i].key > 1)
1182 #define ITEM_COLLIDED(tbl, i) ((tbl)->items[i].key & 1)
1183 #define ITEM_SET_COLLIDED(tbl, i) ((tbl)->items[i].key |= 1)
1184 static inline void
1185 ITEM_SET_KEY(struct hash_id_table *tbl, int i, id_key_t key)
1186 {
1187  tbl->items[i].key = (key << 1) | ITEM_COLLIDED(tbl, i);
1188 }
1189 #endif
1190 
1191 static inline int
1192 round_capa(int capa)
1193 {
1194  /* minsize is 4 */
1195  capa >>= 2;
1196  capa |= capa >> 1;
1197  capa |= capa >> 2;
1198  capa |= capa >> 4;
1199  capa |= capa >> 8;
1200  capa |= capa >> 16;
1201  return (capa + 1) << 2;
1202 }
1203 
1204 static struct hash_id_table *
1205 hash_id_table_init(struct hash_id_table *tbl, int capa)
1206 {
1207  MEMZERO(tbl, struct hash_id_table, 1);
1208  if (capa > 0) {
1209  capa = round_capa(capa);
1210  tbl->capa = (int)capa;
1211  tbl->items = ZALLOC_N(item_t, capa);
1212  }
1213  return tbl;
1214 }
1215 
1216 #ifndef ID_TABLE_USE_MIX
1217 static struct hash_id_table *
1218 hash_id_table_create(size_t capa)
1219 {
1220  struct hash_id_table *tbl = ALLOC(struct hash_id_table);
1221  return hash_id_table_init(tbl, (int)capa);
1222 }
1223 #endif
1224 
1225 static void
1227 {
1228  xfree(tbl->items);
1229  xfree(tbl);
1230 }
1231 
1232 static void
1234 {
1235  tbl->num = 0;
1236  tbl->used = 0;
1237  MEMZERO(tbl->items, item_t, tbl->capa);
1238 }
1239 
1240 static size_t
1242 {
1243  return (size_t)tbl->num;
1244 }
1245 
1246 static size_t
1248 {
1249  return sizeof(item_t) * tbl->capa + sizeof(struct hash_id_table);
1250 }
1251 
1252 static int
1253 hash_table_index(struct hash_id_table* tbl, id_key_t key)
1254 {
1255  if (tbl->capa > 0) {
1256  int mask = tbl->capa - 1;
1257  int ix = key & mask;
1258  int d = 1;
1259  while (key != ITEM_GET_KEY(tbl, ix)) {
1260  if (!ITEM_COLLIDED(tbl, ix))
1261  return -1;
1262  ix = (ix + d) & mask;
1263  d++;
1264  }
1265  return ix;
1266  }
1267  return -1;
1268 }
1269 
1270 static void
1271 hash_table_raw_insert(struct hash_id_table *tbl, id_key_t key, VALUE val)
1272 {
1273  int mask = tbl->capa - 1;
1274  int ix = key & mask;
1275  int d = 1;
1276  assert(key != 0);
1277  while (ITEM_KEY_ISSET(tbl, ix)) {
1278  ITEM_SET_COLLIDED(tbl, ix);
1279  ix = (ix + d) & mask;
1280  d++;
1281  }
1282  tbl->num++;
1283  if (!ITEM_COLLIDED(tbl, ix)) {
1284  tbl->used++;
1285  }
1286  ITEM_SET_KEY(tbl, ix, key);
1287  tbl->items[ix].val = val;
1288 }
1289 
1290 static int
1291 hash_delete_index(struct hash_id_table *tbl, int ix)
1292 {
1293  if (ix >= 0) {
1294  if (!ITEM_COLLIDED(tbl, ix)) {
1295  tbl->used--;
1296  }
1297  tbl->num--;
1298  ITEM_SET_KEY(tbl, ix, 0);
1299  tbl->items[ix].val = 0;
1300  return TRUE;
1301  } else {
1302  return FALSE;
1303  }
1304 }
1305 
1306 static void
1308 {
1309  if (tbl->used + (tbl->used >> 1) >= tbl->capa) {
1310  int new_cap = round_capa(tbl->num + (tbl->num >> 1));
1311  int i;
1312  item_t* old;
1313  struct hash_id_table tmp_tbl = {0, 0, 0};
1314  if (new_cap < tbl->capa) {
1315  new_cap = round_capa(tbl->used + (tbl->used >> 1));
1316  }
1317  tmp_tbl.capa = new_cap;
1318  tmp_tbl.items = ZALLOC_N(item_t, new_cap);
1319  for (i = 0; i < tbl->capa; i++) {
1320  id_key_t key = ITEM_GET_KEY(tbl, i);
1321  if (key != 0) {
1322  hash_table_raw_insert(&tmp_tbl, key, tbl->items[i].val);
1323  }
1324  }
1325  old = tbl->items;
1326  *tbl = tmp_tbl;
1327  xfree(old);
1328  }
1329 }
1330 
1331 #if ID_TABLE_DEBUG && 0
1332 static void
1333 hash_table_show(struct hash_id_table *tbl)
1334 {
1335  const id_key_t *keys = tbl->keys;
1336  const int capa = tbl->capa;
1337  int i;
1338 
1339  fprintf(stderr, "tbl: %p (capa: %d, num: %d, used: %d)\n", tbl, tbl->capa, tbl->num, tbl->used);
1340  for (i=0; i<capa; i++) {
1341  if (ITEM_KEY_ISSET(tbl, i)) {
1342  fprintf(stderr, " -> [%d] %s %d\n", i, rb_id2name(key2id(keys[i])), (int)keys[i]);
1343  }
1344  }
1345 }
1346 #endif
1347 
1348 static int
1350 {
1351  id_key_t key = id2key(id);
1352  int index = hash_table_index(tbl, key);
1353 
1354  if (index >= 0) {
1355  *valp = tbl->items[index].val;
1356  return TRUE;
1357  }
1358  else {
1359  return FALSE;
1360  }
1361 }
1362 
1363 static int
1364 hash_id_table_insert_key(struct hash_id_table *tbl, const id_key_t key, const VALUE val)
1365 {
1366  const int index = hash_table_index(tbl, key);
1367 
1368  if (index >= 0) {
1369  tbl->items[index].val = val;
1370  }
1371  else {
1372  hash_table_extend(tbl);
1373  hash_table_raw_insert(tbl, key, val);
1374  }
1375  return TRUE;
1376 }
1377 
1378 static int
1380 {
1381  return hash_id_table_insert_key(tbl, id2key(id), val);
1382 }
1383 
1384 static int
1386 {
1387  const id_key_t key = id2key(id);
1388  int index = hash_table_index(tbl, key);
1389  return hash_delete_index(tbl, index);
1390 }
1391 
1392 static void
1394 {
1395  int i, capa = tbl->capa;
1396 
1397  for (i=0; i<capa; i++) {
1398  if (ITEM_KEY_ISSET(tbl, i)) {
1399  const id_key_t key = ITEM_GET_KEY(tbl, i);
1400  enum rb_id_table_iterator_result ret = (*func)(key2id(key), tbl->items[i].val, data);
1401  assert(key != 0);
1402 
1403  if (ret == ID_TABLE_DELETE)
1404  hash_delete_index(tbl, i);
1405  else if (ret == ID_TABLE_STOP)
1406  return;
1407  }
1408  }
1409 }
1410 
1411 static void
1413 {
1414  int i, capa = tbl->capa;
1415 
1416  for (i=0; i<capa; i++) {
1417  if (ITEM_KEY_ISSET(tbl, i)) {
1418  enum rb_id_table_iterator_result ret = (*func)(tbl->items[i].val, data);
1419 
1420  if (ret == ID_TABLE_DELETE)
1421  hash_delete_index(tbl, i);
1422  else if (ret == ID_TABLE_STOP)
1423  return;
1424  }
1425  }
1426 }
1427 #endif /* ID_TABLE_USE_SMALL_HASH */
1428 
1429 #if ID_TABLE_USE_MIX
1430 
1432  union {
1433  struct {
1434  int capa;
1435  int num;
1436  } size;
1439  } aux;
1440 };
1441 
1442 #define LIST_LIMIT_P(mix) ((mix)->aux.size.num == ID_TABLE_USE_MIX_LIST_MAX_CAPA)
1443 #define LIST_P(mix) ((mix)->aux.size.capa <= ID_TABLE_USE_MIX_LIST_MAX_CAPA)
1444 
1445 static struct mix_id_table *
1447 {
1448  struct mix_id_table *mix = ZALLOC(struct mix_id_table);
1449  list_id_table_init((struct list_id_table *)mix, size);
1450  return mix;
1451 }
1452 
1453 static void
1455 {
1456  if (LIST_P(tbl)) list_id_table_free(&tbl->aux.list);
1457  else hash_id_table_free(&tbl->aux.hash);
1458 }
1459 
1460 static void
1462 {
1463  if (LIST_P(tbl)) list_id_table_clear(&tbl->aux.list);
1464  else hash_id_table_clear(&tbl->aux.hash);
1465 }
1466 
1467 static size_t
1469 {
1470  if (LIST_P(tbl)) return list_id_table_size(&tbl->aux.list);
1471  else return hash_id_table_size(&tbl->aux.hash);
1472 }
1473 
1474 static size_t
1476 {
1477  if (LIST_P(tbl)) return list_id_table_memsize(&tbl->aux.list) - sizeof(struct list_id_table) + sizeof(struct mix_id_table);
1478  else return hash_id_table_memsize(&tbl->aux.hash);
1479 }
1480 
1481 static int
1483 {
1484  int r;
1485 
1486  if (LIST_P(tbl)) {
1487  if (!LIST_LIMIT_P(tbl)) {
1488  r = list_id_table_insert(&tbl->aux.list, id, val);
1489  }
1490  else {
1491  /* convert to hash */
1492  /* overflow. TODO: this promotion should be done in list_extend_table */
1493  struct list_id_table *list = &tbl->aux.list;
1494  struct hash_id_table hash_body;
1495  id_key_t *keys = list->keys;
1496  VALUE *values = TABLE_VALUES(list);
1497  const int num = list->num;
1498  int i;
1499 
1500  hash_id_table_init(&hash_body, 0);
1501 
1502  for (i=0; i<num; i++) {
1503  /* note that GC can run */
1504  hash_id_table_insert_key(&hash_body, keys[i], values[i]);
1505  }
1506 
1507  tbl->aux.hash = hash_body;
1508 
1509  /* free list keys/values */
1510  xfree(keys);
1511 #if ID_TABLE_USE_CALC_VALUES == 0
1512  xfree(values);
1513 #endif
1514  goto hash_insert;
1515  }
1516  }
1517  else {
1518  hash_insert:
1519  r = hash_id_table_insert(&tbl->aux.hash, id, val);
1520  assert(!LIST_P(tbl));
1521  }
1522  return r;
1523 }
1524 
1525 static int
1526 mix_id_table_lookup(struct mix_id_table *tbl, ID id, VALUE *valp)
1527 {
1528  if (LIST_P(tbl)) return list_id_table_lookup(&tbl->aux.list, id, valp);
1529  else return hash_id_table_lookup(&tbl->aux.hash, id, valp);
1530 }
1531 
1532 static int
1534 {
1535  if (LIST_P(tbl)) return list_id_table_delete(&tbl->aux.list, id);
1536  else return hash_id_table_delete(&tbl->aux.hash, id);
1537 }
1538 
1539 static void
1541 {
1542  if (LIST_P(tbl)) list_id_table_foreach(&tbl->aux.list, func, data);
1543  else hash_id_table_foreach(&tbl->aux.hash, func, data);
1544 }
1545 
1546 static void
1548 {
1549  if (LIST_P(tbl)) list_id_table_foreach_values(&tbl->aux.list, func, data);
1550  else hash_id_table_foreach_values(&tbl->aux.hash, func, data);
1551 }
1552 
1553 #endif /* ID_TABLE_USE_MIX */
1554 
1555 #define IMPL_TYPE1(type, prot, name, args) \
1556  RUBY_ALIAS_FUNCTION_TYPE(type, prot, name, args)
1557 #define IMPL_TYPE(type, name, prot, args) \
1558  IMPL_TYPE1(type, rb_id_table_##name prot, IMPL(_##name), args)
1559 #define IMPL_VOID1(prot, name, args) \
1560  RUBY_ALIAS_FUNCTION_VOID(prot, name, args)
1561 #define IMPL_VOID(name, prot, args) \
1562  IMPL_VOID1(rb_id_table_##name prot, IMPL(_##name), args)
1563 #define id_tbl (ID_TABLE_IMPL_TYPE *)tbl
1564 
1565 IMPL_TYPE(struct rb_id_table *, create, (size_t size), (size))
1566 IMPL_VOID(free, (struct rb_id_table *tbl), (id_tbl))
1567 IMPL_VOID(clear, (struct rb_id_table *tbl), (id_tbl))
1568 IMPL_TYPE(size_t, size, (const struct rb_id_table *tbl), (id_tbl))
1569 IMPL_TYPE(size_t, memsize, (const struct rb_id_table *tbl), (id_tbl))
1570 
1571 IMPL_TYPE(int , insert, (struct rb_id_table *tbl, ID id, VALUE val),
1572  (id_tbl, id, val))
1573 IMPL_TYPE(int, lookup, (struct rb_id_table *tbl, ID id, VALUE *valp),
1574  (id_tbl, id, valp))
1575 IMPL_TYPE(int, delete, (struct rb_id_table *tbl, ID id),
1576  (id_tbl, id))
1577 
1578 IMPL_VOID(foreach,
1579  (struct rb_id_table *tbl, rb_id_table_foreach_func_t *func, void *data),
1580  (id_tbl, func, data))
1581 IMPL_VOID(foreach_values,
1582  (struct rb_id_table *tbl, rb_id_table_foreach_values_func_t *func, void *data),
1583  (id_tbl, func, data))
1584 
1585 #if ID_TABLE_STARTUP_SIG
1586 __attribute__((constructor))
1587 static void
1588 show_impl(void)
1589 {
1590  fprintf(stderr, "impl: %d\n", ID_TABLE_IMPL);
1591 }
1592 #endif
static int hash_id_table_lookup(struct hash_id_table *tbl, ID id, VALUE *valp)
Definition: id_table.c:1349
enum rb_id_table_iterator_result rb_id_table_foreach_values_func_t(VALUE val, void *data)
static void mix_id_table_foreach(struct mix_id_table *tbl, rb_id_table_foreach_func_t *func, void *data)
Definition: id_table.c:1540
static void list_id_table_free(struct list_id_table *tbl)
Definition: id_table.c:411
static rb_id_serial_t rb_id_to_serial(ID id)
Definition: symbol.h:58
void rb_bug(const char *fmt,...)
Definition: error.c:482
#define FALSE
Definition: nkf.h:174
Definition: st.h:79
static void hash_table_raw_insert(struct hash_id_table *tbl, id_key_t key, VALUE val)
Definition: id_table.c:1271
unsigned int UINT8 __attribute__((__mode__(__QI__)))
Definition: ffi_common.h:110
static int max(int a, int b)
Definition: strftime.c:142
static unsigned int hash(str, len) register const char *str
static id_key_t id2key(ID id)
Definition: id_table.c:220
static struct mix_id_table * mix_id_table_create(size_t size)
Definition: id_table.c:1446
#define st_foreach
Definition: regint.h:186
id_key_t * keys
Definition: id_table.c:366
#define ITEM_COLLIDED(tbl, i)
Definition: id_table.c:1182
#define ZALLOC_N(type, n)
Definition: ruby.h:1589
static size_t hash_id_table_size(const struct hash_id_table *tbl)
Definition: id_table.c:1241
#define LIST_MIN_CAPA
Definition: id_table.c:361
#define id_tbl
Definition: id_table.c:1563
static void list_id_table_clear(struct list_id_table *tbl)
Definition: id_table.c:421
SSL_METHOD *(* func)(void)
Definition: ossl_ssl.c:54
static int list_id_table_lookup(struct list_id_table *tbl, ID id, VALUE *valp)
Definition: id_table.c:619
static size_t hash_id_table_memsize(const struct hash_id_table *tbl)
Definition: id_table.c:1247
static int list_id_table_delete(struct list_id_table *tbl, ID id)
Definition: id_table.c:714
static int hash_id_table_delete(struct hash_id_table *tbl, ID id)
Definition: id_table.c:1385
static void tbl_assert(struct list_id_table *tbl)
Definition: id_table.c:528
static int values_i(VALUE key, VALUE value, VALUE ary)
Definition: hash.c:2042
#define st_delete
Definition: regint.h:182
#define st_lookup
Definition: regint.h:185
#define assert(x)
Definition: dlmalloc.c:1176
static ID rb_id_serial_to_id(rb_id_serial_t num)
Definition: symbol.c:359
struct rb_id_item item_t
#define st_init_numtable_with_size
Definition: regint.h:179
static void hash_id_table_foreach_values(struct hash_id_table *tbl, rb_id_table_foreach_values_func_t *func, void *data)
Definition: id_table.c:1412
static int list_delete_index(struct list_id_table *tbl, id_key_t key, int index)
Definition: id_table.c:685
static size_t mix_id_table_size(const struct mix_id_table *tbl)
Definition: id_table.c:1468
static void list_id_table_foreach(struct list_id_table *tbl, rb_id_table_foreach_func_t *func, void *data)
Definition: id_table.c:737
RUBY_SYMBOL_EXPORT_BEGIN typedef unsigned long st_data_t
Definition: st.h:22
#define ITEM_GET_KEY(tbl, i)
Definition: id_table.c:1180
static int mix_id_table_delete(struct mix_id_table *tbl, ID id)
Definition: id_table.c:1533
static int list_ids_bsearch(const id_key_t *keys, id_key_t key, int num)
Definition: id_table.c:548
#define MEMZERO(p, type, n)
Definition: ruby.h:1660
static struct list_id_table * list_id_table_init(struct list_id_table *tbl, size_t capa)
Definition: id_table.c:379
#define IMPL(op)
Definition: id_table.c:192
static size_t list_id_table_memsize(const struct list_id_table *tbl)
Definition: id_table.c:433
static int round_capa(int capa)
Definition: id_table.c:1192
id_key_t key
Definition: id_table.c:1155
static struct hash_id_table * hash_id_table_init(struct hash_id_table *tbl, int capa)
Definition: id_table.c:1205
#define ALLOC_N(type, n)
Definition: ruby.h:1587
struct list_id_table list
Definition: id_table.c:1437
#define val
#define ITEM_KEY_ISSET(tbl, i)
Definition: id_table.c:1181
size_t st_memsize(const st_table *tab)
Definition: st.c:674
return
Definition: zonetab.h:899
static void ITEM_SET_KEY(struct hash_id_table *tbl, int i, id_key_t key)
Definition: id_table.c:1185
#define ITEM_SET_COLLIDED(tbl, i)
Definition: id_table.c:1183
static void mix_id_table_foreach_values(struct mix_id_table *tbl, rb_id_table_foreach_values_func_t *func, void *data)
Definition: id_table.c:1547
#define IMPL_VOID(name, prot, args)
Definition: id_table.c:1561
static size_t mix_id_table_memsize(const struct mix_id_table *tbl)
Definition: id_table.c:1475
rb_id_serial_t id_key_t
Definition: id_table.c:212
static int mix_id_table_insert(struct mix_id_table *tbl, ID id, VALUE val)
Definition: id_table.c:1482
#define ALLOC(type)
Definition: ruby.h:1588
item_t * items
Definition: id_table.c:1166
static int hash_id_table_insert_key(struct hash_id_table *tbl, const id_key_t key, const VALUE val)
Definition: id_table.c:1364
#define ZALLOC(type)
Definition: ruby.h:1590
static int list_table_index(struct list_id_table *tbl, id_key_t key)
Definition: id_table.c:597
#define UNUSED(func)
Definition: id_table.c:197
#define TRUE
Definition: nkf.h:175
static int mix_id_table_lookup(struct mix_id_table *tbl, ID id, VALUE *valp)
Definition: id_table.c:1526
static void list_table_extend(struct list_id_table *tbl)
Definition: id_table.c:439
static void hash_table_extend(struct hash_id_table *tbl)
Definition: id_table.c:1307
static void hash_id_table_foreach(struct hash_id_table *tbl, rb_id_table_foreach_func_t *func, void *data)
Definition: id_table.c:1393
unsigned long ID
Definition: ruby.h:86
unsigned long VALUE
Definition: ruby.h:85
static int list_id_table_insert(struct list_id_table *tbl, ID id, VALUE val)
Definition: id_table.c:646
static void mix_id_table_free(struct mix_id_table *tbl)
Definition: id_table.c:1454
static int hash_delete_index(struct hash_id_table *tbl, int ix)
Definition: id_table.c:1291
const char * rb_id2name(ID)
Definition: symbol.c:759
static int insert(const char *path, VALUE vinfo, void *enc)
Definition: win32.c:1539
static void hash_id_table_free(struct hash_id_table *tbl)
Definition: id_table.c:1226
VALUE val
Definition: id_table.c:1159
int size
Definition: encoding.c:57
static void mix_id_table_clear(struct mix_id_table *tbl)
Definition: id_table.c:1461
static size_t list_id_table_size(const struct list_id_table *tbl)
Definition: id_table.c:427
union mix_id_table::@117 aux
#define xmalloc
Definition: defines.h:183
#define ANYARGS
Definition: defines.h:173
#define ID_TABLE_IMPL
Definition: id_table.c:36
static void list_id_table_foreach_values(struct list_id_table *tbl, rb_id_table_foreach_values_func_t *func, void *data)
Definition: id_table.c:755
#define LIST_P(mix)
Definition: id_table.c:1443
static ID key2id(id_key_t key)
Definition: id_table.c:214
#define IMPL_TYPE(type, name, prot, args)
Definition: id_table.c:1557
struct rb_encoding_entry * list
Definition: encoding.c:55
enum rb_id_table_iterator_result rb_id_table_foreach_func_t(ID id, VALUE val, void *data)
#define LIST_LIMIT_P(mix)
Definition: id_table.c:1442
#define st_insert
Definition: regint.h:184
#define TABLE_VALUES(tbl)
Definition: id_table.c:373
#define xrealloc
Definition: defines.h:186
struct hash_id_table hash
Definition: id_table.c:1438
#define st_free_table
Definition: regint.h:188
static int hash_table_index(struct hash_id_table *tbl, id_key_t key)
Definition: id_table.c:1253
static int hash_id_table_insert(struct hash_id_table *tbl, ID id, VALUE val)
Definition: id_table.c:1379
static void hash_id_table_clear(struct hash_id_table *tbl)
Definition: id_table.c:1233
void st_clear(st_table *)
Definition: st.c:653
rb_id_table_iterator_result
Definition: id_table.h:8
void void xfree(void *)
uint32_t rb_id_serial_t
Definition: symbol.h:55
#define NULL
Definition: _sdbm.c:102
void rb_warn(const char *fmt,...)
Definition: error.c:221
free(psz)
#define FOREACH_LAST()
Definition: id_table.c:721
#define ID_TABLE_IMPL_TYPE
Definition: id_table.c:153