diff --git a/include/pocketpy/interpreter/gc.hpp b/include/pocketpy/interpreter/gc.hpp index 7cf64b2b..bfe640b4 100644 --- a/include/pocketpy/interpreter/gc.hpp +++ b/include/pocketpy/interpreter/gc.hpp @@ -50,11 +50,11 @@ struct ManagedHeap { // backdoor for important builtin types if constexpr(std::is_same_v<__T, DummyInstance>) { - p->_attr = new NameDict(PK_INST_ATTR_LOAD_FACTOR); + p->_attr = new NameDict(); } else if constexpr(std::is_same_v<__T, Type>) { - p->_attr = new NameDict(PK_TYPE_ATTR_LOAD_FACTOR); + p->_attr = new NameDict(); } else if constexpr(std::is_same_v<__T, DummyModule>) { - p->_attr = new NameDict(PK_TYPE_ATTR_LOAD_FACTOR); + p->_attr = new NameDict(); } return p; } diff --git a/include/pocketpy/objects/namedict.h b/include/pocketpy/objects/namedict.h new file mode 100644 index 00000000..45e87c2e --- /dev/null +++ b/include/pocketpy/objects/namedict.h @@ -0,0 +1,24 @@ +#pragma once + +#include "pocketpy/common/vector.h" +#include "pocketpy/common/str.h" +#include + +#include "pocketpy/objects/pyvar.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define SMALLMAP_T__HEADER +#define K uint16_t +#define V pkpy_Var +#define TAG n2v +#include "pocketpy/xmacros/smallmap.h" +#undef SMALLMAP_T__HEADER + +typedef c11_smallmap_n2v pkpy_NameDict; + +#ifdef __cplusplus +} +#endif diff --git a/include/pocketpy/objects/namedict.hpp b/include/pocketpy/objects/namedict.hpp index 3fe57948..466acf1a 100644 --- a/include/pocketpy/objects/namedict.hpp +++ b/include/pocketpy/objects/namedict.hpp @@ -4,58 +4,96 @@ #include "pocketpy/common/str.hpp" #include "pocketpy/common/utils.h" #include "pocketpy/objects/object.hpp" +#include "pocketpy/objects/namedict.h" namespace pkpy { -struct NameDict { +struct NameDict: pkpy_NameDict { PK_ALWAYS_PASS_BY_POINTER(NameDict) using Item = pair; - constexpr static uint16_t kInitialCapacity = 16; - - float _load_factor; - uint16_t _size; - - uint16_t _capacity; - uint16_t _critical_size; - uint16_t _mask; - - Item* _items; - - NameDict(float load_factor = PK_INST_ATTR_LOAD_FACTOR) : _load_factor(load_factor), _size(0) { - _set_capacity_and_alloc_items(kInitialCapacity); + NameDict() { + c11_smallmap_n2v__ctor(this); } - ~NameDict() { std::free(_items); } + ~NameDict() { + c11_smallmap_n2v__dtor(this); + } - uint16_t size() const { return _size; } + uint16_t size() const { + return count; + } - uint16_t capacity() const { return _capacity; } + void set(StrName key, PyVar val){ + pkpy_Var* p = (pkpy_Var*)&val; + c11_smallmap_n2v__set(this, key.index, *p); + } - void _set_capacity_and_alloc_items(uint16_t val); + PyVar try_get(StrName key) const{ + PyVar* p = try_get_2(key); + return p ? *p : nullptr; + } - void set(StrName key, PyVar val); + PyVar* try_get_2(StrName key) const{ + pkpy_Var* p = c11_smallmap_n2v__try_get(this, key.index); + return p ? (PyVar*)p : nullptr; + } - void _rehash_2x(); + PyVar try_get_likely_found(StrName key) const{ + return try_get(key); + } - PyVar try_get(StrName key) const; + PyVar* try_get_2_likely_found(StrName key) const{ + return try_get_2(key); + } - PyVar* try_get_2(StrName key) const; + bool del(StrName key){ + return c11_smallmap_n2v__del(this, key.index); + } - PyVar try_get_likely_found(StrName key) const; + bool contains(StrName key) const{ + return c11_smallmap_n2v__contains(this, key.index); + } - PyVar* try_get_2_likely_found(StrName key) const; + PyVar operator[] (StrName key) const{ + PyVar* val = try_get_2_likely_found(key); + if(val == nullptr){ + PK_FATAL_ERROR("NameDict key not found: %d (%s)\n", (int)key.index, key.escape().c_str()) + } + return *val; + } - bool del(StrName key); + void clear(){ + c11_smallmap_n2v__clear(this); + } - bool contains(StrName key) const; - PyVar operator[] (StrName key) const; - array keys() const; - array items() const; - void clear(); + array keys() const{ + array retval((int)size()); + for(int i=0; ikey); + } + return retval; + } - void apply(void (*f)(StrName, PyVar, void*), void* data); + array items() const{ + array retval((int)size()); + for(int i=0; ivalue; + retval[i] = Item(StrName(it->key), *p); + } + return retval; + } + + void apply(void (*f)(StrName, PyVar, void*), void* data){ + for(int i=0; ivalue; + f(StrName(it->key), *p, data); + } + } }; static_assert(sizeof(NameDict) <= 128); diff --git a/src/interpreter/vm.cpp b/src/interpreter/vm.cpp index 8804d6f8..7a5fa2f4 100644 --- a/src/interpreter/vm.cpp +++ b/src/interpreter/vm.cpp @@ -1796,6 +1796,13 @@ void VM::__breakpoint() { #endif } +/**************************************************************************/ + +PyVar PyObject::attr(StrName name) const { + assert(is_attr_valid()); + return (*_attr)[name]; +} + /**************************************************************************/ void Function::_gc_mark(VM* vm) const { decl->_gc_mark(vm); diff --git a/src/objects/namedict.c b/src/objects/namedict.c new file mode 100644 index 00000000..313330b8 --- /dev/null +++ b/src/objects/namedict.c @@ -0,0 +1,12 @@ +#include "pocketpy/common/vector.h" +#include "pocketpy/common/str.h" +#include + +#include "pocketpy/objects/pyvar.h" + +#define SMALLMAP_T__SOURCE +#define K uint16_t +#define V pkpy_Var +#define TAG n2v +#include "pocketpy/xmacros/smallmap.h" +#undef SMALLMAP_T__SOURCE diff --git a/src/objects/namedict.cpp b/src/objects/namedict.cpp deleted file mode 100644 index 5b475087..00000000 --- a/src/objects/namedict.cpp +++ /dev/null @@ -1,165 +0,0 @@ -#include "pocketpy/objects/namedict.hpp" - -namespace pkpy { - -#define HASH_PROBE_1(key, ok, i) \ - ok = false; \ - i = key.index & _mask; \ - while(!_items[i].first.empty()) { \ - if(_items[i].first == (key)) { \ - ok = true; \ - break; \ - } \ - i = (i + 1) & _mask; \ - } - -#define HASH_PROBE_0 HASH_PROBE_1 - -void NameDict::_set_capacity_and_alloc_items(uint16_t val) { - _capacity = val; - _critical_size = val * _load_factor; - _mask = val - 1; - - _items = (Item*)std::malloc(_capacity * sizeof(Item)); - std::memset(_items, 0, _capacity * sizeof(Item)); -} - -void NameDict::set(StrName key, PyVar val) { - bool ok; - uint16_t i; - HASH_PROBE_1(key, ok, i); - if(!ok) { - _size++; - if(_size > _critical_size) { - _rehash_2x(); - HASH_PROBE_1(key, ok, i); - } - _items[i].first = key; - } - _items[i].second = val; -} - -void NameDict::_rehash_2x() { - Item* old_items = _items; - uint16_t old_capacity = _capacity; - _set_capacity_and_alloc_items(_capacity * 2); - for(uint16_t i = 0; i < old_capacity; i++) { - if(old_items[i].first.empty()) continue; - bool ok; - uint16_t j; - HASH_PROBE_1(old_items[i].first, ok, j); - assert(!ok); - _items[j] = old_items[i]; - } - std::free(old_items); -} - -PyVar NameDict::try_get(StrName key) const { - bool ok; - uint16_t i; - HASH_PROBE_0(key, ok, i); - if(!ok) return nullptr; - return _items[i].second; -} - -PyVar* NameDict::try_get_2(StrName key) const { - bool ok; - uint16_t i; - HASH_PROBE_0(key, ok, i); - if(!ok) return nullptr; - return &_items[i].second; -} - -PyVar NameDict::try_get_likely_found(StrName key) const { - uint16_t i = key.index & _mask; - if(_items[i].first == key) return _items[i].second; - i = (i + 1) & _mask; - if(_items[i].first == key) return _items[i].second; - return try_get(key); -} - -PyVar* NameDict::try_get_2_likely_found(StrName key) const { - uint16_t i = key.index & _mask; - if(_items[i].first == key) return &_items[i].second; - i = (i + 1) & _mask; - if(_items[i].first == key) return &_items[i].second; - return try_get_2(key); -} - -bool NameDict::del(StrName key) { - bool ok; - uint16_t i; - HASH_PROBE_0(key, ok, i); - if(!ok) return false; - _items[i].first = StrName(); - _items[i].second = nullptr; - _size--; - // tidy - uint16_t pre_z = i; - uint16_t z = (i + 1) & _mask; - while(!_items[z].first.empty()) { - uint16_t h = _items[z].first.index & _mask; - if(h != i) break; - std::swap(_items[pre_z], _items[z]); - pre_z = z; - z = (z + 1) & _mask; - } - return true; -} - -bool NameDict::contains(StrName key) const { - bool ok; - uint16_t i; - HASH_PROBE_0(key, ok, i); - return ok; -} - -PyVar NameDict::operator[] (StrName key) const { - PyVar* val = try_get_2_likely_found(key); - if(val == nullptr){ - PK_FATAL_ERROR("NameDict key not found: %d (%s)\n", (int)key.index, key.escape().c_str()) - } - return *val; -} - -array NameDict::keys() const { - array v(_size); - int j = 0; - for(uint16_t i = 0; i < _capacity; i++) { - if(_items[i].first.empty()) continue; - new (&v[j++]) StrName(_items[i].first); - } - return v; -} - -array NameDict::items() const { - array v(_size); - int j = 0; - for(uint16_t i = 0; i < _capacity; i++) { - if(_items[i].first.empty()) continue; - new (&v[j++]) Item(_items[i].first, _items[i].second); - } - return v; -} - -void NameDict::clear() { - std::memset(_items, 0, _capacity * sizeof(Item)); - _size = 0; -} - -void NameDict::apply (void (*f)(StrName, PyVar, void*), void* data) { - for(uint16_t i = 0; i < _capacity; i++) { - if(_items[i].first.empty()) continue; - f(_items[i].first, _items[i].second, data); - } -} - -#undef HASH_PROBE_0 -#undef HASH_PROBE_1 - -PyVar PyObject::attr(StrName name) const { - assert(is_attr_valid()); - return (*_attr)[name]; -} - -} // namespace pkpy