From 92ab0326113d1d6732a6d81dcc25abb330053b22 Mon Sep 17 00:00:00 2001 From: Aaron Green Date: Mon, 23 Sep 2024 19:57:03 +0000 Subject: [PATCH] pw_containers: Fix tree rebalancing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `AATreeItem::Rebalance` did not correctly update the parent of a node when rebalancing a subtree. As a result, when the subtree root was rebalanced into a different position, such as a leaf node, other nodes could become orphaned. The unit tests did not include enough items to encounter this error. The default number of items has been doubled, which triggers the error without the corresponding fix. Change-Id: I7ae4140673d2e1d30b8e193d3750201a4b2ca8a5 Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/237415 Commit-Queue: Aaron Green Docs-Not-Needed: Aaron Green Presubmit-Verified: CQ Bot Account Reviewed-by: Wyatt Hepler Lint: Lint 🤖 --- pw_containers/aa_tree_item.cc | 7 +- pw_containers/intrusive_map_test.cc | 115 +++++++++------- pw_containers/intrusive_multimap_test.cc | 159 ++++++++++++++--------- 3 files changed, 175 insertions(+), 106 deletions(-) diff --git a/pw_containers/aa_tree_item.cc b/pw_containers/aa_tree_item.cc index 681f742cbb..adb484acfc 100644 --- a/pw_containers/aa_tree_item.cc +++ b/pw_containers/aa_tree_item.cc @@ -170,6 +170,8 @@ AATreeItem* AATreeItem::Rebalance() { node->right_->SetLevel(new_level); } } + AATreeItem* parent = node->parent_.get(); + AATreeItem* orig = node; node = node->Skew(); if (node->right_.get() != nullptr) { node->SetRight(node->right_->Skew()); @@ -181,10 +183,11 @@ AATreeItem* AATreeItem::Rebalance() { if (node->right_.get() != nullptr) { node->SetRight(node->right_->Split()); } - if (node->parent_.get() == nullptr) { + if (parent == nullptr) { return node; } - node = node->parent_.get(); + parent->Replace(orig, node); + node = parent; } } diff --git a/pw_containers/intrusive_map_test.cc b/pw_containers/intrusive_map_test.cc index c56fca6b71..d1ec28242b 100644 --- a/pw_containers/intrusive_map_test.cc +++ b/pw_containers/intrusive_map_test.cc @@ -45,7 +45,7 @@ struct TestItem : public ::pw::IntrusiveMap::Item, class IntrusiveMapTest : public ::testing::Test { protected: using IntrusiveMap = ::pw::IntrusiveMap; - static constexpr size_t kNumItems = 5; + static constexpr size_t kNumItems = 10; void SetUp() override { map_.insert(items_.begin(), items_.end()); } @@ -57,6 +57,11 @@ class IntrusiveMapTest : public ::testing::Test { {20, "c"}, {40, "d"}, {10, "e"}, + {35, "A"}, + {55, "B"}, + {25, "C"}, + {45, "D"}, + {15, "E"}, }}; IntrusiveMap map_; @@ -128,10 +133,15 @@ TEST_F(IntrusiveMapTest, Construct_CustomCompare) { EXPECT_EQ(map.size(), items_.size()); auto iter = map.begin(); + EXPECT_EQ((iter++)->key(), 55U); EXPECT_EQ((iter++)->key(), 50U); + EXPECT_EQ((iter++)->key(), 45U); EXPECT_EQ((iter++)->key(), 40U); + EXPECT_EQ((iter++)->key(), 35U); EXPECT_EQ((iter++)->key(), 30U); + EXPECT_EQ((iter++)->key(), 25U); EXPECT_EQ((iter++)->key(), 20U); + EXPECT_EQ((iter++)->key(), 15U); EXPECT_EQ((iter++)->key(), 10U); map.clear(); } @@ -158,6 +168,11 @@ TEST_F(IntrusiveMapTest, Construct_CustomGetKey) { pw::IntrusiveMap; CustomMapType map(items_.begin(), items_.end()); auto iter = map.begin(); + EXPECT_STREQ((iter++)->name(), "A"); + EXPECT_STREQ((iter++)->name(), "B"); + EXPECT_STREQ((iter++)->name(), "C"); + EXPECT_STREQ((iter++)->name(), "D"); + EXPECT_STREQ((iter++)->name(), "E"); EXPECT_STREQ((iter++)->name(), "a"); EXPECT_STREQ((iter++)->name(), "b"); EXPECT_STREQ((iter++)->name(), "c"); @@ -206,13 +221,13 @@ TEST_F(IntrusiveMapTest, Iterator) { for (size_t i = 0; i < kNumItems; ++i) { auto& item = *iter++; EXPECT_EQ(item.key(), key); - key += 10; + key += 5; } EXPECT_EQ(key, 60U); EXPECT_EQ(iter, map.end()); EXPECT_EQ(iter, map.cend()); for (size_t i = 0; i < kNumItems; ++i) { - key -= 10; + key -= 5; EXPECT_EQ((--iter)->key(), key); } EXPECT_EQ(key, 10U); @@ -223,20 +238,20 @@ TEST_F(IntrusiveMapTest, Iterator) { TEST_F(IntrusiveMapTest, ReverseIterator) { const IntrusiveMap& map = map_; auto iter = map.rbegin(); - size_t key = 50; + size_t key = 55; for (size_t i = 0; i < kNumItems; ++i) { auto& item = *iter++; EXPECT_EQ(item.key(), key); - key -= 10; + key -= 5; } - EXPECT_EQ(key, 0U); + EXPECT_EQ(key, 5U); EXPECT_EQ(iter, map.rend()); EXPECT_EQ(iter, map.crend()); for (size_t i = 0; i < kNumItems; ++i) { - key += 10; + key += 5; EXPECT_EQ((--iter)->key(), key); } - EXPECT_EQ(key, 50U); + EXPECT_EQ(key, 55U); EXPECT_EQ(iter, map.rbegin()); EXPECT_EQ(iter, map.crbegin()); } @@ -471,12 +486,14 @@ TEST_F(IntrusiveMapTest, Insert_DerivedItems_CompilationFails) { } TEST_F(IntrusiveMapTest, Erase_OneItem) { - EXPECT_EQ(map_.size(), kNumItems); - EXPECT_EQ(map_.erase(items_[2].key()), 1U); - EXPECT_EQ(map_.size(), kNumItems - 1); - - auto iter = map_.find(items_[2].key()); - EXPECT_EQ(iter, map_.end()); + for (size_t i = 0; i < kNumItems; ++i) { + EXPECT_EQ(map_.size(), kNumItems); + EXPECT_EQ(map_.erase(items_[i].key()), 1U); + EXPECT_EQ(map_.size(), kNumItems - 1); + auto iter = map_.find(items_[i].key()); + EXPECT_EQ(iter, map_.end()); + map_.insert(items_[i]); + } } TEST_F(IntrusiveMapTest, Erase_OnlyItem) { @@ -506,7 +523,7 @@ TEST_F(IntrusiveMapTest, Erase_Range) { auto iter = map_.erase(first, last); EXPECT_EQ(map_.size(), 2U); EXPECT_TRUE(std::is_sorted(map_.begin(), map_.end(), LessThan)); - EXPECT_EQ(iter->key(), 50U); + EXPECT_EQ(iter->key(), 55U); } TEST_F(IntrusiveMapTest, Erase_MissingItem) { EXPECT_EQ(map_.erase(100), 0U); } @@ -586,9 +603,9 @@ TEST_F(IntrusiveMapTest, Swap_Empty) { TEST_F(IntrusiveMapTest, Merge) { std::array items = {{ - {15, "f"}, - {45, "g"}, - {65, "h"}, + {5, "f"}, + {75, "g"}, + {85, "h"}, }}; IntrusiveMap map(items.begin(), items.end()); @@ -597,13 +614,18 @@ TEST_F(IntrusiveMapTest, Merge) { EXPECT_EQ(map_.size(), kNumItems + 3); EXPECT_TRUE(std::is_sorted(map_.begin(), map_.end(), LessThan)); EXPECT_STREQ(map_.at(30).name(), "a"); + EXPECT_STREQ(map_.at(35).name(), "A"); EXPECT_STREQ(map_.at(50).name(), "b"); + EXPECT_STREQ(map_.at(55).name(), "B"); EXPECT_STREQ(map_.at(20).name(), "c"); + EXPECT_STREQ(map_.at(25).name(), "C"); EXPECT_STREQ(map_.at(40).name(), "d"); + EXPECT_STREQ(map_.at(45).name(), "D"); EXPECT_STREQ(map_.at(10).name(), "e"); - EXPECT_STREQ(map_.at(15).name(), "f"); - EXPECT_STREQ(map_.at(45).name(), "g"); - EXPECT_STREQ(map_.at(65).name(), "h"); + EXPECT_STREQ(map_.at(15).name(), "E"); + EXPECT_STREQ(map_.at(5).name(), "f"); + EXPECT_STREQ(map_.at(75).name(), "g"); + EXPECT_STREQ(map_.at(85).name(), "h"); // Explicitly clear the map before items goes out of scope. map_.clear(); @@ -694,18 +716,18 @@ TEST_F(IntrusiveMapTest, Count_NoSuchKey) { TEST_F(IntrusiveMapTest, Find) { const IntrusiveMap& map = map_; - size_t key = 0; + size_t key = 10; for (size_t i = 0; i < kNumItems; ++i) { - key += 10; auto iter = map.find(key); ASSERT_NE(iter, map.end()); EXPECT_EQ(iter->key(), key); + key += 5; } } TEST_F(IntrusiveMapTest, Find_NoSuchKey) { const IntrusiveMap& map = map_; - auto iter = map.find(45); + auto iter = map.find(60); EXPECT_EQ(iter, map.end()); } @@ -734,51 +756,51 @@ TEST_F(IntrusiveMapTest, LowerBound) { TEST_F(IntrusiveMapTest, LowerBound_NoExactKey) { const IntrusiveMap& map = map_; - auto iter = map.lower_bound(5); + auto iter = map.lower_bound(6); ASSERT_NE(iter, map.end()); EXPECT_STREQ(iter->name(), "e"); - iter = map.lower_bound(15); + iter = map.lower_bound(16); ASSERT_NE(iter, map.end()); EXPECT_STREQ(iter->name(), "c"); - iter = map.lower_bound(25); + iter = map.lower_bound(26); ASSERT_NE(iter, map.end()); EXPECT_STREQ(iter->name(), "a"); - iter = map.lower_bound(35); + iter = map.lower_bound(36); ASSERT_NE(iter, map.end()); EXPECT_STREQ(iter->name(), "d"); - iter = map.lower_bound(45); + iter = map.lower_bound(46); ASSERT_NE(iter, map.end()); EXPECT_STREQ(iter->name(), "b"); } TEST_F(IntrusiveMapTest, LowerBound_OutOfRange) { const IntrusiveMap& map = map_; - EXPECT_EQ(map.lower_bound(55), map.end()); + EXPECT_EQ(map.lower_bound(56), map.end()); } TEST_F(IntrusiveMapTest, UpperBound) { const IntrusiveMap& map = map_; - auto iter = map.upper_bound(10); + auto iter = map.upper_bound(15); ASSERT_NE(iter, map.end()); EXPECT_STREQ(iter->name(), "c"); - iter = map.upper_bound(20); + iter = map.upper_bound(25); ASSERT_NE(iter, map.end()); EXPECT_STREQ(iter->name(), "a"); - iter = map.upper_bound(30); + iter = map.upper_bound(35); ASSERT_NE(iter, map.end()); EXPECT_STREQ(iter->name(), "d"); - iter = map.upper_bound(40); + iter = map.upper_bound(45); ASSERT_NE(iter, map.end()); EXPECT_STREQ(iter->name(), "b"); - EXPECT_EQ(map.upper_bound(50), map.end()); + EXPECT_EQ(map.upper_bound(55), map.end()); } TEST_F(IntrusiveMapTest, UpperBound_NoExactKey) { @@ -818,36 +840,37 @@ TEST_F(IntrusiveMapTest, EqualRange) { ASSERT_NE(lower, map.end()); EXPECT_STREQ(lower->name(), "e"); ASSERT_NE(upper, map.end()); - EXPECT_STREQ(upper->name(), "c"); + EXPECT_STREQ(upper->name(), "E"); std::tie(lower, upper) = map.equal_range(20); ASSERT_NE(lower, map.end()); EXPECT_STREQ(lower->name(), "c"); ASSERT_NE(upper, map.end()); - EXPECT_STREQ(upper->name(), "a"); + EXPECT_STREQ(upper->name(), "C"); std::tie(lower, upper) = map.equal_range(30); ASSERT_NE(lower, map.end()); EXPECT_STREQ(lower->name(), "a"); ASSERT_NE(upper, map.end()); - EXPECT_STREQ(upper->name(), "d"); + EXPECT_STREQ(upper->name(), "A"); std::tie(lower, upper) = map.equal_range(40); ASSERT_NE(lower, map.end()); EXPECT_STREQ(lower->name(), "d"); ASSERT_NE(upper, map.end()); - EXPECT_STREQ(upper->name(), "b"); + EXPECT_STREQ(upper->name(), "D"); std::tie(lower, upper) = map.equal_range(50); ASSERT_NE(lower, map.end()); EXPECT_STREQ(lower->name(), "b"); - EXPECT_EQ(upper, map.end()); + ASSERT_NE(upper, map.end()); + EXPECT_STREQ(upper->name(), "B"); } TEST_F(IntrusiveMapTest, EqualRange_NoExactKey) { const IntrusiveMap& map = map_; - auto pair = map.equal_range(5); + auto pair = map.equal_range(6); IntrusiveMap::const_iterator lower = pair.first; IntrusiveMap::const_iterator upper = pair.second; ASSERT_NE(lower, map.end()); @@ -855,25 +878,25 @@ TEST_F(IntrusiveMapTest, EqualRange_NoExactKey) { ASSERT_NE(upper, map.end()); EXPECT_STREQ(upper->name(), "e"); - std::tie(lower, upper) = map.equal_range(15); + std::tie(lower, upper) = map.equal_range(16); ASSERT_NE(lower, map.end()); EXPECT_STREQ(lower->name(), "c"); ASSERT_NE(upper, map.end()); EXPECT_STREQ(upper->name(), "c"); - std::tie(lower, upper) = map.equal_range(25); + std::tie(lower, upper) = map.equal_range(26); ASSERT_NE(lower, map.end()); EXPECT_STREQ(lower->name(), "a"); ASSERT_NE(upper, map.end()); EXPECT_STREQ(upper->name(), "a"); - std::tie(lower, upper) = map.equal_range(35); + std::tie(lower, upper) = map.equal_range(36); ASSERT_NE(lower, map.end()); EXPECT_STREQ(lower->name(), "d"); ASSERT_NE(upper, map.end()); EXPECT_STREQ(upper->name(), "d"); - std::tie(lower, upper) = map.equal_range(45); + std::tie(lower, upper) = map.equal_range(46); ASSERT_NE(lower, map.end()); EXPECT_STREQ(lower->name(), "b"); ASSERT_NE(upper, map.end()); @@ -883,7 +906,7 @@ TEST_F(IntrusiveMapTest, EqualRange_NoExactKey) { TEST_F(IntrusiveMapTest, EqualRange_OutOfRange) { const IntrusiveMap& map = map_; - auto pair = map.equal_range(55); + auto pair = map.equal_range(56); IntrusiveMap::const_iterator lower = pair.first; IntrusiveMap::const_iterator upper = pair.second; EXPECT_EQ(lower, map.end()); diff --git a/pw_containers/intrusive_multimap_test.cc b/pw_containers/intrusive_multimap_test.cc index 47ce5f016f..1da81ed7bf 100644 --- a/pw_containers/intrusive_multimap_test.cc +++ b/pw_containers/intrusive_multimap_test.cc @@ -45,7 +45,7 @@ struct TestItem : public ::pw::IntrusiveMultiMap::Item, class IntrusiveMultiMapTest : public ::testing::Test { protected: using IntrusiveMultiMap = ::pw::IntrusiveMultiMap; - static constexpr size_t kNumItems = 5; + static constexpr size_t kNumItems = 10; void SetUp() override { multimap_.insert(items_.begin(), items_.end()); } @@ -57,6 +57,11 @@ class IntrusiveMultiMapTest : public ::testing::Test { {20, "c"}, {40, "d"}, {10, "e"}, + {35, "A"}, + {55, "B"}, + {25, "C"}, + {45, "D"}, + {15, "E"}, }}; IntrusiveMultiMap multimap_; @@ -125,10 +130,15 @@ TEST_F(IntrusiveMultiMapTest, Construct_CustomCompare) { using CustomMapType = pw::IntrusiveMultiMap; CustomMapType multimap(items_.begin(), items_.end()); auto iter = multimap.begin(); + EXPECT_EQ((iter++)->key(), 55U); EXPECT_EQ((iter++)->key(), 50U); + EXPECT_EQ((iter++)->key(), 45U); EXPECT_EQ((iter++)->key(), 40U); + EXPECT_EQ((iter++)->key(), 35U); EXPECT_EQ((iter++)->key(), 30U); + EXPECT_EQ((iter++)->key(), 25U); EXPECT_EQ((iter++)->key(), 20U); + EXPECT_EQ((iter++)->key(), 15U); EXPECT_EQ((iter++)->key(), 10U); EXPECT_EQ(iter, multimap.end()); multimap.clear(); @@ -156,6 +166,11 @@ TEST_F(IntrusiveMultiMapTest, Construct_CustomGetKey) { pw::IntrusiveMultiMap; CustomMapType multimap(items_.begin(), items_.end()); auto iter = multimap.begin(); + EXPECT_STREQ((iter++)->name(), "A"); + EXPECT_STREQ((iter++)->name(), "B"); + EXPECT_STREQ((iter++)->name(), "C"); + EXPECT_STREQ((iter++)->name(), "D"); + EXPECT_STREQ((iter++)->name(), "E"); EXPECT_STREQ((iter++)->name(), "a"); EXPECT_STREQ((iter++)->name(), "b"); EXPECT_STREQ((iter++)->name(), "c"); @@ -197,13 +212,13 @@ TEST_F(IntrusiveMultiMapTest, Iterator) { for (size_t i = 0; i < kNumItems; ++i) { auto& item = *iter++; EXPECT_EQ(item.key(), key); - key += 10; + key += 5; } EXPECT_EQ(key, 60U); EXPECT_EQ(iter, multimap.end()); EXPECT_EQ(iter, multimap.cend()); for (size_t i = 0; i < kNumItems; ++i) { - key -= 10; + key -= 5; EXPECT_EQ((--iter)->key(), key); } EXPECT_EQ(key, 10U); @@ -214,20 +229,20 @@ TEST_F(IntrusiveMultiMapTest, Iterator) { TEST_F(IntrusiveMultiMapTest, ReverseIterator) { const IntrusiveMultiMap& multimap = multimap_; auto iter = multimap.rbegin(); - size_t key = 50; + size_t key = 55; for (size_t i = 0; i < kNumItems; ++i) { auto& item = *iter++; EXPECT_EQ(item.key(), key); - key -= 10; + key -= 5; } - EXPECT_EQ(key, 0U); + EXPECT_EQ(key, 5U); EXPECT_EQ(iter, multimap.rend()); EXPECT_EQ(iter, multimap.crend()); for (size_t i = 0; i < kNumItems; ++i) { - key += 10; + key += 5; EXPECT_EQ((--iter)->key(), key); } - EXPECT_EQ(key, 50U); + EXPECT_EQ(key, 55U); EXPECT_EQ(iter, multimap.rbegin()); EXPECT_EQ(iter, multimap.crbegin()); } @@ -494,12 +509,14 @@ TEST_F(IntrusiveMultiMapTest, Insert_DerivedItems_CompilationFails) { } TEST_F(IntrusiveMultiMapTest, Erase_OneItem) { - EXPECT_EQ(multimap_.size(), kNumItems); - EXPECT_EQ(multimap_.erase(items_[2].key()), 1U); - EXPECT_EQ(multimap_.size(), kNumItems - 1); - - auto iter = multimap_.find(items_[2].key()); - EXPECT_EQ(iter, multimap_.end()); + for (size_t i = 0; i < kNumItems; ++i) { + EXPECT_EQ(multimap_.size(), kNumItems); + EXPECT_EQ(multimap_.erase(items_[i].key()), 1U); + EXPECT_EQ(multimap_.size(), kNumItems - 1); + auto iter = multimap_.find(items_[i].key()); + EXPECT_EQ(iter, multimap_.end()); + multimap_.insert(items_[i]); + } } TEST_F(IntrusiveMultiMapTest, Erase_OnlyItem) { @@ -529,7 +546,7 @@ TEST_F(IntrusiveMultiMapTest, Erase_Range) { auto iter = multimap_.erase(first, last); EXPECT_EQ(multimap_.size(), 2U); EXPECT_TRUE(std::is_sorted(multimap_.begin(), multimap_.end(), LessThan)); - EXPECT_EQ(iter->key(), 50U); + EXPECT_EQ(iter->key(), 55U); } TEST_F(IntrusiveMultiMapTest, Erase_MissingItem) { @@ -566,14 +583,14 @@ TEST_F(IntrusiveMultiMapTest, Erase_Reinsert) { } TEST_F(IntrusiveMultiMapTest, Erase_Duplicate) { - TestItem item1(35, "1"); - TestItem item2(35, "2"); - TestItem item3(35, "3"); + TestItem item1(32, "1"); + TestItem item2(32, "2"); + TestItem item3(32, "3"); multimap_.insert(item1); multimap_.insert(item2); multimap_.insert(item3); - auto iter = multimap_.find(35); + auto iter = multimap_.find(32); ASSERT_NE(iter, multimap_.end()); EXPECT_STREQ(iter->name(), "1"); @@ -586,7 +603,7 @@ TEST_F(IntrusiveMultiMapTest, Erase_Duplicate) { EXPECT_STREQ(iter->name(), "3"); multimap_.erase(iter); - EXPECT_EQ(multimap_.find(35), multimap_.end()); + EXPECT_EQ(multimap_.find(32), multimap_.end()); } TEST_F(IntrusiveMultiMapTest, Swap) { @@ -602,10 +619,15 @@ TEST_F(IntrusiveMultiMapTest, Swap) { EXPECT_TRUE(std::is_sorted(multimap.begin(), multimap.end(), LessThan)); auto iter = multimap.begin(); EXPECT_STREQ((iter++)->name(), "e"); + EXPECT_STREQ((iter++)->name(), "E"); EXPECT_STREQ((iter++)->name(), "c"); + EXPECT_STREQ((iter++)->name(), "C"); EXPECT_STREQ((iter++)->name(), "a"); + EXPECT_STREQ((iter++)->name(), "A"); EXPECT_STREQ((iter++)->name(), "d"); + EXPECT_STREQ((iter++)->name(), "D"); EXPECT_STREQ((iter++)->name(), "b"); + EXPECT_STREQ((iter++)->name(), "B"); EXPECT_EQ(iter, multimap.end()); multimap.clear(); @@ -629,10 +651,15 @@ TEST_F(IntrusiveMultiMapTest, Swap_Empty) { EXPECT_TRUE(std::is_sorted(multimap.begin(), multimap.end(), LessThan)); auto iter = multimap.begin(); EXPECT_STREQ((iter++)->name(), "e"); + EXPECT_STREQ((iter++)->name(), "E"); EXPECT_STREQ((iter++)->name(), "c"); + EXPECT_STREQ((iter++)->name(), "C"); EXPECT_STREQ((iter++)->name(), "a"); + EXPECT_STREQ((iter++)->name(), "A"); EXPECT_STREQ((iter++)->name(), "d"); + EXPECT_STREQ((iter++)->name(), "D"); EXPECT_STREQ((iter++)->name(), "b"); + EXPECT_STREQ((iter++)->name(), "B"); EXPECT_EQ(iter, multimap.end()); multimap.clear(); @@ -641,9 +668,9 @@ TEST_F(IntrusiveMultiMapTest, Swap_Empty) { TEST_F(IntrusiveMultiMapTest, Merge) { std::array items = {{ - {15, "f"}, - {45, "g"}, - {65, "h"}, + {5, "f"}, + {75, "g"}, + {85, "h"}, }}; IntrusiveMultiMap multimap(items.begin(), items.end()); @@ -652,13 +679,18 @@ TEST_F(IntrusiveMultiMapTest, Merge) { EXPECT_EQ(multimap_.size(), kNumItems + 3); EXPECT_TRUE(std::is_sorted(multimap_.begin(), multimap_.end(), LessThan)); auto iter = multimap_.begin(); - EXPECT_STREQ((iter++)->name(), "e"); EXPECT_STREQ((iter++)->name(), "f"); + EXPECT_STREQ((iter++)->name(), "e"); + EXPECT_STREQ((iter++)->name(), "E"); EXPECT_STREQ((iter++)->name(), "c"); + EXPECT_STREQ((iter++)->name(), "C"); EXPECT_STREQ((iter++)->name(), "a"); + EXPECT_STREQ((iter++)->name(), "A"); EXPECT_STREQ((iter++)->name(), "d"); - EXPECT_STREQ((iter++)->name(), "g"); + EXPECT_STREQ((iter++)->name(), "D"); EXPECT_STREQ((iter++)->name(), "b"); + EXPECT_STREQ((iter++)->name(), "B"); + EXPECT_STREQ((iter++)->name(), "g"); EXPECT_STREQ((iter++)->name(), "h"); EXPECT_EQ(iter, multimap_.end()); @@ -683,9 +715,9 @@ TEST_F(IntrusiveMultiMapTest, Merge_Empty) { TEST_F(IntrusiveMultiMapTest, Merge_WithDuplicates) { std::array items = {{ - {50, "B"}, - {40, "D"}, - {60, "F"}, + {15, "f"}, + {45, "g"}, + {55, "h"}, }}; IntrusiveMultiMap multimap(items.begin(), items.end()); @@ -695,13 +727,18 @@ TEST_F(IntrusiveMultiMapTest, Merge_WithDuplicates) { EXPECT_TRUE(std::is_sorted(multimap_.begin(), multimap_.end(), LessThan)); auto iter = multimap_.begin(); EXPECT_STREQ((iter++)->name(), "e"); + EXPECT_STREQ((iter++)->name(), "E"); + EXPECT_STREQ((iter++)->name(), "f"); EXPECT_STREQ((iter++)->name(), "c"); + EXPECT_STREQ((iter++)->name(), "C"); EXPECT_STREQ((iter++)->name(), "a"); + EXPECT_STREQ((iter++)->name(), "A"); EXPECT_STREQ((iter++)->name(), "d"); EXPECT_STREQ((iter++)->name(), "D"); + EXPECT_STREQ((iter++)->name(), "g"); EXPECT_STREQ((iter++)->name(), "b"); EXPECT_STREQ((iter++)->name(), "B"); - EXPECT_STREQ((iter++)->name(), "F"); + EXPECT_STREQ((iter++)->name(), "h"); EXPECT_EQ(iter, multimap_.end()); // Explicitly clear the multimap before items goes out of scope. @@ -716,9 +753,9 @@ struct MapItem : public ::pw::IntrusiveMap::Item, TEST_F(IntrusiveMultiMapTest, Merge_Map) { std::array items = {{ - {50, "B"}, - {40, "D"}, - {60, "F"}, + {15, "f"}, + {45, "g"}, + {55, "h"}, }}; ::pw::IntrusiveMap map(items.begin(), items.end()); @@ -728,13 +765,18 @@ TEST_F(IntrusiveMultiMapTest, Merge_Map) { EXPECT_TRUE(std::is_sorted(multimap_.begin(), multimap_.end(), LessThan)); auto iter = multimap_.begin(); EXPECT_STREQ((iter++)->name(), "e"); + EXPECT_STREQ((iter++)->name(), "E"); + EXPECT_STREQ((iter++)->name(), "f"); EXPECT_STREQ((iter++)->name(), "c"); + EXPECT_STREQ((iter++)->name(), "C"); EXPECT_STREQ((iter++)->name(), "a"); + EXPECT_STREQ((iter++)->name(), "A"); EXPECT_STREQ((iter++)->name(), "d"); EXPECT_STREQ((iter++)->name(), "D"); + EXPECT_STREQ((iter++)->name(), "g"); EXPECT_STREQ((iter++)->name(), "b"); EXPECT_STREQ((iter++)->name(), "B"); - EXPECT_STREQ((iter++)->name(), "F"); + EXPECT_STREQ((iter++)->name(), "h"); EXPECT_EQ(iter, multimap_.end()); // Explicitly clear the multimap before items goes out of scope. @@ -776,18 +818,18 @@ TEST_F(IntrusiveMultiMapTest, Count_WithDuplicates) { TEST_F(IntrusiveMultiMapTest, Find) { const IntrusiveMultiMap& multimap = multimap_; - size_t key = 0; + size_t key = 10; for (size_t i = 0; i < kNumItems; ++i) { - key += 10; auto iter = multimap.find(key); ASSERT_NE(iter, multimap.end()); EXPECT_EQ(iter->key(), key); + key += 5; } } TEST_F(IntrusiveMultiMapTest, Find_NoSuchKey) { const IntrusiveMultiMap& multimap = multimap_; - auto iter = multimap.find(45); + auto iter = multimap.find(60); EXPECT_EQ(iter, multimap.end()); } @@ -842,30 +884,30 @@ TEST_F(IntrusiveMultiMapTest, LowerBound) { TEST_F(IntrusiveMultiMapTest, LowerBound_NoExactKey) { const IntrusiveMultiMap& multimap = multimap_; - auto iter = multimap.lower_bound(5); + auto iter = multimap.lower_bound(6); ASSERT_NE(iter, multimap.end()); EXPECT_STREQ(iter->name(), "e"); - iter = multimap.lower_bound(15); + iter = multimap.lower_bound(16); ASSERT_NE(iter, multimap.end()); EXPECT_STREQ(iter->name(), "c"); - iter = multimap.lower_bound(25); + iter = multimap.lower_bound(26); ASSERT_NE(iter, multimap.end()); EXPECT_STREQ(iter->name(), "a"); - iter = multimap.lower_bound(35); + iter = multimap.lower_bound(36); ASSERT_NE(iter, multimap.end()); EXPECT_STREQ(iter->name(), "d"); - iter = multimap.lower_bound(45); + iter = multimap.lower_bound(46); ASSERT_NE(iter, multimap.end()); EXPECT_STREQ(iter->name(), "b"); } TEST_F(IntrusiveMultiMapTest, LowerBound_OutOfRange) { const IntrusiveMultiMap& multimap = multimap_; - EXPECT_EQ(multimap.lower_bound(55), multimap.end()); + EXPECT_EQ(multimap.lower_bound(56), multimap.end()); } TEST_F(IntrusiveMultiMapTest, LowerBound_WithDuplicates) { @@ -896,23 +938,23 @@ TEST_F(IntrusiveMultiMapTest, LowerBound_WithDuplicates) { TEST_F(IntrusiveMultiMapTest, UpperBound) { const IntrusiveMultiMap& multimap = multimap_; - auto iter = multimap.upper_bound(10); + auto iter = multimap.upper_bound(15); ASSERT_NE(iter, multimap.end()); EXPECT_STREQ(iter->name(), "c"); - iter = multimap.upper_bound(20); + iter = multimap.upper_bound(25); ASSERT_NE(iter, multimap.end()); EXPECT_STREQ(iter->name(), "a"); - iter = multimap.upper_bound(30); + iter = multimap.upper_bound(35); ASSERT_NE(iter, multimap.end()); EXPECT_STREQ(iter->name(), "d"); - iter = multimap.upper_bound(40); + iter = multimap.upper_bound(45); ASSERT_NE(iter, multimap.end()); EXPECT_STREQ(iter->name(), "b"); - EXPECT_EQ(multimap.upper_bound(50), multimap.end()); + EXPECT_EQ(multimap.upper_bound(55), multimap.end()); } TEST_F(IntrusiveMultiMapTest, UpperBound_NoExactKey) { @@ -971,36 +1013,37 @@ TEST_F(IntrusiveMultiMapTest, EqualRange) { ASSERT_NE(lower, multimap.end()); EXPECT_STREQ(lower->name(), "e"); ASSERT_NE(upper, multimap.end()); - EXPECT_STREQ(upper->name(), "c"); + EXPECT_STREQ(upper->name(), "E"); std::tie(lower, upper) = multimap.equal_range(20); ASSERT_NE(lower, multimap.end()); EXPECT_STREQ(lower->name(), "c"); ASSERT_NE(upper, multimap.end()); - EXPECT_STREQ(upper->name(), "a"); + EXPECT_STREQ(upper->name(), "C"); std::tie(lower, upper) = multimap.equal_range(30); ASSERT_NE(lower, multimap.end()); EXPECT_STREQ(lower->name(), "a"); ASSERT_NE(upper, multimap.end()); - EXPECT_STREQ(upper->name(), "d"); + EXPECT_STREQ(upper->name(), "A"); std::tie(lower, upper) = multimap.equal_range(40); ASSERT_NE(lower, multimap.end()); EXPECT_STREQ(lower->name(), "d"); ASSERT_NE(upper, multimap.end()); - EXPECT_STREQ(upper->name(), "b"); + EXPECT_STREQ(upper->name(), "D"); std::tie(lower, upper) = multimap.equal_range(50); ASSERT_NE(lower, multimap.end()); EXPECT_STREQ(lower->name(), "b"); - EXPECT_EQ(upper, multimap.end()); + ASSERT_NE(upper, multimap.end()); + EXPECT_STREQ(upper->name(), "B"); } TEST_F(IntrusiveMultiMapTest, EqualRange_NoExactKey) { const IntrusiveMultiMap& multimap = multimap_; - auto pair = multimap.equal_range(5); + auto pair = multimap.equal_range(6); IntrusiveMultiMap::const_iterator lower = pair.first; IntrusiveMultiMap::const_iterator upper = pair.second; ASSERT_NE(lower, multimap.end()); @@ -1008,25 +1051,25 @@ TEST_F(IntrusiveMultiMapTest, EqualRange_NoExactKey) { ASSERT_NE(upper, multimap.end()); EXPECT_STREQ(upper->name(), "e"); - std::tie(lower, upper) = multimap.equal_range(15); + std::tie(lower, upper) = multimap.equal_range(16); ASSERT_NE(lower, multimap.end()); EXPECT_STREQ(lower->name(), "c"); ASSERT_NE(upper, multimap.end()); EXPECT_STREQ(upper->name(), "c"); - std::tie(lower, upper) = multimap.equal_range(25); + std::tie(lower, upper) = multimap.equal_range(26); ASSERT_NE(lower, multimap.end()); EXPECT_STREQ(lower->name(), "a"); ASSERT_NE(upper, multimap.end()); EXPECT_STREQ(upper->name(), "a"); - std::tie(lower, upper) = multimap.equal_range(35); + std::tie(lower, upper) = multimap.equal_range(36); ASSERT_NE(lower, multimap.end()); EXPECT_STREQ(lower->name(), "d"); ASSERT_NE(upper, multimap.end()); EXPECT_STREQ(upper->name(), "d"); - std::tie(lower, upper) = multimap.equal_range(45); + std::tie(lower, upper) = multimap.equal_range(46); ASSERT_NE(lower, multimap.end()); EXPECT_STREQ(lower->name(), "b"); ASSERT_NE(upper, multimap.end()); @@ -1036,7 +1079,7 @@ TEST_F(IntrusiveMultiMapTest, EqualRange_NoExactKey) { TEST_F(IntrusiveMultiMapTest, EqualRange_OutOfRange) { const IntrusiveMultiMap& multimap = multimap_; - auto pair = multimap.equal_range(55); + auto pair = multimap.equal_range(56); IntrusiveMultiMap::const_iterator lower = pair.first; IntrusiveMultiMap::const_iterator upper = pair.second; EXPECT_EQ(lower, multimap.end());