thread
Brett 2024-08-12 13:48:06 -04:00
parent 366928fe56
commit 966d64d239
13 changed files with 201 additions and 61 deletions

View File

@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.25)
project(blt-gp VERSION 0.0.137)
project(blt-gp VERSION 0.0.138)
include(CTest)
@ -78,7 +78,7 @@ macro(blt_add_project name source type)
# set (passRegex "Pass" "Passed" "PASS" "PASSED")
# set (failRegex "WARN" "FAIL" "ERROR" "FATAL")
set (failRegex "\[WARN\]" "FAIL" "ERROR" "FATAL" "exception")
set (failRegex "\\[WARN\\]" "FAIL" "ERROR" "FATAL" "exception")
# set_property (TEST ${name} PROPERTY PASS_REGULAR_EXPRESSION "${passRegex}")
set_property (TEST ${name} PROPERTY FAIL_REGULAR_EXPRESSION "${failRegex}")

View File

@ -52,13 +52,22 @@ namespace blt::gp
namespace detail
{
// requires operator[](bit_index), push_back, clear
using bitmask_t = std::vector<bool>;
class operator_storage_test;
// context*, read stack, write stack
using callable_t = std::function<void(void*, stack_allocator&, stack_allocator&)>;
// to, from
using transfer_t = std::function<void(std::optional<std::reference_wrapper<stack_allocator>>, stack_allocator&)>;
using callable_t = std::function<void(void*, stack_allocator&, stack_allocator&, bitmask_t*)>;
// debug function,
using print_func_t = std::function<void(std::ostream&, stack_allocator&)>;
enum class destroy_t
{
ARGS,
RETURN
};
using destroy_func_t = std::function<void(destroy_t, bitmask_t* mask, stack_allocator&)>;
}
}

View File

