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/=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/=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/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/=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" />
|
<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>
|
</component>
|
||||||
|
|
|
@ -27,7 +27,7 @@ macro(compile_options target_name)
|
||||||
sanitizers(${target_name})
|
sanitizers(${target_name})
|
||||||
endmacro()
|
endmacro()
|
||||||
|
|
||||||
project(blt-gp VERSION 0.5.27)
|
project(blt-gp VERSION 0.5.28)
|
||||||
|
|
||||||
include(CTest)
|
include(CTest)
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,15 @@ namespace blt::gp
|
||||||
struct op_container_t;
|
struct op_container_t;
|
||||||
|
|
||||||
class evaluation_context;
|
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;
|
class tree_t;
|
||||||
|
|
||||||
|
|
|
@ -97,15 +97,14 @@ namespace blt::gp
|
||||||
operator_special_flags m_flags;
|
operator_special_flags m_flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
class evaluation_context
|
/**
|
||||||
{
|
* Calculate the number of bytes stored inside the tree's stack between the begin and end iterators
|
||||||
public:
|
*
|
||||||
explicit evaluation_context() = default;
|
* @param begin Begin iterator to the container storing the tree's operators
|
||||||
|
* @param end End iterator
|
||||||
stack_allocator values;
|
* @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)
|
||||||
inline size_t accumulate_type_sizes(const detail::op_iter_t begin, const detail::op_iter_t end)
|
|
||||||
{
|
{
|
||||||
size_t total = 0;
|
size_t total = 0;
|
||||||
for (auto it = begin; it != end; ++it)
|
for (auto it = begin; it != end; ++it)
|
||||||
|
@ -116,6 +115,21 @@ namespace blt::gp
|
||||||
return total;
|
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>
|
template <typename T>
|
||||||
class evaluation_ref
|
class evaluation_ref
|
||||||
{
|
{
|
||||||
|
@ -185,8 +199,54 @@ namespace blt::gp
|
||||||
evaluation_context* m_context;
|
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
|
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:
|
public:
|
||||||
struct subtree_point_t
|
struct subtree_point_t
|
||||||
{
|
{
|
||||||
|
@ -209,51 +269,6 @@ namespace blt::gp
|
||||||
ptrdiff_t start;
|
ptrdiff_t start;
|
||||||
// one past the end
|
// one past the end
|
||||||
ptrdiff_t 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)
|
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.
|
* 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.
|
* 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)
|
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
tree_t(tree_t&& move) = default;
|
tree_t(tree_t&& move) = default;
|
||||||
|
|
||||||
|
|
|
@ -31,8 +31,8 @@ namespace blt::gp
|
||||||
// this is largely to not break the tests :3
|
// 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
|
// 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 advanced_mutation_t s_mutator;
|
||||||
// static subtree_crossover_t s_crossover;
|
static subtree_crossover_t s_crossover;
|
||||||
static one_point_crossover_t s_crossover;
|
// static one_point_crossover_t s_crossover;
|
||||||
static ramped_half_initializer_t s_init;
|
static ramped_half_initializer_t s_init;
|
||||||
|
|
||||||
prog_config_t::prog_config_t(): mutator(s_mutator), crossover(s_crossover), pop_initializer(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_begin_itr = operations.begin() + point.pos;
|
||||||
const auto point_end_itr = operations.begin() + extent;
|
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);
|
const size_t ops = std::distance(point_begin_itr, point_end_itr);
|
||||||
operators.reserve(operators.size() + ops);
|
operators.reserve(operators.size() + ops);
|
||||||
|
@ -342,8 +342,8 @@ namespace blt::gp
|
||||||
c2_subtree_operators.push_back(it);
|
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 c1_stack_after_bytes = calculate_ephemeral_size(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 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 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 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);
|
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_begin_itr = operations.begin() + point.pos;
|
||||||
const auto point_end_itr = operations.begin() + extent;
|
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;
|
size_t for_bytes = 0;
|
||||||
for (auto& it : iterate(point_begin_itr, point_end_itr).rev())
|
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_begin_itr = operations.begin() + point.pos;
|
||||||
const auto point_end_itr = operations.begin() + extent;
|
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;
|
size_t for_bytes = 0;
|
||||||
for (auto& it : iterate(point_begin_itr, point_end_itr).rev())
|
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)
|
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};
|
byte_only_transaction_t transaction{*this, after_bytes};
|
||||||
|
|
||||||
auto insert = operations.begin() + point.pos;
|
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)
|
void tree_t::clear(gp_program& program)
|
||||||
{
|
{
|
||||||
auto* f = &program;
|
auto* f = &program;
|
||||||
|
@ -766,7 +825,7 @@ namespace blt::gp
|
||||||
byte_only_transaction_t move_data{*this};
|
byte_only_transaction_t move_data{*this};
|
||||||
if (operations[point].is_value())
|
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);
|
move_data.move(after_bytes);
|
||||||
if (operations[point].get_flags().is_ephemeral() && operations[point].has_ephemeral_drop())
|
if (operations[point].get_flags().is_ephemeral() && operations[point].has_ephemeral_drop())
|
||||||
{
|
{
|
||||||
|
@ -787,7 +846,7 @@ namespace blt::gp
|
||||||
{
|
{
|
||||||
if (move_data.empty())
|
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);
|
move_data.move(after_bytes);
|
||||||
}
|
}
|
||||||
handle_operator_inserted(operations[point]);
|
handle_operator_inserted(operations[point]);
|
||||||
|
|
Loading…
Reference in New Issue