Stroika Library 3.0d23
 
Loading...
Searching...
No Matches
Range.h
Go to the documentation of this file.
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2026. All rights reserved
3 */
4#ifndef _Stroika_Foundation_Traversal_Range_h_
5#define _Stroika_Foundation_Traversal_Range_h_ 1
6
7#include "Stroika/Foundation/StroikaPreComp.h"
8
9#include <limits>
10#include <optional>
11#include <type_traits>
12
15#include "Stroika/Foundation/Common/Common.h"
18
19/**
20 * \file
21 *
22 * \note Code-Status: <a href="Code-Status.md#Beta">Beta</a>
23 *
24 * \em Design Note
25 * This module was inspired by Ruby Range class, but in the end, it was mostly based on HealthFrame's
26 * DateRangeType/DateTimeRangeType code.
27 *
28 * This notion of 'range' has VERY LITTLE todo with the std::range feature (which is more like Stroika 'Iterable')
29 *
30 * TODO:
31 * @todo Did a DECENT job of constraints/concepts, but could do better, and consider where we have GetPrevious/GetNext.
32 * Its RARELY used here (more fundemental for DiscreteRange) - so maybe just include there?
33 *
34 * @todo Carefully review intersection/union bounds code for new open/closed parameters. Either make sure
35 * it works or at least more carefully document in method headers the quirks of the
36 * chosen definition.
37 */
38
39namespace Stroika::Foundation::Traversal {
40
41 /**
42 * \brief requirements for 'T' to use Range<T>.
43 */
44 template <typename T>
45 concept IRangeable = copyable<T> and totally_ordered<T>;
46
47 /**
48 * \note - ALL these RangeTraits helper classes use template <> struct instead of template<> using because
49 * as of C++17, you cannot do template specialization of using templates (otherwise using would be better)
50 */
51 namespace RangeTraits {
52
53 /**
54 * \note really just used to construct Explicit<> or ExplicitOpennessAndDifferenceType<>
55 */
56 template <typename DIFFERENCE_TYPE, typename UNSIGNED_DIFFERENCE_TYPE = Common::UnsignedOfIf<DIFFERENCE_TYPE>>
58 using SignedDifferenceType = DIFFERENCE_TYPE;
59 using UnsignedDifferenceType = UNSIGNED_DIFFERENCE_TYPE;
60 };
61
62 /**
63 * \note really just used to construct Explicit<> or ExplicitOpennessAndDifferenceType<>
64 */
65 template <typename T>
66 struct DefaultDifferenceTypes : ExplicitDifferenceTypes<Common::DifferenceType<T>> {};
67
68 /**
69 * \note really just used to construct Explicit<> or ExplicitOpennessAndDifferenceType<>
70 */
71 template <Openness LOWER_BOUND, Openness UPPER_BOUND>
73 static constexpr Openness kLowerBound{LOWER_BOUND};
74 static constexpr Openness kUpperBound{UPPER_BOUND};
75 };
76
77 /**
78 * \brief This defines the default openness for a given type T, except for specializaitons. This is used
79 * by Explict<>, and indirectly by Range<> itself.
80 * Generally its eClosed, by default, except for the upper bound on floating point Ranges.
81 * The reason for this exception on floating point, is that its often helpful to have a series of
82 * ranges that form a partition, and that works out more easily with half-open intervals.
83 *
84 * \note really just used to construct Explicit<> or ExplicitOpennessAndDifferenceType<>
85 */
86 template <typename T>
88 : conditional_t<is_floating_point_v<T>, ExplicitOpenness<Openness::eClosed, Openness::eOpen>, ExplicitOpenness<Openness::eClosed, Openness::eClosed>> {
89 };
90
91 /**
92 * \note really just used to construct Explicit<>
93 *
94 * Sadly this doesn't work for floating point types, so you must declare your own class with kLowerBounds and kUpperBounds, and pass its
95 * type.
96 *
97 * https://stackoverflow.com/questions/2183087/why-cant-i-use-float-value-as-a-template-parameter
98 *
99 * More confusingly, this limitation, though part of the C++ standard, only appears to be enforced by gcc/clang compilers, and
100 * not MSVC (as of 2020-12-11)
101 */
102 template <typename T, T MIN, T MAX>
104 static constexpr T kLowerBound{MIN};
105 static constexpr T kUpperBound{MAX};
106 };
107
108 /**
109 * \note really just used to construct Explicit<>
110 *
111 * \note implementation of DefaultBounds<> cannot use ExplicitBounds<> because that wont work with floating point types
112 */
113 template <typename T>
115 static constexpr T kLowerBound{numeric_limits<T>::lowest ()};
116 static constexpr T kUpperBound{numeric_limits<T>::max ()};
117 };
118
119 /**
120 * The ONLY reason this exists (as opposed to just Explicit<> is because we cannot create templates taking arguments
121 * of BOUNDS sometimes (because the VALUES MIN/MAX cannot be used as template parameters).
122 */
123 template <typename T, typename OPENNESS = DefaultOpenness<T>, typename DIFF_TYPE = DefaultDifferenceTypes<T>>
125 using value_type = T;
126 using SignedDifferenceType = typename DIFF_TYPE::SignedDifferenceType;
127 using UnsignedDifferenceType = typename DIFF_TYPE::UnsignedDifferenceType;
128
129 static constexpr Openness kLowerBoundOpenness{OPENNESS::kLowerBound};
130 static constexpr Openness kUpperBoundOpenness{OPENNESS::kUpperBound};
131
132 /**
133 * Compute the difference between two elements of type T for the Range (RHS - LHS)
134 */
135 static constexpr SignedDifferenceType Difference (Common::ArgByValueType<value_type> lhs, Common::ArgByValueType<value_type> rhs);
136
137 // Must be able to convert the underlying 'T' difference type to size_t sometimes
138 static size_t DifferenceToSizeT (UnsignedDifferenceType s)
139 {
140 return size_t (s);
141 }
142 static size_t DifferenceToSizeT (SignedDifferenceType s)
143 requires (not same_as<UnsignedDifferenceType, SignedDifferenceType>)
144 {
145 return size_t (s);
146 }
147 };
148
149 /**
150 * \note Only used to construct/define a specific Range<> type
151 *
152 * Explicit<> can be used to specify inline (type) all the details for the range functionality
153 * for a given type T. Also, it provides often usable default implementations of things like GetNext, GetPrevious ().
154 */
155 template <typename T, typename OPENNESS = DefaultOpenness<T>, typename BOUNDS = DefaultBounds<T>, typename DIFF_TYPE = DefaultDifferenceTypes<T>>
156 struct Explicit : ExplicitOpennessAndDifferenceType<T, OPENNESS, DIFF_TYPE> {
158 using value_type = T;
159 //using value_type = typename inherited::value_type; // @todo debug why this doesn't work!
160 using SignedDifferenceType = typename inherited::SignedDifferenceType;
161 using UnsignedDifferenceType = typename inherited::UnsignedDifferenceType;
162
163 static constexpr T kLowerBound{BOUNDS::kLowerBound};
164 static constexpr T kUpperBound{BOUNDS::kUpperBound};
165
166 /**
167 * Return the Next possible value.
168 *
169 * \pre arg != last-possible-value
170 *
171 * \note its hard todo GetNext() for floating point as constexpr because underlying function in cmath not yet constexpr (as of C++17)
172 */
173 static constexpr value_type GetNext (value_type i)
174 requires (is_integral_v<T> or is_enum_v<T>);
175 static value_type GetNext (value_type i)
176 requires (is_floating_point_v<T>);
177
178 /**
179 * Return the Previous possible value.
180 *
181 * \pre arg != first-possible-value
182 *
183 * \note its hard todo GetPrevious() for floating point as constexpr because underlying function in cmath not yet constexpr (as of C++17)
184 */
185 static constexpr value_type GetPrevious (value_type i)
186 requires (is_integral_v<T> or is_enum_v<T>);
187 static value_type GetPrevious (value_type i)
188 requires (is_floating_point_v<T>);
189 };
190
191 /**
192 * \note Only used to construct/define a specific Range<> type
193 */
194 template <typename T>
195 struct Default_Integral : Explicit<T, ExplicitOpenness<Openness::eClosed, Openness::eClosed>> {};
196
197 /**
198 * \note Only used to construct/define a specific Range<> type
199 *
200 * Default_Enum<> can be used to generate an automatic traits object (with bounds)
201 * if you've applied the Stroika_Define_Enum_Bounds() macro to the given enumeration.
202 */
203 template <typename T>
204 struct Default_Enum : Explicit<T, ExplicitOpenness<Openness::eClosed, Openness::eClosed>, ExplicitBounds<T, T::eSTART, T::eLAST>> {};
205
206 /**
207 * \note Only used to construct/define a specific Range<> type
208 *
209 * This defaults to a half-open (lhs closed, rhs-open) range, and should work for any arithmetic type
210 * (where you can subtract elements, etc)
211 */
212 template <typename T>
213 struct Default_Arithmetic : Explicit<T, ExplicitOpenness<Openness::eClosed, Openness::eOpen>> {};
214
215 /**
216 * Default<> contains the default traits used by a Range<> class. For most builtin types, this will
217 * be fine. For many Stroika types, specializations exist, so that you can just use Range<T> directly.
218 *
219 * But you may find it handy to define your own Range 'traits' object.
220 *
221 * \note The default OPENNESS for Default varies by TYPE T. Integer and enums are both
222 * fully closed by default, and other arithmetic types (floats) are half open [)
223 *
224 * \note Would be nice to use using syntax and not introduce a new type, but apparently
225 * using declarations cannot be specialized in C++17 (@todo add reference)
226 */
227 template <typename T>
228 struct Default
229 : conditional_t<is_enum_v<T>, Common::LazyType_t<Default_Enum, T>,
230 conditional_t<is_integral_v<T>, Common::LazyType_t<Default_Integral, T>,
231 conditional_t<is_arithmetic_v<T> or true, Common::LazyType_t<Default_Arithmetic, T>, void>>> {};
232
233 }
234
235 /**
236 * Legal TRAITS object for Range template.
237 */
238 template <typename TRAITS, typename T>
239 concept IRangeableTraits = requires (T, TRAITS) {
240 typename TRAITS::SignedDifferenceType;
241 typename TRAITS::UnsignedDifferenceType;
242 { TRAITS::kLowerBound } -> convertible_to<T>;
243 { TRAITS::kUpperBound } -> convertible_to<T>;
244 { TRAITS::kLowerBoundOpenness } -> convertible_to<Openness>;
245 { TRAITS::kUpperBoundOpenness } -> convertible_to<Openness>;
246 };
247
248 /**
249 * \brief requirements for 'T' to use Range<T>.
250 *
251 * \todo - should Range<T> require GetNext/GetPrevious? - API CURRENTLY DOES --LGP 2026-02-23, which doesnt always make sense. COULD move that to
252 * DISCRETE TRAITS/DISCRETE Range???
253 */
254 template <typename TRAITS, typename T>
255 concept IAdvanceAndRetreatable = requires (T t, TRAITS) {
256 { TRAITS::GetNext (t) } -> convertible_to<T>;
257 { TRAITS::GetPrevious (t) } -> convertible_to<T>;
258 };
259
260 /**
261 * A Range<> is analogous to a mathematical range. It's left and and its right sides can
262 * be optionally open or closed.
263 *
264 * Range<> is an immutable type (once constructed, will never change), except for allowing operator=.
265 *
266 * A range always has a lower and upper bound (if not specified in CTOR, its specified by the type traits) so no
267 * unbounded ranges).
268 *
269 * For a range to contain a single point, min=max, and both sides must be closed (else its a require error)
270 *
271 * This Range<> template is similar to Ruby range, and fairly DIFFERENT from the std::range<> template.
272 *
273 * This notion of range is **NOT THE SAME as std::range**, though is similar (obviously from the name).
274 *
275 * Somewhat inspired by, and at least influenced by, the definition in
276 * http://ruby-doc.org/core-2.0/Range.html
277 * However - where Ruby has one type "Range" - we have "Range" and DiscreteRange" - and some ruby Range methods/properties
278 * are expressed only in DiscreteRange<>. Also Stroika Range has openness as an optional/configurable
279 * feature of both endpoints, whereas in Ruby, the LHS is always closed and its RHS is optionally open.
280 *
281 * Note - you can do Range<float>, but cannot do DiscreteRange<float> - but can do DiscreteRange<int>.
282 *
283 * A note about an empty range. All empty ranges (of the same type) are equal to one another. It is illegal
284 * to ask for the start or end of an empty range. Empty ranges contain no points.
285 *
286 * It is illegal to call:
287 * Range<int>{1,1, Openness::eOpen, Openness::eOpen} since this would produce an empty range.
288 *
289 * Range<int>{1,1, Openness::eClosed, Openness::eClosed} != Range<int>{3,3, Openness::eClosed, Openness::eClosed}
290 * would be true, since neither is empty and they contain different points (1 vs 3).
291 *
292 * \note The default OPENNESS for Default varies by TYPE T. Integer and enums are both
293 * fully closed by default, and other arithmetic types (floats) are half open [)
294 *
295 * \note <a href="Design-Overview.md#Comparisons">Comparisons</a>:
296 * o Standard Stroika Comparison support (operator==, operator<=>, etc);
297 * o Depends on operator==/operator<=> being defined on T
298 *
299 * @see DiscreteRange
300 * @see DisjointRange
301 * @see DisjointDiscreteRange
302 */
303 template <IRangeable T, IRangeableTraits<T> TRAITS = RangeTraits::Default<T>>
304 class Range {
305 public:
306 /**
307 * \brief Range::value_type is the type of the contained elements of the range (say range of integers, value_type=int)
308 */
309 using value_type = T;
310
311 public:
312 /**
313 */
314 using TraitsType = TRAITS;
315
316 public:
317 /**
318 */
319 using SignedDifferenceType = typename TraitsType::SignedDifferenceType;
320
321 public:
322 /**
323 */
324 using UnsignedDifferenceType = typename TraitsType::UnsignedDifferenceType;
325
326 public:
327 /**
328 * Range{} creates an empty range (note all empty () ranges of the same type are equal to each other).
329 *
330 * optional values - if omitted - are replaced with the TRAITS::kLowerBound and TRAITS::kUpperBound values (as well as 'TRAITs' default openness).
331 * Constructors with actual numeric values (begin/end) MUST construct non-empty ranges (begin == end ==> both sides closed).
332 *
333 * \pre begin <= end (after substitution of optional values)
334 * \pre begin < end or LHS/RHS CLOSED (after substitution of optional values)
335 *
336 * \par Example Usage
337 * \code
338 * Range<double> r1{3, 5};
339 * Assert (r1.Contains (3) and not r1.Contains (3)); // because default arithmetic traits have [) half open
340 * Range<double> r2{ 3, 5, Openness::eOpen, Openness::eOpen };
341 * Assert (not r2.Contains (3));
342 * \endcode
343 */
344 constexpr explicit Range ();
345 template <typename T2, typename TRAITS2>
346 constexpr explicit Range (const Range<T2, TRAITS>& src);
347 constexpr explicit Range (Common::ArgByValueType<T> begin, Common::ArgByValueType<T> end);
348 constexpr explicit Range (const optional<T>& begin, const optional<T>& end);
349 constexpr explicit Range (Common::ArgByValueType<T> begin, Common::ArgByValueType<T> end, Openness lhsOpen, Openness rhsOpen);
350 constexpr explicit Range (const optional<T>& begin, const optional<T>& end, Openness lhsOpen, Openness rhsOpen);
351
352 public:
353 /**
354 * \brief Construct a new Range from this, but with the given start
355 * \pre start <= GetUpperBound ()
356 */
357 constexpr Range ReplaceStart (Common::ArgByValueType<T> start) const;
358
359 public:
360 /**
361 * \brief Construct a new Range from this, but with the given end
362 * \pre GetLowerBound () <= end
363 */
364 constexpr Range ReplaceEnd (Common::ArgByValueType<T> end) const;
365
366 public:
367 /**
368 * \brief returns a range centered around center, with the given radius (and optionally argument openness).
369 */
371 Openness lhsOpen = TRAITS::kLowerBoundOpenness, Openness rhsOpen = TRAITS::kUpperBoundOpenness);
372
373 public:
374 /**
375 * This returns begin>end? EMPTY else Range<T, TRAITS> (begin, end);
376 *
377 * The Range(begin/end) CTOR REQUIRES begin<=end). This does not, and just produces an empty range in that case.
378 */
380
381 public:
382 /**
383 * This returns Range{
384 * TraitsType::kLowerBound, TraitsType::kUpperBound,
385 * TraitsType::kLowerBoundOpenness, TraitsType::kUpperBoundOpenness
386 * };
387 */
388 static constexpr Range FullRange ();
389
390 public:
391 /**
392 * A Range is considered empty if it contains no points. If GetLowerBound () < GetUpperBound (),
393 * then clearly this is non-empty. If created with Range/0() - then the range this is empty.
394 *
395 * But if GetLowerBound () == GetUpperBound () - this is a trickier case. With both ends CLOSED -
396 * that means the GetLowerBound () value is contained in the range, so that is not empty.
397 *
398 * if GetLowerBound () == GetUpperBound (), and both ends open, then there are no points contained.
399 *
400 * But if GetLowerBound () == GetUpperBound (), and one one side is open, and the other closed,
401 * the one closed point endpoint is in the range, so the range is non-empty.
402 */
403 constexpr bool empty () const;
404
405 public:
406 /**
407 * \brief equivalent to not this->empty ();
408 */
409 constexpr explicit operator bool () const;
410
411 public:
412 /**
413 * GetUpperBound ()-GetLowerBound (), or distance from GetLowerBound () to end of the range.
414 * If this is empty (), then GetDistanceSpanned () will be zero but the GetDistanceSpanned CAN be zero without the
415 * range being empty (if both ends are closed).
416 *
417 * \note this just uses TraitsType::Difference ()
418 *
419 * \note For discrete Ranges, this does NOT correspond to the number of points (this is one less)
420 */
421 constexpr UnsignedDifferenceType GetDistanceSpanned () const;
422
423 public:
424 /**
425 * \pre not empty ()
426 */
427 constexpr T GetMidpoint () const;
428
429 public:
430 /**
431 * Compare v with the upper and lower bounds of this range, and return a value as close as
432 * possible to v but in range.
433 *
434 * If 'v' is not in range, and this Range is open, GetNext or GetPrevious maybe used to find a value
435 * in range.
436 *
437 * \pre not empty ()
438 *
439 * @see std::clamp
440 */
441 constexpr T Pin (T v) const
443
444 public:
445 /**
446 * This corresponds to the mathematical set containment. When comparing with the edges
447 * of the range, we check <= if the edge is closed, and < if the edge is open.
448 */
449 constexpr bool Contains (Common::ArgByValueType<T> r) const;
450 constexpr bool Contains (const Range& containee) const;
451
452 public:
453 /**
454 * Returns an identical Range to this, but including its end points.
455 *
456 * \pre not empty ();
457 */
458 nonvirtual constexpr Range Closure () const;
459
460 public:
461 /**
462 * \note All empty ranges (of the same type) are equal to each other.
463 */
464 constexpr bool operator== (const Range& rhs) const;
465
466 public:
467 /**
468 */
469 constexpr partial_ordering operator<=> (const Range& rhs) const;
470
471 public:
472 /**
473 * \brief Compute a less-like notion for Range.
474 *
475 * There is no clear way to provide an ordering of two ranges (of the same type). The ordering of their
476 * left sides, may not agree with the ordering of their right sides, or their midpoints.
477 *
478 * But - OFTEN - they CAN be ordered! And that's often a useful concept. So capture that case at least.
479 * Just return nullopt if not comparable. Then the caller can decide how to break the 'tie' - with midpoint compare, or
480 * left or right edge compares...
481 */
482 [[deprecated ("USE operator<==> - check <=> produces less (vs unordered) ")]] constexpr optional<bool> DefinitelyLessThan (const Range& rhs) const
483 {
484 return (*this <=> rhs) == partial_ordering::less;
485 }
486
487 public:
488 /**
489 * Returns true iff there are any points shared in common between this range and the rhs range.
490 *
491 * \par Example Usage
492 * \code
493 * using RT = Range<int>;
494 * constexpr auto eOpen = Openness::eOpen;
495 * constexpr auto eClosed = Openness::eClosed;
496 * Assert ((RT{1, 2}.Intersects (RT{1, 2})));
497 * Assert ((not RT{1, 2, eOpen, eOpen}.Intersects (RT{2, 3, eOpen, eOpen})));
498 * Assert ((not RT{1, 2, eOpen, eClosed}.Intersects (RT{2, 3, eOpen, eOpen})));
499 * Assert ((RT{1, 2, eOpen, eClosed}.Intersects (RT{2, 3, eClosed, eOpen})));
500 * \endcode
501 *
502 * \see operator^
503 */
504 template <typename T2, typename TRAITS2>
505 constexpr bool Intersects (const Range<T2, TRAITS2>& rhs) const;
506
507 public:
508 /**
509 * Compute the overlap/intersection between two ranges. The resulting range defines exactly the points in both places (so respects openness).
510 *
511 * @see operator^ - an operator alias for this function
512 */
513 constexpr Range Intersection (const Range& rhs) const;
514
515 public:
516 /**
517 * if two regions are disjoint, this can encompass a larger region than the actual union would
518 * \note really returns DisjointRange<>
519 */
520 nonvirtual auto Union (const Range& rhs) const;
521
522 public:
523 /**
524 * if two regions are disjoint, this can encompass a larger region than the actual union would
525 *
526 * \note See also Extend ();
527 * \note See also Union ();
528 */
529 constexpr Range UnionBounds (const Range& rhs) const;
530
531 public:
532 /**
533 * Construct a new range from this range, but including the given point
534 * Note that can produce a range with different openness from the starting range (as the points added close the endpoints).
535 *
536 * \note See also UnionBounds ();
537 */
538 constexpr Range Extend (Common::ArgByValueType<T> value) const;
539
540 public:
541 /**
542 * \pre not empty (); // special case - no upper/lower bound
543 */
544 constexpr T GetLowerBound () const;
545
546 public:
547 /**
548 */
549 constexpr Openness GetLowerBoundOpenness () const;
550
551 public:
552 /**
553 * \pre not empty (); // special case - no upper/lower bound
554 */
555 constexpr T GetUpperBound () const;
556
557 public:
558 /**
559 */
560 constexpr Openness GetUpperBoundOpenness () const;
561
562 public:
563 /**
564 * \pre not empty
565 * \pre the Range produced by applying the given offset to *this remains valid with respect to the constraints on this Range.
566 */
567 constexpr Range Offset (SignedDifferenceType o) const;
568
569 public:
570 /**
571 * \pre not empty
572 * \pre the Range produced by applying the given factor to the upper and lower bounds.
573 * \pre T has operator* (T,T) -> T defined
574 */
575 constexpr Range Times (T o) const;
576
577 public:
578 /**
579 * Print a displayable rendition of the given range, using the argument function to format
580 * the basic value_type.
581 *
582 * \par Example Usage
583 * \code
584 * Assert (Range<int>{3, 4}.ToString () == "[3 ... 4)");
585 * Assert (Range<int>{3, 4}.ToString ([] (int n) { return "{}"_f (n); }) == "[3 ... 4)");
586 * \endcode
587 *
588 * if the 'UpperBound' == kUpperBound, its not shown
589 *
590 * \par Example Usage
591 * \code
592 * Assert (Range<int>{3, nullopt}.ToString () == "[3 ... ]");
593 * \endcode
594 *
595 * Similarly for (only) LowerBound == kLowerBound
596 *
597 * \par Example Usage
598 * \code
599 * Assert (Range<int>{nullopt, 4}.ToString () == "[ ... 4]");
600 * \endcode
601 * @see Characters::ToString ();
602 */
603 nonvirtual Characters::String ToString (const function<Characters::String (const T&)>& elt2String = [] (const T& x) -> Characters::String {
604 return Characters::ToString (x);
605 }) const;
606
607 private:
608 T fBegin_;
609 T fEnd_;
610 Openness fBeginOpenness_;
611 Openness fEndOpenness_;
612 };
613 template <IRangeable T>
614 Range (T, T) -> Range<T, RangeTraits::Default<T>>;
615 template <IRangeable T>
616 Range (T, T, Openness, Openness) -> Range<T, RangeTraits::Default<T>>;
617 template <IRangeable T>
618 Range (optional<T>, optional<T>) -> Range<T, RangeTraits::Default<T>>;
619 template <IRangeable T>
620 Range (optional<T>, optional<T>, Openness, Openness) -> Range<T, RangeTraits::Default<T>>;
621
622 /**
623 */
624 template <typename RANGE_TYPE>
625 concept IRange = derived_from<RANGE_TYPE, Range<typename RANGE_TYPE::value_type, typename RANGE_TYPE::TraitsType>>;
626
627 /**
628 * Alias: T + RANGE => RANGE.Offset(T)
629 * Alias: RANGE + RANGE => RANGE.Union (RANGE)
630 */
631 template <IRangeable T, IRangeableTraits<T> TRAITS>
632 constexpr Range<T, TRAITS> operator+ (const T& lhs, const Range<T, TRAITS>& rhs);
633 template <IRangeable T, IRangeableTraits<T> TRAITS>
634 constexpr Range<T, TRAITS> operator+ (const Range<T, TRAITS>& lhs, const T& rhs);
635 template <IRangeable T, IRangeableTraits<T> TRAITS>
636 auto operator+ (const Range<T, TRAITS>& lhs, const Range<T, TRAITS>& rhs);
637
638 /**
639 * Alias: T * RANGE => RANGE.Times(T)
640 * \pre T has operator* (T,T) -> T defined
641 */
642 template <IRangeable T, IRangeableTraits<T> TRAITS>
643 constexpr Range<T, TRAITS> operator* (const T& lhs, const Range<T, TRAITS>& rhs);
644 template <IRangeable T, IRangeableTraits<T> TRAITS>
645 constexpr Range<T, TRAITS> operator* (const Range<T, TRAITS>& lhs, const T& rhs);
646
647 /**
648 * Alias for lhs.Intersection (rhs)
649 *
650 * \par Example Usage
651 * \code
652 * using RT = Range<int>;
653 * constexpr auto eOpen = Openness::eOpen;
654 * constexpr auto eClosed = Openness::eClosed;
655 * Assert ((RT{1, 2, eOpen, eClosed} ^ RT{2, 3, eClosed, eOpen}));
656 * Assert (((RT{1, 2, eOpen, eClosed} ^ RT{2, 3, eClosed, eOpen}) == RT{2,2,eClosed,eClosed}));
657 * \endcode
658 */
659 template <IRangeable T, IRangeableTraits<T> TRAITS>
660 constexpr Range<T, TRAITS> operator^ (const Range<T, TRAITS>& lhs, const Range<T, TRAITS>& rhs);
661
662}
663
664/*
665 ********************************************************************************
666 ******************************* Implementation Details *************************
667 ********************************************************************************
668 */
669#include "Range.inl"
670
671#endif /*_Stroika_Foundation_Traversal_Range_h_ */
String is like std::u32string, except it is much easier to use, often much more space efficient,...
Definition String.h:201
constexpr T Pin(T v) const
Definition Range.inl:174
constexpr optional< bool > DefinitelyLessThan(const Range &rhs) const
Compute a less-like notion for Range.
Definition Range.h:482
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
T value_type
Range::value_type is the type of the contained elements of the range (say range of integers,...
Definition Range.h:309
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
requirements for 'T' to use Range<T>.
Definition Range.h:45
String ToString(T &&t, ARGS... args)
Return a debug-friendly, display version of the argument: not guaranteed parsable or usable except fo...
Definition ToString.inl:465
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
This defines the default openness for a given type T, except for specializaitons. This is used by Exp...
Definition Range.h:88
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