dict.cpp 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. #include "pocketpy/objects/dict.hpp"
  2. namespace pkpy{
  3. Dict::Dict(): _capacity(__Capacity),
  4. _mask(__Capacity-1),
  5. _size(0), _critical_size(__Capacity*__LoadFactor+0.5f), _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; int i;
  42. _probe_1(vm, key, ok, i);
  43. if(!ok) {
  44. _size++;
  45. _items[i].first = key;
  46. // append to tail
  47. if(_size == 0+1){
  48. _head_idx = i;
  49. _tail_idx = i;
  50. }else{
  51. _items[i].prev = _tail_idx;
  52. _items[_tail_idx].next = i;
  53. _tail_idx = i;
  54. }
  55. }
  56. _items[i].second = val;
  57. }
  58. void Dict::_rehash(VM* vm){
  59. Item* old_items = _items;
  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. __alloc_items();
  68. // copy old items to new dict
  69. int i = old_head_idx;
  70. while(i != -1){
  71. set(vm, old_items[i].first, old_items[i].second);
  72. i = old_items[i].next;
  73. }
  74. std::free(old_items);
  75. }
  76. PyVar Dict::try_get(VM* vm, PyVar key) const{
  77. bool ok; int i;
  78. _probe_0(vm, key, ok, i);
  79. if(!ok) return nullptr;
  80. return _items[i].second;
  81. }
  82. bool Dict::contains(VM* vm, PyVar key) const{
  83. bool ok; int i;
  84. _probe_0(vm, key, ok, i);
  85. return ok;
  86. }
  87. bool Dict::del(VM* vm, PyVar key){
  88. bool ok; int i;
  89. _probe_0(vm, key, ok, i);
  90. if(!ok) return false;
  91. _items[i].first = nullptr;
  92. // _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
  93. _size--;
  94. if(_size == 0){
  95. _head_idx = -1;
  96. _tail_idx = -1;
  97. }else{
  98. if(_head_idx == i){
  99. _head_idx = _items[i].next;
  100. _items[_head_idx].prev = -1;
  101. }else if(_tail_idx == i){
  102. _tail_idx = _items[i].prev;
  103. _items[_tail_idx].next = -1;
  104. }else{
  105. _items[_items[i].prev].next = _items[i].next;
  106. _items[_items[i].next].prev = _items[i].prev;
  107. }
  108. }
  109. _items[i].prev = -1;
  110. _items[i].next = -1;
  111. return true;
  112. }
  113. void Dict::update(VM* vm, const Dict& other){
  114. other.apply([&](PyVar k, PyVar v){ set(vm, 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 = _items[i].next;
  123. }
  124. 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 = _items[i].next;
  134. }
  135. assert(j == _size);
  136. return t;
  137. }
  138. void Dict::clear(){
  139. _size = 0;
  140. _head_idx = -1;
  141. _tail_idx = -1;
  142. for(int i=0; i<_capacity; i++){
  143. _items[i].first = nullptr;
  144. _items[i].second = nullptr;
  145. _items[i].prev = -1;
  146. _items[i].next = -1;
  147. }
  148. }
  149. Dict::~Dict(){
  150. if(_items) std::free(_items);
  151. }
  152. } // namespace pkpy