@ -102,16 +102,16 @@ namespace blt::gp
}
template<typename context = void, typename... NoCtxArgs>
void call_destructors_without_first(stack_allocator& read_allocator)
void call_destructors_without_first(stack_allocator& read_allocator, detail::bitmask_t* mask)
{
if constexpr (sizeof...(NoCtxArgs) > 0)
{
read_allocator.call_destructors<detail::remove_cv_ref<NoCtxArgs>...>();
read_allocator.call_destructors<detail::remove_cv_ref<NoCtxArgs>...>(mask);
}
}
template<typename Func, typename... ExtraArgs>
Return operator()(bool, Func&& func, stack_allocator& read_allocator, ExtraArgs&& ... args)
Return operator()(bool has_context, detail::bitmask_t* mask, Func&& func, stack_allocator& read_allocator, ExtraArgs&& ... args)
{
constexpr auto seq = std::make_integer_sequence<blt::u64, sizeof...(Args)>();
#if BLT_DEBUG_LEVEL > 0
@ -119,10 +119,10 @@ namespace blt::gp
{
#endif
Return ret = exec_sequence_to_indices(std::forward<Func>(func), read_allocator, seq, std::forward<ExtraArgs>(args)...);
/*if (has_context)
call_destructors_without_first<Args...>(read_allocator);
if (has_context)
call_destructors_without_first<Args...>(read_allocator, mask);
else
read_allocator.call_destructors<detail::remove_cv_ref<Args>...>();*/
read_allocator.call_destructors<detail::remove_cv_ref<Args>...>(mask);
read_allocator.pop_bytes((stack_allocator::aligned_size<detail::remove_cv_ref<Args>>() + ...));
return ret;
#if BLT_DEBUG_LEVEL > 0
@ -158,18 +158,18 @@ namespace blt::gp
constexpr explicit operation_t(const Functor& functor, std::optional<std::string_view> name = {}): func(functor), name(name)
{}
[[nodiscard]] constexpr inline Return operator()(stack_allocator& read_allocator) const
[[nodiscard]] constexpr inline Return operator()(stack_allocator& read_allocator, detail::bitmask_t* mask) const
{
if constexpr (sizeof...(Args) == 0)
{
return func();
} else
{
return call_with<Return, Args...>()(false, func, read_allocator);
return call_with<Return, Args...>()(false, mask, func, read_allocator);
}
}
[[nodiscard]] constexpr inline Return operator()(void* context, stack_allocator& read_allocator) const
[[nodiscard]] constexpr inline Return operator()(void* context, stack_allocator& read_allocator, detail::bitmask_t* mask) const
{
// should be an impossible state
if constexpr (sizeof...(Args) == 0)
@ -182,22 +182,22 @@ namespace blt::gp
return func(ctx_ref);
} else
{
return call_without_first<Return, Args...>()(true, func, read_allocator, ctx_ref);
return call_without_first<Return, Args...>()(true, mask, func, read_allocator, ctx_ref);
}
}
template<typename Context>
[[nodiscard]] detail::callable_t make_callable() const
{
return [this](void* context, stack_allocator& read_allocator, stack_allocator& write_allocator) {
return [this](void* context, stack_allocator& read_allocator, stack_allocator& write_allocator, detail::bitmask_t* mask) {
if constexpr (detail::is_same_v<Context, detail::remove_cv_ref<typename detail::first_arg<Args...>::type>>)
{
// first arg is context
write_allocator.push(this->operator()(context, read_allocator));
write_allocator.push(this->operator()(context, read_allocator, mask));
} else
{
// first arg isn't context
write_allocator.push(this->operator()(read_allocator));
write_allocator.push(this->operator()(read_allocator, mask));
}
};
}

View File

@ -91,6 +91,7 @@ namespace blt::gp
blt::hashset_t<operator_id> static_types;
std::vector<operator_info> operators;
std::vector<detail::print_func_t> print_funcs;
std::vector<detail::destroy_func_t> destroy_funcs;
std::vector<std::optional<std::string_view>> names;
};
@ -135,13 +136,24 @@ namespace blt::gp
storage.print_funcs.push_back([&op](std::ostream& out, stack_allocator& stack) {
if constexpr (blt::meta::is_streamable_v<Return>)
{
out << stack.pop<Return>();
out << stack.from<Return>(0);
(void) (op); // remove warning
} else
{
out << "[Printing Value on '" << (op.get_name() ? *op.get_name() : "") << "' Not Supported!]";
}
});
storage.destroy_funcs.push_back([](detail::destroy_t type, detail::bitmask_t* mask, stack_allocator& alloc) {
switch (type)
{
case detail::destroy_t::ARGS:
alloc.call_destructors<Args...>(mask);
break;
case detail::destroy_t::RETURN:
alloc.from<detail::remove_cv_ref<Return>>(0).drop();
break;
}
});
storage.names.push_back(op.get_name());
if (is_static)
storage.static_types.insert(operator_id);
@ -374,6 +386,8 @@ namespace blt::gp
void reset_program(type_id root_type, bool eval_fitness_now = true)
{
current_generation = 0;
for (auto& pop : current_pop)
pop.tree.drop(*this);
current_pop = config.pop_initializer.get().generate(
{*this, root_type, config.population_size, config.initial_min_tree_size, config.initial_max_tree_size});
if (eval_fitness_now)
@ -484,6 +498,11 @@ namespace blt::gp
return storage.print_funcs[id];
}
inline detail::destroy_func_t& get_destroy_func(operator_id id)
{
return storage.destroy_funcs[id];
}
inline std::optional<std::string_view> get_name(operator_id id)
{
return storage.names[id];
@ -521,6 +540,12 @@ namespace blt::gp
~gp_program()
{
std::cout << ("Destroying Program!") << std::endl;
for (auto& pop : current_pop.get_individuals())
{
pop.tree.drop(*this);
pop = {};
}
thread_helper.lifetime_over = true;
thread_helper.barrier.notify_all();
thread_helper.thread_function_condition.notify_all();

View File

@ -234,7 +234,7 @@ namespace blt::gp
NO_REF_T t = *reinterpret_cast<NO_REF_T*>(head->metadata.offset - TYPE_SIZE);
// call destructor
if constexpr (detail::has_func_drop_v<T>)
call_drop<NO_REF_T>(0);
call_drop<NO_REF_T>(0, 0, nullptr);
// move offset back
head->metadata.offset -= TYPE_SIZE;
// moving back allows us to allocate with other data, if there is room.
@ -347,11 +347,22 @@ namespace blt::gp
}
template<typename... Args>
void call_destructors()
void call_destructors(detail::bitmask_t* mask)
{
if constexpr (sizeof...(Args) > 0) {
blt::size_t offset = (stack_allocator::aligned_size<NO_REF_T<Args>>() + ...) -
stack_allocator::aligned_size<NO_REF_T<typename blt::meta::arg_helper<Args...>::First>>();
((call_drop<Args>(offset), offset -= stack_allocator::aligned_size<NO_REF_T<Args>>()), ...);
blt::size_t index = 0;
if (mask != nullptr)
index = mask->size() - sizeof...(Args);
((call_drop<Args>(offset, index, mask), offset -= stack_allocator::aligned_size<NO_REF_T<Args>>(), ++index), ...);
if (mask != nullptr)
{
auto& mask_r = *mask;
for (blt::size_t i = 0; i < sizeof...(Args); i++)
mask_r.pop_back();
}
}
}
[[nodiscard]] bool empty() const noexcept
@ -552,10 +563,16 @@ namespace blt::gp
};
template<typename T>
inline void call_drop(blt::size_t offset)
inline void call_drop(blt::size_t offset, blt::size_t index, detail::bitmask_t* mask)
{
if constexpr (detail::has_func_drop_v<T>)
{
if (mask != nullptr)
{
auto& mask_r = *mask;
if (!mask_r[index])
return;
}
from<NO_REF_T<T>>(offset).drop();
}
}

View File

@ -60,6 +60,31 @@ namespace blt::gp
{
using iter_type = std::vector<op_container_t>::const_iterator;
public:
tree_t(): reference_counter(new std::atomic_int64_t(1))
{}
tree_t(const tree_t& copy): operations(copy.operations), values(copy.values), reference_counter(copy.reference_counter)
{
reference_counter->operator++();
}
tree_t(tree_t&& move) noexcept:
operations(std::move(move.operations)), values(std::move(move.values)), reference_counter(move.reference_counter)
{
move.reference_counter = nullptr;
}
tree_t& operator=(const tree_t& copy) = delete;
tree_t& operator=(tree_t&& move) noexcept
{
operations = std::exchange(operations, std::move(move.operations));
values = std::exchange(values, std::move(move.values));
reference_counter = std::exchange(reference_counter, move.reference_counter);
return *this;
}
[[nodiscard]] inline std::vector<op_container_t>& get_operations()
{
return operations;
@ -147,9 +172,21 @@ namespace blt::gp
return total_value_bytes(operations.begin(), operations.end());
}
void drop(gp_program& program);
~tree_t()
{
if (reference_counter == nullptr)
return;
reference_counter->operator--();
if (*reference_counter == 0)
delete reference_counter;
}
private:
std::vector<op_container_t> operations;
blt::gp::stack_allocator values;
std::atomic_int64_t* reference_counter;
};
struct fitness_t

@ -1 +1 @@
Subproject commit 92300bc6a29927f5354d516df76ad40be7fca868
Subproject commit 644f42684320edc95f9fd5fc3b203bda3c4e6633

View File

@ -71,7 +71,7 @@ namespace blt::gp
if (args.program.is_static(top.id))
{
info.function(nullptr, tree.get_values(), tree.get_values());
info.function(nullptr, tree.get_values(), tree.get_values(), nullptr);
continue;
}

View File

@ -24,7 +24,8 @@
namespace blt::gp
{
inline auto empty_callable = detail::callable_t([](void*, stack_allocator&, stack_allocator&) { BLT_ABORT("This should never be called!"); });
inline auto empty_callable = detail::callable_t(
[](void*, stack_allocator&, stack_allocator&, detail::bitmask_t*) { BLT_ABORT("This should never be called!"); });
evaluation_context tree_t::evaluate(void* context) const
{
@ -47,15 +48,19 @@ namespace blt::gp
auto value_stack = values;
auto& values_process = results.values;
static thread_local detail::bitmask_t bitfield;
bitfield.clear();
for (const auto& operation : blt::reverse_iterate(operations.begin(), operations.end()))
{
if (operation.is_value)
{
value_stack.transfer_bytes(values_process, operation.type_size);
bitfield.push_back(false);
continue;
}
operation.func(context, values_process, values_process);
operation.func(context, values_process, values_process, &bitfield);
bitfield.push_back(true);
}
return results;
@ -222,6 +227,8 @@ namespace blt::gp
bool tree_t::check(gp_program& program, void* context) const
{
static thread_local detail::bitmask_t bitfield;
bitfield.clear();
blt::size_t bytes_expected = 0;
auto bytes_size = values.size().total_used_bytes;
@ -255,12 +262,14 @@ namespace blt::gp
{
value_stack.transfer_bytes(values_process, operation.type_size);
total_produced += stack_allocator::aligned_size(operation.type_size);
bitfield.push_back(false);
continue;
}
auto& info = program.get_operator_info(operation.id);
for (auto& arg : info.argument_types)
total_consumed += stack_allocator::aligned_size(program.get_typesystem().get_type(arg).size());
operation.func(context, values_process, values_process);
operation.func(context, values_process, values_process, &bitfield);
bitfield.push_back(true);
total_produced += stack_allocator::aligned_size(program.get_typesystem().get_type(info.return_type).size());
}
@ -276,4 +285,38 @@ namespace blt::gp
}
return true;
}
void tree_t::drop(gp_program& program)
{
return;
if (values.empty())
return;
std::cout << "---- NEW TREE ---- References " << *reference_counter << " ----" << std::endl;
if (reference_counter->load() > 1)
return;
static blt::hashset_t<blt::size_t> sets;
while (!operations.empty())
{
auto operation = operations.back();
if (operation.is_value)
{
struct hello
{
float* f;
blt::size_t i;
};
auto h = values.from<hello>(0);
if (sets.find(h.i) != sets.end())
std::cout << "HEY ASSHOLE Duplicate Value " << h.i << std::endl;
else
{
std::cout << "Destroying Value " << h.i << std::endl;
sets.insert(h.i);
}
program.get_destroy_func(operation.id)(detail::destroy_t::RETURN, nullptr, values);
values.pop_bytes(static_cast<blt::ptrdiff_t>(stack_allocator::aligned_size(operation.type_size)));
}
operations.pop_back();
}
}
}

