#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} {} ring_list(allocator& _alloc) : any_node{nullptr} , sz{0} , alloc{_alloc} {} template bool insert(Args&&... elem) { allocator& used_allocator = alloc; void* mem; [[unlikely]] if( nullptr == (mem = used_allocator.allocate(sizeof(V))) ) return false; T* p = new(mem) V(elem...); node* to_insert = nullptr; [[unlikely]] 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.pos; if(v == any_node) { if(v->next == v) { any_node = nullptr; } else { any_node = any_node->next; stitch_around(v); } } else { stitch_around(v); } allocator& used_allocator = alloc; v->value->~T(); gp_config::assertion(used_allocator.deallocate(v->value), "Bad free of value"); v->~node(); gp_config::assertion(used_allocator.deallocate(v), "Bad free of node"); } ~ring_list() { // TODO: Find a less hackish way to resove this issue if constexpr (!may_contain_self) { while(any_node) { remove(explore()); } } } }; }