// Copyright 2023 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "src/base/doubly-threaded-list.h" #include "src/base/optional.h" #include "src/base/vector.h" #include "test/unittests/test-utils.h" namespace v8::base { class DoublyThreadedListTest : public TestWithPlatform {}; TEST_F(DoublyThreadedListTest, BasicTest) { struct Elem { int val; bool operator==(const Elem& other) const { return val == other.val && prev_ == other.prev_ && next_ == other.next_; } Elem** prev_; Elem* next_; // Defining getters required by the default DoublyThreadedListTraits. Elem*** prev() { return &prev_; } Elem** next() { return &next_; } }; DoublyThreadedList list; Elem e1{1, nullptr, nullptr}; Elem e2{1, nullptr, nullptr}; Elem e3{1, nullptr, nullptr}; Elem e4{1, nullptr, nullptr}; list.PushFront(&e1); EXPECT_EQ(**(list.begin()), e1); list.PushFront(&e2); list.PushFront(&e3); list.PushFront(&e4); EXPECT_EQ(**(list.begin()), e4); EXPECT_EQ(*e4.next_, e3); EXPECT_EQ(*e3.next_, e2); EXPECT_EQ(*e2.next_, e1); EXPECT_EQ(e1.next_, nullptr); EXPECT_EQ(*e1.prev_, &e1); EXPECT_EQ(*e2.prev_, &e2); EXPECT_EQ(*e3.prev_, &e3); EXPECT_EQ(*e4.prev_, &e4); // Removing front list.Remove(&e4); EXPECT_EQ(**(list.begin()), e3); EXPECT_EQ(*e3.prev_, &e3); EXPECT_EQ(e4.next_, nullptr); EXPECT_EQ(e4.prev_, nullptr); // Removing middle list.Remove(&e2); EXPECT_EQ(*e3.next_, e1); EXPECT_EQ(e2.prev_, nullptr); EXPECT_EQ(e2.next_, nullptr); EXPECT_EQ(e1.prev_, &e3.next_); EXPECT_EQ(*e1.prev_, &e1); // Removing back list.Remove(&e1); EXPECT_EQ(e3.next_, nullptr); EXPECT_EQ(e1.prev_, nullptr); EXPECT_EQ(e1.next_, nullptr); EXPECT_EQ(**(list.begin()), e3); // Removing only item list.Remove(&e3); EXPECT_EQ(e3.prev_, nullptr); EXPECT_EQ(e3.next_, nullptr); EXPECT_TRUE(list.empty()); } TEST_F(DoublyThreadedListTest, IteratorTest) { struct Elem { int val; bool operator==(const Elem& other) const { return val == other.val && prev_ == other.prev_ && next_ == other.next_; } Elem** prev_; Elem* next_; // Defining getters required by the default DoublyThreadedListTraits. Elem*** prev() { return &prev_; } Elem** next() { return &next_; } }; DoublyThreadedList list; Elem e1{1, nullptr, nullptr}; Elem e2{1, nullptr, nullptr}; Elem e3{1, nullptr, nullptr}; Elem e4{1, nullptr, nullptr}; list.PushFront(&e1); list.PushFront(&e2); list.PushFront(&e3); list.PushFront(&e4); int count = 0; for (Elem* e : list) { USE(e); count++; } EXPECT_EQ(count, 4); // Iterating and checking that all items are where they should be auto it = list.begin(); EXPECT_EQ(**it, e4); ++it; EXPECT_EQ(**it, e3); ++it; EXPECT_EQ(**it, e2); ++it; EXPECT_EQ(**it, e1); ++it; EXPECT_FALSE(it != list.end()); // Removing with the iterator it = list.begin(); EXPECT_EQ(**it, e4); it = list.RemoveAt(it); EXPECT_EQ(**it, e3); ++it; EXPECT_EQ(**it, e2); it = list.RemoveAt(it); EXPECT_EQ(**it, e1); EXPECT_EQ(*e3.next_, e1); it = list.RemoveAt(it); EXPECT_FALSE(it != list.end()); EXPECT_EQ(e3.next_, nullptr); it = list.begin(); it = list.RemoveAt(it); EXPECT_TRUE(list.empty()); EXPECT_EQ(e1.next_, nullptr); EXPECT_EQ(e2.next_, nullptr); EXPECT_EQ(e3.next_, nullptr); EXPECT_EQ(e4.next_, nullptr); EXPECT_EQ(e1.prev_, nullptr); EXPECT_EQ(e2.prev_, nullptr); EXPECT_EQ(e3.prev_, nullptr); EXPECT_EQ(e4.prev_, nullptr); } } // namespace v8::base