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