| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132 |
- #pragma once
- #include <array>
- #include <vector>
- #include <string>
- #include <cstdlib>
- #include <cstring>
- #include <cassert>
- #include <optional>
- #include <typeindex>
- #include <stdexcept>
- #include <unordered_map>
- #include "pocketpy.h"
- #include "type_traits.h"
- namespace pkbind {
- class handle;
- struct action {
- using function = void (*)();
- inline static std::vector<function> starts;
- static void initialize() noexcept {
- for(auto func: starts) {
- func();
- }
- }
- // register a function to be called at the start of the vm.
- static void register_start(function func) { starts.push_back(func); }
- };
- /// hold the object long time.
- struct object_pool {
- inline static int cache = -1;
- inline static py_Ref pool = nullptr;
- inline static std::vector<int>* indices_ = nullptr;
- struct object_ref {
- py_Ref data;
- int index;
- };
- static void initialize(int size) noexcept {
- // use 8th register.
- pool = py_getreg(7);
- py_newtuple(pool, size);
- indices_ = new std::vector<int>(size, 0);
- }
- static void finalize() noexcept {
- delete indices_;
- indices_ = nullptr;
- }
- /// alloc an object from pool, note that the object is uninitialized.
- static object_ref alloc() {
- if(!indices_) { initialize(1024); }
- auto& indices = *indices_;
- if(cache != -1) {
- auto index = cache;
- cache = -1;
- indices[index] = 1;
- return {py_tuple_getitem(pool, index), index};
- }
- for(int i = 0; i < indices.size(); ++i) {
- if(indices[i] == 0) {
- indices[i] = 1;
- return {py_tuple_getitem(pool, i), i};
- }
- }
- throw std::runtime_error("object pool is full");
- }
- /// alloc an object from pool, the object is initialized with ref.
- static object_ref realloc(py_Ref ref) {
- auto result = alloc();
- py_assign(result.data, ref);
- return result;
- }
- static void inc_ref(object_ref ref) {
- if(!indices_) { return; }
- if(ref.data == py_tuple_getitem(pool, ref.index)) {
- auto& indices = *indices_;
- indices[ref.index] += 1;
- } else {
- throw std::runtime_error("object_ref is invalid");
- }
- }
- static void dec_ref(object_ref ref) {
- if(!indices_) { return; }
- if(ref.data == py_tuple_getitem(pool, ref.index)) {
- auto& indices = *indices_;
- indices[ref.index] -= 1;
- assert(indices[ref.index] >= 0 && "ref count is negative");
- if(indices[ref.index] == 0) { cache = ref.index; }
- } else {
- throw std::runtime_error("object_ref is invalid");
- }
- }
- };
- template <typename T>
- class lazy {
- public:
- lazy(void (*init)(T&)) : init(init) {}
- operator T& () {
- if(!initialized) {
- if(init) { init(value); }
- initialized = true;
- }
- return value;
- }
- T& operator* () { return static_cast<T&>(*this); }
- void reset() { initialized = false; }
- private:
- T value;
- bool initialized = false;
- void (*init)(T&) = nullptr;
- };
- } // namespace pkbind
|