24namespace sparta::utils
45 template <
class DataT>
65 std::aligned_storage_t<
sizeof(DataT),
alignof(DataT)> type_storage;
67 Node(NodeIdx _index) :
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);
77 auto getStorage(
typename Node::NodeIdx node_idx) {
78 return &nodes_[node_idx].type_storage;
81 auto getStorage(
typename Node::NodeIdx node_idx)
const {
82 return &nodes_[node_idx].type_storage;
93 template<
bool is_const = true>
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;
105 node_idx_(iter.node_idx_)
112 bool isValid()
const {
return (node_idx_ != -1); }
117 return reinterpret_cast<PtrIteratorType
>(flist_->getStorage(node_idx_));
123 return reinterpret_cast<PtrIteratorType
>(flist_->getStorage(node_idx_));
129 return *
reinterpret_cast<PtrIteratorType
>(flist_->getStorage(node_idx_));
135 return *
reinterpret_cast<PtrIteratorType
>(flist_->getStorage(node_idx_));
145 node_idx_ = flist_->advanceNode_(node_idx_);
154 node_idx_ = flist_->advanceNode_(node_idx_);
161 return (rhs.flist_ != flist_) ||
162 (rhs.node_idx_ != node_idx_);
167 return (node.flist_ == flist_) && (node.node_idx_ == node_idx_);
177 NodeIterator(FastListPtrType flist,
typename Node::NodeIdx node_idx) :
182 FastListPtrType flist_ =
nullptr;
183 typename Node::NodeIdx node_idx_ = -1;
193 "Cannot create a sparta::utils::FastList of size 0");
195 nodes_.reserve(
size);
196 for(
size_t i = 0; i <
size; ++i) {
198 n.prev = node_idx - 1;
199 n.next = node_idx + 1;
201 nodes_.emplace_back(n);
203 nodes_.back().next = -1;
235 bool empty()
const {
return size_ == 0; }
238 size_t size()
const {
return size_; };
241 size_t max_size()
const {
return nodes_.capacity(); };
245 void clear() noexcept {
246 const auto my_end =
end();
247 for(
auto it =
begin(); it != my_end;) {
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();
263 if(first_node_ == node_idx) {
264 first_node_ = node_to_erase.next;
266 if(last_node_ == node_idx) {
267 last_node_ = node_to_erase.prev;
272 auto & next_node = nodes_[node_to_erase.next];
273 next_node.prev = node_to_erase.prev;
274 next_elem = node_to_erase.next;
279 auto & prev_node = nodes_[node_to_erase.prev];
280 prev_node.next = node_to_erase.next;
283 node_to_erase.prev = -1;
284 node_to_erase.next = -1;
286 nodes_[free_head_].prev = node_idx;
287 node_to_erase.next = free_head_;
289 free_head_ = node_idx;
294 template<
class ...ArgsT>
298 "FastList is out of element room");
299 const auto index_pos = pos.getIndex();
303 if(index_pos == -1) {
307 auto & new_node = nodes_[free_head_];
308 free_head_ = new_node.next;
309 new (&new_node.type_storage) DataT(args...);
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) {
321 nodes_[new_node.prev].next = new_node.index;
324 if((first_node_ == index_pos) || (first_node_ == -1))
326 first_node_ = new_node.index;
330 return iterator(
this, new_node.index);
338 template<
class ...ArgsT>
342 "FastList is out of element room");
344 auto & new_node = nodes_[free_head_];
345 free_head_ = new_node.next;
346 new (&new_node.type_storage) DataT(args...);
353 auto & old_first = nodes_[first_node_];
354 old_first.prev = new_node.index;
355 new_node.next = old_first.index;
357 first_node_ = new_node.index;
359 last_node_ = first_node_;
363 return iterator(
this, new_node.index);
371 template<
class ...ArgsT>
374 "FastList is out of element room");
376 auto & new_node = nodes_[free_head_];
377 free_head_ = new_node.next;
378 new (&new_node.type_storage) DataT(args...);
385 auto & old_last = nodes_[last_node_];
386 old_last.next = new_node.index;
387 new_node.prev = old_last.index;
389 last_node_ = new_node.index;
391 first_node_ = last_node_;
395 return iterator(
this, new_node.index);
400 template<
class ...ArgsT>
402 return emplace(pos, args...);
408 "Can't pop_back on an empty list");
415 "Can't pop_front on an empty list");
422 friend std::ostream & operator<<(std::ostream & os,
const FastList<DataT> & fl)
424 int next_node = fl.first_node_;
425 if(next_node == -1) {
426 os <<
"<empty>" << std::endl;
429 int index = fl.size_ - 1;
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;
438 }
while(next_node != -1);
444 std::vector<Node> nodes_;
447 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 and 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.