List.cppm 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. module;
  2. #include <cassert>
  3. #include <new>
  4. export module Core.List;
  5. import Core.AlignedData;
  6. import Core.Math;
  7. import Core.Meta;
  8. import Core.Utility;
  9. import Core.ToString;
  10. export namespace Core {
  11. template<typename T>
  12. class List final {
  13. size_t length;
  14. size_t capacity;
  15. T* data;
  16. public:
  17. List() : length(0), capacity(0), data(nullptr) {
  18. }
  19. List(const List& other) :
  20. length(0), capacity(other.capacity),
  21. data(allocate(other.capacity)) {
  22. for(const T& t : other) {
  23. unsafeAdd(t);
  24. }
  25. }
  26. List(List&& other) noexcept : List() {
  27. swap(other);
  28. }
  29. ~List() {
  30. clear();
  31. deleteWithSourceN<AlignedType<T>>(
  32. reinterpret_cast<AlignedType<T>*>(data));
  33. }
  34. List& operator=(List other) noexcept {
  35. swap(other);
  36. return *this;
  37. }
  38. T* begin() {
  39. return data;
  40. }
  41. T* end() {
  42. return data + length;
  43. }
  44. const T* begin() const {
  45. return data;
  46. }
  47. const T* end() const {
  48. return data + length;
  49. }
  50. void reserve(size_t n) {
  51. if(n > capacity) {
  52. setSize(n);
  53. }
  54. }
  55. void shrink() {
  56. if(length != capacity) {
  57. setSize(length);
  58. }
  59. }
  60. void resize(size_t n, const T& t) {
  61. if(length < n) {
  62. reserve(n);
  63. for(size_t i = n - length; i != 0; i--) {
  64. unsafeAdd(t);
  65. }
  66. } else if(length > n) {
  67. for(size_t i = n; i < length; i++) {
  68. data[i].~T();
  69. }
  70. length = n;
  71. }
  72. }
  73. void resize(size_t n) {
  74. if(length < n) {
  75. reserve(n);
  76. for(size_t i = n - length; i != 0; i--) {
  77. unsafeAdd(T());
  78. }
  79. } else if(length > n) {
  80. for(size_t i = n; i < length; i++) {
  81. data[i].~T();
  82. }
  83. length = n;
  84. }
  85. }
  86. template<typename... Args>
  87. T& put(Args&&... args) {
  88. ensureCapacity();
  89. return *unsafeAdd(Core::forward<Args>(args)...);
  90. }
  91. template<typename... Args>
  92. List& add(Args&&... args) {
  93. put(Core::forward<Args>(args)...);
  94. return *this;
  95. }
  96. template<typename... Args>
  97. T& putAt(size_t t, Args&&... args) {
  98. if(t >= length) {
  99. return put(Core::forward<Args>(args)...);
  100. }
  101. // put must not reallocate, to keep the moved element alive
  102. ensureCapacity();
  103. put(Core::move(data[length - 1]));
  104. for(size_t i = length - 2; i > t; i--) {
  105. data[i] = Core::move(data[i - 1]);
  106. }
  107. data[t] = Core::move(T(Core::forward<Args>(args)...));
  108. return data[t];
  109. }
  110. template<typename... Args>
  111. List& addAt(size_t index, Args&&... args) {
  112. putAt(index, Core::forward<Args>(args)...);
  113. return *this;
  114. }
  115. T& operator[](size_t index) {
  116. assert(index < length);
  117. return data[index];
  118. }
  119. const T& operator[](size_t index) const {
  120. assert(index < length);
  121. return data[index];
  122. }
  123. T& getLast() {
  124. assert(length > 0);
  125. return data[length - 1];
  126. }
  127. const T& getLast() const {
  128. assert(length > 0);
  129. return data[length - 1];
  130. }
  131. size_t getLength() const {
  132. return length;
  133. }
  134. size_t getCapacity() const {
  135. return capacity;
  136. }
  137. void clear() {
  138. for(T& t : *this) {
  139. t.~T();
  140. }
  141. length = 0;
  142. }
  143. void removeBySwap(size_t index) {
  144. assert(index < length);
  145. length--;
  146. if(index != length) {
  147. data[index] = Core::move(data[length]);
  148. }
  149. data[length].~T();
  150. }
  151. void remove(size_t index) {
  152. assert(index < length);
  153. length--;
  154. T* currentT = begin() + index;
  155. T* endT = end();
  156. while(currentT != endT) {
  157. T* nextT = currentT + 1;
  158. *currentT = Core::move(*nextT);
  159. currentT = nextT;
  160. }
  161. endT->~T();
  162. }
  163. void removeLast() {
  164. removeBySwap(length - 1);
  165. }
  166. void swap(List& other) noexcept {
  167. Core::swap(length, other.length);
  168. Core::swap(capacity, other.capacity);
  169. Core::swap(data, other.data);
  170. }
  171. private:
  172. static T* allocate(size_t n) {
  173. if(n <= 0) {
  174. return nullptr;
  175. }
  176. return reinterpret_cast<T*>(newWithSourceN<AlignedType<T>>(n));
  177. }
  178. void ensureCapacity() {
  179. if(length >= capacity) {
  180. reserve(capacity + Core::max(4lu, capacity / 4));
  181. }
  182. }
  183. // does not check for capacity
  184. template<typename... Args>
  185. T* unsafeAdd(Args&&... args) {
  186. return new(data + length++) T(Core::forward<Args>(args)...);
  187. }
  188. void setSize(size_t n) {
  189. List copy;
  190. copy.data = allocate(n);
  191. copy.capacity = n;
  192. for(size_t i = 0; i < length; i++) {
  193. copy.unsafeAdd(Core::move(data[i]));
  194. }
  195. swap(copy);
  196. }
  197. };
  198. }