General Purpose library for Freestanding C++ and POSIX systems
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

177 lines
4.1 KiB

4 years ago
4 years ago
  1. #pragma once
  2. #include <gp/algorithms/sort.hpp>
  3. #include <gp/containers/array.hpp>
  4. #include <gp/math/integral.hpp>
  5. #include <gp/utils/iterator.hpp>
  6. #include <gp/functional/optional.hpp>
  7. // UNIMPLEMENTED: see filename
  8. namespace gp {
  9. namespace ordinators {
  10. struct less {
  11. template<typename T>
  12. bool operator() (const T& lhs, const T& rhs){
  13. return lhs < rhs;
  14. }
  15. };
  16. }
  17. /**
  18. * @brief
  19. *
  20. * @tparam T The type to store, must be either final or primitive
  21. * @tparam capacity The number of elements that can be stored in the structure
  22. */
  23. template<typename T, size_t capacity, typename ordinator = gp::ordinators::less>
  24. class flat_tree {
  25. using node_t = gp::optional<T>;
  26. gp::array<node_t, capacity> data_;
  27. static void ordain(auto destination_space, auto value_workspace, index_to_1 idx) {
  28. if(!value_workspace.size()) return;
  29. size_t pivot;
  30. if(value_workspace.size()%2) {
  31. pivot = value_workspace.size()/2;
  32. } else {
  33. pivot = value_workspace.size()/2 + 1;
  34. }
  35. destination_space[idx] = gp::move(value_workspace[pivot]);
  36. auto left = idx;
  37. left.left();
  38. ordain(destination_space, value_workspace.slice_start(pivot), left);
  39. auto right = idx;
  40. right.right();
  41. ordain(destination_space, value_workspace.trim_start(pivot+1), left);
  42. };
  43. public:
  44. using iterator = gp::flat_tree_iterator<flat_tree, T, 1>;
  45. using riterator = gp::flat_tree_iterator<flat_tree, T, -1>;
  46. friend iterator;
  47. friend riterator;
  48. flat_tree(auto data) {
  49. gp_config::assertion(data.size() <= data_.size(), "Couldn't construct flat tree from C array");
  50. for(auto v : data) {
  51. insert(v);
  52. }
  53. }
  54. bool insert(T& value) {
  55. index_to_1 idx(0);
  56. while(idx < data_.size() && data()[idx].has_value()) {
  57. if(ordinator()(data()[idx].value(), value)) {
  58. idx.left();
  59. } else {
  60. idx.right();
  61. }
  62. }
  63. if (idx >= data_.size()) [[unlikely]] {
  64. if(rebalance_with_value(value)) return true;
  65. if constexpr (gp_config::has_exceptions) {
  66. }
  67. return false;
  68. }
  69. data()[idx] = value;
  70. return true;
  71. }
  72. /**
  73. * @brief Rebalance the tree
  74. *
  75. * @param value The value to try to push along with the rebalance
  76. *
  77. * @return true if the operation suceeded
  78. * @return false if the operation failed
  79. */
  80. bool rebalance_with_value(T& value) {
  81. // TODO: Add constant memory shenanigans
  82. /*
  83. auto workspace = data_.as_buffer();
  84. bool ok = false;
  85. for(auto& elem : workspace) {
  86. if(!elem.has_value()) {
  87. ok = true;
  88. break;
  89. }
  90. }
  91. if(!ok) return false;
  92. gp::sort(workspace.begin(), workspace.end(), [](const node_t& lhs, const node_t& rhs){ return lhs.has_value() > rhs.has_value(); });
  93. size_t cnt = 0;
  94. for(auto& elem : workspace) {
  95. if(elem.has_value()) break;
  96. ++cnt;
  97. }
  98. --cnt;
  99. workspace[cnt] = value;
  100. auto value_workspace = workspace.trim_start(cnt);
  101. gp::sort(value_workspace.begin(), value_workspace.end(), [](const node_t& lhs, const node_t& rhs){ return ordinator(lhs.value(), rhs.value()); });
  102. auto destination_space = workspace.slice_start(value_workspace.size());
  103. for(auto )
  104. */
  105. auto oth = gp::move(data_);
  106. auto workspace = oth.as_buffer();
  107. bool ok = false;
  108. for(auto& elem : workspace) {
  109. if(!elem.has_value()) {
  110. ok = true;
  111. break;
  112. }
  113. }
  114. if(!ok) return false;
  115. gp::sort(workspace.begin(), workspace.end(), [](const node_t& lhs, const node_t& rhs){ return lhs.has_value() < rhs.has_value(); });
  116. size_t cnt = 0;
  117. for(auto& elem : workspace) {
  118. if(elem.has_value()) break;
  119. ++cnt;
  120. }
  121. --cnt;
  122. workspace[cnt] = value;
  123. auto value_workspace = workspace.trim_start(cnt);
  124. gp::sort(value_workspace.begin(), value_workspace.end(), [](const node_t& lhs, const node_t& rhs){ return ordinator()(lhs.value(), rhs.value()); });
  125. auto destination_space = workspace.slice_start(value_workspace.size());
  126. ordain(destination_space, value_workspace, 0);
  127. return true;
  128. }
  129. iterator begin() {
  130. return ++iterator{.tree = *this, .index = (size_t)-1};
  131. }
  132. iterator end() {
  133. return iterator{.tree = *this, .index = (size_t)-1};
  134. }
  135. auto data() {
  136. return data_.as_buffer();
  137. }
  138. };
  139. }