27template <std::
integral T>
29 return ((step == T{0} && beg != end) ||
30 (beg < end && step <= T{0}) ||
31 (beg > end && step >= T{0}));
70template <std::
integral T>
71constexpr size_t distance(T beg, T end, T step) {
72 if constexpr (std::is_unsigned_v<T>) {
74 return static_cast<size_t>((end - beg + step - T{1}) / step);
77 return static_cast<size_t>((end - beg + step + (step > T{0} ? T{-1} : T{1})) / step);
92template <std::
integral T,
size_t N = 1>
164template <std::
integral T,
size_t N>
177 static constexpr size_t rank = N;
227 template <
typename... Ranges>
228 requires (
sizeof...(Ranges) == N) &&
231 : _dims{ std::forward<Ranges>(ranges)... } {}
355 const std::array<IndexRange<T, 1>, N>&
dims()
const {
return _dims; }
396 size_t size(
size_t d)
const {
return _dims[d].size(); }
507 std::pair<IndexRange<T, N>,
size_t>
slice_ceil(
size_t flat_beg,
size_t chunk_size)
const;
561 std::pair<IndexRange<T, N>,
size_t>
slice_floor(
size_t flat_beg,
size_t chunk_size)
const;
603 size_t ceil(
size_t chunk_size)
const;
644 size_t floor(
size_t chunk_size)
const;
648 std::array<IndexRange<T, 1>, N> _dims;
655template <std::
integral T,
size_t N>
658template <std::
integral T,
size_t N>
661 for (
size_t d = 0; d < N; ++d) {
662 size_t s = _dims[d].size();
663 if (s == 0)
return d == 0 ? 0 : total;
669template <std::
integral T,
size_t N>
674 for (
size_t d = 0; d < N; ++d) {
675 dim_sizes[d] = _dims[d].size();
676 if (dim_sizes[d] == 0) { d_active = d;
break; }
678 if (d_active == 0)
return 0;
682 size_t inner_volume = 1;
683 if (inner_volume >= chunk_size)
return inner_volume;
684 for (
size_t d = d_active; d-- > 0; ) {
685 inner_volume *= dim_sizes[d];
686 if (inner_volume >= chunk_size)
return inner_volume;
691template <std::
integral T,
size_t N>
696 for (
size_t d = 0; d < N; ++d) {
697 dim_sizes[d] = _dims[d].size();
698 if (dim_sizes[d] == 0) { d_active = d;
break; }
700 if (d_active == 0)
return 0;
704 size_t inner_volume = 1;
706 for (
size_t d = d_active; d-- > 0; ) {
707 size_t next = inner_volume * dim_sizes[d];
708 if (next > chunk_size)
break;
710 last_fit = inner_volume;
715template <std::
integral T,
size_t N>
716std::pair<IndexRange<T, N>,
size_t>
719 if (chunk_size == 0) {
728 for (
size_t d = 0; d < N; ++d) {
729 dim_sizes[d] = _dims[d].size();
730 if (dim_sizes[d] == 0) { d_active = d;
break; }
733 if (d_active == 0)
return { *
this, 0 };
736 size_t coords[N] = {};
737 size_t temp = flat_beg;
738 for (
size_t d = d_active; d-- > 0; ) {
739 coords[d] = temp % dim_sizes[d];
740 temp /= dim_sizes[d];
745 size_t grow_dim = d_active - 1;
746 size_t inner_volume = 1;
747 size_t active_inner_vol = 1;
749 for (
size_t d = d_active; d-- > 0; ) {
750 if (d + 1 < d_active && coords[d + 1] != 0)
break;
753 active_inner_vol = inner_volume;
755 if (inner_volume >= chunk_size)
break;
757 inner_volume *= dim_sizes[d];
761 size_t steps_left = dim_sizes[grow_dim] - coords[grow_dim];
762 size_t steps_needed = (std::max)(
size_t{1}, chunk_size / active_inner_vol);
763 size_t steps_to_take = (std::min)(steps_left, steps_needed);
767 std::array<IndexRange<T, 1>, N> box_dims;
768 for (
size_t d = 0; d < N; ++d) {
769 const auto&
dim = _dims[d];
770 const T step =
dim.step_size();
771 const T beg =
dim.begin();
774 }
else if (d < grow_dim) {
775 T b = beg +
static_cast<T
>(coords[d]) * step;
777 }
else if (d == grow_dim) {
779 beg +
static_cast<T
>(coords[d]) * step,
780 beg +
static_cast<T
>(coords[d] + steps_to_take) * step,
791template <std::
integral T,
size_t N>
792std::pair<IndexRange<T, N>,
size_t>
795 if (chunk_size == 0) {
804 for (
size_t d = 0; d < N; ++d) {
805 dim_sizes[d] = _dims[d].size();
806 if (dim_sizes[d] == 0) { d_active = d;
break; }
809 if (d_active == 0)
return { *
this, 0 };
812 size_t coords[N] = {};
813 size_t temp = flat_beg;
814 for (
size_t d = d_active; d-- > 0; ) {
815 coords[d] = temp % dim_sizes[d];
816 temp /= dim_sizes[d];
821 size_t grow_dim = d_active - 1;
822 size_t active_inner_vol = 1;
823 size_t inner_volume = 1;
825 for (
size_t d = d_active; d-- > 0; ) {
826 if (d + 1 < d_active && coords[d + 1] != 0)
break;
828 size_t next_vol = inner_volume * dim_sizes[d];
829 if (next_vol > chunk_size && inner_volume > 1)
break;
832 active_inner_vol = inner_volume;
833 inner_volume = next_vol;
837 size_t steps_left = dim_sizes[grow_dim] - coords[grow_dim];
838 size_t steps_needed = (std::max)(
size_t{1}, chunk_size / active_inner_vol);
839 size_t steps_to_take = (std::min)(steps_left, steps_needed);
843 std::array<IndexRange<T, 1>, N> box_dims;
844 for (
size_t d = 0; d < N; ++d) {
845 const auto&
dim = _dims[d];
846 const T step =
dim.step_size();
847 const T beg =
dim.begin();
850 }
else if (d < grow_dim) {
851 T b = beg +
static_cast<T
>(coords[d]) * step;
853 }
else if (d == grow_dim) {
855 beg +
static_cast<T
>(coords[d]) * step,
856 beg +
static_cast<T
>(coords[d] + steps_to_take) * step,
912template <std::
integral T>
925 static constexpr size_t rank = 1;
949 T
end()
const {
return _end; }
1037template <std::
integral T>
1039 return distance(_beg, _end, _step_size);
1042template <std::
integral T>
1045 static_cast<T
>(part_beg) * _step_size + _beg,
1046 static_cast<T
>(part_end) * _step_size + _beg,
1078template <std::
integral T>
1100template <
typename T,
size_t N>
1110template <
typename R>
1117template <
typename T>
1124template <
typename T>
1137template <
typename R>
1144template <
typename T>
1152template <
typename T,
size_t N>
1167template <
typename R>
class to create an N-dimensional index range of integral indices
Definition iterator.hpp:165
const std::array< IndexRange< T, 1 >, N > & dims() const
Definition iterator.hpp:355
IndexRange(const std::array< IndexRange< T, 1 >, N > &dims)
constructs an N-D index range from an array of 1D ranges
Definition iterator.hpp:656
T index_type
alias for the index type
Definition iterator.hpp:172
size_t size() const
returns the number of active flat iterations
Definition iterator.hpp:659
IndexRange()=default
constructs an N-dimensional index range without initialization
std::pair< IndexRange< T, N >, size_t > slice_floor(size_t flat_beg, size_t chunk_size) const
returns the largest perfectly-aligned hyperbox reachable from flat_beg whose size does not exceed chu...
Definition iterator.hpp:793
IndexRange(Ranges &&... ranges)
constructs an N-D index range from N 1D IndexRange<T, 1> objects
Definition iterator.hpp:230
const IndexRange< T, 1 > & dim(size_t d) const
returns the 1D range for dimension d (read-only)
Definition iterator.hpp:298
static constexpr size_t rank
the number of dimensions (always 1 for this specialization)
Definition iterator.hpp:925
IndexRange< T, 1 > & step_size(T new_step_size)
updates the step size of the range
Definition iterator.hpp:979
IndexRange< T, 1 > & end(T new_end)
updates the ending index of the range
Definition iterator.hpp:974
T begin() const
queries the starting index of the range
Definition iterator.hpp:944
IndexRange()=default
constructs an index range object without any initialization
size_t floor(size_t chunk_size) const
returns the largest hyperplane-aligned chunk size that is <= chunk_size
Definition iterator.hpp:692
static constexpr size_t rank
the number of dimensions
Definition iterator.hpp:177
T step_size() const
queries the step size of the range
Definition iterator.hpp:954
IndexRange< T, 1 > & begin(T new_begin)
updates the starting index of the range
Definition iterator.hpp:969
T index_type
alias for the index type used in the range
Definition iterator.hpp:920
size_t size(size_t d) const
returns the number of iterations along dimension d
Definition iterator.hpp:396
IndexRange(T beg, T end, T step_size)
constructs an IndexRange object
Definition iterator.hpp:938
T end() const
queries the ending index of the range
Definition iterator.hpp:949
std::pair< IndexRange< T, N >, size_t > slice_ceil(size_t flat_beg, size_t chunk_size) const
returns the smallest perfectly-aligned hyperbox reachable from flat_beg, rounding up to the next hype...
Definition iterator.hpp:717
IndexRange< T, 1 > & dim(size_t d)
returns the 1D range for dimension d (mutable)
Definition iterator.hpp:325
size_t ceil(size_t chunk_size) const
returns the smallest hyperplane-aligned chunk size that is >= chunk_size, capped at size() when chunk...
Definition iterator.hpp:670
IndexRange< T, 1 > & reset(T begin, T end, T step_size)
updates the range with the new starting index, ending index, and step size
Definition iterator.hpp:959
concept to check if a type is a tf::IndexRange<T, 1>.
Definition iterator.hpp:1138
concept to check if a type an tf::IndexRange, regardless of dimensionality
Definition iterator.hpp:1111
concept to check if a type is a tf::IndexRange<T, N> with rank > 1
Definition iterator.hpp:1168
taskflow namespace
Definition small_vector.hpp:20
constexpr bool is_1d_index_range_v
base type trait to detect if a type is a 1D IndexRange
Definition iterator.hpp:1118
constexpr bool is_md_index_range_v
base type trait to detect if a type is a multi-dimensional IndexRange (rank > 1)
Definition iterator.hpp:1145
constexpr bool is_index_range_v
base type trait to detect if a type is an IndexRange
Definition iterator.hpp:1090
constexpr size_t distance(T beg, T end, T step)
calculates the number of iterations in the given index range
Definition iterator.hpp:71
constexpr bool is_index_range_invalid(T beg, T end, T step)
checks if the given index range is invalid
Definition iterator.hpp:28
IndexRange(T, T, T) -> IndexRange< T, 1 >
deduction guide for tf::IndexRange<T, 1>