1#ifndef FIBEROPERATIONS_RANGE_HPP
2#define FIBEROPERATIONS_RANGE_HPP 20241206
4#include <field/MemBase.hpp>
5#include <grid/Representation.hpp>
6#include <memcore/typemap.hpp>
7#include <memcore/Profiler.hpp>
9#include <field/DirectProductArray.hpp>
16#include "RangeBase.hpp"
22template <
typename Type>
23void computeRangeIt(Type&MinValue, Type&MaxValue,
const Iterator<Type>&
Data)
28const int max_threads_possible = omp_get_max_threads();
36 for(
int i=0; i<max_threads_possible; i++)
45 Type localMin =
Data[0];
46 Type localMax =
Data[0];
50 for(index_t i = 1; i<
count ; i++)
52 const Type&value =
Data[i];
53 if (value < localMin) localMin = value;
54 if (value > localMax) localMax = value;
57 const int my_thread_id = omp_get_thread_num();
59 minList[my_thread_id] = localMin;
60 maxList[my_thread_id] = localMax;
62 valueFound[my_thread_id] = 1;
69 for(
int i=0; i<max_threads_possible; i++)
71 if( valueFound[i] == 1 )
73 if( minList[i] < MinValue ) MinValue = minList[i];
74 if( maxList[i] > MaxValue ) MaxValue = maxList[i];
79 for(index_t i=1; i<
count ; i++)
81 const Type&value =
Data[i];
82 if (value < MinValue) MinValue = value;
83 if (value > MaxValue) MaxValue = value;
90void computeRange(T&MinValue, T&MaxValue,
const T*
Data,
size_t size)
94 MinValue = MaxValue =
Data[0];
98 T local_min =
Data[0],
101#pragma omp for nowait
102 for (
size_t i = 1; i <
size; ++i)
104 if (
Data[i] < local_min) local_min =
Data[i];
105 if (
Data[i] > local_max) local_max =
Data[i];
108#pragma omp critical(RangeComputation)
110 if (local_min < MinValue) MinValue = local_min;
111 if (local_max > MaxValue) MaxValue = local_max;
114 RangeVerbose(20) <<
"Compute Scalar Range resulting in " << MinValue <<
" - " << MaxValue;
117template <
typename T,
typename index_t>
121 if (!index_array.
size())
return;
123 MinValue = MaxValue =
Data[ index_array[0] ];
127 T local_min =
Data[ index_array[0] ],
128 local_max =
Data[ index_array[0] ];
130#pragma omp for nowait
131 for (
size_t I = 1; I < index_array.size(); ++I)
133 auto i = index_array[I];
135 if (
Data[i] < local_min) local_min =
Data[i];
136 if (
Data[i] > local_max) local_max =
Data[i];
139#pragma omp critical(RangeComputation)
141 if (local_min < MinValue) MinValue = local_min;
142 if (local_max > MaxValue) MaxValue = local_max;
149template <
typename T, Eagle::dimension_t N>
155 MinValue = MaxValue =
Data[0];
157#pragma omp parallel num_threads(1)
163#pragma omp for nowait
164 for (
size_t i = 1; i <
size; ++i)
166 for(Eagle::dimension_t j = 0; j<N; j++)
168 if (
Data[i][j] < local_min[j]) local_min[j] =
Data[i][j];
169 if (
Data[i][j] > local_max[j]) local_max[j] =
Data[i][j];
174#pragma omp critical(RangeComputation)
176 for(Eagle::dimension_t i = 0; i<N; i++)
178 if (local_min[i] < MinValue[i]) MinValue[i] = local_min[i];
179 if (local_max[i] > MaxValue[i]) MaxValue[i] = local_max[i];
184 RangeVerbose(20) <<
"Compute Range FixedArray<" << N <<
">: resulting in " << MinValue <<
" - " << MaxValue;
187template <
typename T, Eagle::dimension_t N,
typename index_t>
193 if (!index_array.
size())
return;
195 MinValue = MaxValue =
Data[ index_array[0] ];
200 local_min =
Data[ index_array[0] ],
201 local_max =
Data[ index_array[0] ];
203#pragma omp for nowait
204 for (
size_t I = 1; I < index_array.size(); ++I)
206 auto i = index_array[I];
207 for(Eagle::dimension_t j = 0; j<N; j++)
209 if (
Data[i][j] < local_min[j]) local_min[j] =
Data[i][j];
210 if (
Data[i][j] > local_max[j]) local_max[j] =
Data[i][j];
215#pragma omp critical(RangeComputation)
217 for(Eagle::dimension_t i = 0; i<N; i++)
219 if (local_min[i] < MinValue[i]) MinValue[i] = local_min[i];
220 if (local_max[i] > MaxValue[i]) MaxValue[i] = local_max[i];
228template <
typename T, Eagle::dimension_t N>
237template <
typename Type>
240 computeRange(MinValue, MaxValue,
Data.data(),
Data.size() );
243template <
typename Type,
typename index_t>
246 computeIndexedRange(MinValue, MaxValue,
Data.data(),
Data.size(), index_array );
256template <
class Type,
class OtherType>
263template <
class Type,
class OtherType>
264inline bool contains_value(
const Type&Minimum,
const Type&Maximum,
const OtherType&Value)
266 if (Value<Minimum)
return false;
267 if (Value>Maximum)
return false;
281static type convert(
const T&t)
289#if (__cplusplus > 201703L)
297#define HAVE_DerivedFromFixedArray_concept
299template <DerivedFromFixedArray Type, DerivedFromFixedArray OtherType>
300requires (Type::size() == OtherType::size())
302 const OtherType&OtherMinimum,
const OtherType&OtherMaximum)
304constexpr auto N = Minimum.size();
305 for(Eagle::dimension_t i = 0; i<N; i++)
307 if (Minimum[i] > OtherMinimum[i]) Minimum[i] = OtherMinimum[i];
308 if (Maximum [i]< OtherMaximum[i]) Maximum[i] = OtherMaximum[i];
312template <DerivedFromFixedArray Type>
315 computeRange(MinValue.getFixedArray(), MaxValue.getFixedArray(),
Data.data(),
Data.size() );
319template <DerivedFromFixedArray Type,
typename index_t>
322 computeIndexedRange(MinValue.getFixedArray(), MaxValue.getFixedArray(),
Data.data(),
Data.size(), index_array );
326template <DerivedFromFixedArray Type, DerivedFromFixedArray OtherType>
327requires (Type::size() == OtherType::size())
328inline bool contains_value(
const Type&Minimum,
const Type&Maximum,
const OtherType&Value)
330constexpr auto N = Minimum.size();
332 for(Eagle::dimension_t i = 0; i<N; i++)
334 if (Value[i] < Minimum[i])
return false;
335 if (Value[i] > Maximum[i])
return false;
348template <DerivedFromFixedArray T>
349struct Range_as_FloatVersion<T>
351 using type = FixedArray<double, T::size() >;
353static type convert(
const T&t)
356 for(
size_t i=0; i<T::size(); i++)
366inline auto ComputeRangeFromDirectProduct(
const RefPtr<MemBase>&ArrayBase)
372inline auto ComputeRangeFromDirectProduct<Eagle::point3>(
const RefPtr<MemBase>&ArrayBase);
384 Type&Minimum() {
return (*
this)[0]; }
385 Type&Maximum() {
return (*
this)[1]; }
387 const Type&Minimum()
const {
return (*
this)[0]; }
388 const Type&Maximum()
const {
return (*
this)[1]; }
410 ~DataRange()
override
429 float_version::convert(
Min() ),
430 float_version::convert(
Max() ) );
443 template <
class OtherType>
445 :
std::
array<Type, 2>{ DR.Min(), DR.Max() }
449 template <
class OtherType>
468 template <
class CompareType>
471 return contains_value( Minimum(), Maximum(), Value);
491 << CAB.getFirstProvenancePath() <<
" --> "
492 << myChunk[0] <<
" - " << myChunk[1]
493 <<
" Creator Age: " << CAB.
getAge()
494 <<
" DataRange Age: " << DR->getAge()
505 RangeVerbose(31) <<
"set_from_attribute("
506 << CAB.getFirstProvenancePath() <<
" --> " << DR->str()
507 <<
" range age " << DR->getAge()
508 <<
" CAB age " << CAB.
getAge()
516 RangeVerbose(14) <<
"set_from_attribute() did not find a Range attribute on " << CAB.getFirstProvenancePath();
528 if (F.AttributeModificationAge.isOlderThan(F))
535 return new DataRange(F, myChunk[0], myChunk[1] );
550static RefPtr<DataRange> get_cached_range_if_older_than_data(
const CreativeArrayBase&CAB)
552 if (RefPtr<DataRange> DR = interface_cast<DataRange>(CAB) )
554 if (CAB.isNewerThan(*DR))
573 RangeVerbose(21) <<
"get_range_if_older_than_data(): Have Range Interface on " << CAB.getFirstProvenancePath() <<
" --> " << DR->str();
579 RangeVerbose(21) <<
"get_range_if_older_than_data(): GOT Range attribute on " << CAB.getFirstProvenancePath() <<
" --> " << DR->str();
581 Assert( !DR->isOlderThan( CAB ) );
585 RangeVerbose(13) <<
"get_range_if_older_than_data(): No Range Interface on " << CAB.getFirstProvenancePath()
606 if ( !DR->isOlderThan( F ) )
634 if ( !DR->isOlderThan( F ) )
639 RangeVerbose(10) <<
"Getting range from field attribute.";
669 RangeVerbose(5) <<
" Computing the range based on std::vector<"
688 RangeVerbose(5) <<
" NO TypedArray data...";
692 RangeVerbose(11) <<
" GET creative iterator...";
695 if (!values
or !*values )
699 if (!
Data)
return nullptr;
715 RangeVerbose(5) <<
" Computing the range based on Iterator<"
724 template <
typename index_t>
751 return compute_indexed_range(ArrayBase, index_array);
756 return compute_indexed_range(ArrayBase, index_array);
768 Verbose(0) <<
" Creator type "
770 <<
" does not match field type "
772 <<
" , cannot compute range";
780 RangeVerbose(0) <<
"Range CANNOT determine data type of creator fragment without loading it, no fiber type available - bailing out!";
799 myChunk[0]= DR->Minimum();
800 myChunk[1]= DR->Maximum();
802 CAB.updateAttributeAge( *DR );
804 RangeVerbose(11) <<
" Setting attribute " << RangeAttributeName
805 <<
" to {" << DR->Minimum() <<
"," << DR->Maximum() <<
"}"
806 <<
" on " << CAB.getFirstProvenancePath()
808 RangeVerbose(12) <<
" Ages for " << CAB.getFirstProvenancePath()
809 <<
" CAB: " << CAB.
getAge()
811 <<
" Range: " << DR->getAge()
836 RangeVerbose(15) <<
" Range is not computed because data are not available in RAM for "
837 << CAB.getFirstProvenancePath();
843 RangeVerbose(15) <<
" returning for now as asynch loading request."
844 << CAB.getFirstProvenancePath();
851 RangeVerbose(1) <<
" WARNING: Need to LOAD data for range computation on " << CAB.getFirstProvenancePath();
855 RangeVerbose(1) <<
" PROBLEM: Could not LOAD data for range computation on " << CAB.getFirstProvenancePath();
861 RangeVerbose(9) <<
" Need to COMPUTE range @"
862 << CAB.getFirstProvenancePath();
867 RangeVerbose(10) <<
" NO data range, removing " << RangeAttributeName
868 <<
" from " << CAB.getFirstProvenancePath();
869 CAB.removeAttribute( RangeAttributeName );
888 RangeVerbose(40) <<
" Got Range attribute " << DR->getAge();
892 RangeVerbose(16) <<
"DataRange> retrieve(): "
893 << CAB.getFirstProvenancePath() <<
" NO valid data range available"
894 <<
" CAB age " << CAB.
getAge()
912static bool expand_range(
RefPtr<DataRange<Type> >&GlobalRange,
913 const RefPtr<DataRange<Type> >&LocalRange)
915 MEMCORE_PROFILE_THIS(
"FieldRange: expand()", 7);
921 GlobalRange =
new DataRange<Type>( *LocalRange );
923 GlobalRange->expand( *LocalRange );
929static bool compute_and_expand_range(
RefPtr<DataRange<Type> >&GlobalRange,
931 bool theAsynchRequest,
bool theAvoidDataLoading )
940 MEMCORE_PROFILE_THIS(
"FieldRange: call retrieve()", 7);
944 MEMCORE_PROFILE_THIS(
"FieldRange: call expand_range()", 7);
945 return expand_range(GlobalRange, FragmentRange);
948static void computeRangeOnAvailableFragments(Field&F,
bool RequestToLoadMore =
false)
950 DataRangeBase::computeRangeOnAvailableFragments(F,
952 &get_range_if_older_than_creator_data,
963 Verbose(1) <<
"Field::retrieve() without type information!";
967 const type_info&FieldType = F.getElementType();
968 if ( FieldType !=
typeid(Type))
971 MEMCORE_PROFILE_THIS(
"FieldRange: retrieve", 6);
973 bool need_to_compute_field_range = DataRangeBase::need_to_recompute(F);
1022 if (theRange and not need_to_compute_field_range)
1024 RangeVerbose(10) <<
" FieldRange for ["
1026 <<
"] got OLD (but still valid) range "
1028 <<
" with age " << theRange->getAge()
1036 MEMCORE_PROFILE_THIS(
"FieldRange: check", 6);
1038 RangeVerbose(9) <<
" FieldRange COMPUTE for ["
1041 <<
" Field Age: " << F.getAge()
1042 <<
" Newest Field Creator: " << F.getMostRecentCreatorAge()
1043 <<
" Newest Field Fragment Attribute: " << F.getMostRecentAttributeAge()
1047 RangeVerbose(9) <<
" Old Range: " << *theRange
1048 <<
" of age " << theRange->getAge();
1051 MEMCORE_PROFILE_THIS(
"FieldRange: compute", 6);
1054 MEMCORE_PROFILE_THIS(
"FieldRange: compute available", 7);
1055 computeRangeOnAvailableFragments(F);
1058 unsigned IncompleteRangeFragments = 0;
1061 {MEMCORE_PROFILE_THIS(
"FieldRange: expand", 7);
1066 F.iterate( [&theRange, theAsynchRequest,theAvoidDataLoading, &IncompleteRangeFragments]
1069 if (!cab)
return true;
1075 MEMCORE_PROFILE_THIS(
"FieldRange: call compute_and_expand()", 7);
1076 if (!compute_and_expand_range(theRange, f, cab,
1077 theAsynchRequest, theAvoidDataLoading))
1079 IncompleteRangeFragments++;
1084 RangeVerbose(13) <<
" Expanded FieldRange to " << theRange->str() <<
" from " << cab->getFirstProvenancePath();
1086 RangeVerbose(13) <<
" no field range so far.";
1093 RangeVerbose(10) <<
" iterated FieldRange "<<Nfrags<<
" fragments for ["
1096 << IncompleteRangeFragments
1097 <<
" incomplete fragments (no data there)";
1102 MEMCORE_PROFILE_THIS(
"FieldRange: Set Range attribute", 7);
1104 F.addInterface( theRange );
1107 myChunk[0]= theRange->Min();
1108 myChunk[1]= theRange->Max();
1109 F.setAttribute( RangeAttributeName, myChunk);
1111 setRangeCompleteness(F, Nfrags, IncompleteRangeFragments );
1114 F.updateAttributeAge( *theRange );
1116 RangeVerbose(11) <<
" Field: Set computed Range to " << theRange->str()
1117 <<
" with age " << theRange->getAge()
1118 <<
" to Field of attribute age " << F.getAttributeAge()
1124 RangeVerbose(12) <<
" No Range was computed for this field";
1138 F.addInterface( theRange );
1140 theRange->setInfinitelyNew();
1142 theRange->update( F );
1145 myChunk[0]= theRange->Min();
1146 myChunk[1]= theRange->Max();
1147 F.setAttribute( RangeAttributeName, myChunk);
1149 setRangeCompleteness(F, 0, 0);
1152 F.updateAttributeAge( *theRange );
1154 RangeVerbose(11) <<
" Field: Set specified Range to " << theRange->str()
1155 <<
" with age " << theRange->getAge();
1171 myChunk[0]= DR->Minimum();
1172 myChunk[1]= DR->Maximum();
1174 CAB.updateAttributeAge( *DR );
1181#if (__cplusplus > 201703L)
1184inline auto ComputeRangeFromDirectProduct<Eagle::point3>(
const RefPtr<MemBase>&ArrayBase)
1189 if (
RefPtr<DirectProductMemArray<Eagle::point3> > DM = ArrayBase)
1191 auto Start = DM->first(),
1194 retval =
new DataRange<Eagle::point3>(Start, End);
1209template <
class Type>
1221template <
class Type>
1233template <
class Type>
1235[[deprecated(
"Use DataRange<Type> instead of ComputeRange<Type> ")]]
1251 [[deprecated(
"Use range = DataRange<Type>::retrieve() instead")]]
1261 [[deprecated(
"Use range = DataRange<Type>::retrieve() instead")]]
1271template <
class Type>
1272inline bool Contains(CreativeArrayBase&CAB,
const Type&Value,
bool ComputeEventually)
1274 if (ComputeEventually)
1278 return DR->contains( Value );
1283 if (
RefPtr<DataRange<Type> > DR = DataRange<Type>::get(CAB) )
1285 return DR->contains( Value );
1288 throw DataRangeBase::NoDataRange();
1295template <
typename... Type>
1314template <
typename... Type>
1357template <
typename... Type>
1378template <
typename First,
typename... MoreTypes>
1379[[deprecated(
"this function is for educational purposes only")]]
1387 if constexpr (
sizeof...(MoreTypes) > 0)
typename enable_if< _Cond, _Tp >::type enable_if_t
valarray< size_t > size() const
constexpr iterator_traits< _InputIterator >::difference_type count(_InputIterator __first, _InputIterator __last, const _Tp &__value)
basic_string< char > string
constexpr size_type size() const noexcept
Base class for multidimensional arrays that employ deferred storage, i.e.
Definition CreativeArrayBase.hpp:75
An iterator with an optional DataCreator, which is just a class to intercept creation of data along a...
Definition CreativeIterator.hpp:34
A Field is a collection of CreativeArrayBase reference pointers which are accessed via FragmentID obj...
Definition Field.hpp:245
bool isOlderThan(const Ageable &a) const noexcept
constexpr const Ageable & getAge() const
age_t update(age_t age) noexcept
void setAttribute(const std::string &name, const MemCore::RefPtr< MemCore::ChunkBase > &AttribData)
const Ageable & getAttributeAge() const
MemCore::RefPtr< MemCore::ChunkBase > getAttribute(const std::string &name) const
virtual bool request(const result &R=nullptr)
virtual RefPtr< Domain > get() const=0
RefPtr< Domain > create(bool CreateAsOld=false)
void addInterface(const RefPtr< InterfaceBase > &I) const
MEMCORE_API std::string Typename(const std::type_info &t)
Given a fragmented field of curvilinear coordinates, (3D array of coordinates), build a uniform Grid ...
Definition FAQ.dox:2
RefPtr< DataRangeBase > getTypedFragmentRange(CreativeArrayBase &CAB, bool AsynchRequest, bool theAvoidDataLoading, const RefPtr< MemBase > &PossibleData=nullptr)
{
Definition Range.hpp:1297
void expand_by_other_minmax(Type &Minimum, Type &Maximum, const OtherType &OtherMinimum, const OtherType &OtherMaximum)
Expand a range by a given type, which must be convertible.
Definition Range.hpp:257
RefPtr< DataRangeBase > getFragmentRange(CreativeArrayBase &CAB, bool AsynchRequest, bool theAvoidDataLoading, const RefPtr< MemBase > &PossibleData)
TODO: Go via a type registry.
Definition Range.cpp:18
RefPtr< DataRangeBase > recursive_getTypedRange(Field &F, bool AsynchRequest, bool theAvoidDataLoading)
An alternative version of getTypedRange() which does not rely on a fold expression and achieves the s...
Definition Range.hpp:1381
RefPtr< DataRangeBase > getTypedFieldRange(Field &F, bool AsynchRequest, bool theAvoidDataLoading)
Get the range of a field by iterating over a list of types.
Definition Range.hpp:1359
std::string to_string(const span< char > &s)
string to_string(const Eagle::FixedArray< ElementType, N > &A, const char *OpenBrace="{", const char *CloseBrace="}", const char *Separator=",")
A class to compute the range of fields or field fragments.
Definition Range.hpp:1237
ComputeRange(Field &F, bool theAsynchRequest, bool theAvoidDataLoading=false)
Compute the range of an entire field.
Definition Range.hpp:1262
ComputeRange(Field &F, const RefPtr< FragmentID > &f, bool theAsynchRequest, bool theAvoidDataLoading)
Compute the range of a single fragment within a field.
Definition Range.hpp:1252
Base class for ranges that can be attached to Creators.
Definition RangeBase.hpp:33
DataRangeBase()
Constructor, age will be youngest.
Definition RangeBase.cpp:8
Class for ranges of types, such as minimum/maximum.
Definition Range.hpp:379
static RefPtr< DataRange > retrieve(CreativeArrayBase &CAB, bool AsynchRequest=false, bool AvoidDataLoading=false, const RefPtr< MemBase > &PossibleData=nullptr)
Provide a data range on a given CreativeArrayBase from the attribute, if such exists and is older tha...
Definition Range.hpp:880
RefPtr< DataRangeBase > getFloatRange() const override
Always double precison!
Definition Range.hpp:426
static RefPtr< DataRange > get_cached_range(const Field &F)
Get any range information that is available from the Field, used e.g.
Definition Range.hpp:618
void expand(const DataRange< OtherType > &DR)
Expand the range by a given type, which must be convertible.
Definition Range.hpp:450
RefPtr< DataRange< Type > > setCreatorRange(CreativeArrayBase &CAB, const Type &Min, const Type &Max)
Set the range information on a data Creator with type information as provided implicitly by the type ...
Definition Range.hpp:1222
static RefPtr< DataRange > compute_range(const RefPtr< MemBase > &ArrayBase, const string &ProvenancePath)
Perform an actual computation of the range.
Definition Range.hpp:648
void expandRange(const RefPtr< DataRangeBase > &DRB) override
Expand range by same type.
Definition Range.hpp:457
DataRange()
Default constructor, no initializiation.
Definition Range.hpp:392
static RefPtr< DataRangeBase > compute_range_and_set_attribute(CreativeArrayBase &CAB, const RefPtr< MemBase > &ArrayBase)
unconditionally compute: Overwrites a given attribute or interface.
Definition Range.hpp:791
DataRange(const DataRange< OtherType > &DR)
Initialize the range by a given type, which must be convertible.
Definition Range.hpp:444
static RefPtr< DataRange > get_range_if_older_than_field(Field &F)
Get a cached range from the Field if the data are older or than the range.
Definition Range.hpp:630
bool contains(const CompareType &Value) const
Check if certain value is contained here.
Definition Range.hpp:469
static bool creator_has_compatible_type(CreativeArrayBase &CAB)
Definition Range.hpp:760
static RefPtr< DataRange< Type > > setFieldRange(Field &F, const Type &Min, const Type &Max, bool Unchangeable=false)
Set, and overwrite, and explicit range attribute on a Field.
Definition Range.hpp:1135
RefPtr< DataRange< Type > > setFieldRange(Field &F, const Type &Min, const Type &Max)
Set the range information on a field with type information as provided implicitly by the type of the ...
Definition Range.hpp:1210
const Type & Max() const
The maximum.
Definition Range.hpp:420
DataRange(const Ageable &Age, const Type &min, const Type &max)
Initialize constructor age (may be important!!) with min and max.
Definition Range.hpp:405
DataRange(const Type &min, const Type &max)
Initialize constructor with min and max.
Definition Range.hpp:396
static RefPtr< DataRange > get_cached_range_if_older_than_field(const Field &F)
Get a cached range from the Field if the data are older or than the range.
Definition Range.hpp:602
static RefPtr< DataRange< Type > > setCreatorRange(CreativeArrayBase &CAB, const Type &Min, const Type &Max)
Set, and overwrite, and explicit range attribute on a Creator.
Definition Range.hpp:1164
static RefPtr< DataRange > get_attribute(const Field &F)
Get the range attribute for a Field if the attributes are valid, i.e.
Definition Range.hpp:526
static RefPtr< DataRange > get_attribute(const CreativeArrayBase &CAB)
Get the range attribute for a Fragment's Creator if the attributes are valid, i.e.
Definition Range.hpp:479
static RefPtr< DataRange > possibly_compute_and_set_attribute(CreativeArrayBase &CAB, bool AsynchRequest, bool AvoidDataLoading, const RefPtr< MemBase > &PossibleData)
Ignore an existing Range attribute and try to compute the Range newly if the data are available (and ...
Definition Range.hpp:825
static RefPtr< DataRange > get_range_if_older_than_data(CreativeArrayBase &CAB)
Get a cached range from the creative array if the data are older or than the range.
Definition Range.hpp:566
const Type & Min() const
The minimum.
Definition Range.hpp:414
Definition Range.hpp:1330
Type trait class to help DataRange<T> .
Definition Range.hpp:278