dev
Brett 2025-05-02 00:15:31 -04:00
parent 94014ef48a
commit a15270b6b5
6 changed files with 152 additions and 120 deletions

View File

@ -7,6 +7,8 @@
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantFwdClassOrEnumSpecifier/@EntryIndexedValue" value="SUGGESTION" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantQualifierADL/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTooWideScopeInitStatement/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
<option name="/Default/CodeStyle/Generate/=CppDefinitions/@KeyIndexDefined" value="true" type="bool" />
<option name="/Default/CodeStyle/Generate/=CppDefinitions/Options/=GenerateInlineDefinitions/@EntryIndexedValue" value="False" type="string" />
<option name="/Default/CodeStyle/Naming/CppNaming/Rules/=Class_0020and_0020struct_0020fields/@EntryIndexedValue" value="&lt;NamingElement Priority=&quot;11&quot;&gt;&lt;Descriptor Static=&quot;Indeterminate&quot; Constexpr=&quot;Indeterminate&quot; Const=&quot;Indeterminate&quot; Volatile=&quot;Indeterminate&quot; Accessibility=&quot;NOT_APPLICABLE&quot;&gt;&lt;type Name=&quot;class field&quot; /&gt;&lt;type Name=&quot;struct field&quot; /&gt;&lt;/Descriptor&gt;&lt;Policy Inspect=&quot;True&quot; WarnAboutPrefixesAndSuffixes=&quot;False&quot; Prefix=&quot;m_&quot; Suffix=&quot;&quot; Style=&quot;aa_bb&quot; /&gt;&lt;/NamingElement&gt;" type="string" />
<option name="/Default/CodeStyle/Naming/CppNaming/Rules/=Enums/@EntryIndexedValue" value="&lt;NamingElement Priority=&quot;3&quot;&gt;&lt;Descriptor Static=&quot;Indeterminate&quot; Constexpr=&quot;Indeterminate&quot; Const=&quot;Indeterminate&quot; Volatile=&quot;Indeterminate&quot; Accessibility=&quot;NOT_APPLICABLE&quot;&gt;&lt;type Name=&quot;enum&quot; /&gt;&lt;/Descriptor&gt;&lt;Policy Inspect=&quot;True&quot; WarnAboutPrefixesAndSuffixes=&quot;False&quot; Prefix=&quot;&quot; Suffix=&quot;&quot; Style=&quot;AA_BB&quot; /&gt;&lt;/NamingElement&gt;" type="string" />
</component>

View File

@ -27,7 +27,7 @@ macro(compile_options target_name)
sanitizers(${target_name})
endmacro()
project(blt-gp VERSION 0.5.27)
project(blt-gp VERSION 0.5.28)
include(CTest)

View File

@ -44,6 +44,15 @@ namespace blt::gp
class evaluation_context;
template <typename T>
class evaluation_ref;
class tree_manipulator_t;
class single_operation_tree_manipulator_t;
class multi_operation_tree_manipulator_t;
class tree_t;
struct individual_t;

View File

