|
|
- #pragma once
- #include <stddef.h>
- #include "gp/algorithm/tmp_manip.hpp"
- #include "gp/algorithm/modifiers.hpp"
- #include "gp_config.hpp"
-
- namespace gp {
- template<typename T, typename allocator, bool copy_allocator = false>
- 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<T, allocator, copy_allocator>::explorer;
- friend class gp::ring_list<T, allocator, copy_allocator>;
- };
-
- 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<allocator>
- >::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<typename V = T, typename ...Args>
- 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<node*>(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");
- }
- };
- }
|