General Purpose library for Freestanding C++ and POSIX systems
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

142 рядки
2.7 KiB

4 роки тому
  1. #pragma once
  2. #include <stddef.h>
  3. #include "gp/algorithm/tmp_manip.hpp"
  4. #include "gp/algorithm/modifiers.hpp"
  5. #include "gp_config.hpp"
  6. namespace gp {
  7. template<typename T, typename allocator, bool copy_allocator = true>
  8. class ring_list{
  9. public:
  10. class explorer;
  11. class node {
  12. T* value;
  13. node* prev;
  14. node* next;
  15. public:
  16. node(T* p)
  17. : value{p}
  18. , prev{this}
  19. , next{this}
  20. {}
  21. friend class gp::ring_list<T, allocator, copy_allocator>::explorer;
  22. friend class gp::ring_list<T, allocator, copy_allocator>;
  23. };
  24. class explorer {
  25. node* pos;
  26. public:
  27. explorer(node* v)
  28. : pos{v}
  29. {}
  30. bool operator==(const explorer& oth) const {
  31. return pos == oth.pos;
  32. }
  33. bool operator!=(const explorer& oth) const {
  34. return pos != oth.pos;
  35. }
  36. explorer operator++() {
  37. pos = pos->next;
  38. return pos;
  39. }
  40. explorer operator++(int) {
  41. auto tmp = pos;
  42. pos = pos->next;
  43. return tmp;
  44. }
  45. explorer operator--() {
  46. pos = pos->prev;
  47. return pos;
  48. }
  49. explorer operator--(int) {
  50. auto tmp = pos;
  51. pos = pos->prev;
  52. return tmp;
  53. }
  54. T& operator*() {
  55. return *(pos->value);
  56. }
  57. friend class ring_list;
  58. };
  59. private:
  60. node* any_node;
  61. size_t sz;
  62. typename gp::either<
  63. copy_allocator,
  64. allocator,
  65. gp::reference_wrapper<allocator>
  66. >::type alloc;
  67. void stitch_around(node* n) {
  68. n->prev->next = n->next;
  69. n->next->prev = n->prev;
  70. }
  71. public:
  72. ring_list()
  73. : any_node{nullptr}
  74. , sz{0}
  75. , alloc{}
  76. {}
  77. ring_list(node* initial, allocator& _alloc)
  78. : any_node{initial}
  79. , sz{1}
  80. , alloc{_alloc}
  81. {}
  82. template<typename V = T, typename ...Args>
  83. bool insert(Args&&... elem) {
  84. allocator& used_allocator = alloc;
  85. void* mem = used_allocator.allocate(sizeof(V));
  86. T* p = new(mem) V(elem...);
  87. node* to_insert = nullptr;
  88. if(
  89. nullptr == (to_insert = reinterpret_cast<node*>(used_allocator.allocate(sizeof(node))))
  90. ) return false;
  91. to_insert = new(to_insert) node(p);
  92. [[unlikely]] if (any_node == nullptr)
  93. {
  94. any_node = to_insert;
  95. } else {
  96. to_insert->prev = any_node->prev;
  97. to_insert->next = any_node;
  98. to_insert->prev->next = to_insert;
  99. any_node->prev = to_insert;
  100. }
  101. return true;
  102. }
  103. explorer explore() {
  104. return any_node;
  105. }
  106. void remove(explorer& value) {
  107. auto& v = *value;
  108. if(v == explore()) {
  109. if(v->next == v) {
  110. any_node = nullptr;
  111. } else {
  112. stitch_around(any_node);
  113. }
  114. } else {
  115. stitch_around(value.pos);
  116. }
  117. allocator& used_allocator = alloc;
  118. v.value->~T();
  119. gp_config::assertion(used_allocator.deallocate(v.value), "Bad free of value");
  120. value.pos->~node();
  121. gp_config::assertion(used_allocator.deallocate(value.pos), "Bad free of node");
  122. }
  123. };
  124. }