dict.cpp 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. #include "pocketpy/objects/dict.hpp"
  2. namespace pkpy {
  3. Dict::Dict() :
  4. _capacity(__Capacity), _mask(__Capacity - 1), _size(0), _critical_size(__Capacity * __LoadFactor + 0.5f),
  5. _head_idx(-1), _tail_idx(-1) {
  6. __alloc_items();
  7. }
  8. void Dict::__alloc_items() {
  9. _items = (Item*)std::malloc(_capacity * sizeof(Item));
  10. for(int i = 0; i < _capacity; i++) {
  11. _items[i].first = nullptr;
  12. _items[i].second = nullptr;
  13. _items[i].prev = -1;
  14. _items[i].next = -1;
  15. }
  16. }
  17. Dict::Dict(Dict&& other) {
  18. _capacity = other._capacity;
  19. _mask = other._mask;
  20. _size = other._size;
  21. _critical_size = other._critical_size;
  22. _head_idx = other._head_idx;
  23. _tail_idx = other._tail_idx;
  24. _items = other._items;
  25. other._items = nullptr;
  26. }
  27. Dict::Dict(const Dict& other) {
  28. _capacity = other._capacity;
  29. _mask = other._mask;
  30. _size = other._size;
  31. _critical_size = other._critical_size;
  32. _head_idx = other._head_idx;
  33. _tail_idx = other._tail_idx;
  34. // copy items
  35. _items = (Item*)std::malloc(_capacity * sizeof(Item));
  36. std::memcpy(_items, other._items, _capacity * sizeof(Item));
  37. }
  38. void Dict::set(VM* vm, PyVar key, PyVar val) {
  39. // do possible rehash
  40. if(_size + 1 > _critical_size) _rehash(vm);
  41. bool ok;
  42. int i;
  43. _probe_1(vm, key, ok, i);
  44. if(!ok) {
  45. _size++;
  46. _items[i].first = key;
  47. // append to tail
  48. if(_size == 0 + 1) {
  49. _head_idx = i;
  50. _tail_idx = i;
  51. } else {
  52. _items[i].prev = _tail_idx;
  53. _items[_tail_idx].next = i;
  54. _tail_idx = i;
  55. }
  56. }
  57. _items[i].second = val;
  58. }
  59. void Dict::_rehash(VM* vm) {
  60. Item* old_items = _items;
  61. int old_head_idx = _head_idx;
  62. _capacity *= 4;
  63. _mask = _capacity - 1;
  64. _size = 0;
  65. _critical_size = _capacity * __LoadFactor + 0.5f;
  66. _head_idx = -1;
  67. _tail_idx = -1;
  68. __alloc_items();
  69. // copy old items to new dict
  70. int i = old_head_idx;
  71. while(i != -1) {
  72. set(vm, old_items[i].first, old_items[i].second);
  73. i = old_items[i].next;
  74. }
  75. std::free(old_items);
  76. }
  77. PyVar Dict::try_get(VM* vm, PyVar key) const {
  78. bool ok;
  79. int i;
  80. _probe_0(vm, key, ok, i);
  81. if(!ok) return nullptr;
  82. return _items[i].second;
  83. }
  84. bool Dict::contains(VM* vm, PyVar key) const {
  85. bool ok;
  86. int i;
  87. _probe_0(vm, key, ok, i);
  88. return ok;
  89. }
  90. bool Dict::del(VM* vm, PyVar key) {
  91. bool ok;
  92. int i;
  93. _probe_0(vm, key, ok, i);
  94. if(!ok) return false;
  95. _items[i].first = nullptr;
  96. // _items[i].second = PY_DELETED_SLOT; // do not change .second if it is not NULL, it means the slot is occupied by
  97. // a deleted item
  98. _size--;
  99. if(_size == 0) {
  100. _head_idx = -1;
  101. _tail_idx = -1;
  102. } else {
  103. if(_head_idx == i) {
  104. _head_idx = _items[i].next;
  105. _items[_head_idx].prev = -1;
  106. } else if(_tail_idx == i) {
  107. _tail_idx = _items[i].prev;
  108. _items[_tail_idx].next = -1;
  109. } else {
  110. _items[_items[i].prev].next = _items[i].next;
  111. _items[_items[i].next].prev = _items[i].prev;
  112. }
  113. }
  114. _items[i].prev = -1;
  115. _items[i].next = -1;
  116. return true;
  117. }
  118. void Dict::update(VM* vm, const Dict& other) {
  119. other.apply([&](PyVar k, PyVar v) {
  120. set(vm, k, v);
  121. });
  122. }
  123. Tuple Dict::keys() const {
  124. Tuple t(_size);
  125. int i = _head_idx;
  126. int j = 0;
  127. while(i != -1) {
  128. t[j++] = _items[i].first;
  129. i = _items[i].next;
  130. }
  131. assert(j == _size);
  132. return t;
  133. }
  134. Tuple Dict::values() const {
  135. Tuple t(_size);
  136. int i = _head_idx;
  137. int j = 0;
  138. while(i != -1) {
  139. t[j++] = _items[i].second;
  140. i = _items[i].next;
  141. }
  142. assert(j == _size);
  143. return t;
  144. }
  145. void Dict::clear() {
  146. _size = 0;
  147. _head_idx = -1;
  148. _tail_idx = -1;
  149. for(int i = 0; i < _capacity; i++) {
  150. _items[i].first = nullptr;
  151. _items[i].second = nullptr;
  152. _items[i].prev = -1;
  153. _items[i].next = -1;
  154. }
  155. }
  156. Dict::~Dict() {
  157. if(_items) std::free(_items);
  158. }
  159. } // namespace pkpy