The Sparta Modeling Framework
Loading...
Searching...
No Matches
FastList.hpp
Go to the documentation of this file.
1// <FastList.hpp> -*- C++ -*-
2
3
11#pragma once
12
13#include <vector>
14#include <iostream>
15#include <exception>
16#include <iterator>
17#include <cinttypes>
18#include <cassert>
19#include <type_traits>
20
23
24namespace sparta::utils
25{
45 template <class DataT>
47 {
48 struct Node
49 {
50 using NodeIdx = int;
51
52 // Where this node is in the vector
53 const NodeIdx index;
54
55 // Points to the next element or the next free
56 // element if this node has been removed.
57 NodeIdx next = -1;
58
59 // Points to the previous element.
60 NodeIdx prev = -1;
61
62 // Stores the memory for an instance of 'T'.
63 // Use placement new to construct the object and
64 // manually invoke its dtor as necessary.
65 std::aligned_storage_t<sizeof(DataT), alignof(DataT)> type_storage;
66
67 Node(NodeIdx _index) :
68 index(_index)
69 {}
70 };
71
72 typename Node::NodeIdx advanceNode_(typename Node::NodeIdx node_idx) const {
73 typename Node::NodeIdx ret_idx = (node_idx == -1 ? -1 : nodes_[node_idx].next);
74 return ret_idx;
75 }
76
77 auto getStorage(typename Node::NodeIdx node_idx) {
78 return &nodes_[node_idx].type_storage;
79 }
80
81 auto getStorage(typename Node::NodeIdx node_idx) const {
82 return &nodes_[node_idx].type_storage;
83 }
84
85 public:
86 using value_type = DataT;
87
93 template<bool is_const = true>
94 class NodeIterator : public sparta::utils::IteratorTraits<std::forward_iterator_tag, value_type>
95 {
96 typedef std::conditional_t<is_const, const value_type &, value_type &> RefIteratorType;
97 typedef std::conditional_t<is_const, const value_type *, value_type *> PtrIteratorType;
98 typedef std::conditional_t<is_const, const FastList *, FastList *> FastListPtrType;
99 public:
100
101 NodeIterator() = default;
102
103 NodeIterator(const NodeIterator<false> & iter) :
104 flist_(iter.flist_),
105 node_idx_(iter.node_idx_)
106 {}
107
112 bool isValid() const { return (node_idx_ != -1); }
113
115 PtrIteratorType operator->() {
116 assert(isValid());
117 return reinterpret_cast<PtrIteratorType>(flist_->getStorage(node_idx_));
118 }
119
121 PtrIteratorType operator->() const {
122 assert(isValid());
123 return reinterpret_cast<PtrIteratorType>(flist_->getStorage(node_idx_));
124 }
125
127 RefIteratorType operator* () {
128 assert(isValid());
129 return *reinterpret_cast<PtrIteratorType>(flist_->getStorage(node_idx_));
130 }
131
133 RefIteratorType operator* () const {
134 assert(isValid());
135 return *reinterpret_cast<PtrIteratorType>(flist_->getStorage(node_idx_));
136 }
137
139 int getIndex() const { return node_idx_; }
140
143 {
144 assert(isValid());
145 node_idx_ = flist_->advanceNode_(node_idx_);
146 return *this;
147 }
148
151 {
152 NodeIterator orig = *this;
153 assert(isValid());
154 node_idx_ = flist_->advanceNode_(node_idx_);
155 return orig;
156 }
157
159 bool operator!=(const NodeIterator &rhs)
160 {
161 return (rhs.flist_ != flist_) ||
162 (rhs.node_idx_ != node_idx_);
163 }
164
166 bool operator==(const NodeIterator & node) const noexcept {
167 return (node.flist_ == flist_) && (node.node_idx_ == node_idx_);
168 }
169
171 NodeIterator& operator=(const NodeIterator &rhs) = default;
172 NodeIterator& operator=( NodeIterator &&rhs) = default;
173
174 private:
175 friend class FastList<DataT>;
176
177 NodeIterator(FastListPtrType flist, typename Node::NodeIdx node_idx) :
178 flist_(flist),
179 node_idx_(node_idx)
180 { }
181
182 FastListPtrType flist_ = nullptr;
183 typename Node::NodeIdx node_idx_ = -1;
184 };
185
191 {
192 sparta_assert(size != 0,
193 "Cannot create a sparta::utils::FastList of size 0");
194 int node_idx = 0;
195 nodes_.reserve(size);
196 for(size_t i = 0; i < size; ++i) {
197 Node n(node_idx);
198 n.prev = node_idx - 1;
199 n.next = node_idx + 1;
200 ++node_idx;
201 nodes_.emplace_back(n);
202 }
203 nodes_.back().next = -1;
204 }
205
207 ~FastList() { clear(); }
208
211
214 return iterator(this, first_node_);
215 }
216
219 return const_iterator(this, first_node_);
220 }
221
223 iterator end() { return iterator(this, -1); }
224
226 const_iterator end() const { return const_iterator(this, -1); }
227
229 DataT & front() { return *begin(); }
230
232 const DataT & front() const { return *begin(); }
233
235 bool empty() const { return size_ == 0; }
236
238 size_t size() const { return size_; };
239
241 size_t max_size() const { return nodes_.capacity(); };
242
244 // Modifiers
245 void clear() noexcept {
246 const auto my_end = end();
247 for(auto it = begin(); it != my_end;) {
248 erase(it++);
249 }
250 }
251
257 {
258 const auto node_idx = entry.getIndex();
259 auto & node_to_erase = nodes_[node_idx];
260 reinterpret_cast<DataT*>(&node_to_erase.type_storage)->~DataT();
261 int next_elem = -1;
262
263 if(first_node_ == node_idx) {
264 first_node_ = node_to_erase.next;
265 }
266 if(last_node_ == node_idx) {
267 last_node_ = node_to_erase.prev;
268 }
269
270 if(SPARTA_EXPECT_FALSE(node_to_erase.next != -1))
271 {
272 auto & next_node = nodes_[node_to_erase.next];
273 next_node.prev = node_to_erase.prev;
274 next_elem = node_to_erase.next;
275 }
276
277 if(SPARTA_EXPECT_FALSE(node_to_erase.prev != -1))
278 {
279 auto & prev_node = nodes_[node_to_erase.prev];
280 prev_node.next = node_to_erase.next;
281 }
282
283 node_to_erase.prev = -1;
284 node_to_erase.next = -1;
285 if(SPARTA_EXPECT_TRUE(free_head_ != -1)) {
286 nodes_[free_head_].prev = node_idx;
287 node_to_erase.next = free_head_;
288 }
289 free_head_ = node_idx;
290 --size_;
291 return iterator(this, next_elem);
292 }
293
294 template<class ...ArgsT>
295 iterator emplace(const const_iterator & pos, ArgsT&&...args)
296 {
297 sparta_assert(free_head_ != -1,
298 "FastList is out of element room");
299 const auto index_pos = pos.getIndex();
300
301 // If the index pos is -1, it's either end() or begin() on
302 // an empty list. Just emplace_back (or front, don't matter)
303 if(index_pos == -1) {
304 return emplace_back(std::forward<ArgsT>(args)...);
305 }
306
307 auto & new_node = nodes_[free_head_];
308 free_head_ = new_node.next;
309 new (&new_node.type_storage) DataT(args...);
310 // Update pointers. Start with a clean slate
311 new_node.next = -1;
312 new_node.prev = -1;
313
314 // Insert before the given pt
315 auto & insert_pt = nodes_[index_pos];
316 new_node.next = insert_pt.index;
317 new_node.prev = insert_pt.prev;
318 insert_pt.prev = new_node.index;
319 if(new_node.prev != -1) {
320 // update the previous node's next
321 nodes_[new_node.prev].next = new_node.index;
322 }
323
324 if((first_node_ == index_pos) || (first_node_ == -1))
325 {
326 first_node_ = new_node.index;
327 }
328 ++size_;
329
330 return iterator(this, new_node.index);
331 }
332
338 template<class ...ArgsT>
339 iterator emplace_front(ArgsT&&...args)
340 {
341 sparta_assert(free_head_ != -1,
342 "FastList is out of element room");
343
344 auto & new_node = nodes_[free_head_];
345 free_head_ = new_node.next;
346 new (&new_node.type_storage) DataT(args...);
347
348 // Update pointers. Start with a clean slate
349 new_node.next = -1;
350 new_node.prev = -1;
351 if(SPARTA_EXPECT_TRUE(first_node_ != -1))
352 {
353 auto & old_first = nodes_[first_node_];
354 old_first.prev = new_node.index;
355 new_node.next = old_first.index;
356 }
357 first_node_ = new_node.index;
358 if(SPARTA_EXPECT_FALSE(last_node_ == -1)) {
359 last_node_ = first_node_;
360 }
361
362 ++size_;
363 return iterator(this, new_node.index);
364 }
365
371 template<class ...ArgsT>
372 iterator emplace_back(ArgsT&&...args) {
373 sparta_assert(free_head_ != -1,
374 "FastList is out of element room");
375
376 auto & new_node = nodes_[free_head_];
377 free_head_ = new_node.next;
378 new (&new_node.type_storage) DataT(args...);
379
380 // Update pointers. Start with a clean slate
381 new_node.next = -1;
382 new_node.prev = -1;
383 if(SPARTA_EXPECT_TRUE(last_node_ != -1))
384 {
385 auto & old_last = nodes_[last_node_];
386 old_last.next = new_node.index;
387 new_node.prev = old_last.index;
388 }
389 last_node_ = new_node.index;
390 if(SPARTA_EXPECT_FALSE(first_node_ == -1)) {
391 first_node_ = last_node_;
392 }
393
394 ++size_;
395 return iterator(this, new_node.index);
396 }
397
400 template<class ...ArgsT>
401 iterator insert(const const_iterator & pos, ArgsT&&...args) {
402 return emplace(pos, args...);
403 }
404
406 void pop_back() {
407 sparta_assert(last_node_ != -1,
408 "Can't pop_back on an empty list");
409 erase(iterator(this, last_node_));
410 }
411
413 void pop_front() {
414 sparta_assert(first_node_ != -1,
415 "Can't pop_front on an empty list");
416 erase(iterator(this, first_node_));
417 }
418
419 private:
420
421 // Friendly printer
422 friend std::ostream & operator<<(std::ostream & os, const FastList<DataT> & fl)
423 {
424 int next_node = fl.first_node_;
425 if(next_node == -1) {
426 os << "<empty>" << std::endl;
427 }
428 else {
429 int index = fl.size_ - 1;
430 do
431 {
432 const auto & n = fl.nodes_[next_node];
433 os << index << " elem=" << *reinterpret_cast<const DataT*>(&n.type_storage)
434 << " n.next=" << n.next
435 << " n.prev=" << n.prev << std::endl;
436 next_node = n.next;
437 --index;
438 } while(next_node != -1);
439 }
440 return os;
441 }
442
443 // Stores all the nodes.
444 std::vector<Node> nodes_;
445
446 int free_head_ = 0;
447 int first_node_ = -1;
448 int last_node_ = -1;
449 size_t size_ = 0;
450 };
451}
Defines a few handy (and now deprecated) C++ iterator traits.
Set of macros for Sparta assertions. Caught by the framework.
#define sparta_assert(...)
Simple variadic assertion that will throw a sparta_exception if the condition fails.
#define SPARTA_EXPECT_TRUE(x)
A macro for hinting to the compiler a particular condition should be considered most likely true.
#define SPARTA_EXPECT_FALSE(x)
A macro for hinting to the compiler a particular condition should be considered most likely false.
The internal iterator type of FastList. Use FastList<T>::[const_]iterator instead.
Definition FastList.hpp:95
bool operator!=(const NodeIterator &rhs)
Equality of iterator (not the underlying object)
Definition FastList.hpp:159
bool isValid() const
Determine if the iteartor is valid.
Definition FastList.hpp:112
PtrIteratorType operator->()
Iterator dereference.
Definition FastList.hpp:115
bool operator==(const NodeIterator &node) const noexcept
Equality of iterator (not the underlying object)
Definition FastList.hpp:166
NodeIterator & operator=(const NodeIterator &rhs)=default
Assignments.
NodeIterator operator++(int)
Move to the next iterator (post)
Definition FastList.hpp:150
int getIndex() const
Get the index in the list where this iterator points.
Definition FastList.hpp:139
NodeIterator & operator++()
Move to the next iterator (pre)
Definition FastList.hpp:142
PtrIteratorType operator->() const
Iterator dereference (const)
Definition FastList.hpp:121
RefIteratorType operator*()
Iterator dereference.
Definition FastList.hpp:127
An alternative to std::list, about 70% faster.
Definition FastList.hpp:47
iterator emplace_front(ArgsT &&...args)
Add an element to the front of the list.
Definition FastList.hpp:339
void pop_front()
Pop the first element off of the list.
Definition FastList.hpp:413
~FastList()
Destroy (clear) the list.
Definition FastList.hpp:207
iterator end()
Obtain an end iterator.
Definition FastList.hpp:223
iterator begin()
Obtain a beginning iterator.
Definition FastList.hpp:213
iterator emplace_back(ArgsT &&...args)
emplace and object at the back
Definition FastList.hpp:372
size_t size() const
Definition FastList.hpp:238
iterator insert(const const_iterator &pos, ArgsT &&...args)
Definition FastList.hpp:401
DataT value_type
Handy using.
Definition FastList.hpp:86
const_iterator end() const
Obtain an end const_iterator.
Definition FastList.hpp:226
NodeIterator< true > const_iterator
Iterator type, const.
Definition FastList.hpp:210
NodeIterator< false > iterator
Iterator type.
Definition FastList.hpp:209
iterator erase(const const_iterator &entry)
Erase an element with the given iterator.
Definition FastList.hpp:256
size_t max_size() const
Definition FastList.hpp:241
DataT & front()
Get the front of the fast list non-const.
Definition FastList.hpp:229
FastList(size_t size)
Construct FastList of a given size.
Definition FastList.hpp:190
const_iterator begin() const
Obtain a beginning const_iterator.
Definition FastList.hpp:218
const DataT & front() const
Get the front of the fast list, const.
Definition FastList.hpp:232
void pop_back()
Pop the last element off of the list.
Definition FastList.hpp:406