From 30372f1c71b1585ce64ae27af0583eff32f6abf2 Mon Sep 17 00:00:00 2001 From: Brett Laptop Date: Wed, 14 May 2025 21:32:26 -0400 Subject: [PATCH] trying out some new ideas --- CMakeLists.txt | 2 +- include/blt/gp/tree.h | 342 ++++++++++++++++++++++-------------------- src/tree.cpp | 217 ++++++++++++++------------- 3 files changed, 296 insertions(+), 265 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fb350a1..e9323fc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,7 +27,7 @@ macro(compile_options target_name) sanitizers(${target_name}) endmacro() -project(blt-gp VERSION 0.5.29) +project(blt-gp VERSION 0.5.30) include(CTest) diff --git a/include/blt/gp/tree.h b/include/blt/gp/tree.h index 2362658..550dd18 100644 --- a/include/blt/gp/tree.h +++ b/include/blt/gp/tree.h @@ -29,6 +29,8 @@ #include #include +#include "program.h" + namespace blt::gp { namespace detail @@ -232,15 +234,43 @@ namespace blt::gp struct subtree_point_t { - subtree_point_t(const size_t point): point(point) // NOLINT + subtree_point_t(const size_t point, const operator_info_t& info): point(point), info(&info) // NOLINT { } - subtree_point_t(const ptrdiff_t point): point(static_cast(point)) // NOLINT + subtree_point_t(const ptrdiff_t point, const operator_info_t& info): point(static_cast(point)), info(&info) // NOLINT { } + [[nodiscard]] size_t get_point() const + { + return point; + } + + [[nodiscard]] ptrdiff_t get_spoint() const + { + return static_cast(point); + } + + [[nodiscard]] const operator_info_t& get_info() const + { + return *info; + } + + [[nodiscard]] type_id get_type() const + { + return info->return_type; + } + size_t point; + const operator_info_t* info; + }; + + struct child_t + { + ptrdiff_t start; + // one past the end + ptrdiff_t end; }; struct single_operation_tree_manipulator_t @@ -265,6 +295,103 @@ namespace blt::gp detail::tree_modification_context_t context; }; + struct slow_tree_manipulator_t + { + explicit slow_tree_manipulator_t(tree_t* const context): tree(context) + { + } + + /** + * Copies the subtree found at point into the provided out params + * @param point subtree point + * @param extent how far the subtree extends + * @param operators vector for storing subtree operators + * @param stack stack for storing subtree values + */ + void copy_subtree(subtree_point_t point, ptrdiff_t extent, tracked_vector& operators, stack_allocator& stack) const; + + /** + * Copies the subtree found at point into the provided out params + * @param point subtree point + * @param operators vector for storing subtree operators + * @param stack stack for storing subtree values + */ + void copy_subtree(const subtree_point_t point, tracked_vector& operators, stack_allocator& stack) const; + + void copy_subtree(subtree_point_t point, ptrdiff_t extent, tree_t& out_tree) const; + + void copy_subtree(subtree_point_t point, tree_t& out_tree) const; + + void copy_subtree(child_t subtree, tree_t& out_tree) const; + + void swap_subtrees(child_t our_subtree, tree_t& other_tree, child_t other_subtree) const; + + /** + * Swaps the subtrees between this tree and the other tree + * @param our_subtree + * @param other_tree + * @param other_subtree + */ + void swap_subtrees(subtree_point_t our_subtree, tree_t& other_tree, subtree_point_t other_subtree) const; + + /** + * Replaces the point inside our tree with a new tree provided to this function. + * Uses the extent instead of calculating it for removing the existing subtree + * This can be used if you already have child tree information, such as when using @code find_child_extends@endcode + * @param point point to replace at + * @param extent extend of the subtree (child tree) + * @param other_tree other tree to replace with + */ + void replace_subtree(subtree_point_t point, ptrdiff_t extent, const tree_t& other_tree) const; + + /** + * Replaces the point inside our tree with a new tree provided to this function + * @param point point to replace at + * @param other_tree other tree to replace with + */ + void replace_subtree(subtree_point_t point, const tree_t& other_tree) const; + + /** + * Deletes the subtree at a point, bounded by extent. This is useful if you already know the size of the child tree + * Note: if you provide an incorrectly sized extent this will create UB within the GP program + * extent must be one past the last element in the subtree, as returned by all helper functions here. + * @param point point to delete from + * @param extent end point of the tree + */ + void delete_subtree(subtree_point_t point, ptrdiff_t extent) const; + + /** + * Deletes the subtree at a point + * @param point point of subtree to recursively delete + */ + void delete_subtree(subtree_point_t point) const; + + void delete_subtree(child_t subtree) const; + + /** + * Insert a subtree before the specified point + * @param point point to insert into + * @param other_tree the tree to insert + * @return point + other_tree.size() + */ + ptrdiff_t insert_subtree(subtree_point_t point, tree_t& other_tree) const; + + /** + * temporarily moves the last bytes amount of data from the current stack. this can be useful for if you are going to do a lot + * of consecutive operations on the tree as this will avoid extra copy + reinsert. + * The object returned by this function will automatically move the data back in when it goes out of scope. + * @param operator_index operator index to move from. this is inclusive + */ + void temporary_move(const size_t) + { + // return obt_move_t{*this, operator_index}; + } + + void modify_operator(size_t point, operator_id new_id, std::optional return_type = {}) const; + + tree_t* tree; + }; + /** * 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. @@ -272,21 +399,27 @@ namespace blt::gp */ struct tree_manipulator_t { - explicit tree_manipulator_t(tree_t& tree, const subtree_point_t point): context{&tree, point.point} + explicit tree_manipulator_t(tree_t& tree): context{&tree} { } - [[nodiscard]] multi_operation_tree_manipulator_t explode() const + // if you are fine with operations being slowing, this is the function to use as it allows you to modify trees without worrying about byte orders + [[nodiscard]] slow_tree_manipulator_t easy_manipulator() const { - return multi_operation_tree_manipulator_t{context}; + return slow_tree_manipulator_t{context}; } - [[nodiscard]] single_operation_tree_manipulator_t single() const + [[nodiscard]] multi_operation_tree_manipulator_t explode(const subtree_point_t point) const { - return single_operation_tree_manipulator_t{context}; + return multi_operation_tree_manipulator_t{{context, point.point}}; } - detail::tree_modification_context_t context; + [[nodiscard]] single_operation_tree_manipulator_t single(const subtree_point_t point) const + { + return single_operation_tree_manipulator_t{{context, point.point}}; + } + + tree_t* context; }; class tree_t @@ -295,13 +428,50 @@ namespace blt::gp friend struct single_operation_tree_manipulator_t; friend struct multi_operation_tree_manipulator_t; friend struct tree_manipulator_t; + friend struct slow_tree_manipulator_t; public: - struct child_t + struct byte_only_transaction_t { - ptrdiff_t start; - // one past the end - ptrdiff_t end; + 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) @@ -383,154 +553,6 @@ namespace blt::gp [[nodiscard]] std::optional select_subtree_traverse(type_id type, u32 max_tries = 5, double terminal_chance = 0.1, double depth_multiplier = 0.6) const; - void copy_range(temporary_tree_storage_t& storage, const size_t begin, const size_t size) - { - copy_range(storage, operations.begin() + static_cast(begin), operations.begin() + static_cast(begin + size)); - } - - void copy_range(temporary_tree_storage_t& storage, const subtree_point_t point) - { - copy_range(storage, operations.begin() + static_cast(point.point), - operations.begin() + find_endpoint(static_cast(point.point))); - } - - void copy_range(temporary_tree_storage_t& storage, detail::op_iter_t begin, detail::op_iter_t end); - - void move_range(temporary_tree_storage_t& storage, const size_t begin, const size_t size) - { - move_range(storage, operations.begin() + static_cast(begin), operations.begin() + static_cast(begin + size)); - } - - void move_range(temporary_tree_storage_t& storage, const subtree_point_t point) - { - move_range(storage, operations.begin() + static_cast(point.point), - operations.begin() + find_endpoint(static_cast(point.point))); - } - - void move_range(temporary_tree_storage_t& storage, detail::op_iter_t begin, detail::op_iter_t end); - - void delete_range(const size_t begin, const size_t size) - { - delete_range(operations.begin() + static_cast(begin), operations.begin() + static_cast(begin + size)); - } - - void delete_range(const subtree_point_t point) - { - delete_range(operations.begin() + static_cast(point.point), - operations.begin() + find_endpoint(static_cast(point.point))); - } - - void delete_range(detail::op_iter_t begin, detail::op_iter_t end); - - /** - * Copies the subtree found at point into the provided out params - * @param point subtree point - * @param extent how far the subtree extends - * @param operators vector for storing subtree operators - * @param stack stack for storing subtree values - */ - void copy_subtree(subtree_point_t point, ptrdiff_t extent, tracked_vector& operators, stack_allocator& stack); - - /** - * Copies the subtree found at point into the provided out params - * @param point subtree point - * @param operators vector for storing subtree operators - * @param stack stack for storing subtree values - */ - void copy_subtree(const subtree_point_t point, tracked_vector& operators, stack_allocator& stack) - { - copy_subtree(point, find_endpoint(point.pos), operators, stack); - } - - void copy_subtree(const subtree_point_t point, const ptrdiff_t extent, tree_t& out_tree) - { - copy_subtree(point, extent, out_tree.operations, out_tree.values); - } - - void copy_subtree(const subtree_point_t point, tree_t& out_tree) - { - copy_subtree(point, find_endpoint(point.pos), out_tree); - } - - void copy_subtree(const child_t subtree, tree_t& out_tree) - { - copy_subtree(subtree_point_t{subtree.start}, subtree.end, out_tree); - } - - void swap_subtrees(child_t our_subtree, tree_t& other_tree, child_t other_subtree); - - /** - * Swaps the subtrees between this tree and the other tree - * @param our_subtree - * @param other_tree - * @param other_subtree - */ - void swap_subtrees(subtree_point_t our_subtree, tree_t& other_tree, subtree_point_t other_subtree); - - /** - * Replaces the point inside our tree with a new tree provided to this function. - * Uses the extent instead of calculating it for removing the existing subtree - * This can be used if you already have child tree information, such as when using @code find_child_extends@endcode - * @param point point to replace at - * @param extent extend of the subtree (child tree) - * @param other_tree other tree to replace with - */ - void replace_subtree(subtree_point_t point, ptrdiff_t extent, tree_t& other_tree); - - /** - * Replaces the point inside our tree with a new tree provided to this function - * @param point point to replace at - * @param other_tree other tree to replace with - */ - void replace_subtree(const subtree_point_t point, tree_t& other_tree) - { - replace_subtree(point, find_endpoint(point.pos), other_tree); - } - - /** - * Deletes the subtree at a point, bounded by extent. This is useful if you already know the size of the child tree - * Note: if you provide an incorrectly sized extent this will create UB within the GP program - * extent must be one past the last element in the subtree, as returned by all helper functions here. - * @param point point to delete from - * @param extent end point of the tree - */ - void delete_subtree(subtree_point_t point, ptrdiff_t extent); - - /** - * Deletes the subtree at a point - * @param point point of subtree to recursively delete - */ - void delete_subtree(const subtree_point_t point) - { - delete_subtree(point, find_endpoint(point.pos)); - } - - void delete_subtree(const child_t subtree) - { - delete_subtree(subtree_point_t{subtree.start}, subtree.end); - } - - /** - * Insert a subtree before the specified point - * @param point point to insert into - * @param other_tree the tree to insert - * @return point + other_tree.size() - */ - ptrdiff_t insert_subtree(subtree_point_t point, tree_t& other_tree); - - /** - * temporarily moves the last bytes amount of data from the current stack. this can be useful for if you are going to do a lot - * of consecutive operations on the tree as this will avoid extra copy + reinsert. - * The object returned by this function will automatically move the data back in when it goes out of scope. - * @param operator_index operator index to move from. this is inclusive - */ - void temporary_move(const size_t) - { - // return obt_move_t{*this, operator_index}; - } - - void modify_operator(size_t point, operator_id new_id, std::optional return_type = {}); - /** * User function for evaluating this tree using a context reference. This function should only be used if the tree is expecting the context value * This function returns a copy of your value, if it is too large for the stack, or you otherwise need a reference, please use the corresponding diff --git a/src/tree.cpp b/src/tree.cpp index 65f7395..1159a5d 100644 --- a/src/tree.cpp +++ b/src/tree.cpp @@ -197,31 +197,31 @@ namespace blt::gp return depth; } - tree_t::subtree_point_t tree_t::select_subtree(const double terminal_chance) const + subtree_point_t tree_t::select_subtree(const double terminal_chance) const { do { const auto point = m_program->get_random().get_u64(0, operations.size()); const auto& info = m_program->get_operator_info(operations[point].id()); if (!info.argc.is_terminal()) - return {static_cast(point), info.return_type}; + return {static_cast(point), info}; if (m_program->get_random().choice(terminal_chance)) - return {static_cast(point), info.return_type}; + return {static_cast(point), info}; } while (true); } - std::optional tree_t::select_subtree(const type_id type, const u32 max_tries, const double terminal_chance) const + std::optional tree_t::select_subtree(const type_id type, const u32 max_tries, const double terminal_chance) const { for (u32 i = 0; i < max_tries; ++i) { - if (const auto tree = select_subtree(terminal_chance); tree.type == type) + if (const auto tree = select_subtree(terminal_chance); tree.get_type() == type) return tree; } return {}; } - tree_t::subtree_point_t tree_t::select_subtree_traverse(const double terminal_chance, const double depth_multiplier) const + subtree_point_t tree_t::select_subtree_traverse(const double terminal_chance, const double depth_multiplier) const { size_t index = 0; double depth = 0; @@ -232,14 +232,14 @@ namespace blt::gp if (info.argc.is_terminal()) { if (m_program->get_random().choice(terminal_chance)) - return {static_cast(index), info.return_type}; + return {static_cast(index), info}; index = 0; depth = 0; exit_chance = 0; continue; } if (m_program->get_random().choice(exit_chance)) - return {static_cast(index), info.return_type}; + return {static_cast(index), info}; const auto child = m_program->get_random().get_u32(0, info.argc.argc); index++; @@ -251,35 +251,23 @@ namespace blt::gp } } - std::optional tree_t::select_subtree_traverse(const type_id type, const u32 max_tries, const double terminal_chance, + std::optional tree_t::select_subtree_traverse(const type_id type, const u32 max_tries, const double terminal_chance, const double depth_multiplier) const { for (u32 i = 0; i < max_tries; ++i) { - if (const auto tree = select_subtree_traverse(terminal_chance, depth_multiplier); tree.type == type) + if (const auto tree = select_subtree_traverse(terminal_chance, depth_multiplier); tree.get_type() == type) return tree; } return {}; } - void tree_t::copy_range(temporary_tree_storage_t& storage, detail::op_iter_t begin, detail::op_iter_t end) + void slow_tree_manipulator_t::copy_subtree(const subtree_point_t point, const ptrdiff_t extent, tracked_vector& operators, stack_allocator& stack) const { - } + const auto point_begin_itr = tree->operations.begin() + point.get_spoint(); + const auto point_end_itr = tree->operations.begin() + extent; - void tree_t::move_range(temporary_tree_storage_t& storage, detail::op_iter_t begin, detail::op_iter_t end) - { - } - - void tree_t::delete_range(detail::op_iter_t begin, detail::op_iter_t end) - { - } - - void tree_t::copy_subtree(const subtree_point_t point, const ptrdiff_t extent, tracked_vector& operators, stack_allocator& stack) - { - const auto point_begin_itr = operations.begin() + point.pos; - const auto point_end_itr = operations.begin() + extent; - - const size_t after_bytes = calculate_ephemeral_size(point_end_itr, operations.end()); + const size_t after_bytes = calculate_ephemeral_size(point_end_itr, tree->operations.end()); const size_t ops = std::distance(point_begin_itr, point_end_itr); operators.reserve(operators.size() + ops); @@ -295,20 +283,40 @@ namespace blt::gp for_bytes += it.type_size(); if (it.get_flags().is_ephemeral() && it.has_ephemeral_drop()) { - auto [_, ptr] = values.access_pointer(for_bytes + after_bytes, it.type_size()); + auto [_, ptr] = tree->values.access_pointer(for_bytes + after_bytes, it.type_size()); ++*ptr; } } operators[operators.size() - 1 - (pos++)] = it; } - stack.copy_from(values, for_bytes, after_bytes); + stack.copy_from(tree->values, for_bytes, after_bytes); } - void tree_t::swap_subtrees(const child_t our_subtree, tree_t& other_tree, const child_t other_subtree) + void slow_tree_manipulator_t::copy_subtree(const subtree_point_t point, tracked_vector& operators, stack_allocator& stack) const { - const auto c1_subtree_begin_itr = operations.begin() + our_subtree.start; - const auto c1_subtree_end_itr = operations.begin() + our_subtree.end; + copy_subtree(point, tree->find_endpoint(point.get_spoint()), operators, stack); + } + + void slow_tree_manipulator_t::copy_subtree(const subtree_point_t point, const ptrdiff_t extent, tree_t& out_tree) const + { + copy_subtree(point, extent, out_tree.operations, out_tree.values); + } + + void slow_tree_manipulator_t::copy_subtree(const subtree_point_t point, tree_t& out_tree) const + { + copy_subtree(point, tree->find_endpoint(point.get_spoint()), out_tree); + } + + void slow_tree_manipulator_t::copy_subtree(const child_t subtree, tree_t& out_tree) const + { + copy_subtree(subtree_point_t{subtree.start, tree->m_program->get_operator_info(tree->operations[subtree.start].id())}, subtree.end, out_tree); + } + + void slow_tree_manipulator_t::swap_subtrees(const child_t our_subtree, tree_t& other_tree, const child_t other_subtree) const + { + const auto c1_subtree_begin_itr = tree->operations.begin() + our_subtree.start; + const auto c1_subtree_end_itr = tree->operations.begin() + our_subtree.end; const auto c2_subtree_begin_itr = other_tree.operations.begin() + other_subtree.start; const auto c2_subtree_end_itr = other_tree.operations.begin() + other_subtree.end; @@ -328,14 +336,7 @@ namespace blt::gp for (const auto& it : iterate(c1_subtree_begin_itr, c1_subtree_end_itr)) { if (it.is_value()) - { - // if (it.get_flags().is_ephemeral() && it.has_ephemeral_drop()) - // { - // auto& ptr = values.access_pointer_forward(for_our_bytes, it.type_size()); - // ++*ptr; - // } c1_subtree_bytes += it.type_size(); - } c1_subtree_operators.push_back(it); } @@ -343,29 +344,22 @@ namespace blt::gp for (const auto& it : iterate(c2_subtree_begin_itr, c2_subtree_end_itr)) { if (it.is_value()) - { - // if (it.get_flags().is_ephemeral() && it.has_ephemeral_drop()) - // { - // auto& ptr = values.access_pointer_forward(for_other_bytes, it.type_size()); - // ++*ptr; - // } c2_subtree_bytes += it.type_size(); - } c2_subtree_operators.push_back(it); } - const size_t c1_stack_after_bytes = calculate_ephemeral_size(c1_subtree_end_itr, operations.end()); + const size_t c1_stack_after_bytes = calculate_ephemeral_size(c1_subtree_end_itr, 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(c1_stack_after_bytes + c1_subtree_bytes); const auto c2_total = static_cast(c2_stack_after_bytes + c2_subtree_bytes); const auto copy_ptr_c1 = get_thread_pointer_for_size(c1_total); const auto copy_ptr_c2 = get_thread_pointer_for_size(c2_total); - values.reserve(values.stored() - c1_subtree_bytes + c2_subtree_bytes); + tree->values.reserve(tree->values.stored() - c1_subtree_bytes + c2_subtree_bytes); other_tree.values.reserve(other_tree.values.stored() - c2_subtree_bytes + c1_subtree_bytes); - values.copy_to(copy_ptr_c1, c1_total); - values.pop_bytes(c1_total); + tree->values.copy_to(copy_ptr_c1, c1_total); + tree->values.pop_bytes(c1_total); other_tree.values.copy_to(copy_ptr_c2, c2_total); other_tree.values.pop_bytes(c2_total); @@ -373,33 +367,33 @@ namespace blt::gp other_tree.values.copy_from(copy_ptr_c1, c1_subtree_bytes); other_tree.values.copy_from(copy_ptr_c2 + c2_subtree_bytes, c2_stack_after_bytes); - values.copy_from(copy_ptr_c2, c2_subtree_bytes); - values.copy_from(copy_ptr_c1 + c1_subtree_bytes, c1_stack_after_bytes); + tree->values.copy_from(copy_ptr_c2, c2_subtree_bytes); + tree->values.copy_from(copy_ptr_c1 + c1_subtree_bytes, c1_stack_after_bytes); // now swap the operators // auto insert_point_c1 = c1_subtree_begin_itr - 1; // auto insert_point_c2 = c2_subtree_begin_itr - 1; // invalidates [begin, end()) so the insert points should be fine - auto insert_point_c1 = operations.erase(c1_subtree_begin_itr, c1_subtree_end_itr); - auto insert_point_c2 = other_tree.operations.erase(c2_subtree_begin_itr, c2_subtree_end_itr); + const auto insert_point_c1 = tree->operations.erase(c1_subtree_begin_itr, c1_subtree_end_itr); + const auto insert_point_c2 = other_tree.operations.erase(c2_subtree_begin_itr, c2_subtree_end_itr); - operations.insert(insert_point_c1, c2_subtree_operators.begin(), c2_subtree_operators.end()); + tree->operations.insert(insert_point_c1, c2_subtree_operators.begin(), c2_subtree_operators.end()); other_tree.operations.insert(insert_point_c2, c1_subtree_operators.begin(), c1_subtree_operators.end()); } - void tree_t::swap_subtrees(const subtree_point_t our_subtree, tree_t& other_tree, const subtree_point_t other_subtree) + void slow_tree_manipulator_t::swap_subtrees(const subtree_point_t our_subtree, tree_t& other_tree, const subtree_point_t other_subtree) const { - swap_subtrees(child_t{our_subtree.pos, find_endpoint(our_subtree.pos)}, other_tree, - child_t{other_subtree.pos, find_endpoint(other_subtree.pos)}); + swap_subtrees(child_t{our_subtree.get_spoint(), tree->find_endpoint(our_subtree.get_spoint())}, other_tree, + child_t{other_subtree.get_spoint(), tree->find_endpoint(other_subtree.get_spoint())}); } - void tree_t::replace_subtree(const subtree_point_t point, const ptrdiff_t extent, tree_t& other_tree) + void slow_tree_manipulator_t::replace_subtree(const subtree_point_t point, const ptrdiff_t extent, const tree_t& other_tree) const { - const auto point_begin_itr = operations.begin() + point.pos; - const auto point_end_itr = operations.begin() + extent; + const auto point_begin_itr = tree->operations.begin() + point.get_spoint(); + const auto point_end_itr = tree->operations.begin() + extent; - const size_t after_bytes = calculate_ephemeral_size(point_end_itr, operations.end()); + const size_t after_bytes = calculate_ephemeral_size(point_end_itr, tree->operations.end()); size_t for_bytes = 0; for (auto& it : iterate(point_begin_itr, point_end_itr).rev()) @@ -409,18 +403,18 @@ namespace blt::gp for_bytes += it.type_size(); if (it.get_flags().is_ephemeral() && it.has_ephemeral_drop()) { - auto [val, ptr] = values.access_pointer(for_bytes + after_bytes, it.type_size()); + auto [val, ptr] = tree->values.access_pointer(for_bytes + after_bytes, it.type_size()); --*ptr; if (*ptr == 0) - handle_ptr_empty(ptr, val, it.id()); + tree->handle_ptr_empty(ptr, val, it.id()); } } } - auto insert = operations.erase(point_begin_itr, point_end_itr); + auto insert = tree->operations.erase(point_begin_itr, point_end_itr); const auto ptr = get_thread_pointer_for_size(after_bytes); - values.copy_to(ptr, after_bytes); - values.pop_bytes(after_bytes + for_bytes); + tree->values.copy_to(ptr, after_bytes); + tree->values.pop_bytes(after_bytes + for_bytes); size_t copy_bytes = 0; for (const auto& v : other_tree.operations) @@ -434,19 +428,24 @@ namespace blt::gp } copy_bytes += v.type_size(); } - insert = ++operations.emplace(insert, v); + insert = ++tree->operations.emplace(insert, v); } - values.insert(other_tree.values); - values.copy_from(ptr, after_bytes); + tree->values.insert(other_tree.values); + tree->values.copy_from(ptr, after_bytes); } - void tree_t::delete_subtree(const subtree_point_t point, const ptrdiff_t extent) + void slow_tree_manipulator_t::replace_subtree(const subtree_point_t point, const tree_t& other_tree) const { - const auto point_begin_itr = operations.begin() + point.pos; - const auto point_end_itr = operations.begin() + extent; + replace_subtree(point, tree->find_endpoint(point.get_spoint()), other_tree); + } - const size_t after_bytes = calculate_ephemeral_size(point_end_itr, operations.end()); + void slow_tree_manipulator_t::delete_subtree(const subtree_point_t point, const ptrdiff_t extent) const + { + const auto point_begin_itr = tree->operations.begin() + point.get_spoint(); + const auto point_end_itr = tree->operations.begin() + extent; + + const size_t after_bytes = calculate_ephemeral_size(point_end_itr, tree->operations.end()); size_t for_bytes = 0; for (auto& it : iterate(point_begin_itr, point_end_itr).rev()) @@ -456,27 +455,37 @@ namespace blt::gp for_bytes += it.type_size(); if (it.get_flags().is_ephemeral() && it.has_ephemeral_drop()) { - auto [val, ptr] = values.access_pointer(for_bytes + after_bytes, it.type_size()); + auto [val, ptr] = tree->values.access_pointer(for_bytes + after_bytes, it.type_size()); --*ptr; if (*ptr == 0) - handle_ptr_empty(ptr, val, it.id()); + tree->handle_ptr_empty(ptr, val, it.id()); } } } - operations.erase(point_begin_itr, point_end_itr); + tree->operations.erase(point_begin_itr, point_end_itr); const auto ptr = get_thread_pointer_for_size(after_bytes); - values.copy_to(ptr, after_bytes); - values.pop_bytes(after_bytes + for_bytes); - values.copy_from(ptr, after_bytes); + tree->values.copy_to(ptr, after_bytes); + tree->values.pop_bytes(after_bytes + for_bytes); + tree->values.copy_from(ptr, after_bytes); } - ptrdiff_t tree_t::insert_subtree(const subtree_point_t point, tree_t& other_tree) + void slow_tree_manipulator_t::delete_subtree(const subtree_point_t point) const { - const size_t after_bytes = calculate_ephemeral_size(operations.begin() + point.pos, operations.end()); - byte_only_transaction_t transaction{*this, after_bytes}; + delete_subtree(point, tree->find_endpoint(point.get_spoint())); + } - auto insert = operations.begin() + point.pos; + void slow_tree_manipulator_t::delete_subtree(const child_t subtree) const + { + delete_subtree(subtree_point_t{subtree.start, tree->m_program->get_operator_info(tree->operations[subtree.start].id())}, subtree.end); + } + + ptrdiff_t slow_tree_manipulator_t::insert_subtree(const subtree_point_t point, tree_t& other_tree) const + { + const size_t after_bytes = calculate_ephemeral_size(tree->operations.begin() + point.get_spoint(), tree->operations.end()); + tree_t::byte_only_transaction_t transaction{*tree, after_bytes}; + + auto insert = tree->operations.begin() + point.get_spoint(); size_t bytes = 0; for (auto& it : iterate(other_tree.operations).rev()) { @@ -489,11 +498,11 @@ namespace blt::gp ++*ptr; } } - insert = operations.insert(insert, it); + insert = tree->operations.insert(insert, it); } - values.insert(other_tree.values); + tree->values.insert(other_tree.values); - return static_cast(point.pos + other_tree.size()); + return static_cast(point.get_spoint() + other_tree.size()); } @@ -750,9 +759,9 @@ namespace blt::gp operations.insert(operations.begin() + static_cast(index), container); } - tree_t::subtree_point_t tree_t::subtree_from_point(ptrdiff_t point) const + subtree_point_t tree_t::subtree_from_point(const ptrdiff_t point) const { - return {point, m_program->get_operator_info(operations[point].id()).return_type}; + return subtree_point_t{point, m_program->get_operator_info(operations[point].id())}; } size_t tree_t::required_size() const @@ -840,38 +849,38 @@ namespace blt::gp BLT_ASSERT(file.read(values.data(), bytes_in_head) == static_cast(bytes_in_head)); } - void tree_t::modify_operator(const size_t point, operator_id new_id, std::optional return_type) + void slow_tree_manipulator_t::modify_operator(const size_t point, operator_id new_id, std::optional return_type) const { if (!return_type) - return_type = m_program->get_operator_info(new_id).return_type; - byte_only_transaction_t move_data{*this}; - if (operations[point].is_value()) + return_type = tree->m_program->get_operator_info(new_id).return_type; + tree_t::byte_only_transaction_t move_data{*tree}; + if (tree->operations[point].is_value()) { - const size_t after_bytes = calculate_ephemeral_size(operations.begin() + static_cast(point) + 1, operations.end()); + const size_t after_bytes = calculate_ephemeral_size(tree->operations.begin() + static_cast(point) + 1, tree->operations.end()); move_data.move(after_bytes); - if (operations[point].get_flags().is_ephemeral() && operations[point].has_ephemeral_drop()) + if (tree->operations[point].get_flags().is_ephemeral() && tree->operations[point].has_ephemeral_drop()) { - auto [val, ptr] = values.access_pointer(operations[point].type_size(), operations[point].type_size()); + auto [val, ptr] = tree->values.access_pointer(tree->operations[point].type_size(), tree->operations[point].type_size()); --*ptr; if (*ptr == 0) - handle_ptr_empty(ptr, val, operations[point].id()); + tree->handle_ptr_empty(ptr, val, tree->operations[point].id()); } - values.pop_bytes(operations[point].type_size()); + tree->values.pop_bytes(tree->operations[point].type_size()); } - operations[point] = { - m_program->get_typesystem().get_type(*return_type).size(), + tree->operations[point] = { + tree->m_program->get_typesystem().get_type(*return_type).size(), new_id, - m_program->is_operator_ephemeral(new_id), - m_program->get_operator_flags(new_id) + tree->m_program->is_operator_ephemeral(new_id), + tree->m_program->get_operator_flags(new_id) }; - if (operations[point].get_flags().is_ephemeral()) + if (tree->operations[point].get_flags().is_ephemeral()) { if (move_data.empty()) { - const size_t after_bytes = calculate_ephemeral_size(operations.begin() + static_cast(point) + 1, operations.end()); + const size_t after_bytes = calculate_ephemeral_size(tree->operations.begin() + static_cast(point) + 1, tree->operations.end()); move_data.move(after_bytes); } - handle_operator_inserted(operations[point]); + tree->handle_operator_inserted(tree->operations[point]); } }