diff --git a/include/interval-tree/draw.hpp b/include/interval-tree/draw.hpp index f6768ce..6665975 100644 --- a/include/interval-tree/draw.hpp +++ b/include/interval-tree/draw.hpp @@ -21,15 +21,15 @@ namespace lib_interval_tree {}; template <> - struct NumericalPointerEquivalent + struct NumericalPointerEquivalent { - using type = unsigned long; + using type = uint32_t; }; template <> - struct NumericalPointerEquivalent + struct NumericalPointerEquivalent { - using type = unsigned long long; + using type = uint64_t; }; template diff --git a/include/interval-tree/interval_tree.hpp b/include/interval-tree/interval_tree.hpp index 513a555..88990c7 100644 --- a/include/interval-tree/interval_tree.hpp +++ b/include/interval-tree/interval_tree.hpp @@ -886,19 +886,27 @@ namespace lib_interval_tree throw std::out_of_range("cannot erase end iterator"); auto next = iter; - ++next; - node_type* y; - if (!iter.node_->left_ || !iter.node_->right_) - y = iter.node_; - else - y = successor(iter.node_); + node_type* y = [&next, &iter, this]() { + if (!iter.node_->left_ || !iter.node_->right_) + { + ++next; + return iter.node_; + } + else + { + const auto y = successor(iter.node_); + next = iterator{iter.node_, this}; + return y; + } + }(); - node_type* x; - if (y->left_) - x = y->left_; - else - x = y->right_; + node_type* x = [y](){ + if (y->left_) + return y->left_; + else + return y->right_; + }(); if (x) x->parent_ = y->parent_; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index a0cfc23..32b946c 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -28,6 +28,10 @@ target_compile_options(tree-tests PUBLIC "$<$:${DEBUG_OPTIONS}>") set(RELEASE_OPTIONS -fexceptions -O3 -Wall -pedantic) target_compile_options(tree-tests PUBLIC "$<$:${RELEASE_OPTIONS}>") +if (INT_TREE_DRAW_EXAMPLES) + target_link_libraries(tree-tests PRIVATE cairo cairo-wrap) +endif() + # If msys2, copy dynamic libraries to executable directory, visual studio does this automatically. # And there is no need on linux. if (DEFINED ENV{MSYSTEM}) diff --git a/tests/erase_tests.hpp b/tests/erase_tests.hpp index a5ecbdb..e0cce41 100644 --- a/tests/erase_tests.hpp +++ b/tests/erase_tests.hpp @@ -1,5 +1,8 @@ #pragma once +#include "interval_io.hpp" +#include "test_utility.hpp" + #include #include #include @@ -48,7 +51,7 @@ class OracleInterval : public lib_interval_tree::intervallivingInstances; @@ -73,6 +76,23 @@ class EraseTests public: using interval_type = OracleInterval; +public: + auto makeTree() + { + lib_interval_tree::interval_tree_t regularTree; + regularTree.insert({16, 21}); + regularTree.insert({8, 9}); + regularTree.insert({25, 30}); + regularTree.insert({5, 8}); + regularTree.insert({15, 23}); + regularTree.insert({17, 19}); + regularTree.insert({26, 26}); + regularTree.insert({0, 3}); + regularTree.insert({6, 10}); + regularTree.insert({19, 20}); + return regularTree; + } + protected: Oracle oracle; lib_interval_tree::interval_tree > tree; @@ -162,3 +182,84 @@ TEST_F(EraseTests, RandomEraseTest) testMaxProperty(tree); testTreeHeightHealth(tree); } + + + +TEST_F(EraseTests, MassiveDeleteEntireTreeWithEraseReturnIterator) +{ + constexpr int amount = 1000; + + for (int i = 0; i != amount; ++i) + tree.insert(makeSafeOracleInterval(&oracle, distSmall(gen), distSmall(gen))); + + for(auto iter = tree.begin(); !tree.empty();) + { + iter = tree.erase(iter); + } + + EXPECT_EQ(oracle.livingInstances, 0); + testMaxProperty(tree); + testTreeHeightHealth(tree); +} + +TEST_F(EraseTests, ReturnedIteratorPointsToNextInOrderNode) +{ + auto regularTree = makeTree(); + auto iter = regularTree.erase(regularTree.find({16, 21})); + EXPECT_EQ(*iter, (decltype(regularTree)::interval_type{17, 19})) << *iter; + + regularTree = makeTree(); + iter = regularTree.erase(regularTree.find({8, 9})); + EXPECT_EQ(*iter, (decltype(regularTree)::interval_type{15, 23})) << *iter; + + regularTree = makeTree(); + iter = regularTree.erase(regularTree.find({25, 30})); + EXPECT_EQ(*iter, (decltype(regularTree)::interval_type{26, 26})) << *iter; + + regularTree = makeTree(); + iter = regularTree.erase(regularTree.find({5, 8})); + EXPECT_EQ(*iter, (decltype(regularTree)::interval_type{6, 10})) << *iter; + + regularTree = makeTree(); + iter = regularTree.erase(regularTree.find({15, 23})); + EXPECT_EQ(*iter, (decltype(regularTree)::interval_type{16, 21})) << *iter; + + regularTree = makeTree(); + iter = regularTree.erase(regularTree.find({17, 19})); + EXPECT_EQ(*iter, (decltype(regularTree)::interval_type{19, 20})) << *iter; + + regularTree = makeTree(); + iter = regularTree.erase(regularTree.find({26, 26})); + EXPECT_EQ(iter, regularTree.end()); + + regularTree = makeTree(); + iter = regularTree.erase(regularTree.find({0, 3})); + EXPECT_EQ(*iter, (decltype(regularTree)::interval_type{5, 8})) << *iter; + + regularTree = makeTree(); + iter = regularTree.erase(regularTree.find({6, 10})); + EXPECT_EQ(*iter, (decltype(regularTree)::interval_type{8, 9})) << *iter; + + regularTree = makeTree(); + iter = regularTree.erase(regularTree.find({19, 20})); + EXPECT_EQ(*iter, (decltype(regularTree)::interval_type{25, 30})) << *iter; +} + +TEST_F(EraseTests, CanEraseEntireTreeUsingReturnedIterator) +{ + auto tree = makeTree(); + for (auto iter = tree.begin(); iter != tree.end();) + iter = tree.erase(iter); + EXPECT_EQ(tree.empty(), true); +} + +TEST_F(EraseTests, FromNuiTest) +{ + lib_interval_tree::interval_tree_t tree; + tree.insert({0, 0}); + tree.insert({4, 4}); + tree.insert({13, 13}); + + auto iter = tree.erase(tree.find({4, 4})); + EXPECT_EQ(*iter, (decltype(tree)::interval_type{13, 13})) << *iter; +} diff --git a/tests/interval_io.hpp b/tests/interval_io.hpp new file mode 100644 index 0000000..520c4be --- /dev/null +++ b/tests/interval_io.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include + +#include + +namespace lib_interval_tree +{ + template + std::ostream& + operator<<(std::ostream& os, lib_interval_tree::interval const& interval) + { + os << '[' << interval.low() << ", " << interval.high() << ']'; + return os; + } +} \ No newline at end of file