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 };
737 size_t coords[N] = {};
738 size_t temp = flat_beg;
739 for (
size_t d = d_active; d-- > 0; ) {
740 coords[d] = temp % dim_sizes[d];
741 temp /= dim_sizes[d];
746 size_t grow_dim = d_active - 1;
747 size_t inner_volume = 1;
748 size_t active_inner_vol = 1;
750 for (
size_t d = d_active; d-- > 0; ) {
752 if (d + 1 < d_active && coords[d + 1] != 0)
break;
756 active_inner_vol = inner_volume;
758 if (inner_volume >= chunk_size)
break;
760 inner_volume *= dim_sizes[d];
764 size_t steps_left = dim_sizes[grow_dim] - coords[grow_dim];
765 size_t steps_needed = (std::max)(
size_t{1}, chunk_size / active_inner_vol);
766 size_t steps_to_take = (std::min)(steps_left, steps_needed);
773 std::array<IndexRange<T, 1>, N> box_dims;
775 for (
size_t d = 0; d < grow_dim; ++d) {
776 const T beg = _dims[d].begin();
777 const T step = _dims[d].step_size();
779 beg +
static_cast<T
>(coords[d]) * step,
780 beg +
static_cast<T
>(coords[d] + 1) * step,
786 const T beg = _dims[grow_dim].begin();
787 const T step = _dims[grow_dim].step_size();
789 beg +
static_cast<T
>(coords[grow_dim]) * step,
790 beg +
static_cast<T
>(coords[grow_dim] + steps_to_take) * step,
795 for (
size_t d = grow_dim + 1; d < N; ++d) {
796 box_dims[d] = _dims[d];
802template <std::
integral T,
size_t N>
803std::pair<IndexRange<T, N>,
size_t>
806 if (chunk_size == 0) {
813 for (
size_t d = 0; d < N; ++d) {
814 dim_sizes[d] = _dims[d].size();
815 if (dim_sizes[d] == 0) { d_active = d;
break; }
818 if (d_active == 0)
return { *
this, 0 };
822 size_t coords[N] = {};
823 size_t temp = flat_beg;
824 for (
size_t d = d_active; d-- > 0; ) {
825 coords[d] = temp % dim_sizes[d];
826 temp /= dim_sizes[d];
831 size_t grow_dim = d_active - 1;
832 size_t inner_volume = 1;
833 size_t active_inner_vol = 1;
835 for (
size_t d = d_active; d-- > 0; ) {
837 if (d + 1 < d_active && coords[d + 1] != 0)
break;
840 size_t next_vol = inner_volume * dim_sizes[d];
841 if (next_vol > chunk_size && inner_volume > 1)
break;
844 active_inner_vol = inner_volume;
845 inner_volume = next_vol;
849 size_t steps_left = dim_sizes[grow_dim] - coords[grow_dim];
850 size_t steps_needed = (std::max)(
size_t{1}, chunk_size / active_inner_vol);
851 size_t steps_to_take = (std::min)(steps_left, steps_needed);
854 std::array<IndexRange<T, 1>, N> box_dims;
856 for (
size_t d = 0; d < grow_dim; ++d) {
857 const T beg = _dims[d].begin();
858 const T step = _dims[d].step_size();
860 beg +
static_cast<T
>(coords[d]) * step,
861 beg +
static_cast<T
>(coords[d] + 1) * step,
867 const T beg = _dims[grow_dim].begin();
868 const T step = _dims[grow_dim].step_size();
870 beg +
static_cast<T
>(coords[grow_dim]) * step,
871 beg +
static_cast<T
>(coords[grow_dim] + steps_to_take) * step,
876 for (
size_t d = grow_dim + 1; d < N; ++d) {
877 box_dims[d] = _dims[d];
928template <std::
integral T>
941 static constexpr size_t rank = 1;
955 : _beg{beg}, _end{end}, _step_size{step_size} {}
965 T
end()
const {
return _end; }
978 _step_size = step_size;
1009 size_t size()
const;
1053template <std::
integral T>
1055 return distance(_beg, _end, _step_size);
1058template <std::
integral T>
1061 static_cast<T
>(part_beg) * _step_size + _beg,
1062 static_cast<T
>(part_end) * _step_size + _beg,
1094template <std::
integral T>
1116template <
typename T,
size_t N>
1126template <
typename R>
1133template <
typename T>
1140template <
typename T>
1153template <
typename R>
1160template <
typename T>
1168template <
typename T,
size_t N>
1183template <
typename R>
IndexRange< T, 1 > & step_size(T new_step_size)
updates the step size of the range
Definition iterator.hpp:995
IndexRange< T, 1 > & end(T new_end)
updates the ending index of the range
Definition iterator.hpp:990
T begin() const
queries the starting index of the range
Definition iterator.hpp:960
IndexRange()=default
constructs an index range object without any initialization
T step_size() const
queries the step size of the range
Definition iterator.hpp:970
IndexRange< T, 1 > & begin(T new_begin)
updates the starting index of the range
Definition iterator.hpp:985
T index_type
alias for the index type used in the range
Definition iterator.hpp:936
IndexRange(T beg, T end, T step_size)
constructs an IndexRange object
Definition iterator.hpp:954
T end() const
queries the ending index of the range
Definition iterator.hpp:965
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:975
class to create an N-dimensional index range of integral indices
Definition iterator.hpp:165
const std::array< IndexRange< T, 1 >, N > & dims() const
returns the underlying array of all per-dimension 1D ranges
Definition iterator.hpp:355
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:804
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
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
size_t size(size_t d) const
returns the number of iterations along dimension d
Definition iterator.hpp:396
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
concept to check if a type is a tf::IndexRange<T, 1>.
Definition iterator.hpp:1154
concept to check if a type an tf::IndexRange, regardless of dimensionality
Definition iterator.hpp:1127
concept to check if a type is a tf::IndexRange<T, N> with rank > 1
Definition iterator.hpp:1184
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:1134
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:1161
constexpr bool is_index_range_v
base type trait to detect if a type is an IndexRange
Definition iterator.hpp:1106
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>