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.

148 lines
3.5 KiB

  1. #pragma once
  2. #include "gp_config.hpp"
  3. #include "gp/algorithms/move.hpp"
  4. #include "gp/containers/array.hpp"
  5. #include "gp/utils/iterator.hpp"
  6. #include <stddef.h>
  7. namespace gp{
  8. /**
  9. * @brief An array that has static indexes that are not affected by deletions or new additions
  10. *
  11. * @tparam T The stored type
  12. * @tparam _capacity The total capacity of the array
  13. */
  14. template<typename T, size_t _capacity>
  15. class indexed_array{
  16. size_t data_top = 0;
  17. size_t available_indexes_top = 0;
  18. size_t remove_top = 0;
  19. gp::array<char, sizeof(T)*_capacity> data_table;
  20. size_t available_indexes[_capacity];
  21. size_t translation_table[_capacity];
  22. size_t reverse_translation_table[_capacity];
  23. size_t remove_table[_capacity];
  24. public:
  25. indexed_array() {}
  26. template<typename U>
  27. size_t push(U&& value) {
  28. size_t index;
  29. gp_config::assertion(data_top+1 != _capacity, "Indexed array capacity exceeded");
  30. if(available_indexes_top) {
  31. available_indexes_top--;
  32. index = available_indexes[available_indexes_top];
  33. } else {
  34. index = data_top;
  35. }
  36. new(&(data_table.as_buffer().template cast<T>()[data_top])) T(gp::forward<U>(value));
  37. translation_table[index] = data_top;
  38. reverse_translation_table[data_top] = index;
  39. ++data_top;
  40. return index;
  41. }
  42. void pop(size_t idx) {
  43. size_t v_idx = translation_table[idx];
  44. available_indexes[available_indexes_top] = idx;
  45. ++available_indexes_top;
  46. translation_table[idx] = -1;
  47. --data_top;
  48. if(v_idx < data_top) {
  49. size_t u_idx = reverse_translation_table[data_top];
  50. data_table.as_buffer().template cast<T>()[v_idx] = gp::move(reinterpret_cast<T&>(data_table[data_top]));
  51. ::operator delete(&data_table.as_buffer().template cast<T>()[data_top], &(data_table.as_buffer().template cast<T>()[data_top]));
  52. data_table.as_buffer().template cast<T>()[data_top].~T();
  53. translation_table[u_idx] = v_idx;
  54. reverse_translation_table[v_idx] = u_idx;
  55. }
  56. }
  57. void reset() {
  58. auto it = data_table;
  59. auto end = data_table+data_top;
  60. while(it != end) {
  61. ::operator delete(it, it);
  62. ++it;
  63. }
  64. data_top = 0;
  65. available_indexes_top = 0;
  66. remove_top = 0;
  67. }
  68. void mark_internal_for_removal(size_t i_idx) {
  69. remove_table[remove_top] = reverse_translation_table[i_idx];
  70. ++remove_top;
  71. }
  72. void mark_for_removal(size_t idx) {
  73. remove_table[remove_top] = idx;
  74. ++remove_top;
  75. }
  76. void sweep_removed() {
  77. auto it = remove_table;
  78. auto end = remove_table+remove_top;
  79. while(it != end) {
  80. pop(*it);
  81. ++it;
  82. }
  83. }
  84. bool has(size_t idx) {
  85. if(idx > data_top) return false;
  86. if(translation_table[idx] == -1) return false;
  87. return true;
  88. }
  89. template<typename fn_t>
  90. void foreach(fn_t function) {
  91. for(size_t i = 0; i < data_top; ++i) {
  92. function(reverse_translation_table[i], operator[](reverse_translation_table[i]));
  93. }
  94. }
  95. pointer_iterator<T> begin()
  96. {
  97. return data_table.as_buffer().template cast<T>().begin();
  98. }
  99. pointer_iterator<T> end()
  100. {
  101. return data_table.as_buffer().template cast<T>().begin()+data_top;
  102. }
  103. const_pointer_iterator<T> cbegin()
  104. {
  105. return data_table.as_buffer().template cast<T>().cbegin();
  106. }
  107. const_pointer_iterator<T> cend()
  108. {
  109. return data_table.as_buffer().template cast<T>().cbegin()+data_top;
  110. }
  111. size_t size() {
  112. return data_top;
  113. }
  114. size_t capacity() {
  115. return _capacity;
  116. }
  117. T& operator[](size_t idx) {
  118. gp_config::assertion(idx < data_top, "Bad indexed array access");
  119. return data_table.as_buffer().template cast<T>()[translation_table[idx]];
  120. }
  121. };
  122. }