General Purpose library for Freestanding C++ and POSIX systems
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

361 rader
7.4 KiB

4 år sedan
  1. #pragma once
  2. #include <gp/containers/buffer.hpp>
  3. #include <gp/utils/allocators/allocator.hpp>
  4. #include <initializer_list>
  5. namespace gp{
  6. /**
  7. * @brief A vector type most similar to that of the standard library
  8. * Always uses polymorphic allocation, no small value optimization
  9. *
  10. * @tparam T
  11. */
  12. template<typename T>
  13. class vector final {
  14. T* ary = nullptr; //< The data
  15. size_t sz = 0; //< the used size of the array
  16. size_t cap = 0; //< the available capacity of the array
  17. gp::reference_wrapper<allocator> alloc; //< the allocator
  18. public:
  19. using associated_iterator = pointer_iterator<T, 1>;
  20. using associated_const_iterator = const_pointer_iterator<T, 1>;
  21. using associated_riterator = pointer_iterator<T, -1>;
  22. using associated_const_riterator = const_pointer_iterator<T, -1>;
  23. /**
  24. * @brief Construct a new vector object from an allocator
  25. *
  26. * @param v the allocator
  27. */
  28. vector(allocator& v)
  29. : ary()
  30. , alloc(v)
  31. {}
  32. /**
  33. * @brief Construct a new vector object from another vector, copying it
  34. *
  35. * @param oth the other vector
  36. */
  37. vector(vector& oth)
  38. : alloc(oth.alloc)
  39. {
  40. sz = 0;
  41. cap = 0;
  42. ary = nullptr;
  43. gp_config::assertion(reserve(oth.size()), "could not reserve space on building");
  44. sz = oth.size();
  45. cap = oth.size();
  46. auto it_l = begin();
  47. auto it_o = oth.cbegin();
  48. for(size_t i = 0; i < sz; ++i)
  49. {
  50. new(&*(it_l++)) T(*(it_o++));
  51. }
  52. }
  53. /**
  54. * @brief Construct a new vector object by moving objects out of another vector
  55. *
  56. * @param oth
  57. */
  58. vector(vector&& oth)
  59. : ary(oth.ary)
  60. , sz(oth.sz)
  61. , cap(oth.cap)
  62. , alloc(oth.alloc)
  63. {
  64. oth.ary = nullptr;
  65. }
  66. /**
  67. * @brief Copy assignment
  68. *
  69. * @param oth
  70. * @return vector& the reference to this changed vector
  71. */
  72. vector& operator=(vector& oth)
  73. {
  74. gp_config::assertion(reserve(oth.size()), "could not reserve space on assign");
  75. for(size_t i = 0; i < gp::min(sz, oth.sz); ++i)
  76. {
  77. new(ary+i) T(oth[i]);
  78. }
  79. if(sz < oth.sz) {
  80. for(size_t i = sz; i < oth.sz; ++i) {
  81. new(ary+i) T(oth[i]);
  82. }
  83. } else if(sz > oth.sz) {
  84. for(size_t i = oth.sz; i < sz; ++i) {
  85. ary[i]->~T();
  86. }
  87. }
  88. sz = oth.sz;
  89. return *this;
  90. }
  91. /**
  92. * @brief Move assignment
  93. *
  94. * Will not change the allocator of the local vector, is EXPENSIVE if the both vectors have different allocators
  95. *
  96. * @param oth
  97. * @return vector&
  98. */
  99. vector& operator=(vector&& oth)
  100. {
  101. if(&alloc.get() == &oth.alloc.get())
  102. {
  103. gp::swap(ary, oth.ary);
  104. gp::swap(sz, oth.sz);
  105. gp::swap(cap, oth.cap);
  106. } else {
  107. for(auto& elem : *this) {
  108. elem->~T();
  109. }
  110. sz = 0;
  111. if(capacity()<oth.size()) {
  112. reserve(oth.size());
  113. }
  114. size_t idx = 0;
  115. for(auto& elem : oth) {
  116. new(ary+idx) T(gp::move(elem));
  117. elem.~T();
  118. }
  119. sz = idx;
  120. oth.sz = 0;
  121. }
  122. return *this;
  123. }
  124. constexpr T& operator[] (size_t off)
  125. {
  126. if constexpr (gp_config::has_buffer_bounds)
  127. {
  128. gp_config::assertion(
  129. off < sz,
  130. "Array bounds infringed"
  131. );
  132. }
  133. return ary[off];
  134. }
  135. ~vector()
  136. {
  137. if(ary)
  138. {
  139. for(auto& elem : *this) {
  140. elem.~T();
  141. }
  142. gp_config::assertion(alloc.get().deallocate(ary), "could not deallocate");
  143. }
  144. }
  145. /**
  146. * @brief Ensures the vector can hold at least 1 more element
  147. *
  148. * @return true if it is at least now possible to fit one more element
  149. * @return false if fiting one more element is not possible even now
  150. */
  151. bool grow() {
  152. if(sz == cap) return reserve(1 + sz + (sz >> 1));
  153. return true;
  154. }
  155. /**
  156. * @brief Reserves space so that the capacity is at least equal to the provided value.
  157. *
  158. * This will never shrink the datastructure
  159. *
  160. * @param new_cap the new capacity
  161. * @return true on success
  162. * @return false on failure
  163. */
  164. bool reserve(size_t new_cap) {
  165. if(new_cap <= cap) return true;
  166. size_t new_data_size = new_cap*sizeof(T);
  167. if(alloc.get().try_reallocate(ary, new_data_size)) return true;
  168. if(T* new_ary = (T*)alloc.get().allocate(new_data_size); new_ary) {
  169. auto new_it = new_ary;
  170. for(auto& elem : *this) {
  171. new(new_it++) T(gp::move(elem));
  172. }
  173. if(ary != nullptr) gp_config::assertion(alloc.get().deallocate(ary), "failed to deallocate old range");
  174. ary = new_ary;
  175. cap = new_cap;
  176. return true;
  177. }
  178. return false;
  179. }
  180. constexpr const T& operator[] (size_t off) const
  181. {
  182. if constexpr (gp_config::has_buffer_bounds)
  183. {
  184. gp_config::assertion(
  185. off < sz,
  186. "Array bounds infringed"
  187. );
  188. }
  189. return ary[off];
  190. }
  191. constexpr size_t size() const
  192. {
  193. return sz;
  194. }
  195. constexpr size_t capacity() const
  196. {
  197. return cap;
  198. }
  199. /**
  200. * @brief Adds the provided value to the vector
  201. *
  202. * @param value
  203. * @return true on success
  204. * @return false on failure
  205. */
  206. constexpr bool push_back(T& value) {
  207. if(grow()) {
  208. new(ary+sz) T(value);
  209. sz++;
  210. return true;
  211. }
  212. return false;
  213. }
  214. /**
  215. * @brief Moves the provided value to the vector
  216. *
  217. * @param value
  218. * @return true on success
  219. * @return false on failure
  220. */
  221. constexpr bool push_back(T&& value) {
  222. if(grow()) {
  223. new(ary+sz) T(gp::move(value));
  224. sz++;
  225. return true;
  226. }
  227. return false;
  228. }
  229. /**
  230. * @brief Constructs a new element at the end of the vector
  231. *
  232. * @param value the parameters to be sent to the constructor of T
  233. * @return true on success
  234. * @return false on failure
  235. */
  236. template<typename ...U>
  237. constexpr bool emplace_back(U&&... value) {
  238. if(grow()) {
  239. new(ary+sz) T(gp::forward<U>(value)...);
  240. sz++;
  241. return true;
  242. }
  243. return false;
  244. }
  245. /**
  246. * @brief moves the last element of the vector out if it exists, returning an optional.
  247. *
  248. * @return constexpr gp::optional<T> contains a value if it existed, else it is empty
  249. */
  250. constexpr gp::optional<T> pop_back() {
  251. if(sz == 0) return gp::nullopt;
  252. sz--;
  253. gp::optional<T> ret_val = gp::move(ary[sz]);
  254. ary[sz]->~T();
  255. return gp::move(ret_val);
  256. }
  257. void remove(pointer_iterator<T, 1> it) {
  258. for(auto step = it + 1; step<end(); step++) {
  259. (*it++) = gp::move(*step);
  260. }
  261. *rbegin().~T();
  262. sz -= 1;
  263. }
  264. constexpr pointer_iterator<T, 1> begin()
  265. {
  266. return associated_iterator(&ary[0]);
  267. }
  268. constexpr pointer_iterator<T, 1> end()
  269. {
  270. return associated_iterator(&ary[sz]);
  271. }
  272. constexpr const_pointer_iterator<T, 1> cbegin() const
  273. {
  274. return associated_const_iterator(&ary[0]);
  275. }
  276. constexpr const_pointer_iterator<T, 1> cend() const
  277. {
  278. return associated_const_iterator(&ary[sz]);
  279. }
  280. constexpr pointer_iterator<T, -1> rbegin()
  281. {
  282. return associated_riterator(&ary[sz-1]);
  283. }
  284. constexpr pointer_iterator<T, -1> rend()
  285. {
  286. return associated_riterator(ary-1);
  287. }
  288. constexpr const_pointer_iterator<T, -1> crbegin() const
  289. {
  290. return associated_const_riterator(&ary[sz-1]);
  291. }
  292. constexpr const_pointer_iterator<T, -1> crend() const
  293. {
  294. return associated_const_riterator(ary-1);
  295. }
  296. constexpr bool operator==(const vector& oth) const
  297. {
  298. for(size_t idx = 0; idx<sz; idx++)
  299. {
  300. if(ary[idx] != oth.ary[idx])
  301. {
  302. return false;
  303. }
  304. }
  305. return true;
  306. }
  307. constexpr bool operator!=(const vector& oth) const
  308. {
  309. return !(*this == oth);
  310. }
  311. /**
  312. * @brief Provides a span access to the vector
  313. *
  314. * @return A buffer of the vector.
  315. * It is invalidated by any operation that may change the size of the vector.
  316. */
  317. gp::buffer<T> as_buffer()
  318. {
  319. return gp::buffer<T>{(T*)ary, (T*)ary+sz};
  320. }
  321. };
  322. }