Stroika Library 3.0d23
 
Loading...
Searching...
No Matches
Range.inl
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2026. All rights reserved
3 */
8
9namespace Stroika::Foundation::Traversal {
10
11 /*
12 ********************************************************************************
13 **** RangeTraits::ExplicitOpennessAndDifferenceType<T, OPENNESS, DIFF_TYPE> ****
14 ********************************************************************************
15 */
16 template <typename T, typename OPENNESS, typename DIFF_TYPE>
19 -> SignedDifferenceType
20 {
21 if constexpr (is_enum_v<T> or is_convertible_v<T, SignedDifferenceType>) {
22 return static_cast<SignedDifferenceType> (rhs) - static_cast<SignedDifferenceType> (lhs);
23 }
24 else {
25 return static_cast<SignedDifferenceType> (rhs - lhs);
26 }
27 }
28
29 /*
30 ********************************************************************************
31 **********& RangeTraits::Explicit<T, OPENNESS, BOUNDS, DIFF_TYPE> **************
32 ********************************************************************************
33 */
34 template <typename T, typename OPENNESS, typename BOUNDS, typename DIFF_TYPE>
36 requires (is_integral_v<T> or is_enum_v<T>)
37 {
38 Require (i != kUpperBound);
39 return static_cast<value_type> (static_cast<UnsignedDifferenceType> (i) + 1);
40 }
41 template <typename T, typename OPENNESS, typename BOUNDS, typename DIFF_TYPE>
43 requires (is_floating_point_v<T>)
44 {
45 Require (i != kUpperBound);
46 return nextafter (i, kUpperBound);
47 }
48 template <typename T, typename OPENNESS, typename BOUNDS, typename DIFF_TYPE>
50 requires (is_integral_v<T> or is_enum_v<T>)
51 {
52 Require (i != kLowerBound);
53 return static_cast<value_type> (static_cast<SignedDifferenceType> (i) - 1);
54 }
55 template <typename T, typename OPENNESS, typename BOUNDS, typename DIFF_TYPE>
57 requires (is_floating_point_v<T>)
58 {
59 Require (i != kLowerBound);
60 return nextafter (i, kLowerBound);
61 }
62
63 /*
64 ********************************************************************************
65 ***************************** Range<T, TRAITS> *********************************
66 ********************************************************************************
67 */
68 template <IRangeable T, IRangeableTraits<T> TRAITS>
70 : fBegin_{TRAITS::kUpperBound}
71 , fEnd_{TRAITS::kLowerBound}
72 , fBeginOpenness_{TRAITS::kLowerBoundOpenness}
73 , fEndOpenness_{TRAITS::kUpperBoundOpenness}
74 {
75 Ensure (empty ());
76 }
77 template <IRangeable T, IRangeableTraits<T> TRAITS>
78 template <typename T2, typename TRAITS2>
79 constexpr Range<T, TRAITS>::Range (const Range<T2, TRAITS>& src)
80 : Range{src.GetLowerBound (), src.GetUpperBound (), src.GetLowerBoundOpenness (), src.GetUpperBoundOpenness ()}
81 {
82 }
83 template <IRangeable T, IRangeableTraits<T> TRAITS>
85 : Range{begin, end, TRAITS::kLowerBoundOpenness, TRAITS::kUpperBoundOpenness}
86 {
87 }
88 template <IRangeable T, IRangeableTraits<T> TRAITS>
89 constexpr Range<T, TRAITS>::Range (const optional<T>& begin, const optional<T>& end)
90 : Range{begin.has_value () ? *begin : TRAITS::kLowerBound, end.has_value () ? *end : TRAITS::kUpperBound,
91 TRAITS::kLowerBoundOpenness, TRAITS::kUpperBoundOpenness}
92 {
93 }
94 template <IRangeable T, IRangeableTraits<T> TRAITS>
95 constexpr Range<T, TRAITS>::Range (Common::ArgByValueType<T> begin, Common::ArgByValueType<T> end, Openness lhsOpen, Openness rhsOpen)
96 : fBegin_{begin}
97 , fEnd_{end}
98 , fBeginOpenness_{lhsOpen}
99 , fEndOpenness_{rhsOpen}
100 {
101 Require (TRAITS::kLowerBound <= TRAITS::kUpperBound); // always required for class
102 Require (TRAITS::kLowerBound <= begin);
103 Require (begin <= end);
104 Require (end <= TRAITS::kUpperBound);
105 Require (begin < end or (lhsOpen == Openness::eClosed and rhsOpen == Openness::eClosed));
106 Ensure (not empty ());
107 }
108 template <IRangeable T, IRangeableTraits<T> TRAITS>
109 constexpr Range<T, TRAITS>::Range (const optional<T>& begin, const optional<T>& end, Openness lhsOpen, Openness rhsOpen)
110 : Range{begin.has_value () ? *begin : TRAITS::kLowerBound, end.has_value () ? *end : TRAITS::kUpperBound, lhsOpen, rhsOpen}
111 {
112 }
113 template <IRangeable T, IRangeableTraits<T> TRAITS>
115 {
116 Require (start <= GetUpperBound ());
117 return Range{start, GetUpperBound (), GetLowerBoundOpenness (), GetUpperBoundOpenness ()};
118 }
119 template <IRangeable T, IRangeableTraits<T> TRAITS>
121 {
122 Require (GetLowerBound () <= end);
123 return Range{GetLowerBound (), end, GetLowerBoundOpenness (), GetUpperBoundOpenness ()};
124 }
125 template <IRangeable T, IRangeableTraits<T> TRAITS>
127 Openness lhsOpen, Openness rhsOpen)
128 {
129 return Range{center - radius, center + radius, lhsOpen, rhsOpen};
130 }
131 template <IRangeable T, IRangeableTraits<T> TRAITS>
133 {
134 // note the case of begin==end is depends on openness, and already handled in normal CTOR - just avoid assert for having begin/end reversed
135 return begin > end ? Range{} : Range{begin, end};
136 }
137 template <IRangeable T, IRangeableTraits<T> TRAITS>
139 {
140 return Range{TraitsType::kLowerBound, TraitsType::kUpperBound, TraitsType::kLowerBoundOpenness, TraitsType::kUpperBoundOpenness};
141 }
142 template <IRangeable T, IRangeableTraits<T> TRAITS>
143 constexpr bool Range<T, TRAITS>::empty () const
144 {
145 if (fBegin_ > fEnd_) {
146 // internal hack done in Range::Range() - empty range - otherwise not possible to create this situation
147 return true;
148 }
149 else if (fBegin_ == fEnd_) {
150 return fBeginOpenness_ == Openness::eOpen and fEndOpenness_ == Openness::eOpen;
151 }
152 return false;
153 }
154 template <IRangeable T, IRangeableTraits<T> TRAITS>
155 constexpr Range<T, TRAITS>::operator bool () const
156 {
157 return not empty ();
158 }
159 template <IRangeable T, IRangeableTraits<T> TRAITS>
160 constexpr typename Range<T, TRAITS>::UnsignedDifferenceType Range<T, TRAITS>::GetDistanceSpanned () const
161 {
162 if (empty ()) [[unlikely]] {
163 return static_cast<UnsignedDifferenceType> (0);
164 }
165 return static_cast<UnsignedDifferenceType> (TraitsType::Difference (fBegin_, fEnd_));
166 }
167 template <IRangeable T, IRangeableTraits<T> TRAITS>
168 constexpr T Range<T, TRAITS>::GetMidpoint () const
169 {
170 Require (not empty ());
171 return GetLowerBound () + GetDistanceSpanned () / 2;
172 }
173 template <IRangeable T, IRangeableTraits<T> TRAITS>
174 constexpr T Range<T, TRAITS>::Pin (T v) const
176 {
177 Require (not empty ());
178 Assert (fBegin_ != fEnd_ or (fBeginOpenness_ == Openness::eClosed and fEndOpenness_ == Openness::eClosed));
179 if (v < fBegin_ or (v == fBegin_ and fBeginOpenness_ == Openness::eOpen)) {
180 // must advance
181 T tmp{fBeginOpenness_ == Openness::eClosed ? fBegin_ : TraitsType::GetNext (fBegin_)};
182 Require (Contains (tmp));
183 return tmp;
184 }
185 else if (v > fEnd_ or (v == fEnd_ and fEndOpenness_ == Openness::eOpen)) {
186 // must retreat
187 T tmp{fEndOpenness_ == Openness::eClosed ? fEnd_ : TraitsType::GetPrevious (fEnd_)};
188 Require (Contains (tmp));
189 return tmp;
190 }
191 return v;
192 }
193 template <IRangeable T, IRangeableTraits<T> TRAITS>
195 {
196 if (empty ()) {
197 return false;
198 }
199 if (fBegin_ < r and r < fEnd_) {
200 return true;
201 }
202 if (fBeginOpenness_ == Openness::eClosed and r == fBegin_) {
203 return true;
204 }
205 if (fEndOpenness_ == Openness::eClosed and r == fEnd_) {
206 return true;
207 }
208 return false;
209 }
210 template <IRangeable T, IRangeableTraits<T> TRAITS>
211 constexpr bool Range<T, TRAITS>::Contains (const Range& containee) const
212 {
213 /*
214 * First, ANY empty set is contained in any other set: \forall A: \emptyset \subseteq A
215 */
216 if (containee.empty ()) {
217 return true; // \forall A: \emptyset \subseteq A
218 }
219 /*
220 * Roughly, a non-empty range is contained in a range iff both ends are contained - but we need to take care of openness
221 * edge conditions.
222 *
223 * if BOTH container and containee are open, the container wont CONTAIN the lower bound of the containee if the lower bounds are equal
224 *
225 * Check lower bound and upper bound separately.
226 */
227 switch (containee.GetLowerBoundOpenness ()) {
228 case Openness::eClosed:
229 if (not Contains (containee.GetLowerBound ())) {
230 return false;
231 }
232 [[fallthrough]];
233 case Openness::eOpen:
234 if (containee.GetLowerBound () < GetLowerBound ()) {
235 return false;
236 }
237 break;
238 }
239 switch (containee.GetUpperBoundOpenness ()) {
240 case Openness::eClosed:
241 if (not Contains (containee.GetUpperBound ())) {
242 return false;
243 }
244 [[fallthrough]];
245 case Openness::eOpen:
246 if (containee.GetUpperBound () > GetUpperBound ()) {
247 return false;
248 }
249 }
250 return true;
251 }
252 template <IRangeable T, IRangeableTraits<T> TRAITS>
254 {
255 Require (not empty ());
256 return Range{GetLowerBound (), GetUpperBound (), Openness::eClosed, Openness::eClosed};
257 }
258 template <IRangeable T, IRangeableTraits<T> TRAITS>
259 template <typename T2, typename TRAITS2>
260 constexpr bool Range<T, TRAITS>::Intersects (const Range<T2, TRAITS2>& rhs) const
261 {
262#if 0
263 // For SOME cases - if we can check if constexpr/if consteval - we maybe able to use the simpler
264 T mn = min (fEnd, rhs.fEnd);
265 T mx = max (fBegin, rhs.fBegin);
266 int cmp = mx - min;
267 if (cmp == 0) {
268 return rhs.GetUpperBoundOpenness () == eOpen or GetLowerBoundOpenness () == Openness::eClosed;
269 }
270 return cmp > 0;
271 if consteval (I know this is closed) {
272 .... do optimized case;
273 }
274 ...
275 bools as numbers
277#endif
278 [[maybe_unused]] auto oldCode = [this] (const Range<T2, TRAITS2>& rhs) {
279 if (empty () or rhs.empty ()) {
280 return false;
281 }
282 T l = max (fBegin_, rhs.GetLowerBound ());
283 T r = min (fEnd_, rhs.GetUpperBound ());
284 if (l < r) {
285 return true;
286 }
287 else if (l == r) {
288 // must check if the end that has 'l' for each Range that that end is closed. Contains()
289 // is a shortcut for that
290 return Contains (l) and rhs.Contains (l);
291 }
292 else {
293 return false;
294 }
295 };
296 /*
297 * | this |
298 * | A | | B | | C | | D | | E |
299 * | G | | H |
300 * | F |
301 */
302 // note: GetLowerBound () and GetUpperBound () do assert !empty (), so must access fBegin/fEnd directly
303 // since probably more efficient to check past end cases before checking empty cases
304 if (rhs.fEnd_ < fBegin_) {
305 Assert (oldCode (rhs) == false);
306 return false; // the entirety of rhs is strictly BEFORE lhs (see case A)
307 }
308 if (rhs.fBegin_ > fEnd_) {
309 Assert (oldCode (rhs) == false);
310 return false; // the entirety of rhs is strictly AFTER lhs (see case E)
311 }
312 if (empty () or rhs.empty ()) {
313 Assert (oldCode (rhs) == false);
314 return false; // if either side is empty, clearly they cannot share any points
315 }
316 if (rhs.fEnd_ == fBegin_) {
317 Assert (oldCode (rhs) == (rhs.GetUpperBoundOpenness () == Openness::eClosed and GetLowerBoundOpenness () == Openness::eClosed));
318 // if they intersect at a point, both side must be closed (contain that point) - (see case G)
319 return rhs.GetUpperBoundOpenness () == Openness::eClosed and GetLowerBoundOpenness () == Openness::eClosed;
320 }
321 if (rhs.fBegin_ == fEnd_) {
322 Assert (oldCode (rhs) == (rhs.GetLowerBoundOpenness () == Openness::eClosed and GetUpperBoundOpenness () == Openness::eClosed));
323 // if they intersect at a point, both side must be closed (contain that point) - (see case H)
324 return rhs.GetLowerBoundOpenness () == Openness::eClosed and GetUpperBoundOpenness () == Openness::eClosed;
325 }
326 Assert (oldCode (rhs) == true);
327 return true; // see cases B, C, D, and F - they all intersect
328 }
329 template <IRangeable T, IRangeableTraits<T> TRAITS>
331 {
332 if (empty () or rhs.empty ()) {
333 return Range{};
334 }
335 T l = max (fBegin_, rhs.fBegin_);
336 T r = min (fEnd_, rhs.fEnd_);
337 if (l <= r) {
338 // lhs/rhs ends are closed iff BOTH lhs/rhs contains that point
339 Openness lhsO = Contains (l) and rhs.Contains (l) ? Openness::eClosed : Openness::eOpen;
340 Openness rhsO = Contains (r) and rhs.Contains (r) ? Openness::eClosed : Openness::eOpen;
341 if (l != r or (lhsO == Openness::eClosed and rhsO == Openness::eClosed)) {
342 return Range{l, r, lhsO, rhsO};
343 }
345 return Range{};
346 }
347 template <IRangeable T, IRangeableTraits<T> TRAITS>
348 inline auto Range<T, TRAITS>::Union (const Range& rhs) const
349 {
350 return DisjointRange<T, Range>{{*this, rhs}};
351 }
352 template <IRangeable T, IRangeableTraits<T> TRAITS>
354 {
355 if (empty ()) {
356 return rhs;
358 if (rhs.empty ()) {
359 return *this;
360 }
361 T l = min (GetLowerBound (), rhs.GetLowerBound ());
362 T r = max (GetUpperBound (), rhs.GetUpperBound ());
363 Range result;
364 if (l <= r) {
365 // lhs/rhs ends are closed iff BOTH lhs/rhs contains that point
366 Openness lhsO = Contains (l) and rhs.Contains (l) ? Openness::eClosed : Openness::eOpen;
367 Openness rhsO = Contains (r) and rhs.Contains (r) ? Openness::eClosed : Openness::eOpen;
368 result = Range{l, r, lhsO, rhsO};
369 }
370 Ensure (result.GetLowerBound () <= GetLowerBound ());
371 Ensure (result.GetLowerBound () <= GetUpperBound ());
372 Ensure (result.GetLowerBound () <= rhs.GetLowerBound ());
373 Ensure (result.GetLowerBound () <= rhs.GetUpperBound ());
374 Ensure (result.GetUpperBound () >= GetLowerBound ());
375 Ensure (result.GetUpperBound () >= GetUpperBound ());
376 Ensure (result.GetUpperBound () >= rhs.GetLowerBound ());
377 Ensure (result.GetUpperBound () >= rhs.GetUpperBound ());
378 return result;
380 template <IRangeable T, IRangeableTraits<T> TRAITS>
382 {
383 if (empty ()) {
384 return Range{value, value, Openness::eClosed, Openness::eClosed};
385 }
386 if (value < GetLowerBound ()) {
387 return Range{value, GetUpperBound (), Openness::eClosed, GetUpperBoundOpenness ()};
389 if (GetUpperBound () < value) {
390 return Range{GetLowerBound (), value, GetLowerBoundOpenness (), Openness::eClosed};
391 }
392 return *this;
393 }
394 template <IRangeable T, IRangeableTraits<T> TRAITS>
396 {
397 Require (not empty ());
398 return fBegin_;
399 }
400 template <IRangeable T, IRangeableTraits<T> TRAITS>
402 {
403 return fBeginOpenness_;
404 }
405 template <IRangeable T, IRangeableTraits<T> TRAITS>
407 {
408 Require (not empty ());
409 return fEnd_;
410 }
411 template <IRangeable T, IRangeableTraits<T> TRAITS>
413 {
414 return fEndOpenness_;
415 }
416 template <IRangeable T, IRangeableTraits<T> TRAITS>
417 constexpr auto Range<T, TRAITS>::Offset (SignedDifferenceType o) const -> Range
418 {
419 Require (not empty ());
420 return Range{static_cast<T> (GetLowerBound () + o), static_cast<T> (GetUpperBound () + o), GetLowerBoundOpenness (), GetUpperBoundOpenness ()};
422 template <IRangeable T, IRangeableTraits<T> TRAITS>
423 constexpr auto Range<T, TRAITS>::Times (T o) const -> Range
424 {
425 Require (not empty ());
426 return Range{static_cast<T> (GetLowerBound () * o), static_cast<T> (GetUpperBound () * o), GetLowerBoundOpenness (), GetUpperBoundOpenness ()};
428 template <IRangeable T, IRangeableTraits<T> TRAITS>
429 Characters::String Range<T, TRAITS>::ToString (const function<Characters::String (const T&)>& eltToString) const
430 {
432 if (empty ()) {
433 out << "{}"sv;
434 }
435 else if (GetLowerBound () == GetUpperBound ()) {
436 // if single point, open and closed must be same (or always must be closed?)
437 out << "["sv << eltToString (GetLowerBound ()) << "]"sv;
438 }
439 else {
440 out << ((GetLowerBoundOpenness () == Openness::eClosed) ? "["sv : "("sv);
441 if (GetLowerBound () != TRAITS::kLowerBound) {
442 out << eltToString (GetLowerBound ());
443 }
444 out << " ... "sv;
445 if (GetUpperBound () != TRAITS::kUpperBound) {
446 out << eltToString (GetUpperBound ());
447 }
448 out << ((GetUpperBoundOpenness () == Openness::eClosed) ? "]"sv : ")"sv);
450 return out.str ();
451 }
452 template <IRangeable T, IRangeableTraits<T> TRAITS>
453 constexpr bool Range<T, TRAITS>::operator== (const Range& rhs) const
454 {
455 if (empty ()) {
456 return rhs.empty ();
457 }
458 return GetLowerBound () == rhs.GetLowerBound () and GetUpperBound () == rhs.GetUpperBound () and
459 GetLowerBoundOpenness () == rhs.GetLowerBoundOpenness () and GetUpperBoundOpenness () == rhs.GetUpperBoundOpenness ();
460 }
461 template <IRangeable T, IRangeableTraits<T> TRAITS>
462 constexpr partial_ordering Range<T, TRAITS>::operator<=> (const Range& rhs) const
463 {
464 /*
465 * | this |
466 * | rhs |
467 */
468 if (GetUpperBoundOpenness () == eClosed and rhs.GetLowerBoundOpenness () == eClosed) {
469 if (GetUpperBound () < rhs.GetLowerBound ()) {
470 return partial_ordering::less;
471 }
472 }
473 else {
474 if (GetUpperBound () <= rhs.GetLowerBound ()) {
475 return partial_ordering::less;
476 }
477 }
478 /*
479 * | this |
480 * | rhs |
481 */
482 if (GetLowerBoundOpenness () == eClosed and rhs.GetLowerBoundOpenness () == eClosed) {
483 if (GetLowerBound () > rhs.GetUpperBound ()) {
484 return partial_ordering::greater;
485 }
486 }
487 else {
488 if (GetLowerBound () >= rhs.GetUpperBound ()) {
489 return partial_ordering::greater;
490 }
491 }
492 if (*this == rhs) {
493 return partial_ordering::equivalent;
494 }
495 /*
496 * | this |
497 * | rhs |
498 * or
499 * | this |
500 * | rhs |
501 * etc...
502 */
503 return partial_ordering::unordered;
504 }
506 /*
507 ********************************************************************************
508 *************************** Range<T,TRAITS> Operators **************************
509 ********************************************************************************
510 */
511 template <IRangeable T, IRangeableTraits<T> TRAITS>
512 constexpr Range<T, TRAITS> operator+ (const T& lhs, const Range<T, TRAITS>& rhs)
514 return rhs.Offset (lhs);
515 }
516 template <IRangeable T, IRangeableTraits<T> TRAITS>
517 constexpr Range<T, TRAITS> operator+ (const Range<T, TRAITS>& lhs, const T& rhs)
518 {
519 return lhs.Offset (rhs);
521 template <IRangeable T, IRangeableTraits<T> TRAITS>
522 inline auto operator+ (const Range<T, TRAITS>& lhs, const Range<T, TRAITS>& rhs)
523 {
524 return lhs.Union (rhs);
525 }
526
527 template <IRangeable T, IRangeableTraits<T> TRAITS>
528 constexpr Range<T, TRAITS> operator* (const T& lhs, const Range<T, TRAITS>& rhs)
530 return rhs.Times (lhs);
531 }
532 template <IRangeable T, IRangeableTraits<T> TRAITS>
533 constexpr Range<T, TRAITS> operator* (const Range<T, TRAITS>& lhs, const T& rhs)
534 {
535 return lhs.Times (rhs);
536 }
537
538 template <IRangeable T, IRangeableTraits<T> TRAITS>
539 constexpr Range<T, TRAITS> operator^ (const Range<T, TRAITS>& lhs, const Range<T, TRAITS>& rhs)
540 {
541 return lhs.Intersection (rhs);
542 }
543
545
547 template <>
548 constexpr EnumNames<Traversal::Openness> DefaultNames<Traversal::Openness>::k{{{
549 {Traversal::Openness::eOpen, L"Open"},
550 {Traversal::Openness::eClosed, L"Closed"},
551 }}};
552}
Similar to String, but intended to more efficiently construct a String. Mutable type (String is large...
String is like std::u32string, except it is much easier to use, often much more space efficient,...
Definition String.h:201
A DisjointRange is NOT a range, but a collection of non-overlapping (except at the edges) Ranges....
constexpr T Pin(T v) const
Definition Range.inl:174
constexpr bool Contains(Common::ArgByValueType< T > r) const
Definition Range.inl:194
static constexpr Range FullRange()
Definition Range.inl:138
static constexpr Range Ball(Common::ArgByValueType< T > center, Common::ArgByValueType< UnsignedDifferenceType > radius, Openness lhsOpen=TRAITS::kLowerBoundOpenness, Openness rhsOpen=TRAITS::kUpperBoundOpenness)
returns a range centered around center, with the given radius (and optionally argument openness).
Definition Range.inl:126
constexpr Range Extend(Common::ArgByValueType< T > value) const
Definition Range.inl:381
constexpr bool empty() const
Definition Range.inl:143
constexpr Range Offset(SignedDifferenceType o) const
Definition Range.inl:417
constexpr T GetUpperBound() const
Definition Range.inl:406
constexpr Range Intersection(const Range &rhs) const
Definition Range.inl:330
nonvirtual Characters::String ToString(const function< Characters::String(const T &)> &elt2String=[](const T &x) -> Characters::String { return Characters::ToString(x);}) const
Definition Range.inl:429
constexpr bool Intersects(const Range< T2, TRAITS2 > &rhs) const
Definition Range.inl:260
constexpr bool operator==(const Range &rhs) const
Definition Range.inl:453
constexpr Range Times(T o) const
Definition Range.inl:423
constexpr T GetLowerBound() const
Definition Range.inl:395
constexpr Range ReplaceStart(Common::ArgByValueType< T > start) const
Construct a new Range from this, but with the given start.
Definition Range.inl:114
constexpr Range UnionBounds(const Range &rhs) const
Definition Range.inl:353
constexpr Range ReplaceEnd(Common::ArgByValueType< T > end) const
Construct a new Range from this, but with the given end.
Definition Range.inl:120
constexpr T GetMidpoint() const
Definition Range.inl:168
nonvirtual constexpr Range Closure() const
Definition Range.inl:253
nonvirtual auto Union(const Range &rhs) const
Definition Range.inl:348
static constexpr Range ContainedRange(Common::ArgByValueType< T > begin, Common::ArgByValueType< T > end)
Definition Range.inl:132
constexpr UnsignedDifferenceType GetDistanceSpanned() const
Definition Range.inl:160
requirements for 'T' to use Range<T>.
Definition Range.h:255
conditional_t<(sizeof(CHECK_T)<=2 *sizeof(void *)) and is_trivially_copyable_v< CHECK_T >, CHECK_T, const CHECK_T & > ArgByValueType
This is an alias for 'T' - but how we want to pass it on stack as formal parameter.
Definition TypeHints.h:32
static constexpr value_type GetPrevious(value_type i)
Definition Range.inl:49
static constexpr value_type GetNext(value_type i)
Definition Range.inl:35
static constexpr SignedDifferenceType Difference(Common::ArgByValueType< value_type > lhs, Common::ArgByValueType< value_type > rhs)
Definition Range.inl:17