From fa07017299de05b42a099bcfc56ae8cc2a056163 Mon Sep 17 00:00:00 2001
From: Brett <brettmaster1@gmail.com>
Date: Mon, 20 Jan 2025 23:15:20 -0500
Subject: [PATCH] fix bug in debug mode

---
 CMakeLists.txt        |  2 +-
 include/blt/gp/tree.h | 10 +++++-----
 src/tree.cpp          |  6 ++++--
 tests/drop_test.cpp   | 34 ++++++++++++++++++++--------------
 4 files changed, 30 insertions(+), 22 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 48fa62f..749752e 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.3.26)
+project(blt-gp VERSION 0.3.27)
 
 include(CTest)
 
diff --git a/include/blt/gp/tree.h b/include/blt/gp/tree.h
index b82c786..9922f86 100644
--- a/include/blt/gp/tree.h
+++ b/include/blt/gp/tree.h
@@ -290,17 +290,17 @@ namespace blt::gp
             {
                 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;
-                if (copy_it->is_value())
-                {
-                    copy.handle_refcount_increment(copy_it, total_copy_bytes);
-                    total_copy_bytes += copy_it->type_size();
-                }
                 ++copy_it;
             }
             const auto op_it_cpy = op_it;
diff --git a/src/tree.cpp b/src/tree.cpp
index be8ea89..128f718 100644
--- a/src/tree.cpp
+++ b/src/tree.cpp
@@ -273,7 +273,7 @@ namespace blt::gp
         operators.reserve(operators.size() + ops);
         // TODO something better!
         for (size_t i = 0; i < ops; ++i)
-            operators.emplace_back(0,0,false, operator_special_flags{});
+            operators.emplace_back(0, 0, false, operator_special_flags{});
         size_t for_bytes = 0;
         size_t pos = 0;
         for (auto& it : iterate(point_begin_itr, point_end_itr).rev())
@@ -576,7 +576,9 @@ namespace blt::gp
             const auto v1 = results.values.bytes_in_head();
             const auto v2 = static_cast<ptrdiff_t>(operations.front().type_size());
 
-            m_program->get_destroy_func(operations.front().id())(detail::destroy_t::RETURN, results.values.from(operations.front().type_size()));
+            // ephemeral don't need to be dropped as there are no copies which matter when checking the tree
+            if (!operations.front().get_flags().is_ephemeral())
+                m_program->get_destroy_func(operations.front().id())(detail::destroy_t::RETURN, results.values.from(operations.front().type_size()));
             if (v1 != v2)
             {
                 const auto vd = std::abs(v1 - v2);
diff --git a/tests/drop_test.cpp b/tests/drop_test.cpp
index 7d8fccb..9d4d064 100644
--- a/tests/drop_test.cpp
+++ b/tests/drop_test.cpp
@@ -28,25 +28,30 @@ std::atomic_uint64_t ephemeral_drop = 0;
 
 struct drop_type
 {
-    float value;
+    float* m_value;
     bool ephemeral = false;
 
-    drop_type() : value(0)
+    drop_type() : m_value(new float(0))
     {
         ++normal_construct;
     }
 
-    explicit drop_type(const float silly) : value(silly)
+    explicit drop_type(const float silly) : m_value(new float(silly))
     {
         ++normal_construct;
     }
 
-    explicit drop_type(const float silly, bool) : value(silly), ephemeral(true)
+    explicit drop_type(const float silly, bool) : m_value(new float(silly)), ephemeral(true)
     {
         // BLT_TRACE("Constructor with value %f", silly);
         ++ephemeral_construct;
     }
 
+    [[nodiscard]] float value() const
+    {
+        return *m_value;
+    }
+
     void drop() const
     {
         if (ephemeral)
@@ -55,11 +60,12 @@ struct drop_type
             ++ephemeral_drop;
         }else
             ++normal_drop;
+        delete m_value;
     }
 
     friend std::ostream& operator<<(std::ostream& os, const drop_type& dt)
     {
-        os << dt.value;
+        os << dt.m_value;
         return os;
     }
 };
@@ -83,14 +89,14 @@ prog_config_t config = prog_config_t()
 
 example::symbolic_regression_t regression{691ul, config};
 
-operation_t add{[](const drop_type a, const drop_type b) { return drop_type{a.value + b.value}; }, "add"};
-operation_t sub([](const drop_type a, const drop_type b) { return drop_type{a.value - b.value}; }, "sub");
-operation_t mul([](const drop_type a, const drop_type b) { return drop_type{a.value * b.value}; }, "mul");
-operation_t pro_div([](const drop_type a, const drop_type b) { return drop_type{b.value == 0.0f ? 0.0f : a.value / b.value}; }, "div");
-operation_t op_sin([](const drop_type a) { return drop_type{std::sin(a.value)}; }, "sin");
-operation_t op_cos([](const drop_type a) { return drop_type{std::cos(a.value)}; }, "cos");
-operation_t op_exp([](const drop_type a) { return drop_type{std::exp(a.value)}; }, "exp");
-operation_t op_log([](const drop_type a) { return drop_type{a.value <= 0.0f ? 0.0f : std::log(a.value)}; }, "log");
+operation_t add{[](const drop_type a, const drop_type b) { return drop_type{a.value() + b.value()}; }, "add"};
+operation_t sub([](const drop_type a, const drop_type b) { return drop_type{a.value() - b.value()}; }, "sub");
+operation_t mul([](const drop_type a, const drop_type b) { return drop_type{a.value() * b.value()}; }, "mul");
+operation_t pro_div([](const drop_type a, const drop_type b) { return drop_type{b.value() == 0.0f ? 0.0f : a.value() / b.value()}; }, "div");
+operation_t op_sin([](const drop_type a) { return drop_type{std::sin(a.value())}; }, "sin");
+operation_t op_cos([](const drop_type a) { return drop_type{std::cos(a.value())}; }, "cos");
+operation_t op_exp([](const drop_type a) { return drop_type{std::exp(a.value())}; }, "exp");
+operation_t op_log([](const drop_type a) { return drop_type{a.value() <= 0.0f ? 0.0f : std::log(a.value())}; }, "log");
 auto lit = operation_t([]()
 {
     return drop_type{regression.get_program().get_random().get_float(-1.0f, 1.0f), true};
@@ -108,7 +114,7 @@ bool fitness_function(const tree_t& current_tree, fitness_t& fitness, size_t)
     {
         BLT_GP_UPDATE_CONTEXT(fitness_case);
         auto val = current_tree.get_evaluation_ref<drop_type>(fitness_case);
-        const auto diff = std::abs(fitness_case.y - val.get().value);
+        const auto diff = std::abs(fitness_case.y - val.get().value());
         if (diff < value_cutoff)
         {
             fitness.raw_fitness += diff;