forward
parent
94014ef48a
commit
a15270b6b5
|
@ -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="<NamingElement Priority="11"><Descriptor Static="Indeterminate" Constexpr="Indeterminate" Const="Indeterminate" Volatile="Indeterminate" Accessibility="NOT_APPLICABLE"><type Name="class field" /><type Name="struct field" /></Descriptor><Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="m_" Suffix="" Style="aa_bb" /></NamingElement>" type="string" />
|
||||
<option name="/Default/CodeStyle/Naming/CppNaming/Rules/=Enums/@EntryIndexedValue" value="<NamingElement Priority="3"><Descriptor Static="Indeterminate" Constexpr="Indeterminate" Const="Indeterminate" Volatile="Indeterminate" Accessibility="NOT_APPLICABLE"><type Name="enum" /></Descriptor><Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="AA_BB" /></NamingElement>" type="string" />
|
||||
</component>
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 == ©)
|
||||
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;
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
75
src/tree.cpp
75
src/tree.cpp
|
@ -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 == ©)
|
||||
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]);
|
||||
|
|
Loading…
Reference in New Issue