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.

129 lines
2.7 KiB

  1. #pragma once
  2. #include <stddef.h>
  3. #include "gp_config.hpp"
  4. #include "gp/algorithm/move.hpp"
  5. #include "gp/iterator.hpp"
  6. namespace gp{
  7. template<typename T, size_t _capacity>
  8. class indexed_array{
  9. size_t data_top = 0;
  10. size_t available_indexes_top = 0;
  11. size_t remove_top = 0;
  12. T data_table[_capacity];
  13. size_t available_indexes[_capacity];
  14. size_t translation_table[_capacity];
  15. size_t reverse_translation_table[_capacity];
  16. size_t remove_table[_capacity];
  17. public:
  18. indexed_array() {}
  19. size_t push(T&& value) {
  20. size_t index;
  21. gp_config::assertion(data_top+1 != _capacity, "Indexed array capacity exceeded");
  22. if(available_indexes_top) {
  23. available_indexes_top--;
  24. index = available_indexes[available_indexes_top];
  25. } else {
  26. index = data_top;
  27. }
  28. new(&data_table[data_top]) T(gp::move(value));
  29. translation_table[index] = data_top;
  30. reverse_translation_table[data_top] = index;
  31. ++data_top;
  32. return index;
  33. }
  34. void pop(size_t idx) {
  35. size_t v_idx = translation_table[idx];
  36. available_indexes[available_indexes_top] = idx;
  37. ++available_indexes_top;
  38. translation_table[idx] = -1;
  39. --data_top;
  40. if(v_idx < data_top) {
  41. size_t u_idx = reverse_translation_table[data_top];
  42. data_table[v_idx] = gp::move(data_table[data_top]);
  43. ::operator delete(&data_table[data_top], &data_table[data_top]);
  44. data_table[data_top].~T();
  45. translation_table[u_idx] = v_idx;
  46. reverse_translation_table[v_idx] = u_idx;
  47. }
  48. }
  49. void reset() {
  50. auto it = data_table;
  51. auto end = data_table+data_top;
  52. while(it != end) {
  53. ::operator delete(it, it);
  54. ++it;
  55. }
  56. data_top = 0;
  57. available_indexes_top = 0;
  58. remove_top = 0;
  59. }
  60. void mark_internal_for_removal(size_t i_idx) {
  61. remove_table[remove_top] = reverse_translation_table[i_idx];
  62. ++remove_top;
  63. }
  64. void mark_for_removal(size_t idx) {
  65. remove_table[remove_top] = idx;
  66. ++remove_top;
  67. }
  68. void sweep_removed() {
  69. auto it = remove_table;
  70. auto end = remove_table+remove_top;
  71. while(it != end) {
  72. pop(*it);
  73. ++it;
  74. }
  75. }
  76. bool has(size_t idx) {
  77. if(idx > data_top) return false;
  78. if(translation_table[idx] == -1) return false;
  79. return true;
  80. }
  81. pointer_iterator<T> begin()
  82. {
  83. return data_table;
  84. }
  85. pointer_iterator<T> end()
  86. {
  87. return data_table+data_top;
  88. }
  89. const_pointer_iterator<T> cbegin()
  90. {
  91. return data_table;
  92. }
  93. const_pointer_iterator<T> cend()
  94. {
  95. return data_table+data_top;
  96. }
  97. size_t size() {
  98. return data_top;
  99. }
  100. size_t capacity() {
  101. return _capacity;
  102. }
  103. T& operator[](size_t idx) {
  104. gp_config::assertion(idx < data_top, "Bad indexed array access");
  105. return data_table[translation_table[idx]];
  106. }
  107. };
  108. }