wow there is something wrong, check debug mode!
parent
8594c44bae
commit
9eff9ea8ef
tests
|
@ -27,7 +27,7 @@ macro(compile_options target_name)
|
||||||
sanitizers(${target_name})
|
sanitizers(${target_name})
|
||||||
endmacro()
|
endmacro()
|
||||||
|
|
||||||
project(blt-gp VERSION 0.3.13)
|
project(blt-gp VERSION 0.3.14)
|
||||||
|
|
||||||
include(CTest)
|
include(CTest)
|
||||||
|
|
||||||
|
|
|
@ -168,11 +168,11 @@ namespace blt::gp
|
||||||
const auto ptr = static_cast<char*>(allocate_bytes_for_size(aligned_size<NO_REF>()));
|
const auto ptr = static_cast<char*>(allocate_bytes_for_size(aligned_size<NO_REF>()));
|
||||||
std::memcpy(ptr, &t, sizeof(NO_REF));
|
std::memcpy(ptr, &t, sizeof(NO_REF));
|
||||||
|
|
||||||
if constexpr (gp::detail::has_func_drop_ephemeral_v<T>)
|
// if constexpr (gp::detail::has_func_drop_ephemeral_v<T>)
|
||||||
{
|
// {
|
||||||
const auto* ref_counter_ptr = new std::atomic_uint64_t(1); // NOLINT
|
// const auto* ref_counter_ptr = new std::atomic_uint64_t(1); // NOLINT
|
||||||
std::memcpy(ptr + sizeof(NO_REF), &ref_counter_ptr, sizeof(std::atomic_uint64_t*));
|
// std::memcpy(ptr + sizeof(NO_REF), &ref_counter_ptr, sizeof(std::atomic_uint64_t*));
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, typename NO_REF = NO_REF_T<T>>
|
template <typename T, typename NO_REF = NO_REF_T<T>>
|
||||||
|
|
|
@ -171,7 +171,7 @@ namespace blt::gp
|
||||||
public:
|
public:
|
||||||
explicit tree_t(gp_program& program);
|
explicit tree_t(gp_program& program);
|
||||||
|
|
||||||
tree_t(const tree_t& copy): func(copy.func)
|
tree_t(const tree_t& copy): m_program(copy.m_program)
|
||||||
{
|
{
|
||||||
copy_fast(copy);
|
copy_fast(copy);
|
||||||
}
|
}
|
||||||
|
@ -180,6 +180,7 @@ namespace blt::gp
|
||||||
{
|
{
|
||||||
if (this == ©)
|
if (this == ©)
|
||||||
return *this;
|
return *this;
|
||||||
|
m_program = copy.m_program;
|
||||||
copy_fast(copy);
|
copy_fast(copy);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
@ -245,12 +246,14 @@ namespace blt::gp
|
||||||
void insert_operator(const op_container_t& container)
|
void insert_operator(const op_container_t& container)
|
||||||
{
|
{
|
||||||
operations.emplace_back(container);
|
operations.emplace_back(container);
|
||||||
|
handle_operator_inserted(operations.back());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
void emplace_operator(Args&&... args)
|
void emplace_operator(Args&&... args)
|
||||||
{
|
{
|
||||||
operations.emplace_back(std::forward<Args>(args)...);
|
operations.emplace_back(std::forward<Args>(args)...);
|
||||||
|
handle_operator_inserted(operations.back());
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] tracked_vector<op_container_t>& get_operations()
|
[[nodiscard]] tracked_vector<op_container_t>& get_operations()
|
||||||
|
@ -405,17 +408,26 @@ namespace blt::gp
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void handle_operator_inserted(const op_container_t& op);
|
||||||
|
|
||||||
template <typename T, std::enable_if_t<!(std::is_pointer_v<T> || std::is_null_pointer_v<T>), bool> = true>
|
template <typename T, std::enable_if_t<!(std::is_pointer_v<T> || std::is_null_pointer_v<T>), bool> = true>
|
||||||
[[nodiscard]] evaluation_context& evaluate(const T& context) const
|
[[nodiscard]] evaluation_context& evaluate(const T& context) const
|
||||||
{
|
{
|
||||||
return (*func)(*this, const_cast<void*>(static_cast<const void*>(&context)));
|
return evaluate(const_cast<void*>(static_cast<const void*>(&context)));
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] evaluation_context& evaluate() const
|
[[nodiscard]] evaluation_context& evaluate() const
|
||||||
{
|
{
|
||||||
return (*func)(*this, nullptr);
|
return evaluate(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] evaluation_context& evaluate(void* ptr) const;
|
||||||
|
|
||||||
|
tracked_vector<op_container_t> operations;
|
||||||
|
stack_allocator values;
|
||||||
|
gp_program* m_program;
|
||||||
|
|
||||||
|
protected:
|
||||||
template <typename Context, typename Operator>
|
template <typename Context, typename Operator>
|
||||||
static void execute(void* context, stack_allocator& write_stack, stack_allocator& read_stack, Operator& operation)
|
static void execute(void* context, stack_allocator& write_stack, stack_allocator& read_stack, Operator& operation)
|
||||||
{
|
{
|
||||||
|
@ -457,10 +469,6 @@ namespace blt::gp
|
||||||
{
|
{
|
||||||
call_jmp_table_internal<Context>(op, context, write_stack, read_stack, std::index_sequence_for<Operators...>(), operators...);
|
call_jmp_table_internal<Context>(op, context, write_stack, read_stack, std::index_sequence_for<Operators...>(), operators...);
|
||||||
}
|
}
|
||||||
|
|
||||||
tracked_vector<op_container_t> operations;
|
|
||||||
stack_allocator values;
|
|
||||||
detail::eval_func_t* func;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fitness_t
|
struct fitness_t
|
||||||
|
|
|
@ -69,10 +69,7 @@ namespace blt::gp
|
||||||
max_depth = std::max(max_depth, top.depth);
|
max_depth = std::max(max_depth, top.depth);
|
||||||
|
|
||||||
if (args.program.is_operator_ephemeral(top.id))
|
if (args.program.is_operator_ephemeral(top.id))
|
||||||
{
|
|
||||||
info.func(nullptr, tree.get_values(), tree.get_values());
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& child : info.argument_types)
|
for (const auto& child : info.argument_types)
|
||||||
std::forward<Func>(perChild)(args.program, tree_generator, child, top.depth + 1);
|
std::forward<Func>(perChild)(args.program, tree_generator, child, top.depth + 1);
|
||||||
|
|
|
@ -352,8 +352,9 @@ namespace blt::gp
|
||||||
auto copy = c;
|
auto copy = c;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
const auto& result = copy.evaluate(*static_cast<char*>(detail::debug::context_ptr));
|
// TODO a work around for the whole needing to access a now private function
|
||||||
blt::black_box(result);
|
// const auto& result = copy.evaluate(*static_cast<char*>(detail::debug::context_ptr));
|
||||||
|
// blt::black_box(result);
|
||||||
} catch (...)
|
} catch (...)
|
||||||
{
|
{
|
||||||
std::cout << "This occurred at point " << begin_point << " ending at (old) " << end_point << "\n";
|
std::cout << "This occurred at point " << begin_point << " ending at (old) " << end_point << "\n";
|
||||||
|
|
114
src/tree.cpp
114
src/tree.cpp
|
@ -25,7 +25,7 @@
|
||||||
namespace blt::gp
|
namespace blt::gp
|
||||||
{
|
{
|
||||||
// this one will copy previous bytes over
|
// this one will copy previous bytes over
|
||||||
template<typename T>
|
template <typename T>
|
||||||
blt::span<blt::u8> get_pointer_for_size(blt::size_t size)
|
blt::span<blt::u8> get_pointer_for_size(blt::size_t size)
|
||||||
{
|
{
|
||||||
static blt::span<blt::u8> buffer{nullptr, 0};
|
static blt::span<blt::u8> buffer{nullptr, 0};
|
||||||
|
@ -36,7 +36,7 @@ namespace blt::gp
|
||||||
}
|
}
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream& create_indent(std::ostream& out, blt::size_t amount, bool pretty_print)
|
std::ostream& create_indent(std::ostream& out, blt::size_t amount, bool pretty_print)
|
||||||
{
|
{
|
||||||
if (!pretty_print)
|
if (!pretty_print)
|
||||||
|
@ -45,30 +45,30 @@ namespace blt::gp
|
||||||
out << '\t';
|
out << '\t';
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string_view end_indent(bool pretty_print)
|
std::string_view end_indent(bool pretty_print)
|
||||||
{
|
{
|
||||||
return pretty_print ? "\n" : "";
|
return pretty_print ? "\n" : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string get_return_type(gp_program& program, type_id id, bool use_returns)
|
std::string get_return_type(gp_program& program, type_id id, bool use_returns)
|
||||||
{
|
{
|
||||||
if (!use_returns)
|
if (!use_returns)
|
||||||
return "";
|
return "";
|
||||||
return "(" + std::string(program.get_typesystem().get_type(id).name()) + ")";
|
return "(" + std::string(program.get_typesystem().get_type(id).name()) + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
void tree_t::print(gp_program& program, std::ostream& out, bool print_literals, bool pretty_print, bool include_types) const
|
void tree_t::print(gp_program& program, std::ostream& out, bool print_literals, bool pretty_print, bool include_types) const
|
||||||
{
|
{
|
||||||
std::stack<blt::size_t> arguments_left;
|
std::stack<blt::size_t> arguments_left;
|
||||||
blt::size_t indent = 0;
|
blt::size_t indent = 0;
|
||||||
|
|
||||||
stack_allocator reversed;
|
stack_allocator reversed;
|
||||||
if (print_literals)
|
if (print_literals)
|
||||||
{
|
{
|
||||||
// I hate this.
|
// I hate this.
|
||||||
stack_allocator copy = values;
|
stack_allocator copy = values;
|
||||||
|
|
||||||
// reverse the order of the stack
|
// reverse the order of the stack
|
||||||
for (const auto& v : operations)
|
for (const auto& v : operations)
|
||||||
{
|
{
|
||||||
|
@ -87,7 +87,8 @@ namespace blt::gp
|
||||||
indent++;
|
indent++;
|
||||||
arguments_left.emplace(info.argc.argc);
|
arguments_left.emplace(info.argc.argc);
|
||||||
out << name << return_type << end_indent(pretty_print);
|
out << name << return_type << end_indent(pretty_print);
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
if (print_literals)
|
if (print_literals)
|
||||||
{
|
{
|
||||||
|
@ -96,13 +97,15 @@ namespace blt::gp
|
||||||
{
|
{
|
||||||
program.get_print_func(v.id())(out, reversed);
|
program.get_print_func(v.id())(out, reversed);
|
||||||
reversed.pop_bytes(v.type_size());
|
reversed.pop_bytes(v.type_size());
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
out << name;
|
out << name;
|
||||||
out << return_type << end_indent(pretty_print);
|
out << return_type << end_indent(pretty_print);
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
create_indent(out, indent, pretty_print) << name << return_type << end_indent(pretty_print);
|
create_indent(out, indent, pretty_print) << name << return_type << end_indent(pretty_print);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!arguments_left.empty())
|
while (!arguments_left.empty())
|
||||||
{
|
{
|
||||||
auto top = arguments_left.top();
|
auto top = arguments_left.top();
|
||||||
|
@ -112,7 +115,8 @@ namespace blt::gp
|
||||||
indent--;
|
indent--;
|
||||||
create_indent(out, indent, pretty_print) << ")" << end_indent(pretty_print);
|
create_indent(out, indent, pretty_print) << ")" << end_indent(pretty_print);
|
||||||
continue;
|
continue;
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
if (!pretty_print)
|
if (!pretty_print)
|
||||||
out << " ";
|
out << " ";
|
||||||
|
@ -130,20 +134,21 @@ namespace blt::gp
|
||||||
indent--;
|
indent--;
|
||||||
create_indent(out, indent, pretty_print) << ")" << end_indent(pretty_print);
|
create_indent(out, indent, pretty_print) << ")" << end_indent(pretty_print);
|
||||||
continue;
|
continue;
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
BLT_ERROR("Failed to print tree correctly!");
|
BLT_ERROR("Failed to print tree correctly!");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
out << '\n';
|
out << '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t tree_t::get_depth(gp_program& program) const
|
size_t tree_t::get_depth(gp_program& program) const
|
||||||
{
|
{
|
||||||
size_t depth = 0;
|
size_t depth = 0;
|
||||||
|
|
||||||
auto operations_stack = operations;
|
auto operations_stack = operations;
|
||||||
thread_local tracked_vector<size_t> values_process;
|
thread_local tracked_vector<size_t> values_process;
|
||||||
thread_local tracked_vector<size_t> value_stack;
|
thread_local tracked_vector<size_t> value_stack;
|
||||||
|
@ -156,7 +161,7 @@ namespace blt::gp
|
||||||
if (op.is_value())
|
if (op.is_value())
|
||||||
value_stack.push_back(1);
|
value_stack.push_back(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!operations_stack.empty())
|
while (!operations_stack.empty())
|
||||||
{
|
{
|
||||||
auto operation = operations_stack.back();
|
auto operation = operations_stack.back();
|
||||||
|
@ -179,14 +184,14 @@ namespace blt::gp
|
||||||
value_stack.push_back(local_depth + 1);
|
value_stack.push_back(local_depth + 1);
|
||||||
operations_stack.emplace_back(operation.type_size(), operation.id(), true, program.get_operator_flags(operation.id()));
|
operations_stack.emplace_back(operation.type_size(), operation.id(), true, program.get_operator_flags(operation.id()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return depth;
|
return depth;
|
||||||
}
|
}
|
||||||
|
|
||||||
ptrdiff_t tree_t::find_endpoint(gp_program& program, ptrdiff_t start) const
|
ptrdiff_t tree_t::find_endpoint(gp_program& program, ptrdiff_t start) const
|
||||||
{
|
{
|
||||||
i64 children_left = 0;
|
i64 children_left = 0;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
const auto& type = program.get_operator_info(operations[start].id());
|
const auto& type = program.get_operator_info(operations[start].id());
|
||||||
|
@ -196,11 +201,12 @@ namespace blt::gp
|
||||||
if (type.argc.argc > 0)
|
if (type.argc.argc > 0)
|
||||||
children_left += type.argc.argc;
|
children_left += type.argc.argc;
|
||||||
start++;
|
start++;
|
||||||
} while (children_left > 0);
|
}
|
||||||
|
while (children_left > 0);
|
||||||
|
|
||||||
return start;
|
return start;
|
||||||
}
|
}
|
||||||
|
|
||||||
// this function doesn't work!
|
// this function doesn't work!
|
||||||
ptrdiff_t tree_t::find_parent(gp_program& program, ptrdiff_t start) const
|
ptrdiff_t tree_t::find_parent(gp_program& program, ptrdiff_t start) const
|
||||||
{
|
{
|
||||||
|
@ -216,22 +222,37 @@ namespace blt::gp
|
||||||
if (children_left <= 0)
|
if (children_left <= 0)
|
||||||
break;
|
break;
|
||||||
--start;
|
--start;
|
||||||
} while (true);
|
}
|
||||||
|
while (true);
|
||||||
|
|
||||||
return start;
|
return start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tree_t::handle_operator_inserted(const op_container_t& op)
|
||||||
|
{
|
||||||
|
if (m_program->is_operator_ephemeral(op.id()))
|
||||||
|
{
|
||||||
|
// Ephemeral values have corresponding insertions into the stack
|
||||||
|
m_program->get_operator_info(op.id()).func(nullptr, values, values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
evaluation_context& tree_t::evaluate(void* ptr) const
|
||||||
|
{
|
||||||
|
return m_program->get_eval_func()(*this, ptr);
|
||||||
|
}
|
||||||
|
|
||||||
bool tree_t::check(gp_program& program, void* context) const
|
bool tree_t::check(gp_program& program, void* context) const
|
||||||
{
|
{
|
||||||
blt::size_t bytes_expected = 0;
|
blt::size_t bytes_expected = 0;
|
||||||
auto bytes_size = values.size().total_used_bytes;
|
const auto bytes_size = values.size().total_used_bytes;
|
||||||
|
|
||||||
for (const auto& op : get_operations())
|
for (const auto& op : get_operations())
|
||||||
{
|
{
|
||||||
if (op.is_value())
|
if (op.is_value())
|
||||||
bytes_expected += op.type_size();
|
bytes_expected += op.type_size();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bytes_expected != bytes_size)
|
if (bytes_expected != bytes_size)
|
||||||
{
|
{
|
||||||
BLT_WARN_STREAM << "Stack state: " << values.size() << "\n";
|
BLT_WARN_STREAM << "Stack state: " << values.size() << "\n";
|
||||||
|
@ -240,13 +261,13 @@ namespace blt::gp
|
||||||
BLT_WARN("Amount of bytes in stack doesn't match the number of bytes expected for the operations");
|
BLT_WARN("Amount of bytes in stack doesn't match the number of bytes expected for the operations");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy the initial values
|
// copy the initial values
|
||||||
evaluation_context results{};
|
evaluation_context results{};
|
||||||
|
|
||||||
auto value_stack = values;
|
auto value_stack = values;
|
||||||
auto& values_process = results.values;
|
auto& values_process = results.values;
|
||||||
|
|
||||||
blt::size_t total_produced = 0;
|
blt::size_t total_produced = 0;
|
||||||
blt::size_t total_consumed = 0;
|
blt::size_t total_consumed = 0;
|
||||||
|
|
||||||
|
@ -264,7 +285,7 @@ namespace blt::gp
|
||||||
program.get_operator_info(operation.id()).func(context, values_process, values_process);
|
program.get_operator_info(operation.id()).func(context, values_process, values_process);
|
||||||
total_produced += program.get_typesystem().get_type(info.return_type).size();
|
total_produced += program.get_typesystem().get_type(info.return_type).size();
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto v1 = results.values.bytes_in_head();
|
const auto v1 = results.values.bytes_in_head();
|
||||||
const auto v2 = static_cast<ptrdiff_t>(operations.front().type_size());
|
const auto v2 = static_cast<ptrdiff_t>(operations.front().type_size());
|
||||||
if (v1 != v2)
|
if (v1 != v2)
|
||||||
|
@ -277,7 +298,7 @@ namespace blt::gp
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tree_t::find_child_extends(gp_program& program, tracked_vector<child_t>& vec, const size_t parent_node, const size_t argc) const
|
void tree_t::find_child_extends(gp_program& program, tracked_vector<child_t>& vec, const size_t parent_node, const size_t argc) const
|
||||||
{
|
{
|
||||||
while (vec.size() < argc)
|
while (vec.size() < argc)
|
||||||
|
@ -287,35 +308,36 @@ namespace blt::gp
|
||||||
if (current_point == 0)
|
if (current_point == 0)
|
||||||
{
|
{
|
||||||
// first child.
|
// first child.
|
||||||
prev = {static_cast<ptrdiff_t>(parent_node + 1),
|
prev = {
|
||||||
find_endpoint(program, static_cast<ptrdiff_t>(parent_node + 1))};
|
static_cast<ptrdiff_t>(parent_node + 1),
|
||||||
|
find_endpoint(program, static_cast<ptrdiff_t>(parent_node + 1))
|
||||||
|
};
|
||||||
vec.push_back(prev);
|
vec.push_back(prev);
|
||||||
continue;
|
continue;
|
||||||
} else
|
}
|
||||||
prev = vec[current_point - 1];
|
prev = vec[current_point - 1];
|
||||||
child_t next = {prev.end, find_endpoint(program, prev.end)};
|
child_t next = {prev.end, find_endpoint(program, prev.end)};
|
||||||
vec.push_back(next);
|
vec.push_back(next);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tree_t::tree_t(gp_program& program): func(&program.get_eval_func())
|
tree_t::tree_t(gp_program& program): m_program(&program)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void tree_t::clear(gp_program& program)
|
void tree_t::clear(gp_program& program)
|
||||||
{
|
{
|
||||||
auto* f = &program.get_eval_func();
|
auto* f = &program;
|
||||||
if (f != func)
|
if (&program != m_program)
|
||||||
func = f;
|
m_program = f;
|
||||||
for (const auto& op : operations)
|
for (const auto& op : operations)
|
||||||
{
|
{
|
||||||
if (op.has_ephemeral_drop())
|
if (op.has_ephemeral_drop())
|
||||||
{
|
{
|
||||||
|
// TODO:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
operations.clear();
|
operations.clear();
|
||||||
values.reset();
|
values.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ struct drop_type
|
||||||
++ephemeral_construct;
|
++ephemeral_construct;
|
||||||
}
|
}
|
||||||
|
|
||||||
void drop()
|
void drop() const
|
||||||
{
|
{
|
||||||
if (!ephemeral)
|
if (!ephemeral)
|
||||||
++normal_drop;
|
++normal_drop;
|
||||||
|
|
Loading…
Reference in New Issue