1
0
blueloveTH 1 жил өмнө
parent
commit
8b2b8ab83a

+ 0 - 203
include/pocketpy/common/namedict.hpp

@@ -1,203 +0,0 @@
-#pragma once
-
-#include "pocketpy/common/utils.hpp"
-#include "pocketpy/common/str.hpp"
-#include "pocketpy/common/config.h"
-
-#include <stdexcept>
-
-namespace pkpy {
-
-template <typename T>
-constexpr T default_invalid_value() {
-    if constexpr(std::is_same_v<int, T>)
-        return -1;
-    else
-        return nullptr;
-}
-
-template <typename T>
-struct NameDictImpl {
-    PK_ALWAYS_PASS_BY_POINTER(NameDictImpl)
-
-    using Item = std::pair<StrName, T>;
-    constexpr static uint16_t kInitialCapacity = 16;
-    static_assert(is_pod_v<T>);
-
-    float _load_factor;
-    uint16_t _size;
-
-    uint16_t _capacity;
-    uint16_t _critical_size;
-    uint16_t _mask;
-
-    Item* _items;
-
-#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
-
-    NameDictImpl(float load_factor = PK_INST_ATTR_LOAD_FACTOR) : _load_factor(load_factor), _size(0) {
-        _set_capacity_and_alloc_items(kInitialCapacity);
-    }
-
-    ~NameDictImpl() { std::free(_items); }
-
-    uint16_t size() const { return _size; }
-
-    uint16_t capacity() const { return _capacity; }
-
-    void _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 set(StrName key, T 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 _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);
-    }
-
-    T try_get(StrName key) const {
-        bool ok;
-        uint16_t i;
-        HASH_PROBE_0(key, ok, i);
-        if(!ok) return default_invalid_value<T>();
-        return _items[i].second;
-    }
-
-    T* 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;
-    }
-
-    T 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);
-    }
-
-    T* 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 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;
-    }
-
-    template <typename __Func>
-    void apply(__Func func) const {
-        for(uint16_t i = 0; i < _capacity; i++) {
-            if(_items[i].first.empty()) continue;
-            func(_items[i].first, _items[i].second);
-        }
-    }
-
-    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_2_likely_found(key);
-        if(val == nullptr) { throw std::runtime_error(_S("NameDict key not found: ", key.escape()).str()); }
-        return *val;
-    }
-
-    array<StrName> keys() const {
-        array<StrName> 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<Item> items() const {
-        array<Item> v(_size);
-        int j = 0;
-        apply([&](StrName key, T val) {
-            new (&v[j++]) Item(key, val);
-        });
-        return v;
-    }
-
-    void clear() {
-        for(uint16_t i = 0; i < _capacity; i++) {
-            _items[i].first = StrName();
-            _items[i].second = nullptr;
-        }
-        _size = 0;
-    }
-
-#undef HASH_PROBE_0
-#undef HASH_PROBE_1
-};
-
-}  // namespace pkpy

+ 6 - 0
include/pocketpy/common/vector.hpp

@@ -431,6 +431,12 @@ struct small_map {
         return &it->second;
     }
 
+    V get(const K& key, V default_value) const {
+        static_assert(is_pod_v<V>);
+        auto it = try_get(key);
+        return it ? *it : default_value;
+    }
+
     bool contains(const K& key) const { return try_get(key) != nullptr; }
 
     void clear() { _data.clear(); }

+ 5 - 5
include/pocketpy/objects/codeobject.hpp

@@ -2,7 +2,7 @@
 
 #include "pocketpy/common/any.hpp"
 #include "pocketpy/objects/tuplelist.hpp"
