2024-11-26 13:32:21 +00:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include "value.hpp"
|
|
|
|
#include <cstddef>
|
|
|
|
#include <cstdint>
|
|
|
|
#include <optional>
|
|
|
|
#include <string>
|
|
|
|
#include <unordered_map>
|
|
|
|
#include <variant>
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
namespace sliger::heap {
|
|
|
|
|
|
|
|
struct Array {
|
|
|
|
std::vector<Value> values;
|
2024-12-13 15:16:11 +00:00
|
|
|
|
|
|
|
auto at(int32_t index) & -> Value&;
|
2024-11-26 13:32:21 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct Struct {
|
|
|
|
std::unordered_map<std::string, Value> fields;
|
2024-12-31 02:38:38 +00:00
|
|
|
|
|
|
|
auto at(const std::string&) & -> Value&;
|
|
|
|
void assign(const std::string&, Value&& value);
|
2024-11-26 13:32:21 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
enum class AllocType {
|
|
|
|
Value,
|
|
|
|
Array,
|
|
|
|
Struct,
|
|
|
|
};
|
|
|
|
|
|
|
|
// clang-format off
|
|
|
|
template <AllocType type> struct AllocTypeType {};
|
|
|
|
template <> struct AllocTypeType<AllocType::Value> { using Type = Value; };
|
|
|
|
template <> struct AllocTypeType<AllocType::Array> { using Type = Array; };
|
|
|
|
template <> struct AllocTypeType<AllocType::Struct> { using Type = Struct; };
|
|
|
|
// clang-format on
|
|
|
|
|
|
|
|
struct AllocItem {
|
2024-12-13 15:16:11 +00:00
|
|
|
AllocItem(Value&& val)
|
|
|
|
: type(AllocType::Value)
|
|
|
|
, value(val)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
AllocItem(Array&& val)
|
|
|
|
: type(AllocType::Array)
|
|
|
|
, value(val)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
AllocItem(Struct&& val)
|
|
|
|
: type(AllocType::Struct)
|
|
|
|
, value(val)
|
|
|
|
{
|
|
|
|
}
|
2024-12-12 15:07:59 +00:00
|
|
|
|
2024-11-26 13:32:21 +00:00
|
|
|
template <AllocType AT> inline auto as() & -> AllocTypeType<AT>::Type&
|
|
|
|
{
|
|
|
|
return std::get<typename AllocTypeType<AT>::Type>(this->value);
|
|
|
|
}
|
|
|
|
template <AllocType AT>
|
|
|
|
inline auto as() const& -> const AllocTypeType<AT>::Type&
|
|
|
|
{
|
|
|
|
return std::get<typename AllocTypeType<AT>::Type>(this->value);
|
|
|
|
}
|
|
|
|
template <AllocType AT> inline auto as() && -> AllocTypeType<AT>::Type&&
|
|
|
|
{
|
|
|
|
return std::move(
|
|
|
|
std::get<typename AllocTypeType<AT>::Type>(this->value));
|
|
|
|
}
|
|
|
|
template <AllocType AT>
|
|
|
|
inline auto as() const&& -> const AllocTypeType<AT>::Type&&
|
|
|
|
{
|
|
|
|
return std::move(
|
|
|
|
std::get<typename AllocTypeType<AT>::Type>(this->value));
|
|
|
|
}
|
|
|
|
|
2024-12-13 15:16:11 +00:00
|
|
|
inline auto as_value() & -> Value& { return std::get<Value>(this->value); }
|
|
|
|
inline auto as_value() const& -> const Value&
|
|
|
|
{
|
2024-12-12 15:07:59 +00:00
|
|
|
return std::get<Value>(this->value);
|
|
|
|
}
|
2024-12-13 15:16:11 +00:00
|
|
|
inline auto as_array() & -> Array& { return std::get<Array>(this->value); }
|
|
|
|
inline auto as_array() const& -> const Array&
|
|
|
|
{
|
2024-12-12 15:07:59 +00:00
|
|
|
return std::get<Array>(this->value);
|
|
|
|
}
|
2024-12-13 15:16:11 +00:00
|
|
|
inline auto as_struct() & -> Struct&
|
|
|
|
{
|
2024-12-12 15:07:59 +00:00
|
|
|
return std::get<Struct>(this->value);
|
|
|
|
}
|
2024-12-13 15:16:11 +00:00
|
|
|
inline auto as_struct() const& -> const Struct&
|
|
|
|
{
|
2024-12-12 15:07:59 +00:00
|
|
|
return std::get<Struct>(this->value);
|
|
|
|
}
|
|
|
|
|
2024-11-26 13:32:21 +00:00
|
|
|
AllocType type;
|
|
|
|
std::variant<Value, Array, Struct> value;
|
|
|
|
};
|
|
|
|
|
|
|
|
enum class ErrType {
|
|
|
|
InvalidPtrAccess,
|
|
|
|
CannotAllocate,
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename T> struct Res {
|
|
|
|
Res(T val)
|
2024-12-12 15:07:59 +00:00
|
|
|
: m_val(std::forward<T>(val))
|
2024-11-26 13:32:21 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
Res(ErrType err)
|
2024-12-12 15:07:59 +00:00
|
|
|
: m_err(err)
|
2024-11-26 13:32:21 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2024-12-12 15:07:59 +00:00
|
|
|
auto ok() const -> bool { return m_val.has_value(); }
|
|
|
|
auto val() & -> T& { return m_val.value(); }
|
|
|
|
auto val() const& -> const T& { return m_val.value(); }
|
|
|
|
auto val() && -> T&& { return std::move(m_val.value()); }
|
|
|
|
auto val() const&& -> const T&& { return std::move(m_val.value()); }
|
|
|
|
auto err() -> ErrType { return m_err.value(); }
|
|
|
|
|
|
|
|
std::optional<T> m_val;
|
|
|
|
std::optional<ErrType> m_err;
|
2024-11-26 13:32:21 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
class Heap {
|
|
|
|
public:
|
|
|
|
inline auto can_allocate() const -> bool
|
|
|
|
{
|
|
|
|
return this->sel->size() < this->max_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void collect(const std::vector<uint32_t>& 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<AllocItem*>
|
|
|
|
{
|
|
|
|
if (ptr >= this->sel->size()) {
|
|
|
|
return ErrType::InvalidPtrAccess;
|
|
|
|
}
|
|
|
|
return &this->sel->at(ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <AllocType type> auto alloc() -> Res<uint32_t>
|
|
|
|
{
|
|
|
|
if (not can_allocate()) {
|
|
|
|
return ErrType::CannotAllocate;
|
|
|
|
}
|
|
|
|
auto ptr = static_cast<uint32_t>(this->sel->size());
|
|
|
|
this->sel->push_back(typename AllocTypeType<type>::Type {});
|
|
|
|
return ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
inline void move_item_to_other(uint32_t ptr)
|
|
|
|
{
|
|
|
|
auto res = at(ptr);
|
2024-12-12 15:07:59 +00:00
|
|
|
if (!res.ok())
|
2024-11-26 13:32:21 +00:00
|
|
|
return;
|
2024-12-12 15:07:59 +00:00
|
|
|
auto val = res.val();
|
2024-11-26 13:32:21 +00:00
|
|
|
switch (val->type) {
|
|
|
|
case AllocType::Value: {
|
|
|
|
auto& v = val->as<AllocType::Value>();
|
|
|
|
if (v.type() == ValueType::Ptr) {
|
|
|
|
move_item_to_other(v.template as<ValueType::Ptr>().value);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case AllocType::Array: {
|
|
|
|
auto& vs = val->as<AllocType::Array>();
|
|
|
|
for (auto& v : vs.values) {
|
|
|
|
if (v.type() == ValueType::Ptr) {
|
|
|
|
move_item_to_other(
|
|
|
|
v.template as<ValueType::Ptr>().value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case AllocType::Struct: {
|
|
|
|
auto& vs = val->as<AllocType::Struct>();
|
|
|
|
for (auto& [key, v] : vs.fields) {
|
|
|
|
if (v.type() == ValueType::Ptr) {
|
|
|
|
move_item_to_other(
|
|
|
|
v.template as<ValueType::Ptr>().value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-26 04:20:33 +00:00
|
|
|
size_t max_size = 8;
|
2024-11-26 13:32:21 +00:00
|
|
|
|
|
|
|
std::vector<AllocItem> heap_1;
|
|
|
|
std::vector<AllocItem> heap_2;
|
|
|
|
|
|
|
|
std::vector<AllocItem>* sel = &heap_1;
|
|
|
|
std::vector<AllocItem>* other = &heap_2;
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|