diff --git a/CMakeLists.txt b/CMakeLists.txt
index f023f1a..d9f3c28 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.25)
-project(lilfbtf5 VERSION 0.1.8)
+project(lilfbtf5 VERSION 0.1.9)
option(ENABLE_ADDRSAN "Enable the address sanitizer" OFF)
option(ENABLE_UBSAN "Enable the ub sanitizer" OFF)
diff --git a/tests/include/lilfbtf/test4.h b/tests/include/lilfbtf/test4.h
new file mode 100644
index 0000000..b944888
--- /dev/null
+++ b/tests/include/lilfbtf/test4.h
@@ -0,0 +1,27 @@
+#pragma once
+/*
+ * 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 .
+ */
+
+#ifndef LILFBTF5_TEST4_H
+#define LILFBTF5_TEST4_H
+
+namespace fb
+{
+ void test4();
+}
+
+#endif //LILFBTF5_TEST4_H
diff --git a/tests/src/main.cpp b/tests/src/main.cpp
index ad701da..b76b9dc 100644
--- a/tests/src/main.cpp
+++ b/tests/src/main.cpp
@@ -5,6 +5,7 @@
#include
#include
#include
+#include
#include "blt/profiling/profiler_v2.h"
struct data {
@@ -48,7 +49,8 @@ int main(int argc, const char** argv)
if (args.contains("--tests"))
{
//fb::test2();
- fb::test3();
+ //fb::test3();
+ fb::test4();
BLT_PRINT_PROFILE("Tree Construction");
BLT_PRINT_PROFILE("Tree Evaluation");
diff --git a/tests/src/tests3.cpp b/tests/src/tests3.cpp
index 8e57298..1cb0200 100644
--- a/tests/src/tests3.cpp
+++ b/tests/src/tests3.cpp
@@ -25,6 +25,7 @@
#include
#include
#include
+#include
namespace fb
{
diff --git a/tests/src/tests4.cpp b/tests/src/tests4.cpp
new file mode 100644
index 0000000..8d142af
--- /dev/null
+++ b/tests/src/tests4.cpp
@@ -0,0 +1,369 @@
+/*
+ * 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
+
+namespace fb
+{
+ 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, 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, 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::array, static_cast(type_category_t::END)> categories = {
+ VEC_NUM,
+ VEC_BOOL,
+ {type_t::VALUE},
+ {}
+ };
+
+ 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;
+ static 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;
+ }
+ };
+
+ using VALUE = double;
+ using BOOL = bool;
+ using any_t = any_t_base<8>;
+
+ class func_t;
+ class func_any_t;
+
+ using func_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_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_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};
+ case type_t::END:
+ break;
+ }
+ }
+
+ 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};
+ case type_t::END:
+ break;
+ }
+ }
+
+ void test4()
+ {
+ BLT_INFO(sizeof(std::any));
+ BLT_INFO(sizeof(any_t));
+ }
+
+}
\ No newline at end of file