Commit d311ee17 authored by Kei Nakashima's avatar Kei Nakashima Committed by Commit Bot

Transitioned NewLinkedHashSet to use VectorBackedLinkList

In this CL, VectorBackedLinkedList is imported to NewLinkedHashSet. Also it removed old code that we can replace by VectorBackedLinkedList.
Updated constructor/destructor/assignment operator.

Change-Id: Ie0dcfe8751b09bc2547bd206d2d2c38655d406a9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2094494
Commit-Queue: Kei Nakashima <keinakashima@google.com>
Reviewed-by: default avatarYuki Shiino <yukishiino@chromium.org>
Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Reviewed-by: default avatarBartek Nowierski <bartekn@chromium.org>
Cr-Commit-Position: refs/heads/master@{#749069}
parent 5ff1eea2
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
#include "third_party/blink/renderer/platform/wtf/hash_map.h" #include "third_party/blink/renderer/platform/wtf/hash_map.h"
#include "third_party/blink/renderer/platform/wtf/hash_set.h" #include "third_party/blink/renderer/platform/wtf/hash_set.h"
#include "third_party/blink/renderer/platform/wtf/sanitizers.h" #include "third_party/blink/renderer/platform/wtf/sanitizers.h"
#include "third_party/blink/renderer/platform/wtf/vector.h" #include "third_party/blink/renderer/platform/wtf/vector_backed_linked_list.h"
namespace WTF { namespace WTF {
...@@ -1024,110 +1024,6 @@ inline void swap(LinkedHashSetNode<T>& a, LinkedHashSetNode<T>& b) { ...@@ -1024,110 +1024,6 @@ inline void swap(LinkedHashSetNode<T>& a, LinkedHashSetNode<T>& b) {
// TODO(keinakashima): replace existing LinkedHashSet with NewLinkedHashSet // TODO(keinakashima): replace existing LinkedHashSet with NewLinkedHashSet
// after completion // after completion
template <typename NewLinkedHashSet>
class NewLinkedHashSetConstIterator;
template <typename ValueArg>
class NewLinkedHashSetNode {
USING_FAST_MALLOC(NewLinkedHashSetNode);
public:
NewLinkedHashSetNode() = default;
NewLinkedHashSetNode(wtf_size_t prev_index,
wtf_size_t next_index,
const ValueArg& value)
: prev_index_(prev_index), next_index_(next_index), value_(value) {}
NewLinkedHashSetNode(wtf_size_t prev_index,
wtf_size_t next_index,
ValueArg&& value)
: prev_index_(prev_index),
next_index_(next_index),
value_(std::move(value)) {}
NewLinkedHashSetNode(const NewLinkedHashSetNode& other) = delete;
NewLinkedHashSetNode(NewLinkedHashSetNode&& other) = default;
NewLinkedHashSetNode& operator=(const NewLinkedHashSetNode& other) = delete;
NewLinkedHashSetNode& operator=(NewLinkedHashSetNode&& other) = default;
wtf_size_t GetNextIndexForFreeNode() const {
#if DCHECK_IS_ON()
DCHECK(!is_used);
#endif
return next_index_;
}
wtf_size_t GetPrevIndexForUsedNode() const {
#if DCHECK_IS_ON()
DCHECK(is_used);
#endif
return prev_index_;
}
wtf_size_t GetNextIndexForUsedNode() const {
#if DCHECK_IS_ON()
DCHECK(is_used);
#endif
return next_index_;
}
const ValueArg& GetValueForUsedNode() const {
#if DCHECK_IS_ON()
DCHECK(is_used);
#endif
return value_;
}
void SetNextIndexForFreeNode(wtf_size_t next_index) {
#if DCHECK_IS_ON()
DCHECK(!is_used);
#endif
next_index_ = next_index;
}
void SetPrevIndexForUsedNode(wtf_size_t prev_index) {
#if DCHECK_IS_ON()
DCHECK(is_used);
#endif
prev_index_ = prev_index;
}
void SetNextIndexForUsedNode(wtf_size_t next_index) {
#if DCHECK_IS_ON()
DCHECK(is_used);
#endif
next_index_ = next_index;
}
void SetValueForUsedNode(const ValueArg& value) {
#if DCHECK_IS_ON()
DCHECK(is_used);
#endif
value_ = value;
}
void SetValueForUsedNode(ValueArg&& value) {
#if DCHECK_IS_ON()
DCHECK(is_used);
#endif
value_ = std::move(value);
}
private:
wtf_size_t prev_index_ = 0;
wtf_size_t next_index_ = 0;
ValueArg value_ = HashTraits<ValueArg>::EmptyValue();
#if DCHECK_IS_ON()
public:
bool is_used = true;
#endif
};
// This class is yet experimental. Do not use this class. // This class is yet experimental. Do not use this class.
// LinkedHashSet provides a Set interface like HashSet, but also has a // LinkedHashSet provides a Set interface like HashSet, but also has a
...@@ -1146,12 +1042,9 @@ class NewLinkedHashSet { ...@@ -1146,12 +1042,9 @@ class NewLinkedHashSet {
private: private:
using Value = ValueArg; using Value = ValueArg;
using Node = NewLinkedHashSetNode<Value>;
using Map = HashMap<Value, wtf_size_t>; using Map = HashMap<Value, wtf_size_t>;
public: public:
friend class NewLinkedHashSetConstIterator<NewLinkedHashSet>;
using const_iterator = NewLinkedHashSetConstIterator<NewLinkedHashSet>;
// TODO(keinakashima): add security check // TODO(keinakashima): add security check
struct AddResult final { struct AddResult final {
STACK_ALLOCATED(); STACK_ALLOCATED();
...@@ -1175,134 +1068,28 @@ class NewLinkedHashSet { ...@@ -1175,134 +1068,28 @@ class NewLinkedHashSet {
void Swap(NewLinkedHashSet&); void Swap(NewLinkedHashSet&);
wtf_size_t size() const { return value_to_index_.size(); } // TODO(keinakashima): implement size-related functions
bool IsEmpty() const { return value_to_index_.IsEmpty(); }
const_iterator begin() const { return MakeConstIterator(UsedFirstIndex()); }
const_iterator end() const { return MakeConstIterator(anchor_index_); }
// TODO(keinakashima): implement reverse const iterator
const Value& front() const; // TODO(keinakashima): implement begin/end, rbegin/rend
void RemoveFirst();
const Value& back() const; // TODO(keinakashima): implement front/back
void pop_back();
// TODO(keinakashima): implement find, Contains after implementing iterator // TODO(keinakashima): implement find, Contains after implementing iterator
template <typename IncomingValueType> // TODO(keinakahsima): implement functions related to insert
AddResult insert(IncomingValueType&&);
template <typename IncomingValueType> // TODO(keinakashima): implement functions related to erase
AddResult AppendOrMoveToLast(IncomingValueType&&);
template <typename IncomingValueType> // TODO(keinakashima): implement clear (,RemoveAll, Trace)
AddResult PrependOrMoveToFirst(IncomingValueType&&);
void erase(ValuePeekInType);
// TODO(keinakashima): implement erase that has an iterator as an argument
// TODO(keinakashima): implement clear, RemoveAll, Trace
private: private:
bool IsFreeListEmpty() const { return free_head_index_ == anchor_index_; }
wtf_size_t UsedFirstIndex() const {
return nodes_[anchor_index_].GetNextIndexForUsedNode();
}
wtf_size_t UsedLastIndex() const {
return nodes_[anchor_index_].GetPrevIndexForUsedNode();
}
wtf_size_t NewEntryIndex() const {
if (IsFreeListEmpty()) {
return nodes_.size();
}
return free_head_index_;
}
const_iterator MakeConstIterator(wtf_size_t index) const {
return const_iterator(index, this);
}
// Inserts new value before given position to a linked list in vector
// Returns a pointer to the stored value
template <typename IncomingValueType>
const Value* InsertValueBeforeNode(wtf_size_t, IncomingValueType&&);
// Erases the node with the given index from the used list
// and prepends it to the free list as a free node.
// At this time, its value is set to be empty.
void FreeUsedNode(wtf_size_t);
HashMap<Value, wtf_size_t> value_to_index_; HashMap<Value, wtf_size_t> value_to_index_;
Vector<Node> nodes_; VectorBackedLinkedList<Value> list_;
wtf_size_t free_head_index_ = anchor_index_;
static constexpr wtf_size_t anchor_index_ = 0;
};
// TODO(keinakashima): add modification check
// TODO(keinakashima): implement DCHECK that prevents mutations while iterating
template <typename NewLinkedHashSetType>
class NewLinkedHashSetConstIterator {
private:
using Node = typename NewLinkedHashSetType::Node;
using ReferenceType = const typename NewLinkedHashSetType::Value&;
using PointerType = const typename NewLinkedHashSetType::Value*;
protected:
NewLinkedHashSetConstIterator(wtf_size_t index,
const NewLinkedHashSetType* container)
: index_(index), container_(container) {}
public:
ReferenceType operator*() const { return *Get(); }
PointerType operator->() const { return Get(); }
NewLinkedHashSetConstIterator& operator++() {
DCHECK(0 <= index_ && index_ < container_->nodes_.size());
index_ = container_->nodes_[index_].GetNextIndexForUsedNode();
return *this;
}
NewLinkedHashSetConstIterator& operator--() {
DCHECK(0 <= index_ && index_ < container_->nodes_.size());
index_ = container_->nodes_[index_].GetPrevIndexForUsedNode();
return *this;
}
NewLinkedHashSetConstIterator operator++(int) = delete;
NewLinkedHashSetConstIterator operator--(int) = delete;
bool operator==(const NewLinkedHashSetConstIterator& other) {
DCHECK_EQ(container_, other.container_);
return index_ == other.index_;
}
bool operator!=(const NewLinkedHashSetConstIterator& other) {
return !(*this == other);
}
protected:
PointerType Get() const {
DCHECK(0 <= index_ && index_ < container_->nodes_.size());
const Node& node = container_->nodes_[index_];
return &node.GetValueForUsedNode();
}
private:
wtf_size_t index_;
const NewLinkedHashSetType* container_;
template <typename T>
friend class NewLinkedHashSet;
}; };
template <typename T> template <typename T>
NewLinkedHashSet<T>::NewLinkedHashSet() { NewLinkedHashSet<T>::NewLinkedHashSet() {
// TODO(keinakashima): add assertion when considering GC // TODO(keinakashima): add assertion when considering GC
// nodes_[0] is used for anchor, which serves as the beginning and the end of
// the used list.
nodes_.push_back(Node());
} }
// TODO(keinakashima): add copy constructor after implementing iterator if // TODO(keinakashima): add copy constructor after implementing iterator if
...@@ -1331,151 +1118,7 @@ inline NewLinkedHashSet<T>& NewLinkedHashSet<T>::operator=( ...@@ -1331,151 +1118,7 @@ inline NewLinkedHashSet<T>& NewLinkedHashSet<T>::operator=(
template <typename T> template <typename T>
inline void NewLinkedHashSet<T>::Swap(NewLinkedHashSet& other) { inline void NewLinkedHashSet<T>::Swap(NewLinkedHashSet& other) {
value_to_index_.swap(other.value_to_index_); value_to_index_.swap(other.value_to_index_);
nodes_.swap(other.nodes_); list_.swap(other.list_);
swap(free_head_index_, other.free_head_index_);
}
template <typename T>
inline const T& NewLinkedHashSet<T>::front() const {
DCHECK(!IsEmpty());
return nodes_[UsedFirstIndex()].GetValueForUsedNode();
}
template <typename T>
inline void NewLinkedHashSet<T>::RemoveFirst() {
DCHECK(!IsEmpty());
value_to_index_.erase(front());
FreeUsedNode(UsedFirstIndex());
}
template <typename T>
inline const T& NewLinkedHashSet<T>::back() const {
DCHECK(!IsEmpty());
return nodes_[UsedLastIndex()].GetValueForUsedNode();
}
template <typename T>
inline void NewLinkedHashSet<T>::pop_back() {
DCHECK(!IsEmpty());
value_to_index_.erase(back());
FreeUsedNode(UsedLastIndex());
}
template <typename T>
template <typename IncomingValueType>
typename NewLinkedHashSet<T>::AddResult NewLinkedHashSet<T>::insert(
IncomingValueType&& value) {
wtf_size_t new_entry_index = NewEntryIndex();
typename Map::AddResult result =
value_to_index_.insert(value, new_entry_index);
if (!result.is_new_entry) {
wtf_size_t index = result.stored_value->value;
return AddResult(&(nodes_[index].GetValueForUsedNode()), false);
}
const T* stored_value = InsertValueBeforeNode(
anchor_index_, std::forward<IncomingValueType>(value));
return AddResult(stored_value, true);
}
template <typename T>
template <typename IncomingValueType>
typename NewLinkedHashSet<T>::AddResult NewLinkedHashSet<T>::AppendOrMoveToLast(
IncomingValueType&& value) {
typename Map::AddResult result =
value_to_index_.insert(value, NewEntryIndex());
// TODO(keinakashima): just update prev/next indices to avoid reconstruct the
// same value
if (!result.is_new_entry) {
wtf_size_t index = result.stored_value->value;
FreeUsedNode(index);
}
const T* stored_value = InsertValueBeforeNode(
anchor_index_, std::forward<IncomingValueType>(value));
return AddResult(stored_value, result.is_new_entry);
}
template <typename T>
template <typename IncomingValueType>
typename NewLinkedHashSet<T>::AddResult
NewLinkedHashSet<T>::PrependOrMoveToFirst(IncomingValueType&& value) {
typename Map::AddResult result =
value_to_index_.insert(value, NewEntryIndex());
if (!result.is_new_entry) {
wtf_size_t index = result.stored_value->value;
FreeUsedNode(index);
}
const T* stored_value = InsertValueBeforeNode(
UsedFirstIndex(), std::forward<IncomingValueType>(value));
return AddResult(stored_value, result.is_new_entry);
}
template <typename T>
inline void NewLinkedHashSet<T>::erase(ValuePeekInType value) {
typename Map::iterator it = value_to_index_.find(value);
if (it == value_to_index_.end())
return;
wtf_size_t index = it->value;
value_to_index_.erase(it);
FreeUsedNode(index);
}
template <typename T>
template <typename IncomingValueType>
inline const T* NewLinkedHashSet<T>::InsertValueBeforeNode(
wtf_size_t before_index,
IncomingValueType&& new_value) {
wtf_size_t prev_index = nodes_[before_index].GetPrevIndexForUsedNode();
Node& prev = nodes_[prev_index];
Node& next = nodes_[before_index];
wtf_size_t new_entry_index = NewEntryIndex();
prev.SetNextIndexForUsedNode(new_entry_index);
next.SetPrevIndexForUsedNode(new_entry_index);
if (IsFreeListEmpty()) {
DCHECK(nodes_.size() == new_entry_index);
nodes_.push_back(Node(prev_index, before_index,
std::forward<IncomingValueType>(new_value)));
} else {
DCHECK(free_head_index_ == new_entry_index);
Node& free_head = nodes_[free_head_index_];
free_head_index_ = free_head.GetNextIndexForFreeNode();
free_head = Node(prev_index, before_index,
std::forward<IncomingValueType>(new_value));
}
return &(nodes_[new_entry_index].GetValueForUsedNode());
}
template <typename T>
inline void NewLinkedHashSet<T>::FreeUsedNode(wtf_size_t index) {
DCHECK(index != anchor_index_);
Node& node = nodes_[index];
#if DCHECK_IS_ON()
DCHECK(node.is_used);
#endif
wtf_size_t prev_index = node.GetPrevIndexForUsedNode();
wtf_size_t next_index = node.GetNextIndexForUsedNode();
Node& prev_node = nodes_[prev_index];
Node& next_node = nodes_[next_index];
prev_node.SetNextIndexForUsedNode(next_index);
next_node.SetPrevIndexForUsedNode(prev_index);
node.SetValueForUsedNode(HashTraits<T>::EmptyValue());
#if DCHECK_IS_ON()
node.is_used = false;
#endif
node.SetNextIndexForFreeNode(free_head_index_);
free_head_index_ = index;
} }
} // namespace WTF } // namespace WTF
......
...@@ -10,403 +10,8 @@ ...@@ -10,403 +10,8 @@
namespace WTF { namespace WTF {
TEST(NewLinkedHashSetTest, Node) {
NewLinkedHashSetNode<int> node0;
NewLinkedHashSetNode<int> node1(1, 2, 3);
EXPECT_EQ(node0.GetPrevIndexForUsedNode(), 0u);
EXPECT_EQ(node0.GetNextIndexForUsedNode(), 0u);
EXPECT_EQ(node1.GetPrevIndexForUsedNode(), 1u);
EXPECT_EQ(node1.GetNextIndexForUsedNode(), 2u);
node1.SetPrevIndexForUsedNode(3);
EXPECT_EQ(node1.GetPrevIndexForUsedNode(), 3u);
node1.SetNextIndexForUsedNode(4);
EXPECT_EQ(node1.GetNextIndexForUsedNode(), 4u);
EXPECT_EQ(node1.GetValueForUsedNode(), 3);
node1.SetValueForUsedNode(-1);
EXPECT_EQ(node1.GetValueForUsedNode(), -1);
}
TEST(NewLinkedHashSetTest, Construct) { TEST(NewLinkedHashSetTest, Construct) {
NewLinkedHashSet<int> test; NewLinkedHashSet<int> test;
EXPECT_EQ(test.size(), 0u);
}
TEST(NewLinkedHashSetTest, Iterator) {
using Set = NewLinkedHashSet<int>;
Set set;
EXPECT_TRUE(set.begin() == set.end());
set.insert(1);
Set::const_iterator it = set.begin();
EXPECT_EQ(*it, 1);
++it;
EXPECT_TRUE(it == set.end());
set.insert(2);
set.insert(3);
it = set.begin();
EXPECT_EQ(*it, 1);
++it;
EXPECT_EQ(*it, 2);
++it;
EXPECT_EQ(*it, 3);
++it;
EXPECT_TRUE(it == set.end());
--it;
EXPECT_EQ(*it, 3);
--it;
EXPECT_EQ(*it, 2);
--it;
EXPECT_EQ(*it, 1);
EXPECT_TRUE(it == set.begin());
EXPECT_TRUE(it != set.end());
int i = 1;
for (auto it : set) {
EXPECT_EQ(it, i);
i++;
}
}
TEST(NewLinkedHashSetTest, InsertAndEraseForInteger) {
using Set = NewLinkedHashSet<int>;
Set set;
Set::AddResult result = set.insert(1); // set: 1 vector: anchor 1
EXPECT_TRUE(result.is_new_entry);
EXPECT_EQ(*result.stored_value, 1);
EXPECT_EQ(set.front(), 1);
EXPECT_EQ(set.back(), 1);
EXPECT_EQ(set.size(), 1u);
result = set.insert(2); // set: 1, 2 vector: anchor 1, 2
EXPECT_TRUE(result.is_new_entry);
EXPECT_EQ(*result.stored_value, 2);
EXPECT_EQ(set.front(), 1);
EXPECT_EQ(set.back(), 2);
EXPECT_EQ(set.size(), 2u);
result = set.insert(1); // set: 1, 2 vector: anchor 1, 2
EXPECT_FALSE(result.is_new_entry);
EXPECT_EQ(*result.stored_value, 1);
EXPECT_EQ(set.front(), 1);
EXPECT_EQ(set.back(), 2);
EXPECT_EQ(set.size(), 2u);
result = set.insert(3); // set: 1, 2, 3 vector: anchor 1, 2, 3
EXPECT_TRUE(result.is_new_entry);
EXPECT_EQ(*result.stored_value, 3);
EXPECT_EQ(set.front(), 1);
EXPECT_EQ(set.back(), 3);
EXPECT_EQ(set.size(), 3u);
set.erase(1); // set: 2, 3 vector: anchor hole 2, 3
EXPECT_EQ(set.front(), 2);
EXPECT_EQ(set.back(), 3);
EXPECT_EQ(set.size(), 2u);
result = set.insert(1); // set: 2, 3, 1 vector: anchor 1, 2, 3
EXPECT_TRUE(result.is_new_entry);
EXPECT_EQ(*result.stored_value, 1);
EXPECT_EQ(set.front(), 2);
EXPECT_EQ(set.back(), 1);
EXPECT_EQ(set.size(), 3u);
set.erase(3); // set: 2, 1 vector: anchor 1, 2, hole
EXPECT_EQ(set.front(), 2);
EXPECT_EQ(set.back(), 1);
EXPECT_EQ(set.size(), 2u);
result = set.insert(4); // set: 2, 1, 4 vector: anchor 1, 2, 4
EXPECT_TRUE(result.is_new_entry);
EXPECT_EQ(*result.stored_value, 4);
EXPECT_EQ(set.front(), 2);
EXPECT_EQ(set.back(), 4);
EXPECT_EQ(set.size(), 3u);
result = set.insert(5); // set: 2, 1, 4, 5 vector: anchor 1, 2, 4, 5
EXPECT_TRUE(result.is_new_entry);
EXPECT_EQ(*result.stored_value, 5);
EXPECT_EQ(set.front(), 2);
EXPECT_EQ(set.back(), 5);
EXPECT_EQ(set.size(), 4u);
set.erase(10);
set.erase(100);
set.erase(1000);
set.erase(211);
result = set.insert(3); // set: 2, 1, 4, 5, 3 vector: anchor 1, 2, 4, 5, 3
EXPECT_TRUE(result.is_new_entry);
EXPECT_EQ(*result.stored_value, 3);
EXPECT_EQ(set.front(), 2);
EXPECT_EQ(set.back(), 3);
EXPECT_EQ(set.size(), 5u);
}
TEST(NewLinkedHashSetTest, RemoveFirstAndPopBackForInteger) {
using Set = NewLinkedHashSet<int>;
Set set;
for (int i = 1; i <= 5; i++) {
set.insert(i);
}
EXPECT_EQ(set.front(), 1);
EXPECT_EQ(set.back(), 5);
set.RemoveFirst();
EXPECT_EQ(set.front(), 2);
EXPECT_EQ(set.back(), 5);
set.pop_back();
EXPECT_EQ(set.front(), 2);
EXPECT_EQ(set.back(), 4);
set.RemoveFirst();
EXPECT_EQ(set.front(), 3);
EXPECT_EQ(set.back(), 4);
set.pop_back();
EXPECT_EQ(set.front(), 3);
EXPECT_EQ(set.back(), 3);
set.RemoveFirst();
EXPECT_TRUE(set.IsEmpty());
set.insert(1);
EXPECT_EQ(set.front(), 1);
EXPECT_EQ(set.back(), 1);
set.pop_back();
EXPECT_TRUE(set.IsEmpty());
}
TEST(NewLinkedHashSetTest, PrependOrMoveToFirstForInteger) {
using Set = NewLinkedHashSet<int>;
Set set;
Set::AddResult result =
set.PrependOrMoveToFirst(1); // set: 1 vector: anchor 1
EXPECT_TRUE(result.is_new_entry);
EXPECT_EQ(*result.stored_value, 1);
EXPECT_EQ(set.front(), 1);
EXPECT_EQ(set.back(), 1);
EXPECT_EQ(set.size(), 1u);
result = set.insert(2); // set: 1, 2 vector: anchor 1, 2
EXPECT_TRUE(result.is_new_entry);
EXPECT_EQ(*result.stored_value, 2);
EXPECT_EQ(set.front(), 1);
EXPECT_EQ(set.back(), 2);
EXPECT_EQ(set.size(), 2u);
result = set.PrependOrMoveToFirst(2); // set: 2, 1 vector: anchor 1, 2
EXPECT_FALSE(result.is_new_entry);
EXPECT_EQ(*result.stored_value, 2);
EXPECT_EQ(set.front(), 2);
EXPECT_EQ(set.back(), 1);
EXPECT_EQ(set.size(), 2u);
result = set.PrependOrMoveToFirst(3); // set: 3, 2, 1 vector: anchor 1, 2, 3
EXPECT_TRUE(result.is_new_entry);
EXPECT_EQ(*result.stored_value, 3);
EXPECT_EQ(set.front(), 3);
EXPECT_EQ(set.back(), 1);
EXPECT_EQ(set.size(), 3u);
}
TEST(NewLinkedHashSetTest, AppendOrMoveToLastForInteger) {
using Set = NewLinkedHashSet<int>;
Set set;
Set::AddResult result = set.AppendOrMoveToLast(1); // set: 1 vector: anchor 1
EXPECT_TRUE(result.is_new_entry);
EXPECT_EQ(*result.stored_value, 1);
EXPECT_EQ(set.front(), 1);
EXPECT_EQ(set.back(), 1);
EXPECT_EQ(set.size(), 1u);
result = set.insert(2); // set: 1, 2 vector: anchor 1, 2
EXPECT_TRUE(result.is_new_entry);
EXPECT_EQ(*result.stored_value, 2);
EXPECT_EQ(set.front(), 1);
EXPECT_EQ(set.back(), 2);
EXPECT_EQ(set.size(), 2u);
result = set.AppendOrMoveToLast(1); // set: 2, 1 vector: anchor 1, 2
EXPECT_FALSE(result.is_new_entry);
EXPECT_EQ(*result.stored_value, 1);
EXPECT_EQ(set.front(), 2);
EXPECT_EQ(set.back(), 1);
EXPECT_EQ(set.size(), 2u);
result = set.AppendOrMoveToLast(3); // set: 2, 1, 3 vector: anchor 1, 2, 3
EXPECT_TRUE(result.is_new_entry);
EXPECT_EQ(*result.stored_value, 3);
EXPECT_EQ(set.front(), 2);
EXPECT_EQ(set.back(), 3);
EXPECT_EQ(set.size(), 3u);
}
TEST(NewLinkedHashSetTest, InsertAndEraseForString) {
using Set = NewLinkedHashSet<String>;
Set set;
Set::AddResult result = set.insert("a"); // set: "a" vector: anchor "a"
EXPECT_TRUE(result.is_new_entry);
EXPECT_EQ(*result.stored_value, "a");
EXPECT_EQ(set.front(), "a");
EXPECT_EQ(set.back(), "a");
EXPECT_EQ(set.size(), 1u);
result = set.insert("b"); // set: "a" "b" vector: anchor "a" "b"
EXPECT_TRUE(result.is_new_entry);
EXPECT_EQ(*result.stored_value, "b");
EXPECT_EQ(set.front(), "a");
EXPECT_EQ(set.back(), "b");
EXPECT_EQ(set.size(), 2u);
result = set.insert(""); // set: "a" "b" "" vector: anchor "a" "b" ""
EXPECT_TRUE(result.is_new_entry);
EXPECT_EQ(*result.stored_value, "");
EXPECT_EQ(set.front(), "a");
EXPECT_EQ(set.back(), "");
EXPECT_EQ(set.size(), 3u);
result = set.insert(
"abc"); // set: "a" "b" "" "abc" vector: anchor "a" "b" "" "abc"
EXPECT_TRUE(result.is_new_entry);
EXPECT_EQ(*result.stored_value, "abc");
EXPECT_EQ(set.front(), "a");
EXPECT_EQ(set.back(), "abc");
EXPECT_EQ(set.size(), 4u);
set.erase(""); // set: "a" "b" "abc" vector: anchor "a" "b" hole "abc"
EXPECT_EQ(set.front(), "a");
EXPECT_EQ(set.back(), "abc");
EXPECT_EQ(set.size(), 3u);
set.erase("abc"); // set: "a" "b" vector: anchor "a" "b" hole hole
EXPECT_EQ(set.front(), "a");
EXPECT_EQ(set.back(), "b");
EXPECT_EQ(set.size(), 2u);
set.erase("");
EXPECT_EQ(set.front(), "a");
EXPECT_EQ(set.back(), "b");
EXPECT_EQ(set.size(), 2u);
set.erase("c");
EXPECT_EQ(set.front(), "a");
EXPECT_EQ(set.back(), "b");
EXPECT_EQ(set.size(), 2u);
set.insert("c"); // set: "a" "b" "c" vector: anchor "a" "b" hole "c"
EXPECT_EQ(set.front(), "a");
EXPECT_EQ(set.back(), "c");
EXPECT_EQ(set.size(), 3u);
}
TEST(NewLinkedHashSetTest, RemoveFirstAndPopBackForString) {
using Set = NewLinkedHashSet<String>;
Set set;
set.insert("a");
set.insert("b");
set.insert("c");
set.insert("d");
set.insert("e");
EXPECT_EQ(set.front(), "a");
EXPECT_EQ(set.back(), "e");
set.RemoveFirst();
EXPECT_EQ(set.front(), "b");
EXPECT_EQ(set.back(), "e");
set.pop_back();
EXPECT_EQ(set.front(), "b");
EXPECT_EQ(set.back(), "d");
set.RemoveFirst();
EXPECT_EQ(set.front(), "c");
EXPECT_EQ(set.back(), "d");
set.pop_back();
EXPECT_EQ(set.front(), "c");
EXPECT_EQ(set.back(), "c");
set.RemoveFirst();
EXPECT_TRUE(set.IsEmpty());
}
TEST(NewLinkedHashSetTest, PrependOrMoveToFirstForString) {
using Set = NewLinkedHashSet<String>;
Set set;
Set::AddResult result =
set.PrependOrMoveToFirst("a"); // set: "a" vector: anchor "a"
EXPECT_TRUE(result.is_new_entry);
EXPECT_EQ(*result.stored_value, "a");
EXPECT_EQ(set.front(), "a");
EXPECT_EQ(set.back(), "a");
EXPECT_EQ(set.size(), 1u);
result = set.insert("b"); // set: "a", "b" vector: anchor "a", "b"
EXPECT_TRUE(result.is_new_entry);
EXPECT_EQ(*result.stored_value, "b");
EXPECT_EQ(set.front(), "a");
EXPECT_EQ(set.back(), "b");
EXPECT_EQ(set.size(), 2u);
result =
set.PrependOrMoveToFirst("b"); // set: "b", "a" vector: anchor "a", "b"
EXPECT_FALSE(result.is_new_entry);
EXPECT_EQ(*result.stored_value, "b");
EXPECT_EQ(set.front(), "b");
EXPECT_EQ(set.back(), "a");
EXPECT_EQ(set.size(), 2u);
result = set.PrependOrMoveToFirst(
"c"); // set: "c", "b", "a" vector: anchor "a", "b", "c"
EXPECT_TRUE(result.is_new_entry);
EXPECT_EQ(*result.stored_value, "c");
EXPECT_EQ(set.front(), "c");
EXPECT_EQ(set.back(), "a");
EXPECT_EQ(set.size(), 3u);
}
TEST(NewLinkedHashSetTest, AppendOrMoveToLastForString) {
using Set = NewLinkedHashSet<String>;
Set set;
Set::AddResult result =
set.AppendOrMoveToLast("a"); // set: "a" vector: anchor "a"
EXPECT_TRUE(result.is_new_entry);
EXPECT_EQ(*result.stored_value, "a");
EXPECT_EQ(set.front(), "a");
EXPECT_EQ(set.back(), "a");
EXPECT_EQ(set.size(), 1u);
result = set.insert("b"); // set: "a", "b" vector: anchor "a", "b"
EXPECT_TRUE(result.is_new_entry);
EXPECT_EQ(*result.stored_value, "b");
EXPECT_EQ(set.front(), "a");
EXPECT_EQ(set.back(), "b");
EXPECT_EQ(set.size(), 2u);
result =
set.AppendOrMoveToLast("a"); // set: "b", "a" vector: anchor "a", "b"
EXPECT_FALSE(result.is_new_entry);
EXPECT_EQ(*result.stored_value, "a");
EXPECT_EQ(set.front(), "b");
EXPECT_EQ(set.back(), "a");
EXPECT_EQ(set.size(), 2u);
result = set.AppendOrMoveToLast(
"c"); // set: "b", "a", "c" vector: anchor "a", "b", "c"
EXPECT_TRUE(result.is_new_entry);
EXPECT_EQ(*result.stored_value, "c");
EXPECT_EQ(set.front(), "b");
EXPECT_EQ(set.back(), "c");
EXPECT_EQ(set.size(), 3u);
} }
} // namespace WTF } // namespace WTF
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment