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.

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