9namespace Stroika::Foundation::Traversal {
16 template <
typename T,
typename OPENNESS,
typename DIFF_TYPE>
19 -> SignedDifferenceType
21 if constexpr (is_enum_v<T> or is_convertible_v<T, SignedDifferenceType>) {
22 return static_cast<SignedDifferenceType
> (rhs) -
static_cast<SignedDifferenceType
> (lhs);
25 return static_cast<SignedDifferenceType
> (rhs - lhs);
34 template <
typename T,
typename OPENNESS,
typename BOUNDS,
typename DIFF_TYPE>
36 requires (is_integral_v<T> or is_enum_v<T>)
38 Require (i != kUpperBound);
39 return static_cast<value_type
> (
static_cast<UnsignedDifferenceType
> (i) + 1);
41 template <
typename T,
typename OPENNESS,
typename BOUNDS,
typename DIFF_TYPE>
43 requires (is_floating_point_v<T>)
45 Require (i != kUpperBound);
46 return nextafter (i, kUpperBound);
48 template <
typename T,
typename OPENNESS,
typename BOUNDS,
typename DIFF_TYPE>
50 requires (is_integral_v<T> or is_enum_v<T>)
52 Require (i != kLowerBound);
53 return static_cast<value_type
> (
static_cast<SignedDifferenceType
> (i) - 1);
55 template <
typename T,
typename OPENNESS,
typename BOUNDS,
typename DIFF_TYPE>
57 requires (is_floating_point_v<T>)
59 Require (i != kLowerBound);
60 return nextafter (i, kLowerBound);
68 template <IRangeable T, IRangeableTraits<T> TRAITS>
70 : fBegin_{TRAITS::kUpperBound}
71 , fEnd_{TRAITS::kLowerBound}
72 , fBeginOpenness_{TRAITS::kLowerBoundOpenness}
73 , fEndOpenness_{TRAITS::kUpperBoundOpenness}
77 template <IRangeable T, IRangeableTraits<T> TRAITS>
78 template <
typename T2,
typename TRAITS2>
80 :
Range{src.GetLowerBound (), src.GetUpperBound (), src.GetLowerBoundOpenness (), src.GetUpperBoundOpenness ()}
83 template <IRangeable T, IRangeableTraits<T> TRAITS>
85 : Range{begin, end, TRAITS::kLowerBoundOpenness, TRAITS::kUpperBoundOpenness}
88 template <IRangeable T, IRangeableTraits<T> TRAITS>
90 : Range{begin.has_value () ? *begin : TRAITS::kLowerBound, end.has_value () ? *end : TRAITS::kUpperBound,
91 TRAITS::kLowerBoundOpenness, TRAITS::kUpperBoundOpenness}
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)
98 , fBeginOpenness_{lhsOpen}
99 , fEndOpenness_{rhsOpen}
101 Require (TRAITS::kLowerBound <= TRAITS::kUpperBound);
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 ());
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}
113 template <IRangeable T, IRangeableTraits<T> TRAITS>
116 Require (start <= GetUpperBound ());
117 return Range{start, GetUpperBound (), GetLowerBoundOpenness (), GetUpperBoundOpenness ()};
119 template <IRangeable T, IRangeableTraits<T> TRAITS>
122 Require (GetLowerBound () <= end);
123 return Range{GetLowerBound (), end, GetLowerBoundOpenness (), GetUpperBoundOpenness ()};
125 template <IRangeable T, IRangeableTraits<T> TRAITS>
129 return Range{center - radius, center + radius, lhsOpen, rhsOpen};
131 template <IRangeable T, IRangeableTraits<T> TRAITS>
137 template <IRangeable T, IRangeableTraits<T> TRAITS>
140 return Range{TraitsType::kLowerBound, TraitsType::kUpperBound, TraitsType::kLowerBoundOpenness, TraitsType::kUpperBoundOpenness};
142 template <IRangeable T, IRangeableTraits<T> TRAITS>
145 if (fBegin_ > fEnd_) {
149 else if (fBegin_ == fEnd_) {
150 return fBeginOpenness_ == Openness::eOpen and fEndOpenness_ == Openness::eOpen;
154 template <IRangeable T, IRangeableTraits<T> TRAITS>
159 template <IRangeable T, IRangeableTraits<T> TRAITS>
162 if (empty ()) [[unlikely]] {
163 return static_cast<UnsignedDifferenceType
> (0);
165 return static_cast<UnsignedDifferenceType
> (TraitsType::Difference (fBegin_, fEnd_));
167 template <IRangeable T, IRangeableTraits<T> TRAITS>
170 Require (not empty ());
171 return GetLowerBound () + GetDistanceSpanned () / 2;
173 template <IRangeable T, IRangeableTraits<T> TRAITS>
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)) {
181 T tmp{fBeginOpenness_ == Openness::eClosed ? fBegin_ : TraitsType::GetNext (fBegin_)};
182 Require (Contains (tmp));
185 else if (v > fEnd_ or (v == fEnd_ and fEndOpenness_ == Openness::eOpen)) {
187 T tmp{fEndOpenness_ == Openness::eClosed ? fEnd_ : TraitsType::GetPrevious (fEnd_)};
188 Require (Contains (tmp));
193 template <IRangeable T, IRangeableTraits<T> TRAITS>
199 if (fBegin_ < r and r < fEnd_) {
202 if (fBeginOpenness_ == Openness::eClosed and r == fBegin_) {
205 if (fEndOpenness_ == Openness::eClosed and r == fEnd_) {
210 template <IRangeable T, IRangeableTraits<T> TRAITS>
216 if (containee.
empty ()) {
227 switch (containee.GetLowerBoundOpenness ()) {
228 case Openness::eClosed:
233 case Openness::eOpen:
239 switch (containee.GetUpperBoundOpenness ()) {
240 case Openness::eClosed:
245 case Openness::eOpen:
252 template <IRangeable T, IRangeableTraits<T> TRAITS>
255 Require (not empty ());
256 return Range{GetLowerBound (), GetUpperBound (), Openness::eClosed, Openness::eClosed};
258 template <IRangeable T, IRangeableTraits<T> TRAITS>
259 template <
typename T2,
typename TRAITS2>
264 T mn = min (fEnd, rhs.fEnd);
265 T mx = max (fBegin, rhs.fBegin);
268 return rhs.GetUpperBoundOpenness () == eOpen or GetLowerBoundOpenness () == Openness::eClosed;
271 if consteval (I know
this is closed) {
272 ....
do optimized
case;
279 if (empty () or rhs.
empty ()) {
290 return Contains (l) and rhs.
Contains (l);
304 if (rhs.fEnd_ < fBegin_) {
305 Assert (oldCode (rhs) ==
false);
308 if (rhs.fBegin_ > fEnd_) {
309 Assert (oldCode (rhs) ==
false);
312 if (empty () or rhs.
empty ()) {
313 Assert (oldCode (rhs) ==
false);
316 if (rhs.fEnd_ == fBegin_) {
317 Assert (oldCode (rhs) == (rhs.GetUpperBoundOpenness () == Openness::eClosed and GetLowerBoundOpenness () == Openness::eClosed));
319 return rhs.GetUpperBoundOpenness () == Openness::eClosed and GetLowerBoundOpenness () == Openness::eClosed;
321 if (rhs.fBegin_ == fEnd_) {
322 Assert (oldCode (rhs) == (rhs.GetLowerBoundOpenness () == Openness::eClosed and GetUpperBoundOpenness () == Openness::eClosed));
324 return rhs.GetLowerBoundOpenness () == Openness::eClosed and GetUpperBoundOpenness () == Openness::eClosed;
326 Assert (oldCode (rhs) ==
true);
329 template <IRangeable T, IRangeableTraits<T> TRAITS>
332 if (empty () or rhs.
empty ()) {
335 T l = max (fBegin_, rhs.fBegin_);
336 T r = min (fEnd_, rhs.fEnd_);
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};
347 template <IRangeable T, IRangeableTraits<T> TRAITS>
352 template <IRangeable T, IRangeableTraits<T> TRAITS>
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};
370 Ensure (result.GetLowerBound () <= GetLowerBound ());
371 Ensure (result.GetLowerBound () <= GetUpperBound ());
374 Ensure (result.GetUpperBound () >= GetLowerBound ());
375 Ensure (result.GetUpperBound () >= GetUpperBound ());
380 template <IRangeable T, IRangeableTraits<T> TRAITS>
384 return Range{value, value, Openness::eClosed, Openness::eClosed};
386 if (value < GetLowerBound ()) {
387 return Range{value, GetUpperBound (), Openness::eClosed, GetUpperBoundOpenness ()};
389 if (GetUpperBound () < value) {
390 return Range{GetLowerBound (), value, GetLowerBoundOpenness (), Openness::eClosed};
394 template <IRangeable T, IRangeableTraits<T> TRAITS>
397 Require (not empty ());
400 template <IRangeable T, IRangeableTraits<T> TRAITS>
403 return fBeginOpenness_;
405 template <IRangeable T, IRangeableTraits<T> TRAITS>
408 Require (not empty ());
411 template <IRangeable T, IRangeableTraits<T> TRAITS>
414 return fEndOpenness_;
416 template <IRangeable T, IRangeableTraits<T> TRAITS>
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>
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>
435 else if (GetLowerBound () == GetUpperBound ()) {
437 out <<
"["sv << eltToString (GetLowerBound ()) <<
"]"sv;
440 out << ((GetLowerBoundOpenness () == Openness::eClosed) ?
"["sv :
"("sv);
441 if (GetLowerBound () != TRAITS::kLowerBound) {
442 out << eltToString (GetLowerBound ());
445 if (GetUpperBound () != TRAITS::kUpperBound) {
446 out << eltToString (GetUpperBound ());
448 out << ((GetUpperBoundOpenness () == Openness::eClosed) ?
"]"sv :
")"sv);
452 template <IRangeable T, IRangeableTraits<T> TRAITS>
459 GetLowerBoundOpenness () == rhs.GetLowerBoundOpenness () and GetUpperBoundOpenness () == rhs.GetUpperBoundOpenness ();
461 template <IRangeable T, IRangeableTraits<T> TRAITS>
468 if (GetUpperBoundOpenness () == eClosed and rhs.GetLowerBoundOpenness () == eClosed) {
470 return partial_ordering::less;
475 return partial_ordering::less;
482 if (GetLowerBoundOpenness () == eClosed and rhs.GetLowerBoundOpenness () == eClosed) {
484 return partial_ordering::greater;
489 return partial_ordering::greater;
493 return partial_ordering::equivalent;
503 return partial_ordering::unordered;
511 template <IRangeable T, IRangeableTraits<T> TRAITS>
516 template <IRangeable T, IRangeableTraits<T> TRAITS>
521 template <IRangeable T, IRangeableTraits<T> TRAITS>
524 return lhs.
Union (rhs);
527 template <IRangeable T, IRangeableTraits<T> TRAITS>
530 return rhs.
Times (lhs);
532 template <IRangeable T, IRangeableTraits<T> TRAITS>
535 return lhs.
Times (rhs);
538 template <IRangeable T, IRangeableTraits<T> TRAITS>
548 constexpr EnumNames<Traversal::Openness> DefaultNames<Traversal::Openness>::k{{{
549 {Traversal::Openness::eOpen, L
"Open"},
550 {Traversal::Openness::eClosed, L
"Closed"},
Similar to String, but intended to more efficiently construct a String. Mutable type (String is large...
nonvirtual String str() const
String is like std::u32string, except it is much easier to use, often much more space efficient,...
A DisjointRange is NOT a range, but a collection of non-overlapping (except at the edges) Ranges....
constexpr T Pin(T v) const
constexpr bool Contains(Common::ArgByValueType< T > r) const
static constexpr Range FullRange()
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).
constexpr Range Extend(Common::ArgByValueType< T > value) const
constexpr bool empty() const
constexpr Range Offset(SignedDifferenceType o) const
constexpr T GetUpperBound() const
constexpr Range Intersection(const Range &rhs) const
nonvirtual Characters::String ToString(const function< Characters::String(const T &)> &elt2String=[](const T &x) -> Characters::String { return Characters::ToString(x);}) const
constexpr bool Intersects(const Range< T2, TRAITS2 > &rhs) const
constexpr bool operator==(const Range &rhs) const
constexpr Range Times(T o) const
constexpr T GetLowerBound() const
constexpr Range ReplaceStart(Common::ArgByValueType< T > start) const
Construct a new Range from this, but with the given start.
constexpr Range UnionBounds(const Range &rhs) const
constexpr Range ReplaceEnd(Common::ArgByValueType< T > end) const
Construct a new Range from this, but with the given end.
constexpr T GetMidpoint() const
nonvirtual constexpr Range Closure() const
nonvirtual auto Union(const Range &rhs) const
static constexpr Range ContainedRange(Common::ArgByValueType< T > begin, Common::ArgByValueType< T > end)
constexpr UnsignedDifferenceType GetDistanceSpanned() const
requirements for 'T' to use Range<T>.
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.
static constexpr value_type GetPrevious(value_type i)
static constexpr value_type GetNext(value_type i)
static constexpr SignedDifferenceType Difference(Common::ArgByValueType< value_type > lhs, Common::ArgByValueType< value_type > rhs)