#pragma once #include "value.hpp" #include #include #include #include #include #include #include namespace sliger::heap { struct Array { std::vector values; }; struct Struct { std::unordered_map fields; }; enum class AllocType { Value, Array, Struct, }; // clang-format off template struct AllocTypeType {}; template <> struct AllocTypeType { using Type = Value; }; template <> struct AllocTypeType { using Type = Array; }; template <> struct AllocTypeType { using Type = Struct; }; // clang-format on struct AllocItem { template inline auto as() & -> AllocTypeType::Type& { return std::get::Type>(this->value); } template inline auto as() const& -> const AllocTypeType::Type& { return std::get::Type>(this->value); } template inline auto as() && -> AllocTypeType::Type&& { return std::move( std::get::Type>(this->value)); } template inline auto as() const&& -> const AllocTypeType::Type&& { return std::move( std::get::Type>(this->value)); } AllocType type; std::variant value; }; enum class ErrType { InvalidPtrAccess, CannotAllocate, }; template struct Res { Res(T val) : val(std::forward(val)) { } Res(ErrType err) : err(err) { } std::optional val; std::optional err; }; class Heap { public: inline auto can_allocate() const -> bool { return this->sel->size() < this->max_size; } inline void collect(const std::vector& ptr_stack_values) { this->other->reserve(this->max_size); for (auto ptr : ptr_stack_values) { move_item_to_other(ptr); } this->sel->clear(); std::swap(this->sel, this->other); if (this->sel->size() + 1 >= this->max_size) { this->max_size *= 2; this->sel->reserve(this->max_size); } else if (this->sel->size() * 2 < this->max_size) { this->max_size /= 2; this->sel->shrink_to_fit(); this->sel->reserve(this->max_size); } } inline auto at(uint32_t ptr) -> Res { if (ptr >= this->sel->size()) { return ErrType::InvalidPtrAccess; } return &this->sel->at(ptr); } template auto alloc() -> Res { if (not can_allocate()) { return ErrType::CannotAllocate; } auto ptr = static_cast(this->sel->size()); this->sel->push_back(typename AllocTypeType::Type {}); return ptr; } private: inline void move_item_to_other(uint32_t ptr) { auto res = at(ptr); if (!res.val.has_value()) return; auto val = res.val.value(); switch (val->type) { case AllocType::Value: { auto& v = val->as(); if (v.type() == ValueType::Ptr) { move_item_to_other(v.template as().value); } break; } case AllocType::Array: { auto& vs = val->as(); for (auto& v : vs.values) { if (v.type() == ValueType::Ptr) { move_item_to_other( v.template as().value); } } break; } case AllocType::Struct: { auto& vs = val->as(); for (auto& [key, v] : vs.fields) { if (v.type() == ValueType::Ptr) { move_item_to_other( v.template as().value); } } break; } } } size_t max_size = 4; std::vector heap_1; std::vector heap_2; std::vector* sel = &heap_1; std::vector* other = &heap_2; }; }