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 <
typename T,
typename TRAITS>
70 : fBegin_{TRAITS::kUpperBound}
71 , fEnd_{TRAITS::kLowerBound}
72 , fBeginOpenness_{TRAITS::kLowerBoundOpenness}
73 , fEndOpenness_{TRAITS::kUpperBoundOpenness}
77 template <
typename T,
typename TRAITS>
78 template <
typename T2,
typename TRAITS2>
80 :
Range{src.GetLowerBound (), src.GetUpperBound (), src.GetLowerBoundOpenness (), src.GetUpperBoundOpenness ()}
83 template <
typename T,
typename TRAITS>
85 : Range{begin, end, TRAITS::kLowerBoundOpenness, TRAITS::kUpperBoundOpenness}
88 template <
typename T,
typename TRAITS>
90 : Range{begin.has_value () ? *begin : TRAITS::kLowerBound, end.has_value () ? *end : TRAITS::kUpperBound,
91 TRAITS::kLowerBoundOpenness, TRAITS::kUpperBoundOpenness}
94 template <
typename T,
typename 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 <
typename T,
typename 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 <
typename T,
typename TRAITS>
116 Require (start <= GetUpperBound ());
117 return Range{start, GetUpperBound (), GetLowerBoundOpenness (), GetUpperBoundOpenness ()};
119 template <
typename T,
typename TRAITS>
122 Require (GetLowerBound () <= end);
123 return Range{GetLowerBound (), end, GetLowerBoundOpenness (), GetUpperBoundOpenness ()};
125 template <
typename T,
typename TRAITS>
129 return Range{center - radius, center + radius, lhsOpen, rhsOpen};
131 template <
typename T,
typename TRAITS>
135 return begin > end ?
Range{} :
Range{begin, end};
137 template <
typename T,
typename TRAITS>
140 return Range{TraitsType::kLowerBound, TraitsType::kUpperBound, TraitsType::kLowerBoundOpenness, TraitsType::kUpperBoundOpenness};
142 template <
typename T,
typename TRAITS>
145 if (fBegin_ > fEnd_) {
149 else if (fBegin_ == fEnd_) {
150 return fBeginOpenness_ == Openness::eOpen and fEndOpenness_ == Openness::eOpen;
154 template <
typename T,
typename TRAITS>
159 template <
typename T,
typename TRAITS>
162 if (empty ()) [[unlikely]] {
163 return static_cast<UnsignedDifferenceType
> (0);
165 return static_cast<UnsignedDifferenceType
> (TraitsType::Difference (fBegin_, fEnd_));
167 template <
typename T,
typename TRAITS>
170 Require (not empty ());
171 return GetLowerBound () + GetDistanceSpanned () / 2;
173 template <
typename T,
typename TRAITS>
176 Require (not empty ());
177 Assert (fBegin_ != fEnd_ or (fBeginOpenness_ == Openness::eClosed and fEndOpenness_ == Openness::eClosed));
178 if (v < fBegin_ or (v == fBegin_ and fBeginOpenness_ == Openness::eOpen)) {
180 T tmp{fBeginOpenness_ == Openness::eClosed ? fBegin_ : TraitsType::GetNext (fBegin_)};
181 Require (Contains (tmp));
184 else if (v > fEnd_ or (v == fEnd_ and fEndOpenness_ == Openness::eOpen)) {
186 T tmp{fEndOpenness_ == Openness::eClosed ? fEnd_ : TraitsType::GetPrevious (fEnd_)};
187 Require (Contains (tmp));
192 template <
typename T,
typename TRAITS>
198 if (fBegin_ < r and r < fEnd_) {
201 if (fBeginOpenness_ == Openness::eClosed and r == fBegin_) {
204 if (fEndOpenness_ == Openness::eClosed and r == fEnd_) {
209 template <
typename T,
typename TRAITS>
215 if (containee.
empty ()) {
226 switch (containee.GetLowerBoundOpenness ()) {
227 case Openness::eClosed:
232 case Openness::eOpen:
238 switch (containee.GetUpperBoundOpenness ()) {
239 case Openness::eClosed:
244 case Openness::eOpen:
251 template <
typename T,
typename TRAITS>
254 Require (not empty ());
255 return Range{GetLowerBound (), GetUpperBound (), Openness::eClosed, Openness::eClosed};
257 template <
typename T,
typename TRAITS>
258 template <
typename T2,
typename TRAITS2>
263 T mn = min (fEnd, rhs.fEnd);
264 T mx = max (fBegin, rhs.fBegin);
267 return rhs.GetUpperBoundOpenness () == eOpen or GetLowerBoundOpenness () == Openness::eClosed;
270 if consteval (I know
this is closed) {
271 ....
do optimized
case;
278 if (empty () or rhs.
empty ()) {
289 return Contains (l) and rhs.
Contains (l);
303 if (rhs.fEnd_ < fBegin_) {
304 Assert (oldCode (rhs) ==
false);
307 if (rhs.fBegin_ > fEnd_) {
308 Assert (oldCode (rhs) ==
false);
311 if (empty () or rhs.
empty ()) {
312 Assert (oldCode (rhs) ==
false);
315 if (rhs.fEnd_ == fBegin_) {
316 Assert (oldCode (rhs) == (rhs.GetUpperBoundOpenness () == Openness::eClosed and GetLowerBoundOpenness () == Openness::eClosed));
318 return rhs.GetUpperBoundOpenness () == Openness::eClosed and GetLowerBoundOpenness () == Openness::eClosed;
320 if (rhs.fBegin_ == fEnd_) {
321 Assert (oldCode (rhs) == (rhs.GetLowerBoundOpenness () == Openness::eClosed and GetUpperBoundOpenness () == Openness::eClosed));
323 return rhs.GetLowerBoundOpenness () == Openness::eClosed and GetUpperBoundOpenness () == Openness::eClosed;
325 Assert (oldCode (rhs) ==
true);
328 template <
typename T,
typename TRAITS>
331 if (empty () or rhs.
empty ()) {
334 T l = max (fBegin_, rhs.fBegin_);
335 T r = min (fEnd_, rhs.fEnd_);
338 Openness lhsO = Contains (l) and rhs.
Contains (l) ? Openness::eClosed : Openness::eOpen;
339 Openness rhsO = Contains (r) and rhs.
Contains (r) ? Openness::eClosed : Openness::eOpen;
340 if (l != r or (lhsO == Openness::eClosed and rhsO == Openness::eClosed)) {
341 return Range{l, r, lhsO, rhsO};
346 template <
typename T,
typename TRAITS>
351 template <
typename T,
typename TRAITS>
365 Openness lhsO = Contains (l) and rhs.
Contains (l) ? Openness::eClosed : Openness::eOpen;
366 Openness rhsO = Contains (r) and rhs.
Contains (r) ? Openness::eClosed : Openness::eOpen;
367 result =
Range{l, r, lhsO, rhsO};
379 template <
typename T,
typename TRAITS>
383 return Range{value, value, Openness::eClosed, Openness::eClosed};
385 if (value < GetLowerBound ()) {
386 return Range{value, GetUpperBound (), Openness::eClosed, GetUpperBoundOpenness ()};
388 if (GetUpperBound () < value) {
389 return Range{GetLowerBound (), value, GetLowerBoundOpenness (), Openness::eClosed};
393 template <
typename T,
typename TRAITS>
396 Require (not empty ());
399 template <
typename T,
typename TRAITS>
402 return fBeginOpenness_;
404 template <
typename T,
typename TRAITS>
407 Require (not empty ());
410 template <
typename T,
typename TRAITS>
413 return fEndOpenness_;
415 template <
typename T,
typename TRAITS>
418 Require (not empty ());
419 return Range{
static_cast<T
> (GetLowerBound () + o),
static_cast<T
> (GetUpperBound () + o), GetLowerBoundOpenness (), GetUpperBoundOpenness ()};
421 template <
typename T,
typename TRAITS>
424 Require (not empty ());
425 return Range{
static_cast<T
> (GetLowerBound () * o),
static_cast<T
> (GetUpperBound () * o), GetLowerBoundOpenness (), GetUpperBoundOpenness ()};
427 template <
typename T,
typename TRAITS>
434 else if (GetLowerBound () == GetUpperBound ()) {
436 out <<
"["sv << eltToString (GetLowerBound ()) <<
"]"sv;
439 out << ((GetLowerBoundOpenness () == Openness::eClosed) ?
"["sv :
"("sv);
440 if (GetLowerBound () != TRAITS::kLowerBound) {
441 out << eltToString (GetLowerBound ());
444 if (GetUpperBound () != TRAITS::kUpperBound) {
445 out << eltToString (GetUpperBound ());
447 out << ((GetUpperBoundOpenness () == Openness::eClosed) ?
"]"sv :
")"sv);
451 template <
typename T,
typename TRAITS>
458 GetLowerBoundOpenness () == rhs.GetLowerBoundOpenness () and GetUpperBoundOpenness () == rhs.GetUpperBoundOpenness ();
460 template <
typename T,
typename TRAITS>
467 if (GetUpperBoundOpenness () == eClosed and rhs.GetLowerBoundOpenness () == eClosed) {
469 return partial_ordering::less;
474 return partial_ordering::less;
481 if (GetLowerBoundOpenness () == eClosed and rhs.GetLowerBoundOpenness () == eClosed) {
483 return partial_ordering::greater;
488 return partial_ordering::greater;
492 return partial_ordering::equivalent;
502 return partial_ordering::unordered;
510 template <
typename T,
typename TRAITS>
515 template <
typename T,
typename TRAITS>
520 template <
typename T,
typename TRAITS>
521 DisjointRange<T, Range<T, TRAITS>> operator+ (
const Range<T, TRAITS>& lhs,
const Range<T, TRAITS>& rhs)
523 return lhs.
Union (rhs);
526 template <
typename T,
typename TRAITS>
529 return rhs.
Times (lhs);
531 template <
typename T,
typename TRAITS>
532 constexpr Range<T, TRAITS> operator* (
const Range<T, TRAITS>& lhs,
const T& rhs)
534 return lhs.
Times (rhs);
537 template <
typename T,
typename TRAITS>
547 constexpr EnumNames<Traversal::Openness> DefaultNames<Traversal::Openness>::k{{{
548 {Traversal::Openness::eOpen, L
"Open"},
549 {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 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.
nonvirtual DisjointRange< T, Range > Union(const Range &rhs) const
constexpr T GetMidpoint() const
constexpr T Pin(T v) const
nonvirtual constexpr Range Closure() const
static constexpr Range ContainedRange(Common::ArgByValueType< T > begin, Common::ArgByValueType< T > end)
constexpr UnsignedDifferenceType GetDistanceSpanned() const
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)