cesium-native  0.41.0
DoublyLinkedList.h
1 #pragma once
2 
3 #include <cstddef>
4 
5 namespace CesiumUtility {
6 
11 template <class T> class DoublyLinkedListPointers final {
12 public:
16  DoublyLinkedListPointers() noexcept : pNext(nullptr), pPrevious(nullptr) {}
17 
23  // Following the example of boost::instrusive::list's list_member_hook, the
24  // copy constructor and assignment operator do nothing.
25  // https://www.boost.org/doc/libs/1_73_0/doc/html/boost/intrusive/list_member_hook.html
28 
33  operator=(const DoublyLinkedListPointers& /*rhs*/) noexcept {
34  return *this;
35  }
36 
37 private:
38  template <
39  typename TElement,
40  typename TElementBase,
41  DoublyLinkedListPointers<TElement>(TElementBase::*Pointers)>
42  friend class DoublyLinkedListAdvanced;
43 
44  T* pNext;
45  T* pPrevious;
46 };
47 
58 template <
59  typename T,
60  typename TPointerBase,
61  DoublyLinkedListPointers<T>(TPointerBase::*Pointers)>
63 public:
67  void remove(T& node) noexcept {
68  DoublyLinkedListPointers<T>& nodePointers = node.*Pointers;
69 
70  if (nodePointers.pPrevious) {
71  DoublyLinkedListPointers<T>& previousPointers =
72  nodePointers.pPrevious->*Pointers;
73  previousPointers.pNext = nodePointers.pNext;
74  --this->_size;
75  } else if (this->_pHead == &node) {
76  this->_pHead = nodePointers.pNext;
77  --this->_size;
78  }
79 
80  if (nodePointers.pNext) {
81  DoublyLinkedListPointers<T>& nextPointers = nodePointers.pNext->*Pointers;
82  nextPointers.pPrevious = nodePointers.pPrevious;
83  } else if (this->_pTail == &node) {
84  this->_pTail = nodePointers.pPrevious;
85  }
86 
87  nodePointers.pPrevious = nullptr;
88  nodePointers.pNext = nullptr;
89  }
90 
94  void insertAfter(T& after, T& node) noexcept {
95  this->remove(node);
96 
97  DoublyLinkedListPointers<T>& afterPointers = after.*Pointers;
98  DoublyLinkedListPointers<T>& nodePointers = node.*Pointers;
99 
100  nodePointers.pPrevious = &after;
101  nodePointers.pNext = afterPointers.pNext;
102  afterPointers.pNext = &node;
103 
104  if (nodePointers.pNext) {
105  DoublyLinkedListPointers<T>& nextPointers = nodePointers.pNext->*Pointers;
106  nextPointers.pPrevious = &node;
107  }
108 
109  if (this->_pTail == &after) {
110  this->_pTail = &node;
111  }
112 
113  ++this->_size;
114  }
115 
119  void insertBefore(T& before, T& node) noexcept {
120  this->remove(node);
121 
122  DoublyLinkedListPointers<T>& beforePointers = before.*Pointers;
123  DoublyLinkedListPointers<T>& nodePointers = node.*Pointers;
124 
125  nodePointers.pPrevious = beforePointers.pPrevious;
126  nodePointers.pNext = &before;
127  beforePointers.pPrevious = &node;
128 
129  if (nodePointers.pPrevious) {
130  DoublyLinkedListPointers<T>& previousPointers =
131  nodePointers.pPrevious->*Pointers;
132  previousPointers.pNext = &node;
133  }
134 
135  if (this->_pHead == &before) {
136  this->_pHead = &node;
137  }
138 
139  ++this->_size;
140  }
141 
145  void insertAtHead(T& node) noexcept {
146  this->remove(node);
147 
148  if (this->_pHead) {
149  (this->_pHead->*Pointers).pPrevious = &node;
150  (node.*Pointers).pNext = this->_pHead;
151  } else {
152  this->_pTail = &node;
153  }
154  this->_pHead = &node;
155 
156  ++this->_size;
157  }
158 
162  void insertAtTail(T& node) noexcept {
163  this->remove(node);
164 
165  if (this->_pTail) {
166  (this->_pTail->*Pointers).pNext = &node;
167  (node.*Pointers).pPrevious = this->_pTail;
168  } else {
169  this->_pHead = &node;
170  }
171  this->_pTail = &node;
172 
173  ++this->_size;
174  }
175 
179  size_t size() const noexcept { return this->_size; }
180 
185  T* head() noexcept { return this->_pHead; }
186 
188  const T* head() const noexcept { return this->_pHead; }
189 
194  T* tail() noexcept { return this->_pTail; }
195 
197  const T* tail() const noexcept { return this->_pTail; }
198 
203  T* next(T& node) noexcept { return (node.*Pointers).pNext; }
204 
206  const T* next(const T& node) const noexcept { return (node.*Pointers).pNext; }
207 
212  T* next(T* pNode) noexcept {
213  return pNode ? this->next(*pNode) : this->_pHead;
214  }
215 
217  const T* next(const T* pNode) const noexcept {
218  return pNode ? this->next(*pNode) : this->_pHead;
219  }
220 
225  T* previous(T& node) noexcept { return (node.*Pointers).pPrevious; }
226 
228  const T* previous(const T& node) const noexcept {
229  return (node.*Pointers).pPrevious;
230  }
231 
236  T* previous(T* pNode) {
237  return pNode ? this->previous(*pNode) : this->_pTail;
238  }
239 
241  const T* previous(const T* pNode) const noexcept {
242  return pNode ? this->previous(*pNode) : this->_pTail;
243  }
244 
256  bool contains(const T& node) const {
257  return this->next(node) != nullptr || this->previous(node) != nullptr ||
258  this->_pHead == &node;
259  }
260 
261 private:
262  size_t _size = 0;
263  T* _pHead = nullptr;
264  T* _pTail = nullptr;
265 };
266 
267 template <typename T, DoublyLinkedListPointers<T>(T::*Pointers)>
268 using DoublyLinkedList = DoublyLinkedListAdvanced<T, T, Pointers>;
269 
270 } // namespace CesiumUtility
const T * next(const T &node) const noexcept
Returns the next node after the given one, or nullptr if the given node is the tail.
void insertAtHead(T &node) noexcept
Insert the given node as the new head of the list.
void insertAfter(T &after, T &node) noexcept
Insert the given node after the other node.
const T * previous(const T &node) const noexcept
Returns the previous node before the given one, or nullptr if the given node is the head.
T * previous(T *pNode)
Returns the previous node before the given one, or the tail if the given node is nullptr.
void insertBefore(T &before, T &node) noexcept
Insert the given node before the other node.
size_t size() const noexcept
Returns the size of this list.
void remove(T &node) noexcept
Removes the given node from this list.
const T * next(const T *pNode) const noexcept
Returns the next node after the given one, or the head if the given node is nullptr.
T * next(T *pNode) noexcept
Returns the next node after the given one, or the head if the given node is nullptr.
const T * head() const noexcept
Returns the head node of this list, or nullptr if the list is empty.
T * previous(T &node) noexcept
Returns the previous node before the given one, or nullptr if the given node is the head.
const T * previous(const T *pNode) const noexcept
Returns the previous node before the given one, or the tail if the given node is nullptr.
bool contains(const T &node) const
Determines if this list contains a given node in constant time. In order to avoid a full list scan,...
T * next(T &node) noexcept
Returns the next node after the given one, or nullptr if the given node is the tail.
const T * tail() const noexcept
Returns the tail node of this list, or nullptr if the list is empty.
T * tail() noexcept
Returns the tail node of this list, or nullptr if the list is empty.
void insertAtTail(T &node) noexcept
Insert the given node as the new tail of the list.
T * head() noexcept
Returns the head node of this list, or nullptr if the list is empty.
Contains the previous and next pointers for an element in a DoublyLinkedList.
DoublyLinkedListPointers(DoublyLinkedListPointers &rhs) noexcept
Copy constructor.
DoublyLinkedListPointers() noexcept
Default constructor.
DoublyLinkedListPointers & operator=(const DoublyLinkedListPointers &) noexcept
Assignment operator.
Utility classes for Cesium.