/*
* Copyright (C) 2024 Brett Terpstra
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "blt/profiling/profiler_v2.h"
#include "blt/std/allocator.h"
#include "blt/std/format.h"
#include "blt/std/system.h"
namespace fb
{
template
inline bool once()
{
static bool b = true;
return std::exchange(b, false);
}
static constexpr blt::u64 SEED = 691;
struct random_engine
{
private:
std::mt19937_64 engine{SEED};
public:
random_engine() = default;
void reset(blt::u64 seed = SEED)
{
engine = std::mt19937_64{seed};
}
auto& get()
{
return engine;
}
};
inline random_engine engine;
enum class type_t
{
ADD, SUB, MUL, DIV, IF, EQUAL_B, EQUAL_N, LESS, GREATER, NOT, AND, OR, VALUE, END
};
enum class type_category_t
{
NUM, BOOL, NON_TERMINALS, TERMINAL_NUM, TERMINAL_BOOL, END
};
std::vector combine(const std::vector& v1, const std::vector& v2)
{
std::vector types;
types.reserve(v1.size() + v2.size());
for (auto v : v1)
types.push_back(v);
for (auto v : v2)
types.push_back(v);
return types;
}
std::vector VEC_NUM = {type_t::ADD, type_t::SUB, type_t::MUL, type_t::DIV, type_t::IF};
std::vector VEC_NUM_TERMINAL = {type_t::ADD, type_t::SUB, type_t::MUL, type_t::DIV, type_t::IF, type_t::VALUE};
std::vector VEC_BOOL = {type_t::EQUAL_B, type_t::EQUAL_N, type_t::LESS, type_t::GREATER, type_t::NOT, type_t::AND,
type_t::OR};
std::vector VEC_NON_TERMINAL = {type_t::ADD, type_t::SUB, type_t::MUL, type_t::DIV, type_t::IF, type_t::EQUAL_B,
type_t::EQUAL_N, type_t::LESS, type_t::GREATER, type_t::NOT, type_t::AND,
type_t::OR};
std::array, static_cast(type_category_t::END)> categories = {
VEC_NUM,
VEC_BOOL,
VEC_NON_TERMINAL,
VEC_NUM_TERMINAL,
VEC_BOOL
};
const std::array, static_cast(type_t::END)> allowed_arg_types = {
std::vector{type_category_t::NUM, type_category_t::NUM}, // ADD
std::vector{type_category_t::NUM, type_category_t::NUM}, // SUB
std::vector{type_category_t::NUM, type_category_t::NUM}, // MUL
std::vector{type_category_t::NUM, type_category_t::NUM}, // DIV
std::vector{type_category_t::BOOL, type_category_t::NUM, type_category_t::NUM}, // IF
std::vector{type_category_t::BOOL, type_category_t::BOOL}, // EQUAL_B
std::vector{type_category_t::NUM, type_category_t::NUM}, // EQUAL_N
std::vector{type_category_t::NUM, type_category_t::NUM}, // LESS
std::vector{type_category_t::NUM, type_category_t::NUM}, // GREATER
std::vector{type_category_t::BOOL}, // NOT
std::vector{type_category_t::BOOL, type_category_t::BOOL}, // AND
std::vector{type_category_t::BOOL, type_category_t::BOOL}, // OR
std::vector{}, // VALUE
};
inline type_t random_type(const std::vector& allowed_types)
{
static std::random_device dev;
std::uniform_int_distribution dist(0ul, allowed_types.size() - 1);
return allowed_types[dist(engine.get())];
}
inline double random_value()
{
static std::random_device dev;
static std::uniform_real_distribution dist(-2.0, 2.0);
return dist(engine.get());
}
inline bool choice()
{
static std::random_device dev;
static std::uniform_int_distribution dist(0, 1);
return dist(engine.get());
}
template
class any_t_base
{
private:
blt::u8 data[SIZE]{};
public:
any_t_base() = default;
template
any_t_base(T t)
{
static_assert(std::is_trivially_copyable_v && "Type must be byte copyable");
static_assert(sizeof(T) <= SIZE && "Size must be less than or equal to internal buffer");
std::memcpy(data, &t, sizeof(t));
}
template
any_t_base& operator=(T t)
{
static_assert(std::is_trivially_copyable_v && "Type must be byte copyable");
static_assert(sizeof(T) <= SIZE && "Size must be less than or equal to internal buffer");
std::memcpy(data, &t, sizeof(t));
}
template
T any_cast()
{
static_assert(std::is_trivially_copyable_v && "Type must be byte copyable");
static_assert(sizeof(T) <= SIZE && "Size must be less than or equal to internal buffer");
T t;
std::memcpy(&t, data, sizeof(T));
return t;
}
};
class any_t_variant
{
private:
static constexpr auto SIZE = sizeof(std::any);
using array_t = std::array;
std::variant data;
public:
any_t_variant() = default;
template
any_t_variant(T t)
{
if constexpr (sizeof(T) <= SIZE && std::is_trivially_copyable_v)
{
data = array_t{};
std::memcpy(std::get(data).data(), &t, sizeof(t));
} else
data = t;
}
template
any_t_variant& operator=(T t)
{
if constexpr (sizeof(T) <= SIZE && std::is_trivially_copyable_v)
{
if (!std::holds_alternative>(data))
data = std::array{};
std::memcpy(std::get(data).data(), &t, sizeof(t));
} else
data = t;
return *this;
}
template
T any_cast()
{
if constexpr (sizeof(T) <= SIZE && std::is_trivially_copyable_v)
{
if (std::holds_alternative(data))
{
T t;
std::memcpy(&t, std::get(data).data(), sizeof(T));
return t;
}
}
return std::any_cast(std::get(data));
}
};
class any_t_union
{
private:
static constexpr auto SIZE = sizeof(std::any);
union variant_t
{
constexpr variant_t()
{}
blt::u8 data[SIZE]{};
std::any any;
~variant_t()
{}
};
variant_t variant;
bool has_any = false;
public:
any_t_union() = default;
any_t_union(const any_t_union& copy)
{
if (copy.has_any)
{
variant.any = copy.variant.any;
has_any = true;
} else
{
std::memcpy(variant.data, copy.variant.data, SIZE);
}
}
any_t_union(any_t_union&& move) noexcept
{
if (move.has_any)
{
variant.any = std::move(move.variant.any);
has_any = true;
} else
{
std::memcpy(variant.data, move.variant.data, SIZE);
}
}
~any_t_union()
{
if (has_any)
variant.any.~any();
}
template
any_t_union(T t)
{
if constexpr (sizeof(T) <= SIZE && std::is_trivially_copyable_v)
{
std::memcpy(variant.data, &t, sizeof(t));
} else
{
variant.any = t;
has_any = true;
}
}
any_t_union& operator=(const any_t_union& copy)
{
if (has_any)
variant.any.~any();
if (copy.has_any)
{
variant.any = copy.variant.any;
has_any = true;
} else
{
std::memcpy(variant.data, copy.variant.data, SIZE);
has_any = false;
}
return *this;
}
any_t_union& operator=(any_t_union&& move) noexcept
{
if (has_any)
variant.any.~any();
if (move.has_any)
{
variant.any = std::move(move.variant.any);
has_any = true;
} else
{
std::memcpy(variant.data, move.variant.data, SIZE);
has_any = false;
}
return *this;
}
template
any_t_union& operator=(T t)
{
if (has_any)
variant.any.~any();
if constexpr (sizeof(T) <= SIZE && std::is_trivially_copyable_v)
{
std::memcpy(variant.data, &t, sizeof(t));
has_any = false;
} else
{
variant.any = t;
has_any = true;
}
return *this;
}
template
T any_cast()
{
if constexpr (sizeof(T) <= SIZE && std::is_trivially_copyable_v)
{
if (!has_any)
{
T t;
std::memcpy(&t, variant.data, sizeof(T));
return t;
}
}
return std::any_cast(variant.any);
}
};
using any_t = any_t_base<8>;
//using any_t = any_t_variant;
class func_t;
class func_variant_t;
class func_union_t;
class func_any_t;
using func_t_call_t = std::function)>;
using func_variant_t_call_t = std::function)>;
using func_union_t_call_t = std::function)>;
using func_any_t_call_t = std::function)>;
class func_t
{
private:
blt::size_t argc_ = 0;
const func_t_call_t& func;
protected:
any_t value;
public:
explicit func_t(blt::size_t argc, const func_t_call_t& func):
argc_(argc), func(func)
{}
[[nodiscard]] inline blt::size_t argc() const
{ return argc_; }
[[nodiscard]] inline any_t getValue() const
{
return value;
}
inline func_t& setValue(any_t val)
{
this->value = val;
return *this;
}
inline void call(blt::span args)
{
func(*this, args);
};
~func_t() = default;
};
class func_variant_t
{
private:
blt::size_t argc_ = 0;
const func_variant_t_call_t& func;
protected:
any_t_variant value;
public:
explicit func_variant_t(blt::size_t argc, const func_variant_t_call_t& func):
argc_(argc), func(func)
{}
[[nodiscard]] inline blt::size_t argc() const
{ return argc_; }
[[nodiscard]] inline any_t_variant getValue() const
{
return value;
}
inline func_variant_t& setValue(any_t_variant val)
{
this->value = std::move(val);
return *this;
}
inline void call(blt::span args)
{
func(*this, args);
};
~func_variant_t() = default;
};
class func_union_t
{
private:
blt::size_t argc_ = 0;
const func_union_t_call_t& func;
protected:
any_t_union value;
public:
explicit func_union_t(blt::size_t argc, const func_union_t_call_t& func):
argc_(argc), func(func)
{}
[[nodiscard]] inline blt::size_t argc() const
{ return argc_; }
[[nodiscard]] inline any_t_union getValue() const
{
return value;
}
inline func_union_t& setValue(any_t_union val)
{
this->value = val;
return *this;
}
inline void call(blt::span args)
{
func(*this, args);
};
~func_union_t() = default;
};
class func_any_t
{
private:
blt::size_t argc_ = 0;
const func_any_t_call_t& func;
protected:
std::any value;
public:
explicit func_any_t(blt::size_t argc, const func_any_t_call_t& func):
argc_(argc), func(func)
{}
[[nodiscard]] inline blt::size_t argc() const
{ return argc_; }
[[nodiscard]] inline std::any getValue() const
{
return value;
}
inline func_any_t& setValue(std::any val)
{
this->value = std::move(val);
return *this;
}
inline void call(blt::span args)
{
func(*this, args);
};
~func_any_t() = default;
};
const func_t_call_t add_f = [](func_t& us, blt::span args) { us.setValue(args[0].any_cast() + args[1].any_cast()); };
const func_t_call_t sub_f = [](func_t& us, blt::span args) { us.setValue(args[0].any_cast() - args[1].any_cast()); };
const func_t_call_t mul_f = [](func_t& us, blt::span args) { us.setValue(args[0].any_cast() * args[1].any_cast()); };
const func_t_call_t div_f = [](func_t& us, blt::span args) {
auto dim = args[1].any_cast();
if (dim == 0)
us.setValue(0);
else
us.setValue(args[0].any_cast() + dim);
};
const func_t_call_t value_f = [](func_t&, blt::span) {};
const func_t_call_t if_f = [](func_t& us, blt::span args) {
if (args[0].any_cast())
us.setValue(args[1].any_cast());
else
us.setValue(args[2].any_cast());
};
const func_t_call_t equals_b_f = [](func_t& us, blt::span args) { us.setValue(args[0].any_cast() == args[1].any_cast()); };
const func_t_call_t equals_n_f = [](func_t& us, blt::span args) { us.setValue(args[0].any_cast() == args[1].any_cast()); };
const func_t_call_t less_f = [](func_t& us, blt::span args) { us.setValue(args[0].any_cast() < args[1].any_cast()); };
const func_t_call_t greater_f = [](func_t& us, blt::span args) { us.setValue(args[0].any_cast() > args[1].any_cast()); };
const func_t_call_t not_f = [](func_t& us, blt::span args) { us.setValue(!args[0].any_cast()); };
const func_t_call_t and_f = [](func_t& us, blt::span args) { us.setValue(args[0].any_cast() && args[1].any_cast()); };
const func_t_call_t or_f = [](func_t& us, blt::span args) { us.setValue(args[0].any_cast() || args[1].any_cast()); };
const func_variant_t_call_t add_variant_f = [](func_variant_t& us, blt::span args) {
us.setValue(args[0].any_cast() + args[1].any_cast());
};
const func_variant_t_call_t sub_variant_f = [](func_variant_t& us, blt::span args) {
us.setValue(args[0].any_cast() - args[1].any_cast());
};
const func_variant_t_call_t mul_variant_f = [](func_variant_t& us, blt::span args) {
us.setValue(args[0].any_cast() * args[1].any_cast());
};
const func_variant_t_call_t div_variant_f = [](func_variant_t& us, blt::span args) {
auto dim = args[1].any_cast();
if (dim == 0)
us.setValue(0);
else
us.setValue(args[0].any_cast() + dim);
};
const func_variant_t_call_t value_variant_f = [](func_variant_t&, blt::span) {};
const func_variant_t_call_t if_variant_f = [](func_variant_t& us, blt::span args) {
if (args[0].any_cast())
us.setValue(args[1].any_cast());
else
us.setValue(args[2].any_cast());
};
const func_variant_t_call_t equals_b_variant_f = [](func_variant_t& us, blt::span args) {
us.setValue(args[0].any_cast() == args[1].any_cast());
};
const func_variant_t_call_t equals_n_variant_f = [](func_variant_t& us, blt::span args) {
us.setValue(args[0].any_cast() == args[1].any_cast());
};
const func_variant_t_call_t less_variant_f = [](func_variant_t& us, blt::span args) {
us.setValue(args[0].any_cast() < args[1].any_cast());
};
const func_variant_t_call_t greater_variant_f = [](func_variant_t& us, blt::span args) {
us.setValue(args[0].any_cast() > args[1].any_cast());
};
const func_variant_t_call_t not_variant_f = [](func_variant_t& us, blt::span args) { us.setValue(!args[0].any_cast()); };
const func_variant_t_call_t and_variant_f = [](func_variant_t& us, blt::span args) {
us.setValue(args[0].any_cast() && args[1].any_cast());
};
const func_variant_t_call_t or_variant_f = [](func_variant_t& us, blt::span args) {
us.setValue(args[0].any_cast() || args[1].any_cast());
};
const func_union_t_call_t add_union_f = [](func_union_t& us, blt::span args) {
us.setValue(args[0].any_cast() + args[1].any_cast());
};
const func_union_t_call_t sub_union_f = [](func_union_t& us, blt::span args) {
us.setValue(args[0].any_cast() - args[1].any_cast());
};
const func_union_t_call_t mul_union_f = [](func_union_t& us, blt::span args) {
us.setValue(args[0].any_cast() * args[1].any_cast());
};
const func_union_t_call_t div_union_f = [](func_union_t& us, blt::span args) {
auto dim = args[1].any_cast();
if (dim == 0)
us.setValue(0);
else
us.setValue(args[0].any_cast() + dim);
};
const func_union_t_call_t value_union_f = [](func_union_t&, blt::span) {};
const func_union_t_call_t if_union_f = [](func_union_t& us, blt::span args) {
if (args[0].any_cast())
us.setValue(args[1].any_cast());
else
us.setValue(args[2].any_cast());
};
const func_union_t_call_t equals_b_union_f = [](func_union_t& us, blt::span args) {
us.setValue(args[0].any_cast() == args[1].any_cast());
};
const func_union_t_call_t equals_n_union_f = [](func_union_t& us, blt::span args) {
us.setValue(args[0].any_cast() == args[1].any_cast());
};
const func_union_t_call_t less_union_f = [](func_union_t& us, blt::span args) {
us.setValue(args[0].any_cast() < args[1].any_cast());
};
const func_union_t_call_t greater_union_f = [](func_union_t& us, blt::span args) {
us.setValue(args[0].any_cast() > args[1].any_cast());
};
const func_union_t_call_t not_union_f = [](func_union_t& us, blt::span args) { us.setValue(!args[0].any_cast()); };
const func_union_t_call_t and_union_f = [](func_union_t& us, blt::span args) {
us.setValue(args[0].any_cast() && args[1].any_cast());
};
const func_union_t_call_t or_union_f = [](func_union_t& us, blt::span args) {
us.setValue(args[0].any_cast() || args[1].any_cast());
};
const func_any_t_call_t add_any_f = [](func_any_t& us, blt::span args) {
us.setValue(std::any_cast(args[0]) + std::any_cast(args[1]));
};
const func_any_t_call_t sub_any_f = [](func_any_t& us, blt::span args) {
us.setValue(std::any_cast(args[0]) - std::any_cast(args[1]));
};
const func_any_t_call_t mul_any_f = [](func_any_t& us, blt::span args) {
us.setValue(std::any_cast(args[0]) * std::any_cast(args[1]));
};
const func_any_t_call_t div_any_f = [](func_any_t& us, blt::span args) {
auto dim = std::any_cast(args[1]);
if (dim == 0)
us.setValue(0);
else
us.setValue(std::any_cast(args[0]) + dim);
};
const func_any_t_call_t value_any_f = [](func_any_t&, blt::span) {};
const func_any_t_call_t if_any_f = [](func_any_t& us, blt::span args) {
if (std::any_cast(args[0]))
us.setValue(std::any_cast(args[1]));
else
us.setValue(std::any_cast(args[2]));
};
const func_any_t_call_t equals_b_any_f = [](func_any_t& us, blt::span args) {
us.setValue(std::any_cast(args[0]) == std::any_cast(args[1]));
};
const func_any_t_call_t equals_n_any_f = [](func_any_t& us, blt::span args) {
us.setValue(std::any_cast(args[0]) == std::any_cast(args[1]));
};
const func_any_t_call_t less_any_f = [](func_any_t& us, blt::span args) {
us.setValue(std::any_cast(args[0]) < std::any_cast(args[1]));
};
const func_any_t_call_t greater_any_f = [](func_any_t& us, blt::span args) {
us.setValue(std::any_cast(args[0]) > std::any_cast(args[1]));
};
const func_any_t_call_t not_any_f = [](func_any_t& us, blt::span args) { us.setValue(!std::any_cast(args[0])); };
const func_any_t_call_t and_any_f = [](func_any_t& us, blt::span args) {
us.setValue(std::any_cast(args[0]) && std::any_cast(args[1]));
};
const func_any_t_call_t or_any_f = [](func_any_t& us, blt::span args) {
us.setValue(std::any_cast(args[0]) || std::any_cast(args[1]));
};
func_t make_type(type_t type)
{
switch (type)
{
case type_t::ADD:
return func_t{2, add_f};
case type_t::SUB:
return func_t{2, sub_f};
case type_t::MUL:
return func_t{2, mul_f};
case type_t::DIV:
return func_t{2, div_f};
case type_t::IF:
return func_t{3, if_f};
case type_t::EQUAL_B:
return func_t{2, equals_b_f};
case type_t::EQUAL_N:
return func_t{2, equals_n_f};
case type_t::LESS:
return func_t{2, less_f};
case type_t::GREATER:
return func_t{2, greater_f};
case type_t::NOT:
return func_t{1, not_f};
case type_t::AND:
return func_t{2, and_f};
case type_t::OR:
return func_t{2, or_f};
case type_t::VALUE:
return func_t{0, value_f}.setValue(random_value());
case type_t::END:
break;
}
BLT_WARN("How did we get here? input %d", static_cast(type));
return func_t{0, value_f}.setValue(random_value());
}
func_variant_t make_type_variant(type_t type)
{
switch (type)
{
case type_t::ADD:
return func_variant_t{2, add_variant_f};
case type_t::SUB:
return func_variant_t{2, sub_variant_f};
case type_t::MUL:
return func_variant_t{2, mul_variant_f};
case type_t::DIV:
return func_variant_t{2, div_variant_f};
case type_t::IF:
return func_variant_t{3, if_variant_f};
case type_t::EQUAL_B:
return func_variant_t{2, equals_b_variant_f};
case type_t::EQUAL_N:
return func_variant_t{2, equals_n_variant_f};
case type_t::LESS:
return func_variant_t{2, less_variant_f};
case type_t::GREATER:
return func_variant_t{2, greater_variant_f};
case type_t::NOT:
return func_variant_t{1, not_variant_f};
case type_t::AND:
return func_variant_t{2, and_variant_f};
case type_t::OR:
return func_variant_t{2, or_variant_f};
case type_t::VALUE:
return func_variant_t{0, value_variant_f}.setValue(random_value());
case type_t::END:
break;
}
BLT_WARN("How did we get here? input %d", static_cast(type));
return func_variant_t{0, value_variant_f}.setValue(random_value());
}
func_union_t make_type_union(type_t type)
{
switch (type)
{
case type_t::ADD:
return func_union_t{2, add_union_f};
case type_t::SUB:
return func_union_t{2, sub_union_f};
case type_t::MUL:
return func_union_t{2, mul_union_f};
case type_t::DIV:
return func_union_t{2, div_union_f};
case type_t::IF:
return func_union_t{3, if_union_f};
case type_t::EQUAL_B:
return func_union_t{2, equals_b_union_f};
case type_t::EQUAL_N:
return func_union_t{2, equals_n_union_f};
case type_t::LESS:
return func_union_t{2, less_union_f};
case type_t::GREATER:
return func_union_t{2, greater_union_f};
case type_t::NOT:
return func_union_t{1, not_union_f};
case type_t::AND:
return func_union_t{2, and_union_f};
case type_t::OR:
return func_union_t{2, or_union_f};
case type_t::VALUE:
return func_union_t{0, value_union_f}.setValue(random_value());
case type_t::END:
break;
}
BLT_WARN("How did we get here? input %d", static_cast(type));
return func_union_t{0, value_union_f}.setValue(random_value());
}
func_any_t make_type_any(type_t type)
{
switch (type)
{
case type_t::ADD:
return func_any_t{2, add_any_f};
case type_t::SUB:
return func_any_t{2, sub_any_f};
case type_t::MUL:
return func_any_t{2, mul_any_f};
case type_t::DIV:
return func_any_t{2, div_any_f};
case type_t::IF:
return func_any_t{3, if_any_f};
case type_t::EQUAL_B:
return func_any_t{2, equals_b_any_f};
case type_t::EQUAL_N:
return func_any_t{2, equals_n_any_f};
case type_t::LESS:
return func_any_t{2, less_any_f};
case type_t::GREATER:
return func_any_t{2, greater_any_f};
case type_t::NOT:
return func_any_t{1, not_any_f};
case type_t::AND:
return func_any_t{2, and_any_f};
case type_t::OR:
return func_any_t{2, or_any_f};
case type_t::VALUE:
return func_any_t{0, value_any_f}.setValue(random_value());
case type_t::END:
break;
}
BLT_WARN("How did we get here? input %d", static_cast(type));
return func_any_t{0, value_any_f}.setValue(random_value());
}
blt::bump_allocator alloc_2;
class tree_any
{
private:
struct node_t
{
func_t type;
type_t enum_type;
node_t** children = nullptr;
explicit node_t(type_t type): type(make_type(type)), enum_type(type)
{
children = alloc_2.emplace_many(this->type.argc());
for (blt::size_t i = 0; i < this->type.argc(); i++)
children[i] = nullptr;
}
void evaluate()
{
if (type.argc() > 0)
{
any_t d[3]{};
for (blt::size_t i = 0; i < type.argc(); i++)
d[i] = children[i]->type.getValue();
type.call(blt::span{d, type.argc()});
} else
type.call({});
}
double evaluate_tree()
{
std::stack nodes;
std::stack node_stack;
nodes.push(this);
while (!nodes.empty())
{
auto* top = nodes.top();
node_stack.push(top);
nodes.pop();
for (blt::size_t i = 0; i < top->type.argc(); i++)
nodes.push(top->children[i]);
}
while (!node_stack.empty())
{
node_stack.top()->evaluate();
node_stack.pop();
}
return type.getValue().any_cast();
}
~node_t()
{
for (blt::size_t i = 0; i < type.argc(); i++)
{
alloc_2.destroy(children[i]);
alloc_2.deallocate(children[i]);
}
alloc_2.deallocate(children, type.argc());
}
};
node_t* root = nullptr;
public:
tree_any()
{
if (once())
BLT_INFO(sizeof(node_t));
};
void create(blt::u64 size)
{
root = alloc_2.template emplace(random_type(VEC_NON_TERMINAL));
std::stack> stack;
stack.emplace(root, 0);
while (!stack.empty())
{
auto top = stack.top();
auto* node = top.first;
auto depth = top.second;
stack.pop();
auto& allowed_types = allowed_arg_types[static_cast(node->enum_type)];
for (blt::size_t i = 0; i < node->type.argc(); i++)
{
auto type_category = allowed_types[i];
if (depth >= size)
{
if (type_category == type_category_t::BOOL)
{
node->children[i] = alloc_2.template emplace(type_t::GREATER);
node->children[i]->children[0] = alloc_2.template emplace(type_t::VALUE);
node->children[i]->children[1] = alloc_2.template emplace(type_t::VALUE);
} else
{
node->children[i] = alloc_2.template emplace(type_t::VALUE);
}
continue;
}
if (choice())
node->children[i] = alloc_2.template emplace(random_type(categories[static_cast(type_category)]));
else
{
if (type_category == type_category_t::NUM)
{
node->children[i] = alloc_2.template emplace(
random_type(categories[static_cast(type_category_t::TERMINAL_NUM)]));
} else
node->children[i] = alloc_2.template emplace(random_type(categories[static_cast(type_category)]));
}
if (depth < size)
stack.emplace(node->children[i], depth + 1);
}
}
}
double evaluate()
{
return root->evaluate_tree();
}
~tree_any()
{
BLT_START_INTERVAL("Tree Destruction", "any_t tree");
alloc_2.destroy(root);
alloc_2.deallocate(root);
BLT_END_INTERVAL("Tree Destruction", "any_t tree");
}
};
class tree_any_variant
{
private:
struct node_t
{
func_variant_t type;
type_t enum_type;
node_t** children = nullptr;
explicit node_t(type_t type): type(make_type_variant(type)), enum_type(type)
{
children = alloc_2.emplace_many(this->type.argc());
for (blt::size_t i = 0; i < this->type.argc(); i++)
children[i] = nullptr;
}
void evaluate()
{
if (type.argc() > 0)
{
any_t_variant d[3]{};
for (blt::size_t i = 0; i < type.argc(); i++)
d[i] = children[i]->type.getValue();
type.call(blt::span{d, type.argc()});
} else
type.call({});
}
double evaluate_tree()
{
std::stack nodes;
std::stack node_stack;
nodes.push(this);
while (!nodes.empty())
{
auto* top = nodes.top();
node_stack.push(top);
nodes.pop();
for (blt::size_t i = 0; i < top->type.argc(); i++)
nodes.push(top->children[i]);
}
while (!node_stack.empty())
{
node_stack.top()->evaluate();
node_stack.pop();
}
return type.getValue().any_cast();
}
~node_t()
{
for (blt::size_t i = 0; i < type.argc(); i++)
{
alloc_2.destroy(children[i]);
alloc_2.deallocate(children[i]);
}
alloc_2.deallocate(children, type.argc());
}
};
node_t* root = nullptr;
public:
tree_any_variant()
{
if (once())
BLT_INFO(sizeof(node_t));
};
void create(blt::u64 size)
{
root = alloc_2.template emplace