Qx v0.5.7
Qt Extensions Library
Loading...
Searching...
No Matches
qx-index.h
1#ifndef QX_INDEX_H
2#define QX_INDEX_H
3
4// Standard Library Includes
5#include <concepts>
6#include <numeric>
7#include <stdexcept>
8
9// Qt Includes
10#include <QtGlobal>
11
12// Intra-component Includes
13#include "qx/core/qx-global.h"
15
16namespace Qx
17{
18
19template<typename T>
20 requires std::signed_integral<T>
21class Index
22{
23//-Class Types----------------------------------------------------------------------------------------------------
24private:
25 enum class Type {Null, End, Value};
26
27//-Instance Members----------------------------------------------------------------------------------------------------
28private:
29 Type mType;
30 T mValue;
31
32//-Constructor----------------------------------------------------------------------------------------------
33public:
34 constexpr Index() :
35 mType(Type::Null),
36 mValue(0)
37 {}
38
39 constexpr Index(Extent e)
40 {
41 switch(e)
42 {
43 case First:
44 mType = Type::Value;
45 mValue = 0;
46 break;
47
48 case Last:
49 mType = Type::End;
50 mValue = std::numeric_limits<T>::max();
51 break;
52
53 default:
54 qCritical("Invalid extent");
55 }
56 }
57
58 constexpr Index(T value) :
59 mType(Type::Value),
60 mValue(value)
61 {
62 if(value < 0)
63 {
64 mType = Type::Null;
65 mValue = 0;
66 }
67 }
68
69//-Instance Functions----------------------------------------------------------------------------------------------
70public:
71 bool isNull() const { return mType == Type::Null; }
72 bool isLast() const { return mType == Type::End; }
73
74//-Operators-------------------------------------------------------------------------------------------------------
75public:
76 bool operator==(const Index& other) const noexcept { return mType == other.mType && mValue == other.mValue; }
77
78// template<typename N> requires std::integral<N>
79// bool operator==(const N& integer) const { return mType == Type::Value && static_cast<N>(mValue) == integer; }
80
81 std::strong_ordering operator<=>(const Index& other) const noexcept {
82 switch(mType)
83 {
84 case Type::Null:
85 return other.mType == Type::Null ? std::strong_ordering::equal : std::strong_ordering::less;
86
87 case Type::End:
88 return other.mType == Type::End ? std::strong_ordering::equal : std::strong_ordering::greater;
89
90 case Type::Value:
91 default:
92 return other.mType == Type::Null ? std::strong_ordering::greater :
93 other.mType == Type::End ? std::strong_ordering::less :
94 mValue <=> other.mValue;
95 }
96
97 }
98
99 Index operator-(const Index& other)
100 {
101 if(other.mType == Type::End)
102 return 0;
103 else if(mType == Type::End)
104 return Index(Last);
105 else
106 return constrainedSub(mValue, other.mValue, 0);
107 }
108
109 Index& operator-=(const Index& other) { *this = *this - other; return *this; }
110
111 Index operator+(const Index& other)
112 {
113 return (mType == Type::End || other.mType == Type::End) ?
114 Index(Last) : constrainedAdd(mValue, other.mValue, 0);
115 }
116
117
118 Index& operator+=(const Index& other) { *this = *this + other; return *this; }
119
120 Index operator/(const Index& other)
121 {
122 if(other.mValue == 0)
123 qFatal("Divide by zero");
124
125 if(other.mType == Type::End)
126 return mType == Type::End ? 1 : 0;
127 else if(mType == Type::End)
128 return Index(Last);
129 else
130 return constrainedDiv(mValue, other.mValue, 0);
131 }
132
133 Index& operator/=(const Index& other) { *this = *this/other; return *this; }
134
135 Index operator*(const Index& other)
136 {
137 if(mValue == 0 || other.mValue == 0)
138 return 0;
139 else if(mType == Type::End || other.mType == Type::End)
140 return Index(Last);
141 else
142 return constrainedMult(mValue, other.mValue, 0);
143
144 }
145
146 Index& operator*=(const Index& other) { *this = *this * other; return *this; }
147
148
150 {
151 if(mType == Type::Value && mValue != std::numeric_limits<T>::max())
152 ++mValue;
153 return *this;
154 }
156 {
157 Index idx = (*this);
158 operator++();
159 return idx;
160 }
162 {
163 if(!mType == Type::Value && mValue != 0)
164 --mValue;
165 return *this;
166 }
168 {
169 Index idx = (*this);
170 this->operator--();
171 return idx;
172 }
173
174 T& operator*() { return mValue; }
175
176 /* Disabled operators for Index as one opperand and an arithmetic type as another. These were causing
177 * all kinds of ambiguities (for compiler and/or programmer) in terms of implicit conversions so they
178 * have been disabled and the deference operator was added instead for when the underlying type of
179 * the Index is needed. If these are ever reintroduced be sure to discard the relational operators
180 * in favor of a spaceship operator as above
181 *
182 * Static casts in operators here make sure that in cases where the non-index operand is unsigned it is
183 * always the value of the Index that is converted to an unsigned integer instead of the other operand
184 * being converted to a signed integer. This is safe to do since mValue is guaranteed to never be less
185 * than zero. In cases where the other operand is already an unsigned int, the static_cast should
186 * be optimized to a no-op, causing no overhead, with pretty much every compiler
187 */
188// template<typename N> requires std::integral<N>
189// bool operator<(const N& integer) const
190// {
191// return mType == Type::Null || (mType == Type::Value && static_cast<N>(mValue) < integer);
192// }
193
194// template<typename N> requires std::integral<N>
195// friend bool operator<(const N& integer, const Index<T>& index)
196// {
197// return index.mType == Type::End || (index.mType == Type::Value && integer < static_cast<N>(index.mValue));
198// }
199
200// bool operator<=(const Index& other) const { return !(*this > other); }
201
202// template<typename N> requires std::integral<N>
203// bool operator<=(const N& integer) const { return !(*this > integer); }
204
205// template<typename N> requires std::integral<N>
206// friend bool operator<=(const N& integer, const Index<T>& index) { return !(integer > index); }
207
208// bool operator>(const Index& other) const { return other < *this; }
209
210// template<typename N> requires std::integral<N>
211// bool operator>(const N& integer) const { return integer < *this; }
212
213// template<typename N> requires std::integral<N>
214// friend bool operator>(const N& integer, const Index<T>& index) { return index < integer; }
215
216// bool operator>=(const Index& other) const { return !(*this < other); }
217
218// template<typename N> requires std::integral<N>
219// bool operator>=(const N& integer) const { return !(*this < integer); }
220
221// template<typename N> requires std::integral<N>
222// friend bool operator>=(const N& integer, const Index<T>& index) { return !(integer < index); }
223
224// template<typename N> requires std::integral<N>
225// Index operator-(const N& integer)
226// {
227// if(mType == Type::End)
228// return LAST;
229// else
230// return Number::constrainedSub(static_cast<N>(mValue), integer, 0);
231// }
232
233// template<typename N> requires std::integral<N>
234// friend T operator-(N integer, const Index<T>& index) { integer -= index; return integer; }
235
236// template<typename N> requires std::integral<N>
237// Index& operator-=(const N& integer) { *this = *this - integer; return *this; }
238
239// template<typename N> requires std::integral<N>
240// friend T& operator-=(N& integer, const Index<T>& index) { integer -= static_cast<N>(index.mValue); return integer; }
241
242// template<typename N> requires std::integral<N>
243// Index operator+(const N& integer)
244// {
245// return mType == Type::End ? LAST : Number::constrainedAdd(static_cast<N>(mValue), integer, 0);
246// }
247
248
249// template<typename N> requires std::integral<N>
250// friend T operator+(N integer, const Index<T>& index) { integer += index; return integer; }
251
252// template<typename N> requires std::integral<N>
253// Index& operator+=(const N& integer) { *this = *this + integer; return *this; }
254
255// template<typename N> requires std::integral<N>
256// friend T& operator+=(N& integer, const Index<T>& index) { integer += static_cast<N>(index.mValue); return integer; }
257
258// template<typename N> requires std::integral<N>
259// Index operator/(const N& integer)
260// {
261// if(integer == 0)
262// qFatal("Divide by zero");
263
264// if(mType == Type::End)
265// return LAST;
266// else
267// return Number::constrainedDiv(static_cast<N>(mValue), integer, 0);
268// }
269
270// template<typename N> requires std::integral<N>
271// friend T operator/(N integer, const Index<T>& index) { integer /= index; return integer; }
272
273// template<typename N> requires std::integral<N>
274// Index& operator/=(const N& integer) { *this = *this/integer; return *this; }
275
276// template<typename N> requires std::integral<N>
277// friend T& operator/=(N& integer, const Index<T>& index) { integer /= static_cast<N>(index.mValue); return integer; }
278
279// template<typename N> requires std::integral<N>
280// Index operator*(const N& integer)
281// {
282// if(mValue == 0 || integer == 0)
283// return 0;
284// else if(mType == Type::End)
285// return LAST;
286// else
287// return Number::constrainedMult(static_cast<N>(mValue), integer, 0);
288// }
289
290// template<typename N> requires std::integral<N>
291// friend T operator*(N integer, const Index<T>& index) { integer *= index; return integer; }
292
293// template<typename N> requires std::integral<N>
294// Index& operator*=(const N& integer) { *this = *this * integer; return *this; }
295
296// template<typename N> requires std::integral<N>
297// friend T& operator*=(N& integer, const Index<T>& index) { integer *= static_cast<N>(index.mValue); return integer; }
298};
299
300//-Outer Class Types----------------------------------------------------------------------------------------
305
306}
307
308#endif // QX_INDEX_H
The Index template class provides a wrapper for integers with the notion of 'first',...
Definition qx-index.h:22
bool isNull() const
Definition qx-index.h:71
Index & operator*=(const Index &other)
Definition qx-index.h:146
Index operator/(const Index &other)
Definition qx-index.h:120
T & operator*()
Definition qx-index.h:174
Index & operator+=(const Index &other)
Definition qx-index.h:118
Index operator-(const Index &other)
Definition qx-index.h:99
Index & operator--()
Definition qx-index.h:161
bool isLast() const
Definition qx-index.h:72
Index operator*(const Index &other)
Definition qx-index.h:135
Index operator+(const Index &other)
Definition qx-index.h:111
Index & operator++()
Definition qx-index.h:149
Index & operator-=(const Index &other)
Definition qx-index.h:109
Index & operator/=(const Index &other)
Definition qx-index.h:133
bool operator==(const Index &other) const noexcept
Definition qx-index.h:76
constexpr Index(Extent e)
Definition qx-index.h:39
constexpr Index()
Definition qx-index.h:34
Index operator--(int)
Definition qx-index.h:167
std::strong_ordering operator<=>(const Index &other) const noexcept
Definition qx-index.h:81
Index operator++(int)
Definition qx-index.h:155
constexpr Index(T value)
Definition qx-index.h:58
The Qx namespace is the main namespace through which all non-global functionality of the Qx library i...
Definition qx-processwaiter.cpp:5
Extent
Definition qx-global.h:18
@ Last
Definition qx-global.h:21
@ End
Definition qx-global.h:22
@ First
Definition qx-global.h:19
T constrainedAdd(T a, T b, T min=std::numeric_limits< T >::min(), T max=std::numeric_limits< T >::max())
Definition qx-algorithm.h:65
T constrainedDiv(T a, T b, T min=std::numeric_limits< T >::min(), T max=std::numeric_limits< T >::max())
Definition qx-algorithm.h:141
Index< qint32 > Index64
Definition qx-index.h:304
T constrainedSub(T a, T b, T min=std::numeric_limits< T >::min(), T max=std::numeric_limits< T >::max())
Definition qx-algorithm.h:87
Index< qint32 > Index32
Definition qx-index.h:303
Index< qint8 > Index8
Definition qx-index.h:301
Index< qint16 > Index16
Definition qx-index.h:302
T constrainedMult(T a, T b, T min=std::numeric_limits< T >::min(), T max=std::numeric_limits< T >::max())
Definition qx-algorithm.h:109
The qx-algorithm header file provides various mathematical/algorithmic functions.