1#ifndef GIMBAL_GENERICS_HPP
2#define GIMBAL_GENERICS_HPP
9template<
typename CRTP,
typename Key,
typename Value,
bool Writable>
16 static constexpr bool ReadWrite = Writable;
17 using DerivedPtrType = std::conditional_t<ReadWrite, CRTP*,
const CRTP*>;
19 DerivedPtrType pObject_{};
22 SubscriptProxy(DerivedPtrType pObject, Key key):
23 pObject_(pObject), key_(std::move(key)) {}
25 operator Value()
const {
26 return pObject_->getElement_(key_);
29 ThisType& operator=(Value value) {
30 pObject_->setElement_(key_, std::move(value));
44 Value operator[](Key key)
const {
45 return static_cast<
const CRTP*>(
this)->getElement_(key);
54template<
typename CRTP,
typename Index,
typename Value,
bool Writable>
60 using IndexableProxy =
typename ReadWriteIndexable<CRTP, Index, Value, Writable>::SubscriptProxy;
63 void checkBounds(Index index)
const {
64 if(index >= size())
throw std::out_of_range{
"index > size"};
67 Index size(
void)
const {
68 return static_cast<
const CRTP*>(
this)->getElementCount_();
71 Index length(
void)
const {
return size(); }
73 Index empty(
void)
const {
77 Value at(Index index)
const {
79 return static_cast<
const CRTP*>(
this)->getElement_(index);
82 IndexableProxy at(Index index) {
84 return IndexableProxy {
static_cast<CRTP*>(
this), index };
87 Value front(Index index)
const {
91 IndexableProxy front(
void) {
92 return IndexableProxy {
static_cast<CRTP*>(
this), 0 };
95 Value back(
void)
const {
96 return *
this[size() - 1];
99 IndexableProxy back(
void) {
100 return IndexableProxy {
static_cast<CRTP*>(
this), size() - 1 };
108 template<
typename O,
typename Index,
typename Value,
bool Reverse>
111 constexpr static inline bool
113 using object_type = O;
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;
130 void checkBounds(Index index)
const {
131 if(index >= pObj_->getElementCount_())
throw std::out_of_range{
"Index >= obj.elementCount"};
142 reference operator* () {
144 return pObj_->getElement_(index_);
147 const_reference operator* ()
const {
149 return const_cast<
const O*>(pObj_)->getElement_(index_);
152 pointer operator& () {
154 return &pObj_->getElement_(index_);
157 iterator_type& operator++ () {
158 if constexpr(Reverse) --index_;
162 iterator_type operator++ (
int) {
163 const auto temp(*
this);
164 if constexpr(Reverse) --*
this;
168 iterator_type& operator--() {
169 if constexpr(Reverse) ++index_;
173 iterator_type operator--(
int) {
174 const auto temp(*
this);
175 if constexpr(Reverse) ++*
this;
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; }
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_; }
187 difference_type operator-(
const iterator_type& rhs)
const {
auto temp(*
this); temp.index_ -= rhs.index_;
return temp.index_; }
189 reference operator[](difference_type offset)
const {
190 return pObj_->getElement_(index_ + offset);
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); }
200 RandomAccessIterator(
void)=
default;
212 index_type index_ = -1;
216template<
typename CRTP,
typename Index,
typename Value>
223 using reverse_const_iterator =
RandomAccessIterator<std::add_const_t<CRTP>, Index, Value,
true>;
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()); }