dict.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  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(PyObject* key, PyObject* val){
  38. // do possible rehash
  39. if(_size+1 > _critical_size) _rehash();
  40. bool ok; int i;
  41. _probe(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. int old_capacity = _capacity;
  60. _capacity *= 2;
  61. _mask = _capacity - 1;
  62. _size = 0;
  63. _critical_size = _capacity*__LoadFactor+0.5f;
  64. _head_idx = -1;
  65. _tail_idx = -1;
  66. pool64.dealloc(_nodes);
  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. for(int i=0; i<old_capacity; i++){
  72. if(old_items[i].first == nullptr) continue;
  73. set(old_items[i].first, old_items[i].second);
  74. }
  75. pool128.dealloc(old_items);
  76. }
  77. PyObject* Dict::try_get(PyObject* key) const{
  78. bool ok; int i;
  79. _probe(key, ok, i);
  80. if(!ok) return nullptr;
  81. return _items[i].second;
  82. }
  83. bool Dict::contains(PyObject* key) const{
  84. bool ok; int i;
  85. _probe(key, ok, i);
  86. return ok;
  87. }
  88. void Dict::erase(PyObject* key){
  89. bool ok; int i;
  90. _probe(key, ok, i);
  91. if(!ok) return;
  92. _items[i].first = nullptr;
  93. _items[i].second = nullptr;
  94. _size--;
  95. if(_size == 0){
  96. _head_idx = -1;
  97. _tail_idx = -1;
  98. }else{
  99. if(_head_idx == i){
  100. _head_idx = _nodes[i].next;
  101. _nodes[_head_idx].prev = -1;
  102. }else if(_tail_idx == i){
  103. _tail_idx = _nodes[i].prev;
  104. _nodes[_tail_idx].next = -1;
  105. }else{
  106. _nodes[_nodes[i].prev].next = _nodes[i].next;
  107. _nodes[_nodes[i].next].prev = _nodes[i].prev;
  108. }
  109. }
  110. _nodes[i].prev = -1;
  111. _nodes[i].next = -1;
  112. }
  113. void Dict::update(const Dict& other){
  114. other.apply([&](PyObject* k, PyObject* v){ set(k, v); });
  115. }
  116. Tuple Dict::keys() const{
  117. Tuple t(_size);
  118. int i = _head_idx;
  119. int j = 0;
  120. while(i != -1){
  121. t[j++] = _items[i].first;
  122. i = _nodes[i].next;
  123. }
  124. PK_ASSERT(j == _size);
  125. return t;
  126. }
  127. Tuple Dict::values() const{
  128. Tuple t(_size);
  129. int i = _head_idx;
  130. int j = 0;
  131. while(i != -1){
  132. t[j++] = _items[i].second;
  133. i = _nodes[i].next;
  134. }
  135. PK_ASSERT(j == _size);
  136. return t;
  137. }
  138. void Dict::clear(){
  139. _size = 0;
  140. _head_idx = -1;
  141. _tail_idx = -1;
  142. memset(_items, 0, _capacity * sizeof(Item));
  143. memset(_nodes, -1, _capacity * sizeof(ItemNode));
  144. }
  145. Dict::~Dict(){
  146. if(_items==nullptr) return;
  147. pool128.dealloc(_items);
  148. pool64.dealloc(_nodes);
  149. }
  150. void Dict::_gc_mark() const{
  151. apply([](PyObject* k, PyObject* v){
  152. PK_OBJ_MARK(k);
  153. PK_OBJ_MARK(v);
  154. });
  155. }
  156. } // namespace pkpy