diff --git a/include/pocketpy/namedict.h b/include/pocketpy/namedict.h index 941a4655..6eafc072 100644 --- a/include/pocketpy/namedict.h +++ b/include/pocketpy/namedict.h @@ -13,89 +13,6 @@ constexpr T default_invalid_value(){ else return Discarded(); } -#define PK_SMALL_NAME_DICT_CAPACITY 6 -#define PK_SMALL_NAME_DICT_LOOP(B) for(int i=0; i -struct SmallNameDict{ - using K = StrName; - static_assert(is_pod_v); - - bool _is_small; - uint16_t _size; - K _keys[PK_SMALL_NAME_DICT_CAPACITY]; - V _values[PK_SMALL_NAME_DICT_CAPACITY]; - - SmallNameDict(): _is_small(true), _size(0) {} - - bool try_set(K key, V val){ - PK_SMALL_NAME_DICT_LOOP( - if(_keys[i] == key){ _values[i] = val; return true; } - ) - - if(_size == PK_SMALL_NAME_DICT_CAPACITY) return false; - if(_keys[_size].empty()){ - _keys[_size] = key; - _values[_size] = val; - _size++; - return true; - } - - PK_SMALL_NAME_DICT_LOOP( - if(_keys[i].empty()){ - _keys[i] = key; - _values[i] = val; - _size++; - return true; - } - ) - PK_UNREACHABLE() - } - - V try_get(K key) const { - PK_SMALL_NAME_DICT_LOOP( - if(_keys[i] == key) return _values[i]; - ) - return default_invalid_value(); - } - - V* try_get_2(K key) { - PK_SMALL_NAME_DICT_LOOP( - if(_keys[i] == key) return &_values[i]; - ) - return nullptr; - } - - bool del(K key){ - PK_SMALL_NAME_DICT_LOOP( - if(_keys[i] == key){ _keys[i] = StrName(); _size--; return true; } - ) - return false; - } - - template - void apply(Func func) const { - PK_SMALL_NAME_DICT_LOOP( - if(!_keys[i].empty()) func(_keys[i], _values[i]); - ) - } - - void clear(){ - PK_SMALL_NAME_DICT_LOOP( - _keys[i] = StrName(); - ) - _size = 0; - } - - uint16_t size() const { return _size; } - uint16_t capacity() const { return PK_SMALL_NAME_DICT_CAPACITY; } -}; - template struct NameDictItem{ StrName first; @@ -103,14 +20,13 @@ struct NameDictItem{ }; template -struct LargeNameDict { - PK_ALWAYS_PASS_BY_POINTER(LargeNameDict) +struct NameDictImpl { + PK_ALWAYS_PASS_BY_POINTER(NameDictImpl) using Item = NameDictItem; - static constexpr uint16_t kInitialCapacity = 32; + static constexpr uint16_t kInitialCapacity = 16; static_assert(is_pod_v); - bool _is_small; float _load_factor; uint16_t _size; @@ -130,11 +46,11 @@ while(!_items[i].first.empty()) { \ #define HASH_PROBE_0 HASH_PROBE_1 - LargeNameDict(float load_factor=PK_INST_ATTR_LOAD_FACTOR): _is_small(false), _load_factor(load_factor), _size(0) { + NameDictImpl(float load_factor=PK_INST_ATTR_LOAD_FACTOR): _load_factor(load_factor), _size(0) { _set_capacity_and_alloc_items(kInitialCapacity); } - ~LargeNameDict(){ free(_items); } + ~NameDictImpl(){ free(_items); } uint16_t size() const { return _size; } uint16_t capacity() const { return _capacity; } @@ -234,6 +150,22 @@ while(!_items[i].first.empty()) { \ } } + bool contains(StrName key) const { + bool ok; uint16_t i; + HASH_PROBE_0(key, ok, i); + return ok; + } + + T operator[](StrName key) const { + T val = try_get_likely_found(key); +#if PK_DEBUG_EXTRA_CHECK + if(val == default_invalid_value()){ + throw std::runtime_error(_S("NameDict key not found: ", key.escape()).str()); + } +#endif + return val; + } + pod_vector keys() const { pod_vector v; for(uint16_t i=0; i<_capacity; i++){ @@ -243,6 +175,14 @@ while(!_items[i].first.empty()) { \ return v; } + pod_vector> items() const{ + pod_vector> v; + apply([&](StrName key, T val){ + v.push_back(NameDictItem{key, val}); + }); + return v; + } + void clear(){ for(uint16_t i=0; i<_capacity; i++){ _items[i].first = StrName(); @@ -254,90 +194,6 @@ while(!_items[i].first.empty()) { \ #undef HASH_PROBE_1 }; -template -struct NameDictImpl{ - PK_ALWAYS_PASS_BY_POINTER(NameDictImpl) - - union{ - SmallNameDict _small; - LargeNameDict _large; - }; - - NameDictImpl(): _small() {} - NameDictImpl(float load_factor): _large(load_factor) {} - - bool is_small() const{ - const bool* p = reinterpret_cast(this); - return *p; - } - - void set(StrName key, V val){ - if(is_small()){ - bool ok = _small.try_set(key, val); - if(!ok){ - SmallNameDict copied(_small); - // move to large name dict - new (&_large) LargeNameDict(); - copied.apply([&](StrName key, V val){ - _large.set(key, val); - }); - _large.set(key, val); - } - }else{ - _large.set(key, val); - } - } - - uint16_t size() const{ return is_small() ?_small.size() : _large.size(); } - uint16_t capacity() const{ return is_small() ?_small.capacity() : _large.capacity(); } - V try_get(StrName key) const { return is_small() ?_small.try_get(key) : _large.try_get(key); } - V* try_get_2(StrName key) { return is_small() ?_small.try_get_2(key) : _large.try_get_2(key); } - bool del(StrName key){ return is_small() ?_small.del(key) : _large.del(key); } - - V try_get_likely_found(StrName key) const { return is_small() ?_small.try_get(key) : _large.try_get_likely_found(key); } - V* try_get_2_likely_found(StrName key) { return is_small() ?_small.try_get_2(key) : _large.try_get_2_likely_found(key); } - - bool contains(StrName key) const { return try_get(key) != default_invalid_value(); } - - V operator[](StrName key) const { - V val = try_get_likely_found(key); - if(val == default_invalid_value()){ - throw std::runtime_error(_S("NameDict key not found: ", key.escape()).str()); - } - return val; - } - - void clear(){ - if(is_small()) _small.clear(); - else _large.clear(); - } - - template - void apply(Func func) const { - if(is_small()) _small.apply(func); - else _large.apply(func); - } - - pod_vector keys() const{ - pod_vector v; - apply([&](StrName key, V val){ - v.push_back(key); - }); - return v; - } - - pod_vector> items() const{ - pod_vector> v; - apply([&](StrName key, V val){ - v.push_back(NameDictItem{key, val}); - }); - return v; - } - - ~NameDictImpl(){ - if(!is_small()) _large.~LargeNameDict(); - } -}; using NameDict = NameDictImpl; using NameDict_ = std::shared_ptr; diff --git a/include/pocketpy/vm.h b/include/pocketpy/vm.h index a08933fa..d87ac92b 100644 --- a/include/pocketpy/vm.h +++ b/include/pocketpy/vm.h @@ -488,11 +488,11 @@ public: void __unpack_as_list(ArgsView args, List& list); void __unpack_as_dict(ArgsView args, Dict& dict); [[noreturn]] void __raise_exc(bool re_raise=false); - void __init_builtin_types(); - void __post_init_builtin_types(); [[noreturn]] void __builtin_error(StrName type); [[noreturn]] void __builtin_error(StrName type, PyVar arg); [[noreturn]] void __builtin_error(StrName type, const Str& msg); + void __init_builtin_types(); + void __post_init_builtin_types(); void __push_varargs(){} void __push_varargs(PyVar _0){ PUSH(_0); } void __push_varargs(PyVar _0, PyVar _1){ PUSH(_0); PUSH(_1); }