#pragma once #include #include "gp/algorithm/tmp_manip.hpp" #include "gp/algorithm/modifiers.hpp" #include "gp_config.hpp" namespace gp { template class ring_list{ public: class explorer; class node { T* value; node* prev; node* next; public: node(T* p) : value{p} , prev{this} , next{this} {} friend class gp::ring_list::explorer; friend class gp::ring_list; }; class explorer { node* pos; public: explorer(node* v) : pos{v} {} bool operator==(const explorer& oth) const { return pos == oth.pos; } bool operator!=(const explorer& oth) const { return pos != oth.pos; } explorer operator++() { pos = pos->next; return pos; } explorer operator++(int) { auto tmp = pos; pos = pos->next; return tmp; } explorer operator--() { pos = pos->prev; return pos; } explorer operator--(int) { auto tmp = pos; pos = pos->prev; return tmp; } T& operator*() { return *(pos->value); } friend class ring_list; }; private: node* any_node; size_t sz; typename gp::either< copy_allocator, allocator, gp::reference_wrapper >::type alloc; void stitch_around(node* n) { n->prev->next = n->next; n->next->prev = n->prev; } public: ring_list() : any_node{nullptr} , sz{0} , alloc{} {} ring_list(node* initial, allocator& _alloc) : any_node{initial} , sz{1} , alloc{_alloc} {} template bool insert(Args&&... elem) { allocator& used_allocator = alloc; void* mem = used_allocator.allocate(sizeof(V)); T* p = new(mem) V(elem...); node* to_insert = nullptr; if( nullptr == (to_insert = reinterpret_cast(used_allocator.allocate(sizeof(node)))) ) return false; to_insert = new(to_insert) node(p); [[unlikely]] if (any_node == nullptr) { any_node = to_insert; } else { to_insert->prev = any_node->prev; to_insert->next = any_node; to_insert->prev->next = to_insert; any_node->prev = to_insert; } return true; } explorer explore() { return any_node; } void remove(explorer& value) { auto& v = *value; if(v == explore()) { if(v->next == v) { any_node = nullptr; } else { stitch_around(any_node); } } else { stitch_around(value.pos); } allocator& used_allocator = alloc; v.value->~T(); gp_config::assertion(used_allocator.deallocate(v.value), "Bad free of value"); value.pos->~node(); gp_config::assertion(used_allocator.deallocate(value.pos), "Bad free of node"); } }; }