25namespace sparta::utils
46 template <
class DataT>
66 alignas(DataT) std::byte type_storage[
sizeof(DataT)];
68 Node(NodeIdx _index) :
73 typename Node::NodeIdx advanceNode_(
typename Node::NodeIdx node_idx)
const {
74 typename Node::NodeIdx ret_idx = (node_idx == -1 ? -1 : nodes_[node_idx].next);
78 auto getStorage(
typename Node::NodeIdx node_idx) {
79 return &nodes_[node_idx].type_storage;
82 auto getStorage(
typename Node::NodeIdx node_idx)
const {
83 return &nodes_[node_idx].type_storage;
94 template<
bool is_const = true>
97 typedef std::conditional_t<is_const, const value_type &, value_type &> RefIteratorType;
98 typedef std::conditional_t<is_const, const value_type *, value_type *> PtrIteratorType;
99 typedef std::conditional_t<is_const, const FastList *, FastList *> FastListPtrType;
106 node_idx_(iter.node_idx_)
113 bool isValid()
const {
return (node_idx_ != -1); }
118 return reinterpret_cast<PtrIteratorType
>(flist_->getStorage(node_idx_));
124 return reinterpret_cast<PtrIteratorType
>(flist_->getStorage(node_idx_));
130 return *
reinterpret_cast<PtrIteratorType
>(flist_->getStorage(node_idx_));
136 return *
reinterpret_cast<PtrIteratorType
>(flist_->getStorage(node_idx_));
146 node_idx_ = flist_->advanceNode_(node_idx_);
155 node_idx_ = flist_->advanceNode_(node_idx_);
162 return (rhs.flist_ != flist_) ||
163 (rhs.node_idx_ != node_idx_);
168 return (node.flist_ == flist_) && (node.node_idx_ == node_idx_);
178 NodeIterator(FastListPtrType flist,
typename Node::NodeIdx node_idx) :
183 FastListPtrType flist_ =
nullptr;
184 typename Node::NodeIdx node_idx_ = -1;
194 "Cannot create a sparta::utils::FastList of size 0");
196 nodes_.reserve(
size);
197 for(
size_t i = 0; i <
size; ++i) {
199 n.prev = node_idx - 1;
200 n.next = node_idx + 1;
202 nodes_.emplace_back(n);
204 nodes_.back().next = -1;
236 bool empty()
const {
return size_ == 0; }
239 size_t size()
const {
return size_; };
242 size_t max_size()
const {
return nodes_.capacity(); };
246 void clear() noexcept {
247 const auto my_end =
end();
248 for(
auto it =
begin(); it != my_end;) {
259 const auto node_idx = entry.
getIndex();
260 auto & node_to_erase = nodes_[node_idx];
261 reinterpret_cast<DataT*
>(&node_to_erase.type_storage)->~DataT();
264 if(first_node_ == node_idx) {
265 first_node_ = node_to_erase.next;
267 if(last_node_ == node_idx) {
268 last_node_ = node_to_erase.prev;
273 auto & next_node = nodes_[node_to_erase.next];
274 next_node.prev = node_to_erase.prev;
275 next_elem = node_to_erase.next;
280 auto & prev_node = nodes_[node_to_erase.prev];
281 prev_node.next = node_to_erase.next;
284 node_to_erase.prev = -1;
285 node_to_erase.next = -1;
287 nodes_[free_head_].prev = node_idx;
288 node_to_erase.next = free_head_;
290 free_head_ = node_idx;
295 template<
class ...ArgsT>
299 "FastList is out of element room");
300 const auto index_pos = pos.getIndex();
304 if(index_pos == -1) {
308 auto & new_node = nodes_[free_head_];
309 free_head_ = new_node.next;
310 new (&new_node.type_storage) DataT(args...);
316 auto & insert_pt = nodes_[index_pos];
317 new_node.next = insert_pt.index;
318 new_node.prev = insert_pt.prev;
319 insert_pt.prev = new_node.index;
320 if(new_node.prev != -1) {
322 nodes_[new_node.prev].next = new_node.index;
325 if((first_node_ == index_pos) || (first_node_ == -1))
327 first_node_ = new_node.index;
331 return iterator(
this, new_node.index);
339 template<
class ...ArgsT>
343 "FastList is out of element room");
345 auto & new_node = nodes_[free_head_];
346 free_head_ = new_node.next;
347 new (&new_node.type_storage) DataT(args...);
354 auto & old_first = nodes_[first_node_];
355 old_first.prev = new_node.index;
356 new_node.next = old_first.index;
358 first_node_ = new_node.index;
360 last_node_ = first_node_;
364 return iterator(
this, new_node.index);
372 template<
class ...ArgsT>
375 "FastList is out of element room");
377 auto & new_node = nodes_[free_head_];
378 free_head_ = new_node.next;
379 new (&new_node.type_storage) DataT(args...);
386 auto & old_last = nodes_[last_node_];
387 old_last.next = new_node.index;
388 new_node.prev = old_last.index;
390 last_node_ = new_node.index;
392 first_node_ = last_node_;
396 return iterator(
this, new_node.index);
401 template<
class ...ArgsT>
403 return emplace(pos, args...);
409 "Can't pop_back on an empty list");
416 "Can't pop_front on an empty list");
423 friend std::ostream & operator<<(std::ostream & os,
const FastList<DataT> & fl)
425 int next_node = fl.first_node_;
426 if(next_node == -1) {
427 os <<
"<empty>" << std::endl;
430 int index = fl.size_ - 1;
433 const auto & n = fl.nodes_[next_node];
434 os << index <<
" elem=" << *
reinterpret_cast<const DataT*
>(&n.type_storage)
435 <<
" n.next=" << n.next
436 <<
" n.prev=" << n.prev << std::endl;
439 }
while(next_node != -1);
445 std::vector<Node> nodes_;
448 int first_node_ = -1;
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.
bool operator!=(const NodeIterator &rhs)
Equality of iterator (not the underlying object)
bool isValid() const
Determine if the iteartor is valid.
PtrIteratorType operator->()
Iterator dereference.
bool operator==(const NodeIterator &node) const noexcept
Equality of iterator (not the underlying object)
NodeIterator & operator=(const NodeIterator &rhs)=default
Assignments.
NodeIterator operator++(int)
Move to the next iterator (post)
int getIndex() const
Get the index in the list where this iterator points.
NodeIterator & operator++()
Move to the next iterator (pre)
PtrIteratorType operator->() const
Iterator dereference (const)
RefIteratorType operator*()
Iterator dereference.
An alternative to std::list, about 70% faster.
iterator emplace_front(ArgsT &&...args)
Add an element to the front of the list.
void pop_front()
Pop the first element off of the list.
~FastList()
Destroy (clear) the list.
iterator end()
Obtain an end iterator.
iterator begin()
Obtain a beginning iterator.
iterator emplace_back(ArgsT &&...args)
emplace an object at the back
iterator insert(const const_iterator &pos, ArgsT &&...args)
DataT value_type
Handy using.
const_iterator end() const
Obtain an end const_iterator.
NodeIterator< true > const_iterator
Iterator type, const.
NodeIterator< false > iterator
Iterator type.
iterator erase(const const_iterator &entry)
Erase an element with the given iterator.
DataT & front()
Get the front of the fast list non-const.
FastList(size_t size)
Construct FastList of a given size.
const_iterator begin() const
Obtain a beginning const_iterator.
const DataT & front() const
Get the front of the fast list, const.
void pop_back()
Pop the last element off of the list.