trying out some new ideas
parent
3f4c63c8d1
commit
30372f1c71
|
@ -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)
|
||||
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
#include <utility>
|
||||
#include <stack>
|
||||
|
||||
#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<size_t>(point)) // NOLINT
|
||||
subtree_point_t(const ptrdiff_t point, const operator_info_t& info): point(static_cast<size_t>(point)), info(&info) // NOLINT
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] size_t get_point() const
|
||||
{
|
||||
return point;
|
||||
}
|
||||
|
||||
[[nodiscard]] ptrdiff_t get_spoint() const
|
||||
{
|
||||
return static_cast<ptrdiff_t>(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<op_container_t>& 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<op_container_t>& 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<type_id> 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<subtree_point_t> 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<ptrdiff_t>(begin), operations.begin() + static_cast<ptrdiff_t>(begin + size));
|
||||
}
|
||||
|
||||
void copy_range(temporary_tree_storage_t& storage, const subtree_point_t point)
|
||||
{
|
||||
copy_range(storage, operations.begin() + static_cast<ptrdiff_t>(point.point),
|
||||
operations.begin() + find_endpoint(static_cast<ptrdiff_t>(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<ptrdiff_t>(begin), operations.begin() + static_cast<ptrdiff_t>(begin + size));
|
||||
}
|
||||
|
||||
void move_range(temporary_tree_storage_t& storage, const subtree_point_t point)
|
||||
{
|
||||
move_range(storage, operations.begin() + static_cast<ptrdiff_t>(point.point),
|
||||
operations.begin() + find_endpoint(static_cast<ptrdiff_t>(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<ptrdiff_t>(begin), operations.begin() + static_cast<ptrdiff_t>(begin + size));
|
||||
}
|
||||
|
||||
void delete_range(const subtree_point_t point)
|
||||
{
|
||||
delete_range(operations.begin() + static_cast<ptrdiff_t>(point.point),
|
||||
operations.begin() + find_endpoint(static_cast<ptrdiff_t>(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<op_container_t>& 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<op_container_t>& 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<type_id> 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
|
||||
|
|
217
src/tree.cpp
217
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<ptrdiff_t>(point), info.return_type};
|
||||
return {static_cast<ptrdiff_t>(point), info};
|
||||
if (m_program->get_random().choice(terminal_chance))
|
||||
return {static_cast<ptrdiff_t>(point), info.return_type};
|
||||
return {static_cast<ptrdiff_t>(point), info};
|
||||
}
|
||||
while (true);
|
||||
}
|
||||
|
||||
std::optional<tree_t::subtree_point_t> tree_t::select_subtree(const type_id type, const u32 max_tries, const double terminal_chance) const
|
||||
std::optional<subtree_point_t> 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<ptrdiff_t>(index), info.return_type};
|
||||
return {static_cast<ptrdiff_t>(index), info};
|
||||
index = 0;
|
||||
depth = 0;
|
||||
exit_chance = 0;
|
||||
continue;
|
||||
}
|
||||
if (m_program->get_random().choice(exit_chance))
|
||||
return {static_cast<ptrdiff_t>(index), info.return_type};
|
||||
return {static_cast<ptrdiff_t>(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::subtree_point_t> tree_t::select_subtree_traverse(const type_id type, const u32 max_tries, const double terminal_chance,
|
||||
std::optional<subtree_point_t> 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<op_container_t>& 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<op_container_t>& 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<op_container_t>& 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<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);
|
||||
const auto copy_ptr_c2 = get_thread_pointer_for_size<struct c2_t>(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<struct replace>(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<struct replace>(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<ptrdiff_t>(point.pos + other_tree.size());
|
||||
return static_cast<ptrdiff_t>(point.get_spoint() + other_tree.size());
|
||||
}
|
||||
|
||||
|
||||
|
@ -750,9 +759,9 @@ namespace blt::gp
|
|||
operations.insert(operations.begin() + static_cast<ptrdiff_t>(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<i64>(bytes_in_head));
|
||||
}
|
||||
|
||||
void tree_t::modify_operator(const size_t point, operator_id new_id, std::optional<type_id> return_type)
|
||||
void slow_tree_manipulator_t::modify_operator(const size_t point, operator_id new_id, std::optional<type_id> 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<ptrdiff_t>(point) + 1, operations.end());
|
||||
const size_t after_bytes = calculate_ephemeral_size(tree->operations.begin() + static_cast<ptrdiff_t>(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<ptrdiff_t>(point) + 1, operations.end());
|
||||
const size_t after_bytes = calculate_ephemeral_size(tree->operations.begin() + static_cast<ptrdiff_t>(point) + 1, tree->operations.end());
|
||||
move_data.move(after_bytes);
|
||||
}
|
||||
handle_operator_inserted(operations[point]);
|
||||
tree->handle_operator_inserted(tree->operations[point]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue