General Purpose library for Freestanding C++ and POSIX systems
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

371 строка
7.9 KiB

4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
3 лет назад
4 лет назад
3 лет назад
4 лет назад
4 лет назад
3 лет назад
4 лет назад
3 лет назад
4 лет назад
3 лет назад
4 лет назад
3 лет назад
4 лет назад
3 лет назад
4 лет назад
4 лет назад
3 лет назад
4 лет назад
3 лет назад
3 лет назад
3 лет назад
3 лет назад
3 лет назад
3 лет назад
3 лет назад
4 лет назад
3 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
  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.sz = 0;
  65. oth.cap = 0;
  66. oth.ary = nullptr;
  67. }
  68. /**
  69. * @brief Copy assignment
  70. *
  71. * @param oth
  72. * @return vector& the reference to this changed vector
  73. */
  74. vector& operator=(vector& oth)
  75. {
  76. gp_config::assertion(reserve(oth.size()), "could not reserve space on assign");
  77. for(size_t i = 0; i < gp::min(sz, oth.sz); ++i)
  78. {
  79. if constexpr (!std::is_trivially_destructible_v<T>) ary[i]->~T();
  80. new(ary+i) T(oth[i]);
  81. }
  82. if(sz < oth.sz) {
  83. for(size_t i = sz; i < oth.sz; ++i) {
  84. if constexpr (!std::is_trivially_destructible_v<T>) ary[i]->~T();
  85. new(ary+i) T(oth[i]);
  86. }
  87. } else if(sz > oth.sz) {
  88. if constexpr (!std::is_trivially_destructible_v<T>)
  89. for(size_t i = oth.sz; i < sz; ++i) {
  90. ary[i]->~T();
  91. }
  92. }
  93. sz = oth.sz;
  94. return *this;
  95. }
  96. /**
  97. * @brief Move assignment
  98. *
  99. * Will not change the allocator of the local vector, is EXPENSIVE if the both vectors have different allocators
  100. *
  101. * @param oth
  102. * @return vector&
  103. */
  104. vector& operator=(vector&& oth)
  105. {
  106. if(&alloc.get() == &oth.alloc.get())
  107. {
  108. gp::swap(ary, oth.ary);
  109. gp::swap(sz, oth.sz);
  110. gp::swap(cap, oth.cap);
  111. } else {
  112. for(auto& elem : *this) {
  113. elem->~T();
  114. }
  115. sz = 0;
  116. if(capacity()<oth.size()) {
  117. reserve(oth.size());
  118. }
  119. size_t idx = 0;
  120. for(auto& elem : oth) {
  121. new(ary+idx) T(gp::move(elem));
  122. ++idx;
  123. elem.~T();
  124. }
  125. gp_config::assertion(alloc.get().deallocate(oth.ary), "could not deallocate");
  126. sz = idx;
  127. oth.sz = 0;
  128. oth.capacity = 0;
  129. oth.ary = nullptr;
  130. }
  131. return *this;
  132. }
  133. constexpr T& operator[] (size_t off)
  134. {
  135. if constexpr (gp_config::has_buffer_bounds)
  136. {
  137. gp_config::assertion(
  138. off < sz,
  139. "Array bounds infringed"
  140. );
  141. }
  142. return ary[off];
  143. }
  144. ~vector()
  145. {
  146. if(ary)
  147. {
  148. if constexpr (!std::is_trivially_destructible_v<T>)
  149. for(auto& elem : *this) {
  150. elem.~T();
  151. }
  152. gp_config::assertion(alloc.get().deallocate(ary), "could not deallocate");
  153. }
  154. }
  155. /**
  156. * @brief Ensures the vector can hold at least 1 more element
  157. *
  158. * @return true if it is at least now possible to fit one more element
  159. * @return false if fiting one more element is not possible even now
  160. */
  161. bool grow() {
  162. if(sz == cap) return reserve(1 + sz + (sz >> 1));
  163. return true;
  164. }
  165. /**
  166. * @brief Reserves space so that the capacity is at least equal to the provided value.
  167. *
  168. * This will never shrink the datastructure
  169. *
  170. * @param new_cap the new capacity
  171. * @return true on success
  172. * @return false on failure
  173. */
  174. bool reserve(size_t new_cap) {
  175. if(new_cap <= cap) return true;
  176. size_t new_data_size = new_cap*sizeof(T);
  177. if(alloc.get().try_reallocate(ary, new_data_size)) return true;
  178. if(T* new_ary = (T*)alloc.get().allocate(new_data_size); new_ary) {
  179. auto new_it = new_ary;
  180. for(auto& elem : *this) {
  181. new(new_it++) T(gp::move(elem));
  182. }
  183. if(ary != nullptr) gp_config::assertion(alloc.get().deallocate(ary), "failed to deallocate old range");
  184. ary = new_ary;
  185. cap = new_cap;
  186. return true;
  187. }
  188. return false;
  189. }
  190. constexpr const T& operator[] (size_t off) const
  191. {
  192. if constexpr (gp_config::has_buffer_bounds)
  193. {
  194. gp_config::assertion(
  195. off < sz,
  196. "Array bounds infringed"
  197. );
  198. }
  199. return ary[off];
  200. }
  201. constexpr size_t size() const
  202. {
  203. return sz;
  204. }
  205. constexpr size_t capacity() const
  206. {
  207. return cap;
  208. }
  209. /**
  210. * @brief Adds the provided value to the vector
  211. *
  212. * @param value
  213. * @return true on success
  214. * @return false on failure
  215. */
  216. constexpr bool push_back(T& value) {
  217. if(grow()) {
  218. new(ary+sz) T(value);
  219. sz++;
  220. return true;
  221. }
  222. return false;
  223. }
  224. /**
  225. * @brief Moves the provided value to the vector
  226. *
  227. * @param value
  228. * @return true on success
  229. * @return false on failure
  230. */
  231. constexpr bool push_back(T&& value) {
  232. if(grow()) {
  233. new(ary+sz) T(gp::move(value));
  234. sz++;
  235. return true;
  236. }
  237. return false;
  238. }
  239. /**
  240. * @brief Constructs a new element at the end of the vector
  241. *
  242. * @param value the parameters to be sent to the constructor of T
  243. * @return true on success
  244. * @return false on failure
  245. */
  246. template<typename ...U>
  247. constexpr bool emplace_back(U&&... value) {
  248. if(grow()) {
  249. new(ary+sz) T(gp::forward<U>(value)...);
  250. sz++;
  251. return true;
  252. }
  253. return false;
  254. }
  255. /**
  256. * @brief moves the last element of the vector out if it exists, returning an optional.
  257. *
  258. * @return constexpr gp::optional<T> contains a value if it existed, else it is empty
  259. */
  260. constexpr gp::optional<T> pop_back() {
  261. if(sz == 0) return gp::nullopt;
  262. sz--;
  263. gp::optional<T> ret_val = gp::move(ary[sz]);
  264. ary[sz]->~T();
  265. return gp::move(ret_val);
  266. }
  267. void remove(pointer_iterator<T, 1> it) {
  268. for(auto step = it + 1; step<end(); step++) {
  269. (*it++) = gp::move(*step);
  270. }
  271. *rbegin().~T();
  272. sz -= 1;
  273. }
  274. constexpr pointer_iterator<T, 1> begin()
  275. {
  276. return associated_iterator(&ary[0]);
  277. }
  278. constexpr pointer_iterator<T, 1> end()
  279. {
  280. return associated_iterator(&ary[sz]);
  281. }
  282. constexpr const_pointer_iterator<T, 1> cbegin() const
  283. {
  284. return associated_const_iterator(&ary[0]);
  285. }
  286. constexpr const_pointer_iterator<T, 1> cend() const
  287. {
  288. return associated_const_iterator(&ary[sz]);
  289. }
  290. constexpr pointer_iterator<T, -1> rbegin()
  291. {
  292. return associated_riterator(&ary[sz-1]);
  293. }
  294. constexpr pointer_iterator<T, -1> rend()
  295. {
  296. return associated_riterator(ary-1);
  297. }
  298. constexpr const_pointer_iterator<T, -1> crbegin() const
  299. {
  300. return associated_const_riterator(&ary[sz-1]);
  301. }
  302. constexpr const_pointer_iterator<T, -1> crend() const
  303. {
  304. return associated_const_riterator(ary-1);
  305. }
  306. constexpr bool operator==(const vector& oth) const
  307. {
  308. for(size_t idx = 0; idx<sz; idx++)
  309. {
  310. if(ary[idx] != oth.ary[idx])
  311. {
  312. return false;
  313. }
  314. }
  315. return true;
  316. }
  317. constexpr bool operator!=(const vector& oth) const
  318. {
  319. return !(*this == oth);
  320. }
  321. /**
  322. * @brief Provides a span access to the vector
  323. *
  324. * @return A buffer of the vector.
  325. * It is invalidated by any operation that may change the size of the vector.
  326. */
  327. gp::buffer<T> as_buffer()
  328. {
  329. return gp::buffer<T>{(T*)ary, (T*)ary+sz};
  330. }
  331. };
  332. }