6#define ID_TABLE_DEBUG 0
13#include "ruby_assert.h"
15typedef rb_id_serial_t id_key_t;
20 return rb_id_serial_to_id(key);
26 return rb_id_to_serial(
id);
42#define COLLISION_TABLE_SIZE(capa) roomof((size_t)(capa), CHAR_BIT)
43#define ID_TABLE_BUF_SIZE(capa) \
44 ((sizeof(VALUE) + sizeof(id_key_t)) * (size_t)(capa) + COLLISION_TABLE_SIZE(capa))
49 return (
VALUE *)tbl->buf;
52static inline id_key_t *
55 return (id_key_t *)(id_table_items(tbl) + tbl->capa);
58static inline uint8_t *
61 return (uint8_t *)(id_table_keys(tbl) + tbl->capa);
64#define ITEM_GET_KEY(tbl, i) (id_table_keys(tbl)[i])
65#define ITEM_KEY_ISSET(tbl, i) ((tbl)->buf && id_table_keys(tbl)[i])
66#define ITEM_COLLIDED(tbl, i) (id_table_collision_table(tbl)[(i) / CHAR_BIT] & ((uint8_t)1 << ((i) % CHAR_BIT)))
67#define ITEM_SET_COLLIDED(tbl, i) (id_table_collision_table(tbl)[(i) / CHAR_BIT] |= ((uint8_t)1 << ((i) % CHAR_BIT)))
68#define ITEM_VALUE(tbl, i) (id_table_items(tbl)[i])
71ITEM_SET_KEY(
struct rb_id_table *tbl,
int i, id_key_t key)
73 id_table_keys(tbl)[i] = key;
81#define ID_TABLE_BUF_SIZE(capa) (sizeof(item_t) * (size_t)(capa))
82#define id_table_items(tbl) ((item_t *)(tbl)->buf)
84#define ITEM_GET_KEY(tbl, i) (id_table_items(tbl)[i].key >> 1)
85#define ITEM_KEY_ISSET(tbl, i) (id_table_items(tbl)[i].key > 1)
86#define ITEM_COLLIDED(tbl, i) (id_table_items(tbl)[i].key & 1)
87#define ITEM_SET_COLLIDED(tbl, i) (id_table_items(tbl)[i].key |= 1)
88#define ITEM_VALUE(tbl, i) (id_table_items(tbl)[i].val)
91ITEM_SET_KEY(
struct rb_id_table *tbl,
int i, id_key_t key)
93 id_table_items(tbl)[i].key = (key << 1) | ITEM_COLLIDED(tbl, i);
107 return (
capa + 1) << 2;
114 tbl->buf = ruby_xcalloc(1, ID_TABLE_BUF_SIZE(
capa));
121rb_id_table_init(
struct rb_id_table *tbl,
size_t s_capa)
123 int capa = (int)s_capa;
127 tbl->capa = (int)
capa;
128 id_table_alloc_buf(tbl,
capa);
134rb_id_table_create(
size_t capa)
137 return rb_id_table_init(tbl,
capa);
159 memset(tbl->buf, 0, ID_TABLE_BUF_SIZE(tbl->capa));
166 return (
size_t)tbl->num;
172 return ID_TABLE_BUF_SIZE(tbl->capa) +
sizeof(
struct rb_id_table);
176hash_table_index(
struct rb_id_table* tbl, id_key_t key)
179 int mask = tbl->capa - 1;
182 while (key != ITEM_GET_KEY(tbl, ix)) {
183 if (!ITEM_COLLIDED(tbl, ix))
185 ix = (ix + d) & mask;
196 int mask = tbl->capa - 1;
200 while (ITEM_KEY_ISSET(tbl, ix)) {
201 ITEM_SET_COLLIDED(tbl, ix);
202 ix = (ix + d) & mask;
206 if (!ITEM_COLLIDED(tbl, ix)) {
209 ITEM_SET_KEY(tbl, ix, key);
210 ITEM_VALUE(tbl, ix) = val;
217 if (!ITEM_COLLIDED(tbl, ix)) {
221 ITEM_SET_KEY(tbl, ix, 0);
222 ITEM_VALUE(tbl, ix) = 0;
233 if (tbl->used + (tbl->used >> 1) >= tbl->capa) {
234 int new_cap = round_capa(tbl->num + (tbl->num >> 1));
238 if (new_cap < tbl->
capa) {
239 new_cap = round_capa(tbl->used + (tbl->used >> 1));
241 tmp_tbl.capa = new_cap;
242 id_table_alloc_buf(&tmp_tbl, new_cap);
243 for (i = 0; i < tbl->capa; i++) {
244 id_key_t key = ITEM_GET_KEY(tbl, i);
246 hash_table_raw_insert(&tmp_tbl, key, ITEM_VALUE(tbl, i));
255#if ID_TABLE_DEBUG && 0
259 const int capa = tbl->capa;
262 fprintf(stderr,
"tbl: %p (capa: %d, num: %d, used: %d)\n", tbl, tbl->capa, tbl->num, tbl->used);
263 for (i=0; i<
capa; i++) {
264 if (ITEM_KEY_ISSET(tbl, i)) {
265 const id_key_t key = ITEM_GET_KEY(tbl, i);
266 fprintf(stderr,
" -> [%d] %s %d\n", i, rb_id2name(key2id(key)), (
int)key);
275 id_key_t key = id2key(
id);
276 int index = hash_table_index(tbl, key);
279 *valp = ITEM_VALUE(tbl, index);
288rb_id_table_insert_key(
struct rb_id_table *tbl,
const id_key_t key,
const VALUE val)
290 const int index = hash_table_index(tbl, key);
293 ITEM_VALUE(tbl, index) = val;
296 hash_table_extend(tbl);
297 hash_table_raw_insert(tbl, key, val);
305 return rb_id_table_insert_key(tbl, id2key(
id), val);
311 const id_key_t key = id2key(
id);
312 int index = hash_table_index(tbl, key);
313 return hash_delete_index(tbl, index);
317rb_id_table_foreach(
struct rb_id_table *tbl, rb_id_table_foreach_func_t *func,
void *data)
319 int i,
capa = tbl->capa;
321 for (i=0; i<
capa; i++) {
322 if (ITEM_KEY_ISSET(tbl, i)) {
323 const id_key_t key = ITEM_GET_KEY(tbl, i);
324 enum rb_id_table_iterator_result ret = (*func)(key2id(key), ITEM_VALUE(tbl, i), data);
327 if (ret == ID_TABLE_DELETE)
328 hash_delete_index(tbl, i);
329 else if (ret == ID_TABLE_STOP)
336rb_id_table_foreach_values(
struct rb_id_table *tbl, rb_id_table_foreach_values_func_t *func,
void *data)
338 int i,
capa = tbl->capa;
344 for (i=0; i<
capa; i++) {
345 if (ITEM_KEY_ISSET(tbl, i)) {
346 enum rb_id_table_iterator_result ret = (*func)(ITEM_VALUE(tbl, i), data);
348 if (ret == ID_TABLE_DELETE)
349 hash_delete_index(tbl, i);
350 else if (ret == ID_TABLE_STOP)
357rb_id_table_foreach_values_with_replace(
struct rb_id_table *tbl, rb_id_table_foreach_values_func_t *func, rb_id_table_update_value_callback_func_t *replace,
void *data)
359 int i,
capa = tbl->capa;
361 for (i = 0; i <
capa; i++) {
362 if (ITEM_KEY_ISSET(tbl, i)) {
363 enum rb_id_table_iterator_result ret = (*func)(ITEM_VALUE(tbl, i), data);
365 if (ret == ID_TABLE_REPLACE) {
366 VALUE val = ITEM_VALUE(tbl, i);
367 ret = (*replace)(&val, data, TRUE);
368 ITEM_VALUE(tbl, i) = val;
371 if (ret == ID_TABLE_STOP)
378managed_id_table_free(
void *data)
381 rb_id_table_free_items(tbl);
385managed_id_table_memsize(
const void *data)
388 return rb_id_table_memsize(tbl) -
sizeof(
struct rb_id_table);
395 .dfree = managed_id_table_free,
396 .dsize = managed_id_table_memsize,
398 .flags = RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE,
402managed_id_table_ptr(
VALUE obj)
407 return RTYPEDDATA_GET_DATA(obj);
415 RB_OBJ_SET_SHAREABLE(obj);
416 rb_id_table_init(tbl,
capa);
421rb_managed_id_table_new(
size_t capa)
423 return rb_managed_id_table_create(&rb_managed_id_table_type,
capa);
426static enum rb_id_table_iterator_result
427managed_id_table_dup_i(
ID id,
VALUE val,
void *data)
430 rb_id_table_insert(new_tbl,
id, val);
431 return ID_TABLE_CONTINUE;
435rb_managed_id_table_dup(
VALUE old_table)
442 RB_OBJ_SET_SHAREABLE(obj);
443 struct rb_id_table *old_tbl = managed_id_table_ptr(old_table);
444 rb_id_table_init(new_tbl, old_tbl->num + 1);
445 rb_id_table_foreach(old_tbl, managed_id_table_dup_i, new_tbl);
453rb_managed_id_table_lookup(
VALUE table,
ID id,
VALUE *valp)
455 return rb_id_table_lookup(managed_id_table_ptr(table),
id, valp);
459rb_managed_id_table_insert(
VALUE table,
ID id,
VALUE val)
461 return rb_id_table_insert(managed_id_table_ptr(table),
id, val);
465rb_managed_id_table_size(
VALUE table)
467 return rb_id_table_size(managed_id_table_ptr(table));
471rb_managed_id_table_foreach(
VALUE table, rb_id_table_foreach_func_t *func,
void *data)
473 rb_id_table_foreach(managed_id_table_ptr(table), func, data);
480rb_managed_id_table_foreach_values(
VALUE table, rb_id_table_foreach_values_func_t *func,
void *data)
482 rb_id_table_foreach_values(managed_id_table_ptr(table), func, data);
487rb_managed_id_table_delete(
VALUE table,
ID id)
489 return rb_id_table_delete(managed_id_table_ptr(table),
id);
492static enum rb_id_table_iterator_result
493marked_id_table_mark_i(
VALUE val,
void *data)
495 rb_gc_mark_movable(val);
496 return ID_TABLE_CONTINUE;
500marked_id_table_mark(
void *ptr)
503 rb_id_table_foreach_values(tbl, marked_id_table_mark_i, NULL);
506static enum rb_id_table_iterator_result
507marked_id_table_compact_check_i(
VALUE value,
void *data)
509 if (rb_gc_location(value) != value) {
510 return ID_TABLE_REPLACE;
512 return ID_TABLE_CONTINUE;
515static enum rb_id_table_iterator_result
516marked_id_table_compact_replace_i(
VALUE *value,
void *data,
int existing)
518 *value = rb_gc_location(*value);
519 return ID_TABLE_CONTINUE;
523marked_id_table_compact(
void *ptr)
526 rb_id_table_foreach_values_with_replace(tbl, marked_id_table_compact_check_i, marked_id_table_compact_replace_i, NULL);
532 .dmark = marked_id_table_mark,
533 .dfree = managed_id_table_free,
534 .dsize = managed_id_table_memsize,
535 .dcompact = marked_id_table_compact,
537 .parent = &rb_managed_id_table_type,
538 .
flags = RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE,
542rb_marked_id_table_new(
size_t capa)
544 return rb_managed_id_table_create(&rb_marked_id_table_type,
capa);
550 int result = rb_managed_id_table_insert(table,
id, val);
555static enum rb_id_table_iterator_result
556marked_id_table_dup_i(
VALUE val,
void *data)
560 return ID_TABLE_CONTINUE;
564rb_marked_id_table_dup(
VALUE old_table)
566 VALUE new_table = rb_managed_id_table_dup(old_table);
567 rb_managed_id_table_foreach_values(new_table, marked_id_table_dup_i, (
void *)new_table);
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
#define ALLOC
Old name of RB_ALLOC.
#define xfree
Old name of ruby_xfree.
#define Qundef
Old name of RUBY_Qundef.
#define T_DATA
Old name of RUBY_T_DATA.
#define ZALLOC_N
Old name of RB_ZALLOC_N.
#define RB_OBJ_WRITTEN(old, oldv, young)
Identical to RB_OBJ_WRITE(), except it doesn't write any values, but only a WB declaration.
int capa
Designed capacity of the buffer.
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
VALUE type(ANYARGS)
ANYARGS-ed function type.
static const rb_data_type_t * RTYPEDDATA_TYPE(VALUE obj)
Queries for the type of given object.
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
This is the struct that holds necessary info for a struct.
const char * wrap_struct_name
Name of structs of this kind.
VALUE flags
Type-specific behavioural characteristics.
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
uintptr_t VALUE
Type that represents a Ruby object.
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.