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.

322 lines
6.6 KiB

4 years ago
  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;
  15. size_t sz = 0;
  16. size_t cap = 0;
  17. gp::reference_wrapper<allocator> alloc;
  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. vector(allocator& v)
  24. : ary()
  25. , alloc(v)
  26. {}
  27. vector(vector& oth)
  28. : alloc(oth.alloc)
  29. {
  30. sz = 0;
  31. cap = 0;
  32. ary = nullptr;
  33. gp_config::assertion(reserve(oth.size()), "could not reserve space on building");
  34. sz = oth.size();
  35. cap = oth.size();
  36. auto it_l = begin();
  37. auto it_o = oth.cbegin();
  38. for(size_t i = 0; i < sz; ++i)
  39. {
  40. new(&*(it_l++)) T(*(it_o++));
  41. }
  42. }
  43. vector(vector&& oth)
  44. : ary(oth.ary)
  45. , sz(oth.sz)
  46. , cap(oth.cap)
  47. , alloc(oth.alloc)
  48. {
  49. oth.ary = nullptr;
  50. }
  51. /* TODO: Build the templated equivalents
  52. array(T (& oth)[sz]) {
  53. gp::move_uninitialized<T>(
  54. gp::nameless_range<int*>(oth, oth+sz),
  55. gp::nameless_range<associated_iterator>(begin(), end())
  56. );
  57. }
  58. array(T (&& oth)[sz]) {
  59. gp::move_uninitialized(
  60. gp::nameless_range<int*>((T*)oth, (T*)oth+sz),
  61. gp::nameless_range<associated_iterator>(begin(), end())
  62. );
  63. }*/
  64. vector& operator=(vector& oth)
  65. {
  66. gp_config::assertion(reserve(oth.size()), "could not reserve space on assign");
  67. for(size_t i = 0; i < gp::min(sz, oth.sz); ++i)
  68. {
  69. new(ary+i) T(oth[i]);
  70. }
  71. if(sz < oth.sz) {
  72. for(size_t i = sz; i < oth.sz; ++i) {
  73. new(ary+i) T(oth[i]);
  74. }
  75. } else if(sz > oth.sz) {
  76. for(size_t i = oth.sz; i < sz; ++i) {
  77. ary[i]->~T();
  78. }
  79. }
  80. sz = oth.sz;
  81. return *this;
  82. }
  83. vector& operator=(vector&& oth)
  84. {
  85. gp::swap(ary, oth.ary);
  86. gp::swap(alloc, oth.alloc);
  87. gp::swap(sz, oth.sz);
  88. gp::swap(cap, oth.cap);
  89. return *this;
  90. }
  91. constexpr T& operator[] (size_t off)
  92. {
  93. if constexpr (gp_config::has_buffer_bounds)
  94. {
  95. gp_config::assertion(
  96. off < sz,
  97. "Array bounds infringed"
  98. );
  99. }
  100. return ary[off];
  101. }
  102. ~vector()
  103. {
  104. if(ary)
  105. {
  106. for(auto& elem : *this) {
  107. elem.~T();
  108. }
  109. gp_config::assertion(alloc.get().deallocate(ary), "could not deallocate");
  110. }
  111. }
  112. /**
  113. * @brief Ensures the vector can hold at least 1 more element
  114. *
  115. * @return true if it is at least now possible to fit one more element
  116. * @return false if fiting one more element is not possible even now
  117. */
  118. bool grow() {
  119. if(sz == cap) return reserve(1 + sz + (sz >> 1));
  120. return true;
  121. }
  122. /**
  123. * @brief Reserves space so that the capacity is at least equal to the provided value.
  124. *
  125. * This will never shrink the datastructure
  126. *
  127. * @param new_cap the new capacity
  128. * @return true on success
  129. * @return false on failure
  130. */
  131. bool reserve(size_t new_cap) {
  132. if(new_cap <= cap) return true;
  133. size_t new_data_size = new_cap*sizeof(T);
  134. if(alloc.get().try_reallocate(ary, new_data_size)) return true;
  135. if(T* new_ary = (T*)alloc.get().allocate(new_data_size); new_ary) {
  136. auto new_it = new_ary;
  137. for(auto& elem : *this) {
  138. new(new_it++) T(gp::move(elem));
  139. }
  140. if(ary != nullptr) gp_config::assertion(alloc.get().deallocate(ary), "failed to deallocate old range");
  141. ary = new_ary;
  142. cap = new_cap;
  143. return true;
  144. }
  145. return false;
  146. }
  147. constexpr const T& operator[] (size_t off) const
  148. {
  149. if constexpr (gp_config::has_buffer_bounds)
  150. {
  151. gp_config::assertion(
  152. off < sz,
  153. "Array bounds infringed"
  154. );
  155. }
  156. return ary[off];
  157. }
  158. constexpr size_t size() const
  159. {
  160. return sz;
  161. }
  162. constexpr size_t capacity() const
  163. {
  164. return cap;
  165. }
  166. /**
  167. * @brief Adds the provided value to the vector
  168. *
  169. * @param value
  170. * @return true on success
  171. * @return false on failure
  172. */
  173. constexpr bool push_back(T& value) {
  174. if(grow()) {
  175. new(ary+sz) T(value);
  176. sz++;
  177. return true;
  178. }
  179. return false;
  180. }
  181. /**
  182. * @brief Moves the provided value to the vector
  183. *
  184. * @param value
  185. * @return true on success
  186. * @return false on failure
  187. */
  188. constexpr bool push_back(T&& value) {
  189. if(grow()) {
  190. new(ary+sz) T(gp::move(value));
  191. sz++;
  192. return true;
  193. }
  194. return false;
  195. }
  196. /**
  197. * @brief Constructs a new element at the end of the vector
  198. *
  199. * @param value the parameters to be sent to the constructor of T
  200. * @return true on success
  201. * @return false on failure
  202. */
  203. template<typename ...U>
  204. constexpr bool emplace_back(U&&... value) {
  205. if(grow()) {
  206. new(ary+sz) T(gp::forward<U>(value)...);
  207. sz++;
  208. return true;
  209. }
  210. return false;
  211. }
  212. /**
  213. * @brief moves the last element of the vector out if it exists, returning an optional.
  214. *
  215. * @return constexpr gp::optional<T> contains a value if it existed, else it is empty
  216. */
  217. constexpr gp::optional<T> pop_back() {
  218. if(sz == 0) return gp::nullopt;
  219. sz--;
  220. gp::optional<T> ret_val = gp::move(ary[sz]);
  221. ary[sz]->~T();
  222. return gp::move(ret_val);
  223. }
  224. constexpr pointer_iterator<T, 1> begin()
  225. {
  226. return associated_iterator(&ary[0]);
  227. }
  228. constexpr pointer_iterator<T, 1> end()
  229. {
  230. return associated_iterator(&ary[sz]);
  231. }
  232. constexpr const_pointer_iterator<T, 1> cbegin() const
  233. {
  234. return associated_const_iterator(&ary[0]);
  235. }
  236. constexpr const_pointer_iterator<T, 1> cend() const
  237. {
  238. return associated_const_iterator(&ary[sz]);
  239. }
  240. constexpr pointer_iterator<T, -1> rbegin()
  241. {
  242. return associated_riterator(&ary[sz-1]);
  243. }
  244. constexpr pointer_iterator<T, -1> rend()
  245. {
  246. return associated_riterator(ary-1);
  247. }
  248. constexpr const_pointer_iterator<T, -1> crbegin() const
  249. {
  250. return associated_const_riterator(&ary[sz-1]);
  251. }
  252. constexpr const_pointer_iterator<T, -1> crend() const
  253. {
  254. return associated_const_riterator(ary-1);
  255. }
  256. constexpr bool operator==(const vector& oth) const
  257. {
  258. for(size_t idx = 0; idx<sz; idx++)
  259. {
  260. if(ary[idx] != oth.ary[idx])
  261. {
  262. return false;
  263. }
  264. }
  265. return true;
  266. }
  267. constexpr bool operator!=(const vector& oth) const
  268. {
  269. return !(*this == oth);
  270. }
  271. /**
  272. * @brief Provides a span access to the vector
  273. *
  274. * @return A buffer of the vector.
  275. * It is invalidated by any operation that may change the size of the vector.
  276. */
  277. gp::buffer<T> as_buffer()
  278. {
  279. return gp::buffer<T>{(T*)ary, (T*)ary+sz};
  280. }
  281. };
  282. }