libGimbal 0.1.0
C17-Based Extended Standard Library and Cross-Language Runtime Framework
Loading...
Searching...
No Matches
gimbal_vector.hpp
1#ifndef GIMBAL_ARRAY_LIST_HPP
2#define GIMBAL_ARRAY_LIST_HPP
3
6#include "../objects/gimbal_context.hpp"
7#include <algorithm>
8
9
10namespace gbl {
11
12class Context;
13
14namespace tags {
15 struct VectorBase {};
16}
17
18template<typename V>
19concept vector_base =
20 std::is_base_of_v<gimbal::tags::VectorBase, V> &&
21 requires(V v) {
22 typename V::value_type;
23 };
24
25template<typename V, typename T>
26concept type_compatible_vector_base =
27 vector_base<V> &&
28 type_compatible_contiguous_container<V, T>;
29
30template<typename V1, typename V2>
31concept vector_compatible_gbl =
32 requires(V1 v1, V2 v2) {
33 typename V1::value_type;
34 typename V2::value_type;
35 } &&
36 std::same_as<typename V1::ValueType, typename V2::ValueType>;
37
38
39template<typename T=void*>
40class Vector;
41
42template<typename T=void*>
43class VectorView;
44
45template<typename CRTP, typename T>
46class VectorViewBase:
47 public tags::VectorBase,
50{
51public:
52 using VectorViewBaseType = VectorViewBase<CRTP, T>;
53 using DerivedType = CRTP;
56
57 // C++ STL-compliant traits
58 using value_type = T;
59 using allocator_type = Context*;
60 using size_type = Size;
61 using difference_type = std::ptrdiff_t;
62 using reference = value_type&;
63 using const_reference = const value_type&;
64 using pointer = T*;
65 using const_pointer = const T*;
66
67 using iterator = typename IterableType::iterator;
71
72protected:
73 decltype(auto) vec_(void) const {
74 return static_cast<const CRTP*>(this)->getVector_();
75 }
76
77 decltype(auto) vec_(void) {
78 return static_cast<CRTP*>(this)->getVector_();
79 }
80
81 void* at_(Size index) const {
82 void* pData = nullptr;
83 Exception::checkThrow([&]() {
84 pData = GblArrayList_at(vec_(), index);
85 });
86 return pData;
87 }
88
89public:
90 operator const GblArrayList*() const { return vec_(); }
91
92 // === FIXME UP ===
93 const_reference getElement_(size_type index) const {
94 return *static_cast<const T*>(at_(index));
95 }
96
97 reference getElement_(size_type index) {
98 return *static_cast<T*>(at_(index));
99 }
100
101 void setElement_(size_type index, value_type value) {
102 *static_cast<pointer>(at_(index)) = value;
103 }
104
105 size_t getElementCount_(void) const {
106 return getSize();
107 }
108
109 // === / FIXME UP ===
110
111 // Accessors
112 bool isEmpty(void) const {
113 return GblArrayList_empty(vec_());
114 }
115
116 bool isStack(void) const {
117 return GblArrayList_stack(vec_());
118 }
119
120 bool isHeap(void) const { return !isStack(); }
121#ifdef GBL_PMR_VECTOR
122 std::pmr::vector<value_type> toStdPmrVector(void) const {
124 }
125#endif
126
127 std::vector<value_type> toStdVector(void) const {
128 std::vector<value_type> stdVec(&front(), &back());
129 }
130
131 Size getStackBytes(void) const {
132 return GblArrayList_stackBytes(vec_());
133 }
134
135 Context* getContext(void) const {
136 return Context::fromGblObj(GblArrayList_context(vec_()));
137 }
138
139 allocator_type get_allocator(void) const {
140 return getContext();
141 }
142
143 Size getSize(void) const {
144 return GblArrayList_size(vec_());
145 }
146
147 Size getSizeBytes(void) const {
148 return getSize() * getElementSize();
149 }
150
151 Size size_bytes(void) const {
152 return getSizeBytes();
153 }
154
155 Size getCapacity(void) const {
156 return GblArrayList_capacity(vec_());
157 }
158
159 Size capacity(void) const {
160 return getCapacity();
161 }
162
163 Size getElementSize(void) const {
164 return GblArrayList_elementSize(vec_());
165 }
166
167 size_type element_size(void) const { return getElementSize(); }
168
169 size_type max_size(void) const { //kinda bullshit, no idea if you can allocate that much
170 return std::numeric_limits<size_type>::max();
171 }
172
173 const void* getData(void) const {
174 return GblArrayList_data(vec_());
175 }
176
177 constexpr pointer data(void) {
178 return static_cast<pointer>(const_cast<void*>(getData()));
179 }
180
181 constexpr const_pointer data(void) const {
182 return static_cast<const_pointer>(const_cast<VectorViewBaseType*>(this)->data());
183 }
184
185 T& front(void) const {
186 T* pValue = nullptr;
187 Exception::checkThrow([&]() {
188 pValue = reinterpret_cast<T*>(GblArrayList_front(vec_()));
189 });
190 return *pValue;
191 }
192
193 T& back(void) const {
194 T* pValue = nullptr;
195 Exception::checkThrow([&]() {
196 pValue = reinterpret_cast<T*>(GblArrayList_back(vec_()));
197 });
198 return *pValue;
199 }
200
201 friend bool operator==(const CRTP& vec, const type_compatible_container_readable<T> auto& con) {
202 if(std::size(vec) != std::size(con)) return false;
203 return std::equal(vec.cbegin(), vec.cend(), std::cbegin(con));
204 }
205
206 friend constexpr auto operator<=>(const CRTP& vec, const type_compatible_container_readable<T> auto& con) noexcept {
207#ifdef GBL_LEX_CMP_3WAY
209#else
211#endif
212 }
213
214 friend bool operator==(const CRTP& vec, const VectorView<T>& rhs) {
215 if(std::size(vec) != std::size(rhs)) return false;
216 return std::equal(vec.cbegin(), vec.cend(), rhs.cbegin());
217 }
218
219 friend constexpr auto operator<=>(const CRTP& vec, const VectorView<T>& rhs) noexcept {
220#ifdef GBL_LEX_CMP_3WAY
222#else
224#endif
225 }
226
227};
228
229template<typename T>
230class VectorView final: public VectorViewBase<VectorView<T>, T> {
231private:
232 const GblArrayList* pGblArrayList_ = nullptr;
233public:
234 VectorView(void) = default;
235
236 VectorView(const GblArrayList& gblVector):
237 pGblArrayList_(&gblVector) {}
238
239 VectorView(const GblArrayList* pGblArrayList):
240 pGblArrayList_(pGblArrayList) {}
241
242 VectorView(const Vector<T>& vector):
243 VectorView(static_cast<const GblArrayList*>(&vector)) {}
244
245 const GblArrayList* getVector_(void) const { return pGblArrayList_; }
246
247 bool isValid(void) const { return pGblArrayList_; }
248};
249
250template<typename T>
251VectorView(Vector<T> base) -> VectorView<T>;
252
253
254/* SHIT THAT ISN'T DONE
255 - 1) emplace
256 - 2) swap
257 - 3) insert
258 - 4) shrink_to_fit
259 - 5) erase_if
260 - 6) operator <=> (DONE, BITCH)
261 - 7) C++ destructor callbacks!!1111
262 Should eventually be some Vtable looking shit ideally:
263 typedef struct GblArrayListTypeInfo {
264 GblMetaType* pMetaType;
265 GblSize elementSize;
266 void (*pDestructor)(void* pData, GblSize count);
267 void (*pAssign)(void* pLhs, const void* pRhs);
268 void (*pMove)(void* pLhs, void* pRhs);
269 void (*pCompare)(const void* pLhs, const void* pRhs, GBL_OPERATOR_COMPARISON comp, GblBool* pResult);
270 } GblArrayListTypeInfo;
271 */
272
273template<typename T>
274class Vector:
275 public GblArrayList,
276 public VectorViewBase<Vector<T>, T>
277{
278protected:
279
280 void destruct_(Size startPos, Size count=1) {
281 if constexpr(std::is_destructible_v<T>) {
282 for(Size i = startPos; i < count; ++i) {
283 this->data()[i].~T();
284 }
285 }
286 }
287
288public:
289 using VectorType = Vector<T>;
290 using VectorViewBaseType = VectorViewBase<Vector<T>, T>;
291 using ViewType = VectorViewBaseType;
292 using MoveValues = std::tuple<void*, Size, Size>;
293 using iterator = typename VectorViewBaseType::iterator;
294 using const_iterator = typename VectorViewBaseType::const_iterator;
295 using difference_type = typename VectorViewBaseType::difference_type;
296
297 const GblArrayList* getVector_(void) const {
298 return static_cast<const GblArrayList*>(this);
299 }
300
301 GblArrayList* getVector_(void) {
302 return static_cast<GblArrayList*>(this);
303 }
304
305 // =========== VALUE CONSTRUCTORS ==========
306
307 // explicit null constructor
308 explicit Vector(std::nullptr_t, Size allocSize=sizeof(VectorType)):
309 Vector(nullptr, 0, nullptr, allocSize) {}
310
311 // default constructor
312 explicit Vector(Context* pCtx=nullptr, Size allocSize=sizeof(VectorType)):
313 Vector(nullptr, 0, pCtx, allocSize) {}
314
315 // raw pointer constructor
316 explicit Vector(const T* pInitialData, Size elementCount, Context* pCtx=nullptr, Size allocSize=sizeof(VectorType), Size elementSize=sizeof(T)) {
317 Exception::checkThrow(GblArrayList_construct(this, elementSize, elementCount, pInitialData, allocSize, pCtx));
318 }
319
320 // fill constructor
321 explicit Vector(Size count, const T& value=T(), Context* pCtx=nullptr, Size allocSize=sizeof(VectorType)) {
322 T* pTempArray = static_cast<T*>(GBL_ALLOCA(count * sizeof(T)));
323 std::fill(pTempArray, pTempArray+count, value);
324 Exception::checkThrow(GblArrayList_construct(this, sizeof(T), count, pTempArray, allocSize, pCtx));
325 }
326
327 // initializer list constructor
328 Vector(std::initializer_list<T> c, Context* pCtx=nullptr, Size allocSize=sizeof(VectorType)):
329 Vector(pCtx, allocSize)
330 {
331 insert(this->begin(), c.begin(), c.end());
332 }
333
334
335 // generic container constructor
336 explicit Vector(type_compatible_container_readable<T> auto&& c, Context* pCtx=nullptr, Size allocSize=sizeof(VectorType)):
337 Vector(pCtx, allocSize)
338 {
339 *this = std::forward<decltype(c)>(c);
340 }
341
342 // generic iterator constructor
343 explicit Vector(const type_compatible_iterator_readable<T> auto& first, const type_compatible_iterator_readable<T> auto& last, Context* pCtx=nullptr, Size allocSize=sizeof(VectorType)):
344 Vector(pCtx, allocSize)
345 {
346 insert(this->end(), first, last);
347 }
348
349 // =========== COPY CONSTRUCTORS ==========
350
351 // copy constructors - regular
352 Vector(const VectorType& other, Context* pCtx=nullptr, Size allocSize=sizeof(VectorType)):
353 Vector(VectorView(other), pCtx, allocSize) {}
354
355 // copy constructor - view
356 Vector(VectorView<T> other, Context* pCtx=nullptr, Size allocSize=sizeof(VectorType)):
357 Vector(other.data(), other.size(), pCtx, allocSize) {}
358
359
360 // =========== MOVE CONSTRUCTORS ==========
361
362 // move constructor - regular
363 Vector(VectorType&& rhs, Context* pCtx=nullptr, Size allocSize=sizeof(VectorType)):
364 Vector(static_cast<GblArrayList&&>(rhs), pCtx, allocSize) {}
365
366 // move constructor - GblArrayList
367 Vector(GblArrayList&& rhs, Context* pCtx=nullptr, Size allocSize=sizeof(VectorType)):
368 Vector(pCtx, allocSize)
369 {
370 *this = std::move(rhs);
371 }
372
373 static MoveValues take(GblArrayList* pVec) {
374 auto moveValues = MoveValues(nullptr, 0, 0);
375 auto& [pData, size, capacity] = moveValues;
376 Exception::checkThrow(GblArrayList_release(pVec, &pData, &size, &capacity));
377 return moveValues;
378 }
379
380 auto take(void) {
381 return take(this);
382 }
383
384 void give(MoveValues moveValues) {
385 auto& [pData, size, capacity] = moveValues;
386 Exception::checkThrow(GblArrayList_acquire(this, pData, size, capacity));
387 }
388
389 ~Vector(void) {
390 destruct_(0, size());
391 Exception::checkThrow(GblArrayList_destruct(this));
392 }
393
394 using VectorViewBaseType::size;
395 using VectorViewBaseType::capacity;
396
397 void reserve(Size count) {
398 Exception::checkThrow(GblArrayList_reserve(this, count));
399 }
400
401 void resize(Size newSize) {
402 if(newSize < size()) {
403 destruct_(newSize, size() - newSize);
404 }
405 Exception::checkThrow(GblArrayList_resize(this, newSize));
406 }
407
408 void shrink_to_fit(void) {
409 Exception::checkThrow(GblArrayList_shrinkToFit(this));
410 }
411
412 void pushBack(T value) {
413 Exception::checkThrow(GblArrayList_pushBack(this, &value));
414 }
415
416 void push_back(T value) {
417 pushBack(std::move(value));
418 }
419
420 template<typename... Args>
421 T& emplace_back(Args&&... args) {
422 resize(size()+1);
423 void* pData = this->at_(size()-1);
424 T* pObj = new (pData) T(std::forward<Args>(args)...);
425 return *pObj;
426 }
427
428 void pushFront(T value) {
429 Exception::checkThrow(GblArrayList_pushFront(this, &value));
430 }
431
432 void push_front(T value) {
433 pushFront(std::move(value));
434 }
435
436 iterator insert(const_iterator position, const T* pValue, Size count) {
437 const auto index = std::distance(this->cbegin(), position);
438 Exception::checkThrow([&]() {
439 GblArrayList_insert(this, index, count, pValue);
440 });
441 return iterator(*this, index);
442 }
443
444 iterator insert(const_iterator position, const T& val) {
445 return insert(std::move(position), &val, 1);
446 }
447
448 iterator insert(const_iterator position, gimbal::Size size, const T& val) {
449 T* pTempArray = static_cast<T*>(GBL_ALLOCA(size * sizeof(T)));
450 std::fill(pTempArray, pTempArray+size, val);
451 return insert(std::move(position), pTempArray, size);
452 }
453
454 iterator insert(const_iterator position, const type_compatible_iterator_readable<T> auto& first, const type_compatible_iterator_readable<T> auto& last) {
455 const auto size = std::distance(first, last);
456 T* pTempArray = static_cast<T*>(GBL_ALLOCA(size * sizeof(T)));
457 std::copy(first, last, pTempArray);
458 return insert(std::move(position), pTempArray, size);
459 }
460
461 template<type_compatible_iterator_readable<T> It>
462 requires contiguous_iterator<It>
463 iterator insert(const_iterator position, const It& first, const It& last) {
464 return insert(std::move(position), &first[0], std::distance(first, last));
465 }
466
467 iterator insert(const_iterator position, const type_compatible_container_readable<T> auto &c) {
468 return insert(std::move(position), std::cbegin(c), std::cend(c));
469 }
470
471 iterator insert(const_iterator position, const type_compatible_contiguous_container_readable<T> auto &c) {
472 return insert(std::move(position), c.data(), std::size(c));
473 }
474
475 template<typename... Args>
476 iterator emplace(const_iterator position, Args&&... args) {
477 const auto index = std::distance(this->cbegin(), position);
478 void* pData = nullptr;
479 Exception::checkThrow([&]() {
480 pData = GblArrayList_insert(this, index, 1, nullptr);
481 });
482 T* pObj = new (pData) T(std::forward<Args>(args)...);
483 return iterator(*this, index);
484 }
485
486 void popBack(void) {// throw if bullshit
487 destruct_(this->getSize()-1, 1);
488 erase(this->end()-1);
489 }
490
491 void pop_back(void) {
492 popBack();
493 }
494
495 iterator erase(const_iterator pos) {
496 return erase(pos, pos+1);
497 }
498
499 iterator erase(const_iterator first, const_iterator last) {
500 const auto index = std::distance<const_iterator>(this->begin(), first);
501 const auto count = std::distance(first, last);
502 destruct_(index, count);
503 Exception::checkThrow(GblArrayList_erase(this, index, count));
504 return iterator(*this, index+count);
505 }
506
507 void clear(void) {
508 destruct_(0, this->getSize());
509 Exception::checkThrow(GblArrayList_clear(this));
510 }
511
512 void assign(const T* pData, Size elementCount) {
513 Exception::checkThrow(GblArrayList_assign(this, pData, elementCount));
514 }
515
516 void assign(gimbal::Size size, const T& value) {
517 T* pTempArray = static_cast<T*>(GBL_ALLOCA(size * sizeof(T)));
518 std::fill(pTempArray, pTempArray+size, value);
519 assign(pTempArray, size);
520 }
521
522 void assign(const type_compatible_contiguous_container_readable<T> auto &c) {
523 assign(c.data(), std::size(c));
524 }
525
526 void assign(const type_compatible_container_readable<T> auto& c) {
527 T* pTempArray = static_cast<T*>(GBL_ALLOCA(std::size(c) * sizeof(T)));
528 std::copy(begin(c), end(c), pTempArray);
529 Exception::checkThrow(GblArrayList_assign(this, pTempArray, std::size(c)));
530 }
531
532 void assign(const type_compatible_iterator_readable<T> auto& first, const type_compatible_iterator_readable<T> auto& last) {
533 const auto size = std::distance(first, last);
534 T* pTempArray = static_cast<T*>(GBL_ALLOCA(size * sizeof(T)));
535 std::copy(first, last, pTempArray);
536 assign(pTempArray, size);
537 }
538
539 template<type_compatible_iterator_readable<T> It>
540 requires contiguous_iterator<It>
541 void assign(const It& first, const It& last) {
542
543 const T* pData = &first[0];
544 const auto dist = std::distance(first, last);
545
546 assign(pData, dist);
547 }
548
549 const VectorType& operator=(VectorView<T> rhs) {
550 Exception::checkThrow(GblArrayList_assign(this, rhs.data(), rhs.size()));
551 return *this;
552 }
553
554 const VectorType& operator=(const VectorType& rhs) {
555 return *this = VectorView<T>(rhs);
556 }
557
558 const VectorType& operator=(VectorType&& rhs) {
559 return *this = static_cast<GblArrayList&&>(rhs);
560 }
561
562 const VectorType& operator=(GblArrayList&& rhs) {
563 VectorView<T> rhsView(rhs); //C++ wrapper "viewing" C object
564
565 if(this->getContext() == rhsView.getContext() && rhsView.isHeap()) {
566 give(take(&rhs));
567 } else {
568 *this = rhsView; //do regular-ass copy assignment for generic view
569 }
570 return *this;
571 }
572
573 const VectorType& operator=(const type_compatible_container<T> auto&& c) {
574 // check for supported move semantics!
575#ifdef GBL_PMR_VECTOR
576 if constexpr(std::same_as<decltype(c), gimbal::pmr::vector<T>&&>) {
577 if(this->get_allocator() == c.get_allocator()) {
578 assign(c);
579 }
580 } else {
581#endif
582 assign(c);
583#ifdef GBL_PMR_VECTOR
584 }
585#endif
586 return *this;
587 }
588
589 const VectorType& operator+=(const type_compatible_container_readable<T> auto& view) {
590 insert(this->end(), view);
591 return *this;
592 }
593
594 const VectorType& operator+=(const type_compatible_iterator_readable<T> auto& it) {
595 insert(this->end(), it);
596 return *this;
597 }
598
599 const VectorType& operator+=(const T& value) {
600 insert(this->end(), 1, value);
601 return *this;
602 }
603
604 const VectorType& operator+=(VectorView<T> view) {
605 insert(this->end(), view.data(), view.size());
606 return *this;
607 }
608};
609
610
611// overflow when copying shit into the bitch without enough room on stack when no context is present
612template<Size ExtraStackSize, typename T=void*>
613class FlexibleVector final: public Vector<T> {
614public:
615 using FlexibleVectorType = FlexibleVector<ExtraStackSize, T>;
616 constexpr static const inline Size ExtraStackBufferSize = ExtraStackSize;
617private:
618 char extraStackBuffer_[ExtraStackSize] = { 0 };
619public:
620
621};
622/*
623template<typename T>
624Vector(std::initializer_list<T> list, Context* pCtx=nullptr, Size allocSize=sizeof(Vector<T>)) -> Vector<T>;
625*/
626
627template<generic_container_readable Container,
628 typename T = container_value_t<Container>>
629Vector(const Container& c, Context* pCtx=nullptr, Size allocSize=sizeof(Vector<T>)) -> Vector<T>;
630
631
632template<std::input_iterator Iterator,
633 typename T = iterator_value_t<Iterator>>
634Vector(Iterator begin, Iterator end, Context* pCtx=nullptr, Size allocSize=sizeof(Vector<T>)) -> Vector<T>;
635
636template<typename T>
637Vector(VectorView<T> view, Context* pCtx=nullptr, Size allocSize=sizeof(Vector<T>)) -> Vector<T>;
638
639template<typename T, size_t N>
640Vector(std::array<T, N> array, Context* pCtx=nullptr, Size allocSize=sizeof(Vector<T>)) -> Vector<T>;
641
642Vector(GblArrayList gblVec, Context* pCtx=nullptr, Size allocSize=sizeof(Vector<void*>)) -> Vector<void*>;
643Vector(const GblArrayList* pVec, Context* pCtx=nullptr, Size allocSize=sizeof(Vector<void*>)) -> Vector<void*>;
644
645
646template<typename T>
647gimbal::Size erase(gimbal::Vector<T>& vec, const T& value) {
648 auto it = std::remove(vec.begin(), vec.end(), value);
649 auto r = std::distance(it, vec.end());
650 vec.erase(it, vec.end());
651 return r;
652}
653
654template<typename T, typename Pred>
655gimbal::Size erase_if(gimbal::Vector<T>& vec, Pred pred) {
656 auto it = std::remove_if(vec.begin(), vec.end(), pred);
657 auto r = std::distance(it, vec.end());
658 vec.erase(it, vec.end());
659 return r;
660}
661
662template<typename T>
663void swap(gimbal::Vector<T>& lhs, gimbal::Vector<T>& rhs) {
664 void* plData = GBL_ALLOCA(lhs.size_bytes());
665 const auto lSize = lhs.size();
666 memcpy(plData, lhs.data(), lhs.size_bytes());
667 lhs = rhs;
668 rhs.assign(static_cast<const T*>(plData), lSize);
669}
670
671}
672
673#endif // GIMBAL_ARRAY_LIST_HPP
#define GblArrayList_construct(...)
#define GBL_ALLOCA
Contiguous, array-based abstract list container with C++-style STL API.