v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
doubly-threaded-list.h
Go to the documentation of this file.
1// Copyright 2023 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef V8_BASE_DOUBLY_THREADED_LIST_H_
6#define V8_BASE_DOUBLY_THREADED_LIST_H_
7
9#include "src/base/iterator.h"
10#include "src/base/logging.h"
11
12namespace v8::base {
13
14template <typename T>
16 static T** prev(T t) { return t->prev(); }
17 static T* next(T t) { return t->next(); }
18 static bool non_empty(T t) { return t != nullptr; }
19};
20
21// `DoublyThreadedList` is an intrusive doubly-linked list that threads through
22// its nodes, somewhat like `v8::base::ThreadedList`.
23//
24// Of interest is the fact that instead of having regular next/prev pointers,
25// nodes have a regular "next" pointer, but their "prev" pointer contains the
26// address of the "next" of the previous element. This way, removing an element
27// doesn't require special treatment for the head of the list, and does not
28// even require to know the head of the list.
29template <class T, class DTLTraits = DoublyThreadedListTraits<T>>
31 public:
32 // Since C++17, it is possible to have a sentinel end-iterator that is not an
33 // iterator itself.
34 class end_iterator {};
35
36 class iterator : public base::iterator<std::forward_iterator_tag, T> {
37 public:
38 explicit iterator(T head) : curr_(head) {}
39
40 T operator*() { return curr_; }
41
43 DCHECK(DTLTraits::non_empty(curr_));
44 curr_ = *DTLTraits::next(curr_);
45 return *this;
46 }
47
49 DCHECK(DTLTraits::non_empty(curr_));
50 iterator tmp(*this);
51 operator++();
52 return tmp;
53 }
54
55 bool operator==(end_iterator) { return !DTLTraits::non_empty(curr_); }
56 bool operator!=(end_iterator) { return DTLTraits::non_empty(curr_); }
57
58 private:
61 };
62
63 // Removes `x` from the list. Iterators that are currently on `x` are
64 // invalidated. To remove while iterating, use RemoveAt.
65 static void Remove(T x) {
66 if (*DTLTraits::prev(x) == nullptr) {
67 DCHECK(empty(*DTLTraits::next(x)));
68 // {x} already removed from the list.
69 return;
70 }
71 T** prev = DTLTraits::prev(x);
72 T* next = DTLTraits::next(x);
73 **prev = *next;
74 if (DTLTraits::non_empty(*next)) *DTLTraits::prev(*next) = *prev;
75 *DTLTraits::prev(x) = nullptr;
76 *DTLTraits::next(x) = {};
77 }
78
79 DoublyThreadedList() = default;
80
81 // Defining move constructor so that when resizing container, the prev pointer
82 // of the next(head_) doesn't point to the old head_ but rather to the new
83 // one.
85 head_ = other.head_;
86 if (DTLTraits::non_empty(head_)) {
87 *DTLTraits::prev(head_) = &head_;
88 }
89 other.head_ = {};
90 }
91
92 // Add `x` at the beginning of the list. `x` will not be visible to any
93 // existing iterator. Does not invalidate any existing iterator.
94 void PushFront(T x) {
95 DCHECK(empty(*DTLTraits::next(x)));
96 DCHECK_EQ(*DTLTraits::prev(x), nullptr);
97 *DTLTraits::next(x) = head_;
98 *DTLTraits::prev(x) = &head_;
99 if (DTLTraits::non_empty(head_)) {
100 *DTLTraits::prev(head_) = DTLTraits::next(x);
101 }
102 head_ = x;
103 }
104
105 T Front() const {
106 DCHECK(!empty());
107 return *begin();
108 }
109
110 void PopFront() {
111 DCHECK(!empty());
112 Remove(Front());
113 }
114
115 bool empty() const { return !DTLTraits::non_empty(head_); }
116
117 iterator begin() const { return iterator{head_}; }
118 end_iterator end() const { return end_iterator{}; }
119
120 // Removes the element at `it`, and make `it` point to the next element.
121 // Iterators on the same element as `it` are invalidated. Other iterators are
122 // not affected.
124 DCHECK(DTLTraits::non_empty(it.curr_));
125 T curr = *it;
126 T next = *DTLTraits::next(curr);
127 Remove(curr);
128 return iterator{next};
129 }
130
131 bool Contains(T needle) const {
132 const bool in_use = DTLTraits::in_use(needle);
133 DCHECK_EQ(in_use, ContainsSlow(needle));
134 return in_use;
135 }
136
137 bool ContainsSlow(T needle) const {
138 for (T element : *this) {
139 if (element == needle) {
140 return true;
141 }
142 }
143 return false;
144 }
145
146 private:
147 static bool empty(T x) { return !DTLTraits::non_empty(x); }
148 T head_{};
149};
150
151} // namespace v8::base
152
153#endif // V8_BASE_DOUBLY_THREADED_LIST_H_
DoublyThreadedList(DoublyThreadedList &&other) V8_NOEXCEPT
int x
#define V8_NOEXCEPT
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485