diff --git a/include/pocketpy/gc.h b/include/pocketpy/gc.h index ad79f8ca..4ba75f1d 100644 --- a/include/pocketpy/gc.h +++ b/include/pocketpy/gc.h @@ -41,7 +41,7 @@ struct ManagedHeap{ PyObject* gcnew(Type type, Args&&... args){ using __T = Py_>; // https://github.com/blueloveTH/pocketpy/issues/94#issuecomment-1594784476 - PyObject* obj = new(pool64.alloc<__T>()) Py_>(type, std::forward(args)...); + PyObject* obj = new(pool64_alloc<__T>()) Py_>(type, std::forward(args)...); gen.push_back(obj); gc_counter++; return obj; @@ -51,7 +51,7 @@ struct ManagedHeap{ PyObject* _new(Type type, Args&&... args){ using __T = Py_>; // https://github.com/blueloveTH/pocketpy/issues/94#issuecomment-1594784476 - PyObject* obj = new(pool64.alloc<__T>()) Py_>(type, std::forward(args)...); + PyObject* obj = new(pool64_alloc<__T>()) Py_>(type, std::forward(args)...); obj->gc.enabled = false; _no_gc.push_back(obj); return obj; diff --git a/include/pocketpy/memory.h b/include/pocketpy/memory.h index 53a384f3..befe63b4 100644 --- a/include/pocketpy/memory.h +++ b/include/pocketpy/memory.h @@ -4,249 +4,20 @@ namespace pkpy{ -struct LinkedListNode{ - LinkedListNode* prev; - LinkedListNode* next; -}; +void* pool64_alloc(size_t); +void pool64_dealloc(void*); + +void* pool128_alloc(size_t); +void pool128_dealloc(void*); template -struct DoubleLinkedList{ - static_assert(std::is_base_of_v); - int _size; - LinkedListNode head; - LinkedListNode tail; - - DoubleLinkedList(): _size(0){ - head.prev = nullptr; - head.next = &tail; - tail.prev = &head; - tail.next = nullptr; - } +void* pool64_alloc(){ + return pool64_alloc(sizeof(T)); +} - void push_back(T* node){ - node->prev = tail.prev; - node->next = &tail; - tail.prev->next = node; - tail.prev = node; - _size++; - } - - void push_front(T* node){ - node->prev = &head; - node->next = head.next; - head.next->prev = node; - head.next = node; - _size++; - } - - void pop_back(){ -#if PK_DEBUG_MEMORY_POOL - if(empty()) throw std::runtime_error("DoubleLinkedList::pop_back() called on empty list"); -#endif - tail.prev->prev->next = &tail; - tail.prev = tail.prev->prev; - _size--; - } - - void pop_front(){ -#if PK_DEBUG_MEMORY_POOL - if(empty()) throw std::runtime_error("DoubleLinkedList::pop_front() called on empty list"); -#endif - head.next->next->prev = &head; - head.next = head.next->next; - _size--; - } - - T* back() const { -#if PK_DEBUG_MEMORY_POOL - if(empty()) throw std::runtime_error("DoubleLinkedList::back() called on empty list"); -#endif - return static_cast(tail.prev); - } - - T* front() const { -#if PK_DEBUG_MEMORY_POOL - if(empty()) throw std::runtime_error("DoubleLinkedList::front() called on empty list"); -#endif - return static_cast(head.next); - } - - void erase(T* node){ -#if PK_DEBUG_MEMORY_POOL - if(empty()) throw std::runtime_error("DoubleLinkedList::erase() called on empty list"); - LinkedListNode* n = head.next; - while(n != &tail){ - if(n == node) break; - n = n->next; - } - if(n != node) throw std::runtime_error("DoubleLinkedList::erase() called on node not in the list"); -#endif - node->prev->next = node->next; - node->next->prev = node->prev; - _size--; - } - - // void move_all_back(DoubleLinkedList& other){ - // if(other.empty()) return; - // other.tail.prev->next = &tail; - // tail.prev->next = other.head.next; - // other.head.next->prev = tail.prev; - // tail.prev = other.tail.prev; - // _size += other._size; - // other.head.next = &other.tail; - // other.tail.prev = &other.head; - // other._size = 0; - // } - - bool empty() const { -#if PK_DEBUG_MEMORY_POOL - if(size() == 0){ - if(head.next != &tail || tail.prev != &head){ - throw std::runtime_error("DoubleLinkedList::size() returned 0 but the list is not empty"); - } - return true; - } -#endif - return _size == 0; - } - - int size() const { return _size; } - - template - void apply(Func func){ - LinkedListNode* p = head.next; - while(p != &tail){ - LinkedListNode* next = p->next; - func(static_cast(p)); - p = next; - } - } -}; - -template -struct MemoryPool{ - static const size_t __MaxBlocks = 256*1024 / __BlockSize; - struct Block{ - void* arena; - char data[__BlockSize]; - }; - - struct Arena: LinkedListNode{ - Block _blocks[__MaxBlocks]; - Block* _free_list[__MaxBlocks]; - int _free_list_size; - bool dirty; - - Arena(): _free_list_size(__MaxBlocks), dirty(false){ - for(int i=0; i<__MaxBlocks; i++){ - _blocks[i].arena = this; - _free_list[i] = &_blocks[i]; - } - } - - bool empty() const { return _free_list_size == 0; } - bool full() const { return _free_list_size == __MaxBlocks; } - - size_t allocated_size() const{ - return __BlockSize * (__MaxBlocks - _free_list_size); - } - - Block* alloc(){ -#if PK_DEBUG_MEMORY_POOL - if(empty()) throw std::runtime_error("Arena::alloc() called on empty arena"); -#endif - _free_list_size--; - return _free_list[_free_list_size]; - } - - void dealloc(Block* block){ -#if PK_DEBUG_MEMORY_POOL - if(full()) throw std::runtime_error("Arena::dealloc() called on full arena"); -#endif - _free_list[_free_list_size] = block; - _free_list_size++; - } - }; - - MemoryPool() = default; - MemoryPool(const MemoryPool&) = delete; - MemoryPool& operator=(const MemoryPool&) = delete; - MemoryPool(MemoryPool&&) = delete; - MemoryPool& operator=(MemoryPool&&) = delete; - - DoubleLinkedList _arenas; - DoubleLinkedList _empty_arenas; - - template - void* alloc() { return alloc(sizeof(__T)); } - - void* alloc(size_t size){ - PK_GLOBAL_SCOPE_LOCK(); -#if PK_DEBUG_NO_MEMORY_POOL - return malloc(size); -#endif - if(size > __BlockSize){ - void* p = malloc(sizeof(void*) + size); - memset(p, 0, sizeof(void*)); - return (char*)p + sizeof(void*); - } - - if(_arenas.empty()){ - // std::cout << _arenas.size() << ',' << _empty_arenas.size() << ',' << _full_arenas.size() << std::endl; - _arenas.push_back(new Arena()); - } - Arena* arena = _arenas.back(); - void* p = arena->alloc()->data; - if(arena->empty()){ - _arenas.pop_back(); - arena->dirty = true; - _empty_arenas.push_back(arena); - } - return p; - } - - void dealloc(void* p){ - PK_GLOBAL_SCOPE_LOCK(); -#if PK_DEBUG_NO_MEMORY_POOL - free(p); - return; -#endif -#if PK_DEBUG_MEMORY_POOL - if(p == nullptr) throw std::runtime_error("MemoryPool::dealloc() called on nullptr"); -#endif - Block* block = (Block*)((char*)p - sizeof(void*)); - if(block->arena == nullptr){ - free(block); - }else{ - Arena* arena = (Arena*)block->arena; - if(arena->empty()){ - _empty_arenas.erase(arena); - _arenas.push_front(arena); - arena->dealloc(block); - }else{ - arena->dealloc(block); - if(arena->full() && arena->dirty){ - _arenas.erase(arena); - delete arena; - } - } - } - } - - size_t allocated_size() { - size_t n = 0; - _arenas.apply([&n](Arena* arena){ n += arena->allocated_size(); }); - _empty_arenas.apply([&n](Arena* arena){ n += arena->allocated_size(); }); - return n; - } - - ~MemoryPool(){ - _arenas.apply([](Arena* arena){ delete arena; }); - _empty_arenas.apply([](Arena* arena){ delete arena; }); - } -}; - -inline MemoryPool<64> pool64; -inline MemoryPool<128> pool128; +template +void* pool128_alloc(){ + return pool128_alloc(sizeof(T)); +} }; // namespace pkpy diff --git a/include/pocketpy/namedict.h b/include/pocketpy/namedict.h index 32958510..8a61cde9 100644 --- a/include/pocketpy/namedict.h +++ b/include/pocketpy/namedict.h @@ -38,7 +38,7 @@ while(!_items[i].first.empty()) { \ } #define NAMEDICT_ALLOC() \ - _items = (Item*)pool128.alloc(_capacity * sizeof(Item)); \ + _items = (Item*)pool128_alloc(_capacity * sizeof(Item)); \ memset(_items, 0, _capacity * sizeof(Item)); \ NameDictImpl(float load_factor=0.67f): @@ -54,14 +54,14 @@ while(!_items[i].first.empty()) { \ } NameDictImpl& operator=(const NameDictImpl& other) { - pool128.dealloc(_items); + pool128_dealloc(_items); memcpy(this, &other, sizeof(NameDictImpl)); NAMEDICT_ALLOC() for(int i=0; i<_capacity; i++) _items[i] = other._items[i]; return *this; } - ~NameDictImpl(){ pool128.dealloc(_items); } + ~NameDictImpl(){ pool128_dealloc(_items); } NameDictImpl(NameDictImpl&&) = delete; NameDictImpl& operator=(NameDictImpl&&) = delete; @@ -103,7 +103,7 @@ while(!_items[i].first.empty()) { \ if(ok) FATAL_ERROR(); _items[j] = old_items[i]; } - pool128.dealloc(old_items); + pool128_dealloc(old_items); } void _try_perfect_rehash(){ diff --git a/include/pocketpy/obj.h b/include/pocketpy/obj.h index b59871f5..bbe89617 100644 --- a/include/pocketpy/obj.h +++ b/include/pocketpy/obj.h @@ -119,7 +119,7 @@ struct PyObject{ virtual ~PyObject(); void enable_instance_dict(float lf=kInstAttrLoadFactor) { - _attr = new(pool64.alloc()) NameDict(lf); + _attr = new(pool64_alloc()) NameDict(lf); } }; diff --git a/include/pocketpy/vector.h b/include/pocketpy/vector.h index 6715374d..32b824a7 100644 --- a/include/pocketpy/vector.h +++ b/include/pocketpy/vector.h @@ -16,15 +16,15 @@ struct pod_vector{ T* _data; pod_vector(): _size(0), _capacity(N) { - _data = (T*)pool64.alloc(_capacity * sizeof(T)); + _data = (T*)pool64_alloc(_capacity * sizeof(T)); } pod_vector(int size): _size(size), _capacity(std::max(N, size)) { - _data = (T*)pool64.alloc(_capacity * sizeof(T)); + _data = (T*)pool64_alloc(_capacity * sizeof(T)); } pod_vector(const pod_vector& other): _size(other._size), _capacity(other._capacity) { - _data = (T*)pool64.alloc(_capacity * sizeof(T)); + _data = (T*)pool64_alloc(_capacity * sizeof(T)); memcpy(_data, other._data, sizeof(T) * _size); } @@ -36,7 +36,7 @@ struct pod_vector{ } pod_vector& operator=(pod_vector&& other) noexcept { - if(_data!=nullptr) pool64.dealloc(_data); + if(_data!=nullptr) pool64_dealloc(_data); _size = other._size; _capacity = other._capacity; _data = other._data; @@ -63,10 +63,10 @@ struct pod_vector{ if(cap <= _capacity) return; _capacity = cap; T* old_data = _data; - _data = (T*)pool64.alloc(_capacity * sizeof(T)); + _data = (T*)pool64_alloc(_capacity * sizeof(T)); if(old_data!=nullptr){ memcpy(_data, old_data, sizeof(T) * _size); - pool64.dealloc(old_data); + pool64_dealloc(old_data); } } @@ -115,7 +115,7 @@ struct pod_vector{ } ~pod_vector() { - if(_data!=nullptr) pool64.dealloc(_data); + if(_data!=nullptr) pool64_dealloc(_data); } }; diff --git a/src/dict.cpp b/src/dict.cpp index 905c0209..95f3dffe 100644 --- a/src/dict.cpp +++ b/src/dict.cpp @@ -5,9 +5,9 @@ namespace pkpy{ Dict::Dict(VM* vm): vm(vm), _capacity(__Capacity), _mask(__Capacity-1), _size(0), _critical_size(__Capacity*__LoadFactor+0.5f), _head_idx(-1), _tail_idx(-1){ - _items = (Item*)pool128.alloc(_capacity * sizeof(Item)); + _items = (Item*)pool128_alloc(_capacity * sizeof(Item)); memset(_items, 0, _capacity * sizeof(Item)); - _nodes = (ItemNode*)pool64.alloc(_capacity * sizeof(ItemNode)); + _nodes = (ItemNode*)pool64_alloc(_capacity * sizeof(ItemNode)); memset(_nodes, -1, _capacity * sizeof(ItemNode)); } @@ -33,9 +33,9 @@ namespace pkpy{ _critical_size = other._critical_size; _head_idx = other._head_idx; _tail_idx = other._tail_idx; - _items = (Item*)pool128.alloc(_capacity * sizeof(Item)); + _items = (Item*)pool128_alloc(_capacity * sizeof(Item)); memcpy(_items, other._items, _capacity * sizeof(Item)); - _nodes = (ItemNode*)pool64.alloc(_capacity * sizeof(ItemNode)); + _nodes = (ItemNode*)pool64_alloc(_capacity * sizeof(ItemNode)); memcpy(_nodes, other._nodes, _capacity * sizeof(ItemNode)); } @@ -73,9 +73,9 @@ namespace pkpy{ _head_idx = -1; _tail_idx = -1; - _items = (Item*)pool128.alloc(_capacity * sizeof(Item)); + _items = (Item*)pool128_alloc(_capacity * sizeof(Item)); memset(_items, 0, _capacity * sizeof(Item)); - _nodes = (ItemNode*)pool64.alloc(_capacity * sizeof(ItemNode)); + _nodes = (ItemNode*)pool64_alloc(_capacity * sizeof(ItemNode)); memset(_nodes, -1, _capacity * sizeof(ItemNode)); // copy old items to new dict @@ -84,8 +84,8 @@ namespace pkpy{ set(old_items[i].first, old_items[i].second); i = old_nodes[i].next; } - pool128.dealloc(old_items); - pool64.dealloc(old_nodes); + pool128_dealloc(old_items); + pool64_dealloc(old_nodes); } @@ -167,8 +167,8 @@ namespace pkpy{ Dict::~Dict(){ if(_items==nullptr) return; - pool128.dealloc(_items); - pool64.dealloc(_nodes); + pool128_dealloc(_items); + pool64_dealloc(_nodes); } void Dict::_gc_mark() const{ diff --git a/src/gc.cpp b/src/gc.cpp index 9fac2e8e..d68e3998 100644 --- a/src/gc.cpp +++ b/src/gc.cpp @@ -14,7 +14,7 @@ namespace pkpy{ #endif if(_gc_on_delete) _gc_on_delete(vm, obj); obj->~PyObject(); - pool64.dealloc(obj); + pool64_dealloc(obj); } } @@ -47,8 +47,8 @@ namespace pkpy{ } ManagedHeap::~ManagedHeap(){ - for(PyObject* obj: _no_gc) { obj->~PyObject(); pool64.dealloc(obj); } - for(PyObject* obj: gen) { obj->~PyObject(); pool64.dealloc(obj); } + for(PyObject* obj: _no_gc) { obj->~PyObject(); pool64_dealloc(obj); } + for(PyObject* obj: gen) { obj->~PyObject(); pool64_dealloc(obj); } #if PK_DEBUG_GC_STATS for(auto& [type, count]: deleted){ std::cout << "GC: " << obj_type_name(vm, type) << "=" << count << std::endl; diff --git a/src/memory.cpp b/src/memory.cpp new file mode 100644 index 00000000..09f73dd8 --- /dev/null +++ b/src/memory.cpp @@ -0,0 +1,253 @@ +#include "pocketpy/memory.h" + +namespace pkpy{ + +struct LinkedListNode{ + LinkedListNode* prev; + LinkedListNode* next; +}; + +template +struct DoubleLinkedList{ + static_assert(std::is_base_of_v); + int _size; + LinkedListNode head; + LinkedListNode tail; + + DoubleLinkedList(): _size(0){ + head.prev = nullptr; + head.next = &tail; + tail.prev = &head; + tail.next = nullptr; + } + + void push_back(T* node){ + node->prev = tail.prev; + node->next = &tail; + tail.prev->next = node; + tail.prev = node; + _size++; + } + + void push_front(T* node){ + node->prev = &head; + node->next = head.next; + head.next->prev = node; + head.next = node; + _size++; + } + + void pop_back(){ +#if PK_DEBUG_MEMORY_POOL + if(empty()) throw std::runtime_error("DoubleLinkedList::pop_back() called on empty list"); +#endif + tail.prev->prev->next = &tail; + tail.prev = tail.prev->prev; + _size--; + } + + void pop_front(){ +#if PK_DEBUG_MEMORY_POOL + if(empty()) throw std::runtime_error("DoubleLinkedList::pop_front() called on empty list"); +#endif + head.next->next->prev = &head; + head.next = head.next->next; + _size--; + } + + T* back() const { +#if PK_DEBUG_MEMORY_POOL + if(empty()) throw std::runtime_error("DoubleLinkedList::back() called on empty list"); +#endif + return static_cast(tail.prev); + } + + T* front() const { +#if PK_DEBUG_MEMORY_POOL + if(empty()) throw std::runtime_error("DoubleLinkedList::front() called on empty list"); +#endif + return static_cast(head.next); + } + + void erase(T* node){ +#if PK_DEBUG_MEMORY_POOL + if(empty()) throw std::runtime_error("DoubleLinkedList::erase() called on empty list"); + LinkedListNode* n = head.next; + while(n != &tail){ + if(n == node) break; + n = n->next; + } + if(n != node) throw std::runtime_error("DoubleLinkedList::erase() called on node not in the list"); +#endif + node->prev->next = node->next; + node->next->prev = node->prev; + _size--; + } + + // void move_all_back(DoubleLinkedList& other){ + // if(other.empty()) return; + // other.tail.prev->next = &tail; + // tail.prev->next = other.head.next; + // other.head.next->prev = tail.prev; + // tail.prev = other.tail.prev; + // _size += other._size; + // other.head.next = &other.tail; + // other.tail.prev = &other.head; + // other._size = 0; + // } + + bool empty() const { +#if PK_DEBUG_MEMORY_POOL + if(size() == 0){ + if(head.next != &tail || tail.prev != &head){ + throw std::runtime_error("DoubleLinkedList::size() returned 0 but the list is not empty"); + } + return true; + } +#endif + return _size == 0; + } + + int size() const { return _size; } + + template + void apply(Func func){ + LinkedListNode* p = head.next; + while(p != &tail){ + LinkedListNode* next = p->next; + func(static_cast(p)); + p = next; + } + } +}; + +template +struct MemoryPool{ + static const size_t __MaxBlocks = 256*1024 / __BlockSize; + struct Block{ + void* arena; + char data[__BlockSize]; + }; + + struct Arena: LinkedListNode{ + Block _blocks[__MaxBlocks]; + Block* _free_list[__MaxBlocks]; + int _free_list_size; + bool dirty; + + Arena(): _free_list_size(__MaxBlocks), dirty(false){ + for(int i=0; i<__MaxBlocks; i++){ + _blocks[i].arena = this; + _free_list[i] = &_blocks[i]; + } + } + + bool empty() const { return _free_list_size == 0; } + bool full() const { return _free_list_size == __MaxBlocks; } + + size_t allocated_size() const{ + return __BlockSize * (__MaxBlocks - _free_list_size); + } + + Block* alloc(){ +#if PK_DEBUG_MEMORY_POOL + if(empty()) throw std::runtime_error("Arena::alloc() called on empty arena"); +#endif + _free_list_size--; + return _free_list[_free_list_size]; + } + + void dealloc(Block* block){ +#if PK_DEBUG_MEMORY_POOL + if(full()) throw std::runtime_error("Arena::dealloc() called on full arena"); +#endif + _free_list[_free_list_size] = block; + _free_list_size++; + } + }; + + MemoryPool() = default; + MemoryPool(const MemoryPool&) = delete; + MemoryPool& operator=(const MemoryPool&) = delete; + MemoryPool(MemoryPool&&) = delete; + MemoryPool& operator=(MemoryPool&&) = delete; + + DoubleLinkedList _arenas; + DoubleLinkedList _empty_arenas; + + void* alloc(size_t size){ + PK_GLOBAL_SCOPE_LOCK(); +#if PK_DEBUG_NO_MEMORY_POOL + return malloc(size); +#endif + if(size > __BlockSize){ + void* p = malloc(sizeof(void*) + size); + memset(p, 0, sizeof(void*)); + return (char*)p + sizeof(void*); + } + + if(_arenas.empty()){ + // std::cout << _arenas.size() << ',' << _empty_arenas.size() << ',' << _full_arenas.size() << std::endl; + _arenas.push_back(new Arena()); + } + Arena* arena = _arenas.back(); + void* p = arena->alloc()->data; + if(arena->empty()){ + _arenas.pop_back(); + arena->dirty = true; + _empty_arenas.push_back(arena); + } + return p; + } + + void dealloc(void* p){ + PK_GLOBAL_SCOPE_LOCK(); +#if PK_DEBUG_NO_MEMORY_POOL + free(p); + return; +#endif +#if PK_DEBUG_MEMORY_POOL + if(p == nullptr) throw std::runtime_error("MemoryPool::dealloc() called on nullptr"); +#endif + Block* block = (Block*)((char*)p - sizeof(void*)); + if(block->arena == nullptr){ + free(block); + }else{ + Arena* arena = (Arena*)block->arena; + if(arena->empty()){ + _empty_arenas.erase(arena); + _arenas.push_front(arena); + arena->dealloc(block); + }else{ + arena->dealloc(block); + if(arena->full() && arena->dirty){ + _arenas.erase(arena); + delete arena; + } + } + } + } + + // size_t allocated_size() { + // size_t n = 0; + // _arenas.apply([&n](Arena* arena){ n += arena->allocated_size(); }); + // _empty_arenas.apply([&n](Arena* arena){ n += arena->allocated_size(); }); + // return n; + // } + + ~MemoryPool(){ + _arenas.apply([](Arena* arena){ delete arena; }); + _empty_arenas.apply([](Arena* arena){ delete arena; }); + } +}; + +static MemoryPool<64> pool64; +static MemoryPool<128> pool128; + +void* pool64_alloc(size_t size){ return pool64.alloc(size); } +void pool64_dealloc(void* p){ pool64.dealloc(p); } + +void* pool128_alloc(size_t size){ return pool128.alloc(size); } +void pool128_dealloc(void* p){ pool128.dealloc(p); } + +} \ No newline at end of file diff --git a/src/obj.cpp b/src/obj.cpp index 8cb04ab1..c67d9d29 100644 --- a/src/obj.cpp +++ b/src/obj.cpp @@ -4,6 +4,6 @@ namespace pkpy{ PyObject::~PyObject() { if(_attr == nullptr) return; _attr->~NameDict(); - pool64.dealloc(_attr); + pool64_dealloc(_attr); } } // namespace pkpy \ No newline at end of file diff --git a/src/str.cpp b/src/str.cpp index ab8a254b..be2a72b7 100644 --- a/src/str.cpp +++ b/src/str.cpp @@ -75,12 +75,12 @@ int utf8len(unsigned char c, bool suppress){ if(size <= 16){ this->data = _inlined; }else{ - this->data = (char*)pool64.alloc(size); + this->data = (char*)pool64_alloc(size); } } Str& Str::operator=(const Str& other){ - if(!is_inlined()) pool64.dealloc(data); + if(!is_inlined()) pool64_dealloc(data); size = other.size; is_ascii = other.is_ascii; _cached_c_str = nullptr; @@ -150,7 +150,7 @@ int utf8len(unsigned char c, bool suppress){ } Str::~Str(){ - if(!is_inlined()) pool64.dealloc(data); + if(!is_inlined()) pool64_dealloc(data); if(_cached_c_str != nullptr) free((void*)_cached_c_str); } diff --git a/src/tuplelist.cpp b/src/tuplelist.cpp index 515b171c..2dec9c8f 100644 --- a/src/tuplelist.cpp +++ b/src/tuplelist.cpp @@ -6,7 +6,7 @@ Tuple::Tuple(int n){ if(n <= 3){ this->_args = _inlined; }else{ - this->_args = (PyObject**)pool64.alloc(n * sizeof(void*)); + this->_args = (PyObject**)pool64_alloc(n * sizeof(void*)); } this->_size = n; } @@ -38,7 +38,7 @@ Tuple::Tuple(std::initializer_list list): Tuple(list.size()){ for(PyObject* obj: list) _args[i++] = obj; } -Tuple::~Tuple(){ if(!is_inlined()) pool64.dealloc(_args); } +Tuple::~Tuple(){ if(!is_inlined()) pool64_dealloc(_args); } List ArgsView::to_list() const{ List ret(size());