dict.cpp 5.1 KB

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