View File

@ -53,41 +53,47 @@ class move_float
move_float(): f(new float()), assignment(++last_value)
{
constructions++;
BLT_TRACE("Value %ld Default Constructed", assignment);
//BLT_TRACE("Value %ld Default Constructed", assignment);
}
explicit move_float(float f): f(new float(f)), assignment(++last_value)
{
constructions++;
BLT_TRACE("Value %ld Constructed", assignment);
//BLT_TRACE("Value %ld Constructed", assignment);
}
explicit operator float() const
{
BLT_TRACE("Using value %ld", assignment);
//BLT_TRACE("Using value %ld", assignment);
return *f;
}
[[nodiscard]] float get() const
{
BLT_TRACE("Using value %ld", assignment);
//BLT_TRACE("Using value %ld", assignment);
return *f;
}
float operator*() const
{
BLT_TRACE("Using value %ld", assignment);
//BLT_TRACE("Using value %ld", assignment);
return *f;
}
void drop() // NOLINT
{
BLT_TRACE("Drop Called On %ld", assignment);
//BLT_TRACE("Drop Called On %ld", assignment);
delete f;
f = nullptr;
destructions++;
}
friend std::ostream& operator<<(std::ostream& stream, const move_float& e)
{
stream << *e;
return stream;
}
private:
float* f = nullptr;
blt::size_t assignment;
@ -106,13 +112,13 @@ std::array<context, 200> fitness_cases;
blt::gp::prog_config_t config = blt::gp::prog_config_t()
.set_initial_min_tree_size(2)
.set_initial_max_tree_size(6)
.set_elite_count(2)
.set_elite_count(0)
.set_crossover_chance(0.9)
.set_mutation_chance(0.1)
.set_reproduction_chance(0)
.set_max_generations(1)
.set_pop_size(1)
.set_thread_count(1);
.set_max_generations(5)
.set_pop_size(500)
.set_thread_count(0);
blt::gp::type_provider type_system;
blt::gp::gp_program program{type_system, SEED, config};
@ -137,7 +143,10 @@ constexpr auto fitness_function = [](blt::gp::tree_t& current_tree, blt::gp::fit
constexpr double value_cutoff = 1.e15;
for (auto& fitness_case : fitness_cases)
{
auto diff = std::abs(fitness_case.y - *current_tree.get_evaluation_value<move_float>(&fitness_case));
auto ctx = current_tree.evaluate(&fitness_case);
auto diff = std::abs(fitness_case.y - *current_tree.get_evaluation_ref<move_float>(ctx));
// this will call the drop function.
current_tree.get_evaluation_value<move_float>(ctx);
if (diff < value_cutoff)
{
fitness.raw_fitness += diff;
@ -211,7 +220,7 @@ int main()
BLT_END_INTERVAL("Symbolic Regression", "Main");
auto best = program.get_best_individuals<3>();
auto best = program.get_best_individuals<1>();
BLT_INFO("Best approximations:");
for (auto& i_ref : best)

View File

@ -63,7 +63,7 @@ blt::gp::op_container_t make_container(blt::gp::operator_id id)
blt::gp::op_container_t make_value(const blt::gp::type& id)
{
static blt::gp::detail::callable_t empty([](void*, blt::gp::stack_allocator&, blt::gp::stack_allocator&) {});
static blt::gp::detail::callable_t empty([](void*, blt::gp::stack_allocator&, blt::gp::stack_allocator&, blt::gp::detail::bitmask_t*) {});
return {empty, id.size(), 0, true};
}

View File

@ -424,7 +424,7 @@ int main()
return f + g;
});
std::cout << silly_op(alloc) << std::endl;
std::cout << silly_op(alloc, nullptr) << std::endl;
std::cout << "Is empty? " << alloc.empty() << std::endl;
@ -456,15 +456,15 @@ int main()
context hello{5, 10};
alloc.push(1.153f);
de[0](static_cast<void*>(&hello), alloc, alloc);
de[0](static_cast<void*>(&hello), alloc, alloc, nullptr);
BLT_TRACE("first value: %f", alloc.pop<float>());
de[1](static_cast<void*>(&hello), alloc, alloc);
de[1](static_cast<void*>(&hello), alloc, alloc, nullptr);
BLT_TRACE("second value: %f", alloc.pop<float>());
alloc.push(1.0f);
alloc.push(52.213f);
de[2](static_cast<void*>(&hello), alloc, alloc);
de[2](static_cast<void*>(&hello), alloc, alloc, nullptr);
BLT_TRACE("third value: %f", alloc.pop<float>());
//auto* pointer = static_cast<void*>(head->metadata.offset);
@ -482,7 +482,7 @@ int main()
//blt::span<void*, 3> spv{arr};
std::cout << silly_op.operator()(alloc) << std::endl;
std::cout << silly_op.operator()(alloc, nullptr) << std::endl;
std::cout << "Hello World!" << std::endl;

View File

@ -301,7 +301,7 @@ void test_basic()
stack.push(50.0f);
stack.push(10.0f);
BLT_TRACE_STREAM << stack.size() << "\n";
basic_2.make_callable<blt::gp::detail::empty_t>()(nullptr, stack, stack);
basic_2.make_callable<blt::gp::detail::empty_t>()(nullptr, stack, stack, nullptr);
BLT_TRACE_STREAM << stack.size() << "\n";
auto val = stack.pop<float>();
RUN_TEST(val != 60.000000f, stack, "Basic 2 Test Passed", "Basic 2 Test Failed. Unexpected value produced '%lf'", val);
@ -317,7 +317,7 @@ void test_basic()
auto size = stack.size();
BLT_TRACE_STREAM << size << "\n";
BLT_ASSERT(size.blocks > 1 && "Stack doesn't have more than one block!");
basic_2.make_callable<blt::gp::detail::empty_t>()(nullptr, stack, stack);
basic_2.make_callable<blt::gp::detail::empty_t>()(nullptr, stack, stack, nullptr);
BLT_TRACE_STREAM << stack.size() << "\n";
auto val = stack.pop<float>();
stack.pop<std::array<blt::u8, blt::gp::stack_allocator::page_size_no_block() - sizeof(float)>>();
@ -338,7 +338,7 @@ void test_mixed()
stack.push(false);
BLT_TRACE_STREAM << stack.size() << "\n";
basic_mixed_4.make_callable<blt::gp::detail::empty_t>()(nullptr, stack, stack);
basic_mixed_4.make_callable<blt::gp::detail::empty_t>()(nullptr, stack, stack, nullptr);
BLT_TRACE_STREAM << stack.size() << "\n";
auto val = stack.pop<float>();
RUN_TEST(val != 50.000000f, stack, "Mixed 4 Test Passed", "Mixed 4 Test Failed. Unexpected value produced '%lf'", val);
@ -356,7 +356,7 @@ void test_mixed()
auto size = stack.size();
BLT_TRACE_STREAM << size << "\n";
BLT_ASSERT(size.blocks > 1 && "Stack doesn't have more than one block!");
basic_mixed_4.make_callable<blt::gp::detail::empty_t>()(nullptr, stack, stack);
basic_mixed_4.make_callable<blt::gp::detail::empty_t>()(nullptr, stack, stack, nullptr);
BLT_TRACE_STREAM << stack.size() << "\n";
auto val = stack.pop<float>();
stack.pop<std::array<blt::u8, blt::gp::stack_allocator::page_size_no_block() - sizeof(float)>>();
@ -376,7 +376,7 @@ void test_large_256()
stack.push(69.420f);
BLT_TRACE_STREAM << stack.size() << "\n";
large_256_basic_3.make_callable<blt::gp::detail::empty_t>()(nullptr, stack, stack);
large_256_basic_3.make_callable<blt::gp::detail::empty_t>()(nullptr, stack, stack, nullptr);
BLT_TRACE_STREAM << stack.size() << "\n";
auto val = stack.pop<large_256>();
RUN_TEST(!compare(val, base_256), stack, "Large 256 3 Test Passed", "Large 256 3 Test Failed. Unexpected value produced '%lf'", val);
@ -393,7 +393,7 @@ void test_large_256()
auto size = stack.size();
BLT_TRACE_STREAM << size << "\n";
BLT_ASSERT(size.blocks > 1 && "Stack doesn't have more than one block!");
large_256_basic_3.make_callable<blt::gp::detail::empty_t>()(nullptr, stack, stack);
large_256_basic_3.make_callable<blt::gp::detail::empty_t>()(nullptr, stack, stack, nullptr);
BLT_TRACE_STREAM << stack.size() << "\n";
auto val = stack.pop<large_256>();
stack.pop<std::array<blt::u8, blt::gp::stack_allocator::page_size_no_block() - sizeof(large_256)>>();
@ -412,7 +412,7 @@ void test_large_4096()
stack.push(33.0f);
stack.push(true);
BLT_TRACE_STREAM << stack.size() << "\n";
large_4096_basic_3b.make_callable<blt::gp::detail::empty_t>()(nullptr, stack, stack);
large_4096_basic_3b.make_callable<blt::gp::detail::empty_t>()(nullptr, stack, stack, nullptr);
BLT_TRACE_STREAM << stack.size() << "\n";
auto val = stack.pop<large_4096>();
RUN_TEST(!compare(val, base_4096), stack, "Large 4096 3 Test Passed", "Large 4096 3 Test Failed. Unexpected value produced '%lf'", val);
@ -428,7 +428,7 @@ void test_large_4096()
auto size = stack.size();
BLT_TRACE_STREAM << size << "\n";
BLT_ASSERT(size.blocks > 1 && "Stack doesn't have more than one block!");
large_4096_basic_3b.make_callable<blt::gp::detail::empty_t>()(nullptr, stack, stack);
large_4096_basic_3b.make_callable<blt::gp::detail::empty_t>()(nullptr, stack, stack, nullptr);
BLT_TRACE_STREAM << stack.size() << "\n";
auto val = stack.pop<large_4096>();
RUN_TEST(!compare(val, base_4096), stack, "Large 4096 3 Boundary Test Passed", "Large 4096 3 Test Failed. Unexpected value produced '%lf'", val);
@ -446,7 +446,7 @@ void test_large_18290()
stack.push(-2543.0f);
stack.push(true);
BLT_TRACE_STREAM << stack.size() << "\n";
large_18290_basic_3b.make_callable<blt::gp::detail::empty_t>()(nullptr, stack, stack);
large_18290_basic_3b.make_callable<blt::gp::detail::empty_t>()(nullptr, stack, stack, nullptr);
BLT_TRACE_STREAM << stack.size() << "\n";
auto val = stack.pop<large_18290>();
RUN_TEST(!compare(val, base_18290), stack, "Large 18290 3 Test Passed", "Large 4096 3 Test Failed. Unexpected value produced '%lf'", val);
@ -463,7 +463,7 @@ void test_large_18290()
auto size = stack.size();
BLT_TRACE_STREAM << size << "\n";
BLT_ASSERT(size.blocks > 1 && "Stack doesn't have more than one block!");
large_18290_basic_3b.make_callable<blt::gp::detail::empty_t>()(nullptr, stack, stack);
large_18290_basic_3b.make_callable<blt::gp::detail::empty_t>()(nullptr, stack, stack, nullptr);
BLT_TRACE_STREAM << stack.size() << "\n";
auto val = stack.pop<large_18290>();
stack.pop<std::array<blt::u8, 20480 - 18290 - blt::gp::stack_allocator::block_size()>>();
@ -479,12 +479,12 @@ void test_large_18290()
stack.push(true);
auto size = stack.size();
BLT_TRACE_STREAM << size << "\n";
large_18290_basic_3b.make_callable<blt::gp::detail::empty_t>()(nullptr, stack, stack);
large_18290_basic_3b.make_callable<blt::gp::detail::empty_t>()(nullptr, stack, stack, nullptr);
BLT_TRACE_STREAM << stack.size() << "\n";
stack.push(-2543.0f);
stack.push(true);
BLT_TRACE_STREAM << stack.size() << "\n";
large_18290_basic_3b.make_callable<blt::gp::detail::empty_t>()(nullptr, stack, stack);
large_18290_basic_3b.make_callable<blt::gp::detail::empty_t>()(nullptr, stack, stack, nullptr);
BLT_TRACE_STREAM << stack.size() << "\n";
auto val = stack.pop<large_18290>();
RUN_TEST(!compare(val, base_18290), stack, "Large 18290 3 Boundary Test Passed", "Large 4096 3 Test Failed. Unexpected value produced '%lf'", val);