@ -97,15 +97,14 @@ namespace blt::gp
operator_special_flags m_flags;
};
class evaluation_context
{
public:
explicit evaluation_context() = default;
stack_allocator values;
};
inline size_t accumulate_type_sizes(const detail::op_iter_t begin, const detail::op_iter_t end)
/**
* Calculate the number of bytes stored inside the tree's stack between the begin and end iterators
*
* @param begin Begin iterator to the container storing the tree's operators
* @param end End iterator
* @return bytes used by operators between [begin, end)
*/
inline size_t calculate_ephemeral_size(const detail::op_iter_t begin, const detail::op_iter_t end)
{
size_t total = 0;
for (auto it = begin; it != end; ++it)
@ -116,6 +115,21 @@ namespace blt::gp
return total;
}
/**
* Stores the stack used to evaluate a tree. This is done such that executing a tree doesn't modify the internal stack
*/
class evaluation_context
{
public:
explicit evaluation_context() = default;
stack_allocator values;
};
/**
* Provides a method for accessing an evaluated tree's returned type;
* this class ensures that the drop function is properly called for the evaluation context
*/
template <typename T>
class evaluation_ref
{
@ -185,8 +199,54 @@ namespace blt::gp
evaluation_context* m_context;
};
struct temporary_tree_storage_t
{
explicit temporary_tree_storage_t(tree_t& tree);
temporary_tree_storage_t(tracked_vector<op_container_t>& operations, stack_allocator& values): operations(&operations), values(&values)
{
}
void clear() const
{
operations->clear();
values->reset();
}
tracked_vector<op_container_t>* operations;
stack_allocator* values;
};
class single_operation_tree_manipulator_t
{
};
class multi_operation_tree_manipulator_t
{
};
/**
* This is the parent class responsible for managing a tree's internal state at runtime.
* While it is possible to create a tree without a need for this class, you should not attempt to modify a tree's internal state after creation.
* This class provides helper methods to ensure that a tree remains well-ordered and that drop functions are called correctly.
*/
class tree_manipulator_t
{
public:
explicit tree_manipulator_t(tree_t& tree): m_tree(&tree)
{
}
private:
tree_t* m_tree;
};
class tree_t
{
friend struct temporary_tree_storage_t;
friend class single_operation_tree_manipulator_t;
friend class multi_operation_tree_manipulator_t;
friend class tree_manipulator_t;
public:
struct subtree_point_t
{
@ -209,51 +269,6 @@ namespace blt::gp
ptrdiff_t start;
// one past the end
ptrdiff_t end;
};
struct byte_only_transaction_t
{
byte_only_transaction_t(tree_t& tree, const size_t bytes): tree(tree), data(nullptr), bytes(bytes)
{
move(bytes);
}
explicit byte_only_transaction_t(tree_t& tree): tree(tree), data(nullptr), bytes(0)
{
}
byte_only_transaction_t(const byte_only_transaction_t& copy) = delete;
byte_only_transaction_t& operator=(const byte_only_transaction_t& copy) = delete;
byte_only_transaction_t(byte_only_transaction_t&& move) noexcept: tree(move.tree), data(std::exchange(move.data, nullptr)),
bytes(std::exchange(move.bytes, 0))
{
}
byte_only_transaction_t& operator=(byte_only_transaction_t&& move) noexcept = delete;
void move(size_t bytes_to_move);
[[nodiscard]] bool empty() const
{
return bytes == 0;
}
~byte_only_transaction_t()
{
if (!empty())
{
tree.values.copy_from(data, bytes);
bytes = 0;
}
}
private:
tree_t& tree;
u8* data;
size_t bytes;
};
explicit tree_t(gp_program& program): m_program(&program)
@ -278,62 +293,9 @@ namespace blt::gp
* This function copies the data from the provided tree, will attempt to reserve and copy in one step.
* will avoid reallocation if enough space is already present.
*
* This function is meant to copy into and replaces data inside the tree.
* This function is meant to copy into and replace data inside the tree.
*/
void copy_fast(const tree_t& copy)
{
if (this == &copy)
return;
operations.reserve(copy.operations.size());
auto copy_it = copy.operations.begin();
auto op_it = operations.begin();
size_t total_op_bytes = 0;
size_t total_copy_bytes = 0;
for (; op_it != operations.end(); ++op_it)
{
if (copy_it == copy.operations.end())
break;
if (copy_it->is_value())
{
copy.handle_refcount_increment(copy_it, total_copy_bytes);
total_copy_bytes += copy_it->type_size();
}
if (op_it->is_value())
{
handle_refcount_decrement(op_it, total_op_bytes);
total_op_bytes += op_it->type_size();
}
*op_it = *copy_it;
++copy_it;
}
const auto op_it_cpy = op_it;
for (; op_it != operations.end(); ++op_it)
{
if (op_it->is_value())
{
handle_refcount_decrement(op_it, total_op_bytes);
total_op_bytes += op_it->type_size();
}
}
operations.erase(op_it_cpy, operations.end());
for (; copy_it != copy.operations.end(); ++copy_it)
{
if (copy_it->is_value())
{
copy.handle_refcount_increment(copy_it, total_copy_bytes);
total_copy_bytes += copy_it->type_size();
}
operations.emplace_back(*copy_it);
}
values.reserve(copy.values.stored());
values.reset();
values.insert(copy.values);
}
void copy_fast(const tree_t& copy);
tree_t(tree_t&& move) = default;

View File

@ -31,8 +31,8 @@ namespace blt::gp
// this is largely to not break the tests :3
// it's also to allow for quick setup of a gp program if you don't care how crossover or mutation is handled
static advanced_mutation_t s_mutator;
// static subtree_crossover_t s_crossover;
static one_point_crossover_t s_crossover;
static subtree_crossover_t s_crossover;
// static one_point_crossover_t s_crossover;
static ramped_half_initializer_t s_init;
prog_config_t::prog_config_t(): mutator(s_mutator), crossover(s_crossover), pop_initializer(s_init)

View File

@ -267,7 +267,7 @@ namespace blt::gp
const auto point_begin_itr = operations.begin() + point.pos;
const auto point_end_itr = operations.begin() + extent;
const size_t after_bytes = accumulate_type_sizes(point_end_itr, operations.end());
const size_t after_bytes = calculate_ephemeral_size(point_end_itr, operations.end());
const size_t ops = std::distance(point_begin_itr, point_end_itr);
operators.reserve(operators.size() + ops);
@ -342,8 +342,8 @@ namespace blt::gp
c2_subtree_operators.push_back(it);
}
const size_t c1_stack_after_bytes = accumulate_type_sizes(c1_subtree_end_itr, operations.end());
const size_t c2_stack_after_bytes = accumulate_type_sizes(c2_subtree_end_itr, other_tree.operations.end());
const size_t c1_stack_after_bytes = calculate_ephemeral_size(c1_subtree_end_itr, operations.end());
const size_t c2_stack_after_bytes = calculate_ephemeral_size(c2_subtree_end_itr, other_tree.operations.end());
const auto c1_total = static_cast<ptrdiff_t>(c1_stack_after_bytes + c1_subtree_bytes);
const auto c2_total = static_cast<ptrdiff_t>(c2_stack_after_bytes + c2_subtree_bytes);
const auto copy_ptr_c1 = get_thread_pointer_for_size<struct c1_t>(c1_total);
@ -387,7 +387,7 @@ namespace blt::gp
const auto point_begin_itr = operations.begin() + point.pos;
const auto point_end_itr = operations.begin() + extent;
const size_t after_bytes = accumulate_type_sizes(point_end_itr, operations.end());
const size_t after_bytes = calculate_ephemeral_size(point_end_itr, operations.end());
size_t for_bytes = 0;
for (auto& it : iterate(point_begin_itr, point_end_itr).rev())
@ -434,7 +434,7 @@ namespace blt::gp
const auto point_begin_itr = operations.begin() + point.pos;
const auto point_end_itr = operations.begin() + extent;
const size_t after_bytes = accumulate_type_sizes(point_end_itr, operations.end());
const size_t after_bytes = calculate_ephemeral_size(point_end_itr, operations.end());
size_t for_bytes = 0;
for (auto& it : iterate(point_begin_itr, point_end_itr).rev())
@ -461,7 +461,7 @@ namespace blt::gp
ptrdiff_t tree_t::insert_subtree(const subtree_point_t point, tree_t& other_tree)
{
const size_t after_bytes = accumulate_type_sizes(operations.begin() + point.pos, operations.end());
const size_t after_bytes = calculate_ephemeral_size(operations.begin() + point.pos, operations.end());
byte_only_transaction_t transaction{*this, after_bytes};
auto insert = operations.begin() + point.pos;
@ -635,6 +635,65 @@ namespace blt::gp
}
}
temporary_tree_storage_t::temporary_tree_storage_t(tree_t& tree): operations(&tree.operations), values(&tree.values)
{
}
void tree_t::copy_fast(const tree_t& copy)
{
if (this == &copy)
return;
operations.reserve(copy.operations.size());
auto copy_it = copy.operations.begin();
auto op_it = operations.begin();
size_t total_op_bytes = 0;
size_t total_copy_bytes = 0;
for (; op_it != operations.end(); ++op_it)
{
if (copy_it == copy.operations.end())
break;
if (copy_it->is_value())
{
copy.handle_refcount_increment(copy_it, total_copy_bytes);
total_copy_bytes += copy_it->type_size();
}
if (op_it->is_value())
{
handle_refcount_decrement(op_it, total_op_bytes);
total_op_bytes += op_it->type_size();
}
*op_it = *copy_it;
++copy_it;
}
const auto op_it_cpy = op_it;
for (; op_it != operations.end(); ++op_it)
{
if (op_it->is_value())
{
handle_refcount_decrement(op_it, total_op_bytes);
total_op_bytes += op_it->type_size();
}
}
operations.erase(op_it_cpy, operations.end());
for (; copy_it != copy.operations.end(); ++copy_it)
{
if (copy_it->is_value())
{
copy.handle_refcount_increment(copy_it, total_copy_bytes);
total_copy_bytes += copy_it->type_size();
}
operations.emplace_back(*copy_it);
}
values.reserve(copy.values.stored());
values.reset();
values.insert(copy.values);
}
void tree_t::clear(gp_program& program)
{
auto* f = &program;
@ -766,7 +825,7 @@ namespace blt::gp
byte_only_transaction_t move_data{*this};
if (operations[point].is_value())
{
const size_t after_bytes = accumulate_type_sizes(operations.begin() + static_cast<ptrdiff_t>(point) + 1, operations.end());
const size_t after_bytes = calculate_ephemeral_size(operations.begin() + static_cast<ptrdiff_t>(point) + 1, operations.end());
move_data.move(after_bytes);
if (operations[point].get_flags().is_ephemeral() && operations[point].has_ephemeral_drop())
{
@ -787,7 +846,7 @@ namespace blt::gp
{
if (move_data.empty())
{
const size_t after_bytes = accumulate_type_sizes(operations.begin() + static_cast<ptrdiff_t>(point) + 1, operations.end());
const size_t after_bytes = calculate_ephemeral_size(operations.begin() + static_cast<ptrdiff_t>(point) + 1, operations.end());
move_data.move(after_bytes);
}
handle_operator_inserted(operations[point]);