-#include "pocketpy/objects/object.hpp"
+#include "pocketpy/objects/namedict.hpp"
 #include "pocketpy/objects/sourcedata.hpp"
 
 namespace pkpy {
@@ -89,9 +89,9 @@ struct CodeObject {
     small_vector_2<StrName, 8> varnames;  // local variables
     int nlocals;                          // varnames.size()
 
-    NameDictInt varnames_inv;
+    small_map<StrName, int> varnames_inv;
     vector<CodeBlock> blocks;
-    NameDictInt labels;
+    small_map<StrName, int> labels;
     vector<FuncDecl_> func_decls;
 
     int start_line;
@@ -131,10 +131,10 @@ struct FuncDecl {
 
     FuncType type = FuncType::UNSET;
 
-    NameDictInt kw_to_index;
+    small_map<StrName, int> kw_to_index;
 
     void add_kwarg(int index, StrName key, PyVar value) {
-        kw_to_index.set(key, index);
+        kw_to_index.insert(key, index);
         kwargs.push_back(KwArg{index, key, value});
     }
 

+ 64 - 0
include/pocketpy/objects/namedict.hpp

@@ -0,0 +1,64 @@
+#pragma once
+
+#include "pocketpy/common/config.h"
+#include "pocketpy/common/str.hpp"
+#include "pocketpy/common/utils.hpp"
+#include "pocketpy/objects/object.hpp"
+
+namespace pkpy {
+
+struct NameDict {
+    PK_ALWAYS_PASS_BY_POINTER(NameDict)
+
+    using Item = std::pair<StrName, PyVar>;
+    constexpr static uint16_t kInitialCapacity = 16;
+    static_assert(is_pod_v<PyVar>);
+
+    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() { std::free(_items); }
+
+    uint16_t size() const { return _size; }
+
+    uint16_t capacity() const { return _capacity; }
+
+    void _set_capacity_and_alloc_items(uint16_t val);
+
+    void set(StrName key, PyVar val);
+
+    void _rehash_2x();
+
+    PyVar try_get(StrName key) const;
+
+    PyVar* try_get_2(StrName key) const;
+
+    PyVar try_get_likely_found(StrName key) const;
+
+    PyVar* try_get_2_likely_found(StrName key) const;
+
+    bool del(StrName key);
+
+    bool contains(StrName key) const;
+    PyVar operator[] (StrName key) const;
+    array<StrName> keys() const;
+    array<Item> items() const;
+    void clear();
+
+    void apply(void (*f)(StrName, PyVar, void*), void* data);
+};
+
+static_assert(sizeof(NameDict) <= 128);
+using NameDict_ = std::shared_ptr<NameDict>;
+
+}  // namespace pkpy

+ 9 - 13
include/pocketpy/objects/object.hpp

@@ -1,14 +1,12 @@
 #pragma once
 
-#include "pocketpy/common/namedict.hpp"
+#include "pocketpy/common/str.hpp"
+#include "pocketpy/common/config.h"
 #include "pocketpy/objects/base.hpp"
 
 namespace pkpy {
-using NameDict = NameDictImpl<PyVar>;
-using NameDict_ = std::shared_ptr<NameDict>;
-using NameDictInt = NameDictImpl<int>;
 
-static_assert(sizeof(NameDict) <= 128);
+struct NameDict;
 
 struct PyObject final {
     bool gc_marked;   // whether this object is marked
@@ -30,13 +28,11 @@ struct PyObject final {
         return *_attr;
     }
 
-    PyVar attr(StrName name) const {
-        assert(is_attr_valid());
-        return (*_attr)[name];
-    }
-
     PyObject(Type type) : gc_marked(false), type(type), _attr(nullptr) {}
 
+    PyVar attr(StrName name) const;
+    static NameDict* __init_namedict(float lf);
+
     template <typename T, typename... Args>
     void placement_new(Args&&... args) {
         static_assert(std::is_same_v<T, std::decay_t<T>>);
@@ -44,11 +40,11 @@ struct PyObject final {
 
         // backdoor for important builtin types
         if constexpr(std::is_same_v<T, DummyInstance>) {
-            _attr = new NameDict();
+            _attr = __init_namedict(PK_INST_ATTR_LOAD_FACTOR);
         } else if constexpr(std::is_same_v<T, Type>) {
-            _attr = new NameDict(PK_TYPE_ATTR_LOAD_FACTOR);
+            _attr = __init_namedict(PK_TYPE_ATTR_LOAD_FACTOR);
         } else if constexpr(std::is_same_v<T, DummyModule>) {
-            _attr = new NameDict(PK_TYPE_ATTR_LOAD_FACTOR);
+            _attr = __init_namedict(PK_TYPE_ATTR_LOAD_FACTOR);
         }
     }
 };

+ 4 - 4
src/compiler/expr.cpp

@@ -99,18 +99,18 @@ void CodeEmitContext::patch_jump(int index) {
 
 bool CodeEmitContext::add_label(StrName name) {
     if(co->labels.contains(name)) return false;
-    co->labels.set(name, co->codes.size());
+    co->labels.insert(name, co->codes.size());
     return true;
 }
 
 int CodeEmitContext::add_varname(StrName name) {
     // PK_MAX_CO_VARNAMES will be checked when pop_context(), not here
-    int index = co->varnames_inv.try_get(name);
+    int index = co->varnames_inv.get(name, -1);
     if(index >= 0) return index;
     co->varnames.push_back(name);
     co->nlocals++;
     index = co->varnames.size() - 1;
-    co->varnames_inv.set(name, index);
+    co->varnames_inv.insert(name, index);
     return index;
 }
 
@@ -156,7 +156,7 @@ void CodeEmitContext::emit_store_name(NameScope scope, StrName name, int line) {
 }
 
 void NameExpr::emit_(CodeEmitContext* ctx) {
-    int index = ctx->co->varnames_inv.try_get(name);
+    int index = ctx->co->varnames_inv.get(name, -1);
     if(scope == NAME_LOCAL && index >= 0) {
         ctx->emit_(OP_LOAD_FAST, index, line);
     } else {

+ 1 - 1
src/interpreter/ceval.cpp

@@ -780,7 +780,7 @@ PyVar VM::__run_top_frame() {
                     case OP_JUMP_ABSOLUTE_TOP: DISPATCH_JUMP_ABSOLUTE(_CAST(int, POPX()))
                     case OP_GOTO: {
                         StrName _name(byte.arg);
-                        int target = frame->co->labels.try_get_likely_found(_name);
+                        int target = frame->co->labels.get(_name, -1);
                         if(target < 0) RuntimeError(_S("label ", _name.escape(), " not found"));
                         frame->prepare_jump_break(&s_data, target);
                         DISPATCH_JUMP_ABSOLUTE(target)

+ 3 - 3
src/interpreter/frame.cpp

@@ -5,17 +5,17 @@
 
 namespace pkpy {
 PyVar* FastLocals::try_get_name(StrName name) {
-    int index = co->varnames_inv.try_get(name);
+    int index = co->varnames_inv.get(name, -1);
     if(index == -1) return nullptr;
     return &a[index];
 }
 
 NameDict_ FastLocals::to_namedict() {
     NameDict_ dict = std::make_shared<NameDict>();
-    co->varnames_inv.apply([&](StrName name, int index) {
+    for(auto [name, index]: co->varnames_inv){
         PyVar value = a[index];
         if(value) dict->set(name, value);
-    });
+    }
     return dict;
 }
 

+ 11 - 9
src/interpreter/vm.cpp

@@ -437,9 +437,10 @@ void VM::__obj_gc_mark(PyObject* obj) {
     const PyTypeInfo* ti = _tp_info(obj->type);
     if(ti->vt._gc_mark) ti->vt._gc_mark(obj->_value_ptr(), this);
     if(obj->is_attr_valid()) {
-        obj->attr().apply([this](StrName _, PyVar obj) {
+        obj->attr().apply([](StrName _, PyVar obj, void* userdata) {
+            VM* vm = (VM*)userdata;
             if(obj.is_ptr) vm->__obj_gc_mark((obj).get());
-        });
+        }, vm);
     }
 }
 
@@ -602,16 +603,16 @@ PyVar VM::__py_exec_internal(const CodeObject_& code, PyVar globals, PyVar local
 
     if(globals_dict) {
         globals_dict->clear();
-        globals_obj->attr().apply([&](StrName k, PyVar v) {
+        for(auto [k, v]: globals_obj->attr().items()){
             globals_dict->set(vm, VAR(k.sv()), v);
-        });
+        }
     }
 
     if(locals_dict) {
         locals_dict->clear();
-        locals_closure->apply([&](StrName k, PyVar v) {
+        for(auto [k, v]: locals_closure->items()){
             locals_dict->set(vm, VAR(k.sv()), v);
-        });
+        }
     }
     return retval;
 }
@@ -1024,7 +1025,7 @@ void VM::__prepare_py_call(PyVar* buffer, ArgsView args, ArgsView kwargs, const
 
     for(int j = 0; j < kwargs.size(); j += 2) {
         StrName key(_CAST(uint16_t, kwargs[j]));
-        int index = decl->kw_to_index.try_get_likely_found(key);
+        int index = decl->kw_to_index.get(key, -1);
         // if key is an explicit key, set as local variable
         if(index >= 0) {
             buffer[index] = kwargs[j + 1];
@@ -1844,9 +1845,10 @@ void VM::__breakpoint() {
 void Function::_gc_mark(VM* vm) const {
     decl->_gc_mark(vm);
     if(_closure) {
-        _closure->apply([=](StrName _, PyVar obj) {
+        _closure->apply([](StrName _, PyVar obj, void* userdata) {
+            VM* vm = (VM*)userdata;
             vm->obj_gc_mark(obj);
-        });
+        }, vm);
     }
 }
 

+ 169 - 0
src/objects/namedict.cpp

@@ -0,0 +1,169 @@
+#include "pocketpy/objects/namedict.hpp"
+
+#include <stdexcept>
+
+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) { throw std::runtime_error(_S("NameDict key not found: ", key.escape()).str()); }
+    return *val;
+}
+
+array<StrName> NameDict::keys() const {
+    array<StrName> 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::Item> NameDict::items() const {
+    array<Item> 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];
+}
+
+NameDict* PyObject::__init_namedict(float lf) {
+    return new NameDict(lf);
+}
+
+}  // namespace pkpy