libGimbal 0.1.0
C17-Based Extended Standard Library and Cross-Language Runtime Framework
Loading...
Searching...
No Matches
gimbal_generics.hpp
1#ifndef GIMBAL_GENERICS_HPP
2#define GIMBAL_GENERICS_HPP
3
4#include <iterator>
5#include <stdexcept>
6
7namespace gbl {
8
9template<typename CRTP, typename Key, typename Value, bool Writable>
11protected:
12
13 class SubscriptProxy {
14 public:
15 using ThisType = SubscriptProxy;
16 static constexpr bool ReadWrite = Writable;
17 using DerivedPtrType = std::conditional_t<ReadWrite, CRTP*, const CRTP*>;
18
19 DerivedPtrType pObject_{};
20 Key key_{};
21 public:
22 SubscriptProxy(DerivedPtrType pObject, Key key):
23 pObject_(pObject), key_(std::move(key)) {}
24
25 operator Value() const {
26 return pObject_->getElement_(key_);
27 }
28
29 ThisType& operator=(Value value) {
30 pObject_->setElement_(key_, std::move(value));
31 return *this;
32 }
33
34 template<typename RValue>
38 return *this;
39 }
40 };
41
42public:
43
44 Value operator[](Key key) const {
45 return static_cast<const CRTP*>(this)->getElement_(key);
46 }
47
48 SubscriptProxy operator[](Key key) requires SubscriptProxy::ReadWrite {
49 return SubscriptProxy { static_cast<CRTP*>(this), key };
50 }
51};
52
53
54template<typename CRTP, typename Index, typename Value, bool Writable>
56 public ReadWriteIndexable<CRTP, Index, Value, Writable>
57{
58private:
59
60 using IndexableProxy = typename ReadWriteIndexable<CRTP, Index, Value, Writable>::SubscriptProxy;
61
62public:
63 void checkBounds(Index index) const {
64 if(index >= size()) throw std::out_of_range{"index > size"};
65 }
66
67 Index size(void) const {
68 return static_cast<const CRTP*>(this)->getElementCount_();
69 }
70
71 Index length(void) const { return size(); }
72
73 Index empty(void) const {
74 return size() == 0;
75 }
76
77 Value at(Index index) const {
78 checkBounds(index);
79 return static_cast<const CRTP*>(this)->getElement_(index);
80 }
81
82 IndexableProxy at(Index index) {
83 checkBounds(index);
84 return IndexableProxy { static_cast<CRTP*>(this), index };
85 }
86
87 Value front(Index index) const {
88 return *this[index];
89 }
90
91 IndexableProxy front(void) {
92 return IndexableProxy { static_cast<CRTP*>(this), 0 };
93 }
94
95 Value back(void) const {
96 return *this[size() - 1];
97 }
98
99 IndexableProxy back(void) {
100 return IndexableProxy { static_cast<CRTP*>(this), size() - 1 };
101 }
102};
103
104 namespace tags {
105 struct RandomAccessIteratorBase {};
106 }
107
108 template<typename O, typename Index, typename Value, bool Reverse>
110 {
111 constexpr static inline bool
112 reverse = Reverse;
113 using object_type = O;
114 using iterator_type = RandomAccessIterator<O, Index, Value, Reverse>;
115 using const_iterator_type = RandomAccessIterator<std::add_const_t<O>, Index, Value, Reverse>;
116 using nonconst_iterator_type = RandomAccessIterator<std::remove_const_t<O>, Index, Value, Reverse>;
117 using value_type = Value;
118 using index_type = std::make_signed_t<Index>;
122 using const_reference = std::add_lvalue_reference_t<std::add_const_t<Value>>;
126 using difference_type = std::ptrdiff_t;
129
130 void checkBounds(Index index) const {
131 if(index >= pObj_->getElementCount_()) throw std::out_of_range{"Index >= obj.elementCount"};
132 }
133#if 0
134 template<typename T = reference>
137 return pObj_->getElement_(index_);
138 }
139
140 }
141#else
142 reference operator* () {
143 checkBounds(index_);
144 return pObj_->getElement_(index_);
145 }
146#endif
147 const_reference operator* () const {
148 checkBounds(index_);
149 return const_cast<const O*>(pObj_)->getElement_(index_);
150 }
151
152 pointer operator& () {
153 checkBounds(index_);
154 return &pObj_->getElement_(index_);
155 }
156
157 iterator_type& operator++ () {
158 if constexpr(Reverse) --index_;
159 else ++index_ ;
160 return *this;
161 }
162 iterator_type operator++ (int) {
163 const auto temp(*this);
164 if constexpr(Reverse) --*this;
165 else ++*this;
166 return temp;
167 }
168 iterator_type& operator--() {
169 if constexpr(Reverse) ++index_;
170 else --index_;
171 return *this;
172 }
173 iterator_type operator--(int) {
174 const auto temp(*this);
175 if constexpr(Reverse) ++*this;
176 else --*this;
177 return temp;
178 }
179 iterator_type& operator+=(index_type offset) { if constexpr(Reverse) index_ -= offset; else index_ += offset; return *this; }
180 iterator_type& operator-=(index_type offset) { if constexpr(Reverse) index_ += offset; else index_ -= offset; return *this; }
181
182 friend iterator_type operator+(const iterator_type& it, index_type offset) { auto temp(it); if constexpr(Reverse) temp.index_ -= offset; else temp.index_ += offset; return temp; }
183 friend iterator_type operator+(index_type offset, const iterator_type& it) { if constexpr(!Reverse) return it + offset; else return it - offset; }
184 friend iterator_type operator-(const iterator_type& it, index_type offset) { auto temp(it); if constexpr(Reverse) temp.index_ += offset; else temp.index_ -= offset; return temp; }
185 iterator_type operator+(const iterator_type& rhs) const { if constexpr(!Reverse) return *this + rhs.index_; else return *this - rhs.index_; }
186 //difference_type operator-(const iterator_type& rhs) const { auto temp(*this); if constexpr(Reverse) temp.index_ += rhs.index_; else temp.index_ -= rhs.index_; return temp.index_; }
187 difference_type operator-(const iterator_type& rhs) const { auto temp(*this); temp.index_ -= rhs.index_; return temp.index_; }
188
189 reference operator[](difference_type offset) const {
190 return pObj_->getElement_(index_ + offset);
191 }
192
193 bool operator== (const iterator_type& rhs) const { return pObj_ == pObj_ && index_ == rhs.index_; }
194 bool operator<= (const iterator_type& rhs) const { return pObj_ == rhs.pObj_ && index_ <= rhs.index_; }
195 bool operator< (const iterator_type& rhs) const { return pObj_ == rhs.pObj_ && index_ < rhs.index_; }
196 bool operator> (const iterator_type& rhs) const { return pObj_ == rhs.pObj_ && index_ > rhs.index_; }
197 bool operator>= (const iterator_type& rhs) const { return pObj_ == rhs.pObj_ && index_ >= rhs.index_; }
198 bool operator!= (const iterator_type& rhs) const { return !(*this == rhs); }
199
200 RandomAccessIterator(void)=default;
201
202 RandomAccessIterator(const const_iterator_type& rhs) requires(std::is_const_v<O>):
204
207
210
211 O* pObj_ = nullptr;
212 index_type index_ = -1;
213 };
214
215
216template<typename CRTP, typename Index, typename Value>
218public:
219
220 using iterator = RandomAccessIterator<CRTP, Index, Value, false>;
221 using reverse_iterator = RandomAccessIterator<CRTP, Index, Value, true>;
222 using const_iterator = RandomAccessIterator<std::add_const_t<CRTP>, Index, Value, false>;
223 using reverse_const_iterator = RandomAccessIterator<std::add_const_t<CRTP>, Index, Value, true>;
224
225 //static_assert(std::random_access_iterator<const_iterator>, "const_iterator not STL-compatible!");
226 //static_assert(std::random_access_iterator<reverse_const_iterator>, "reverse_const_iterator not STL-compatible!");
227
228public:
229 //return revierse iterators
230 iterator begin(void) { return {*static_cast<CRTP*>(this), 0}; }
231 auto begin(void) const { return cbegin(); }
232 auto rbegin(void) { return std::make_reverse_iterator(end()); }
233 auto rbegin(void) const { return crbegin(); }
234 iterator end(void) { return iterator(*static_cast<CRTP*>(this), (Index)static_cast<const CRTP*>(this)->getElementCount_()); }
235 auto end(void) const { return cend(); }
236 auto rend(void) { return std::make_reverse_iterator(begin()); }
237 auto rend(void) const { return crend(); }
238 const_iterator cbegin(void) const { return {*static_cast<const CRTP*>(this), 0}; }
239 auto crbegin(void) const { return std::make_reverse_iterator(cend()); }
240 const_iterator cend(void) const { return const_iterator(*static_cast<const CRTP*>(this), (Index)static_cast<const CRTP*>(this)->getElementCount_()); }
241 auto crend(void) const { return std::make_reverse_iterator(cbegin()); }
242};
243
244}
245
246#endif // GIMBAL_GENERICS_HPP