namedict.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. #include "pocketpy/objects/namedict.h"
  2. #include "pocketpy/common/utils.h"
  3. #include <stdint.h>
  4. #include <string.h>
  5. #include <assert.h>
  6. #define HASH_KEY(__k) ((uintptr_t)(__k) >> 3U)
  7. #define HASH_PROBE_0(__k, ok, i) \
  8. ok = false; \
  9. i = HASH_KEY(__k) & self->mask; \
  10. do { \
  11. if(self->items[i].key == (__k)) { \
  12. ok = true; \
  13. break; \
  14. } \
  15. if(self->items[i].key == NULL) break; \
  16. i = (i + 1) & self->mask; \
  17. } while(true);
  18. #define HASH_PROBE_1(__k, ok, i) \
  19. ok = false; \
  20. i = HASH_KEY(__k) & self->mask; \
  21. while(self->items[i].key != NULL) { \
  22. if(self->items[i].key == (__k)) { \
  23. ok = true; \
  24. break; \
  25. } \
  26. i = (i + 1) & self->mask; \
  27. }
  28. static void NameDict__set_capacity_and_alloc_items(NameDict* self, int val) {
  29. self->capacity = val;
  30. self->critical_size = val * self->load_factor;
  31. self->mask = (uintptr_t)val - 1;
  32. self->items = PK_MALLOC(self->capacity * sizeof(NameDict_KV));
  33. memset(self->items, 0, self->capacity * sizeof(NameDict_KV));
  34. }
  35. static void NameDict__rehash_2x(NameDict* self) {
  36. NameDict_KV* old_items = self->items;
  37. int old_capacity = self->capacity;
  38. NameDict__set_capacity_and_alloc_items(self, self->capacity * 2);
  39. for(int i = 0; i < old_capacity; i++) {
  40. if(old_items[i].key == NULL) continue;
  41. bool ok;
  42. uintptr_t j;
  43. HASH_PROBE_1(old_items[i].key, ok, j);
  44. c11__rtassert(!ok);
  45. self->items[j] = old_items[i];
  46. }
  47. PK_FREE(old_items);
  48. }
  49. NameDict* NameDict__new(float load_factor) {
  50. NameDict* p = PK_MALLOC(sizeof(NameDict));
  51. NameDict__ctor(p, load_factor);
  52. return p;
  53. }
  54. void NameDict__delete(NameDict* self) {
  55. NameDict__dtor(self);
  56. PK_FREE(self);
  57. }
  58. void NameDict__ctor(NameDict* self, float load_factor) {
  59. assert(load_factor > 0.0f && load_factor < 1.0f);
  60. self->length = 0;
  61. self->load_factor = load_factor;
  62. NameDict__set_capacity_and_alloc_items(self, 4);
  63. }
  64. void NameDict__dtor(NameDict* self) { PK_FREE(self->items); }
  65. py_TValue* NameDict__try_get(NameDict* self, py_Name key) {
  66. bool ok;
  67. uintptr_t i;
  68. HASH_PROBE_0(key, ok, i);
  69. if(!ok) return NULL;
  70. return &self->items[i].value;
  71. }
  72. bool NameDict__contains(NameDict* self, py_Name key) {
  73. bool ok;
  74. uintptr_t i;
  75. HASH_PROBE_0(key, ok, i);
  76. return ok;
  77. }
  78. void NameDict__set(NameDict* self, py_Name key, py_TValue* val) {
  79. bool ok;
  80. uintptr_t i;
  81. HASH_PROBE_1(key, ok, i);
  82. if(!ok) {
  83. self->length++;
  84. if(self->length > self->critical_size) {
  85. NameDict__rehash_2x(self);
  86. HASH_PROBE_1(key, ok, i);
  87. }
  88. self->items[i].key = key;
  89. }
  90. self->items[i].value = *val;
  91. }
  92. bool NameDict__del(NameDict* self, py_Name key) {
  93. bool ok;
  94. uintptr_t i;
  95. HASH_PROBE_0(key, ok, i);
  96. if(!ok) return false;
  97. self->items[i].key = NULL;
  98. self->items[i].value = *py_NIL();
  99. self->length--;
  100. /* tidy */
  101. uintptr_t posToRemove = i;
  102. uintptr_t posToShift = posToRemove;
  103. while(true) {
  104. posToShift = (posToShift + 1) & self->mask;
  105. if(self->items[posToShift].key == NULL) break;
  106. uintptr_t hash_z = HASH_KEY(self->items[posToShift].key);
  107. uintptr_t insertPos = hash_z & self->mask;
  108. bool cond1 = insertPos <= posToRemove;
  109. bool cond2 = posToRemove <= posToShift;
  110. if((cond1 && cond2) ||
  111. // chain wrapped around capacity
  112. (posToShift < insertPos && (cond1 || cond2))) {
  113. NameDict_KV tmp = self->items[posToRemove];
  114. assert(tmp.key == NULL);
  115. self->items[posToRemove] = self->items[posToShift];
  116. self->items[posToShift] = tmp;
  117. posToRemove = posToShift;
  118. }
  119. }
  120. return true;
  121. }
  122. void NameDict__clear(NameDict* self) {
  123. for(int i = 0; i < self->capacity; i++) {
  124. self->items[i].key = NULL;
  125. self->items[i].value = *py_NIL();
  126. }
  127. self->length = 0;
  128. }
  129. #undef HASH_PROBE_0
  130. #undef HASH_PROBE_1
  131. #undef HASH_KEY