Loading...
Searching...
No Matches
tf::IndexRanges< T, N > Class Template Reference

class to create an N-dimensional index range of integral indices More...

#include <taskflow/utility/iterator.hpp>

Public Types

using index_type = T
 alias for the index type
 

Public Member Functions

 IndexRanges ()=default
 constructs an index range without initialization
 
 IndexRanges (T beg, T end, T step_size)
 constructs a 1D index range (only available when N == 1)
 
template<typename... Ranges>
requires (sizeof...(Ranges) == N) && (std::same_as<std::decay_t<Ranges>, IndexRanges<T, 1>> && ...)
 IndexRanges (Ranges &&... ranges)
 constructs an N-D index range from N 1D ranges
 
 IndexRanges (const std::array< std::tuple< T, T, T >, N > &dims)
 constructs an index range from an array of (begin, end, step) tuples
 
const std::tuple< T, T, T > & dim (size_t d) const
 returns the (begin, end, step) tuple for dimension d (read-only)
 
std::tuple< T, T, T > & dim (size_t d)
 returns the (begin, end, step) tuple for dimension d (mutable)
 
begin () const
 queries the starting index of the range (only available when N == 1)
 
end () const
 queries the ending index of the range (only available when N == 1)
 
step_size () const
 queries the step size of the range (only available when N == 1)
 
IndexRangesreset (T beg, T end, T step_size)
 updates the range with a new starting index, ending index, and step size (only available when N == 1)
 
IndexRangesbegin (T new_begin)
 updates the starting index of the range (only available when N == 1)
 
IndexRangesend (T new_end)
 updates the ending index of the range (only available when N == 1)
 
IndexRangesstep_size (T new_step_size)
 updates the step size of the range (only available when N == 1)
 
IndexRanges unravel (size_t part_beg, size_t part_end) const
 maps a contiguous index partition back to the corresponding subrange (only available when N == 1)
 
size_t size (size_t d) const
 returns the number of iterations along dimension d
 
size_t size () const
 returns the number of active flat iterations
 

Static Public Attributes

static constexpr size_t rank = N
 the number of dimensions
 

Detailed Description

template<std::integral T, size_t N = 1>
class tf::IndexRanges< T, N >

class to create an N-dimensional index range of integral indices

Template Parameters
Tthe integral type of the indices
Nthe number of dimensions (defaults to 1)

This class represents the Cartesian product of N independent 1D index ranges, each defined by a starting index, ending index, and step size. Each dimension is stored as a std::tuple<T, T, T> of (begin, end, step), accessible and mutable through dim(d).

For N == 1, the class behaves like a plain 1D range: tf::IndexRange<T> (an alias for tf::IndexRanges<T, 1>) exposes convenience accessors begin(), end(), step_size(), reset(), and unravel() directly, without going through dim(0).

tf::IndexRange<int> range(0, 10, 2);
for(auto i=range.begin(); i<range.end(); i+=range.step_size()) {
printf("%d ", i);
}
IndexRanges< T, 1 > IndexRange
alias for the common 1D case of tf::IndexRanges
Definition iterator.hpp:612

You can reset the range to a different value using tf::IndexRanges::reset. This is particularly useful when the range value is only known at runtime.

range.reset(0, 10, 2);
for(auto i=range.begin(); i<range.end(); i+=range.step_size()) {
printf("%d ", i);
}
IndexRanges & reset(T beg, T end, T step_size)
updates the range with a new starting index, ending index, and step size (only available when N == 1)
Definition iterator.hpp:534
T end() const
queries the ending index of the range (only available when N == 1)
Definition iterator.hpp:358
T begin() const
queries the starting index of the range (only available when N == 1)
Definition iterator.hpp:346
T step_size() const
queries the step size of the range (only available when N == 1)
Definition iterator.hpp:370
Attention
It is the user's responsibility to ensure the given range is valid. For instance, a range from 0 to 10 with a step size of -2 is invalid.

For N > 1, iteration order is row-major: the last dimension varies fastest, matching the natural nesting of C-style for-loops.

// 3D range: i in [0,4), j in [0,6), k in [0,8), all step 1
);
printf("%zu\n", r.size()); // 4*6*8 = 192
class to create an N-dimensional index range of integral indices
Definition iterator.hpp:188
Note
If any dimension has zero size (e.g. an empty range such as [0,0)), the active iteration space stops at that dimension. size() returns the product of all outer dimensions before the first zero, and upper_slice / lower_slice copy the zero-size dimension and all inner dimensions as full extent into each returned sub-box. This matches the behaviour of sequential nested loops:
// Zero in the middle dimension: outer i-loop still runs, j/k body never executes.
tf::IndexRange<int>(0, 100, 1), // i: 100 iters (active)
tf::IndexRange<int>(0, 0, 1), // j: 0 iters (stops accumulation here)
tf::IndexRange<int>(0, 100, 1) // k: 100 iters (inactive — never reached)
);
r.size(); // 100 (only the i-dimension contributes)

Constructor & Destructor Documentation

◆ IndexRanges() [1/4]

template<std::integral T, size_t N = 1>
tf::IndexRanges< T, N >::IndexRanges ( )
default

constructs an index range without initialization

The per-dimension ranges are left in an indeterminate state. Use this when the bounds will be set later via reset() (N==1) or dim(d) (any N).

◆ IndexRanges() [2/4]

template<std::integral T, size_t N = 1>
tf::IndexRanges< T, N >::IndexRanges ( T beg,
T end,
T step_size )
inlineexplicit

constructs a 1D index range (only available when N == 1)

Parameters
begstarting index of the range
endending index of the range (exclusive)
step_sizestep size between consecutive indices in the range
tf::IndexRange<int> range(0, 10, 2); // elements: 0, 2, 4, 6, 8

◆ IndexRanges() [3/4]

template<std::integral T, size_t N = 1>
template<typename... Ranges>
requires (sizeof...(Ranges) == N) && (std::same_as<std::decay_t<Ranges>, IndexRanges<T, 1>> && ...)
tf::IndexRanges< T, N >::IndexRanges ( Ranges &&... ranges)
inlineexplicit

constructs an N-D index range from N 1D ranges

Parameters
rangesexactly N 1D ranges (each a tf::IndexRanges<T, 1>, i.e. a tf::IndexRange<T>), one per dimension in order from outermost (dim 0) to innermost (dim N-1)

Each 1D range defines the begin, end, and step_size for its dimension. Dimensions are independent — any combination of positive, negative, or zero step sizes is supported, as long as each 1D range is individually valid.

// 3D: mixed step sizes
tf::IndexRange<int>(0, 4, 1), // dim 0: 4 elements
tf::IndexRange<int>(0, 10, 2), // dim 1: 5 elements (0,2,4,6,8)
tf::IndexRange<int>(0, 6, 1) // dim 2: 6 elements
);
r3.size(); // 120

◆ IndexRanges() [4/4]

template<std::integral T, size_t N = 1>
tf::IndexRanges< T, N >::IndexRanges ( const std::array< std::tuple< T, T, T >, N > & dims)
inlineexplicit

constructs an index range from an array of (begin, end, step) tuples

Parameters
dimsstd::array of exactly N (begin, end, step) tuples

Useful when the per-dimension bounds are constructed programmatically.

std::array<std::tuple<int,int,int>, 2> dims = {
std::tuple{0, 4, 1},
std::tuple{0, 5, 1}
};
tf::IndexRanges<int, 2> r(dims);
r.size(); // 20

Member Function Documentation

◆ begin() [1/2]

template<std::integral T, size_t N = 1>
T tf::IndexRanges< T, N >::begin ( ) const
inline

queries the starting index of the range (only available when N == 1)

Returns
the starting index of the range
tf::IndexRange<int> range(0, 10, 2);
auto b = range.begin(); // b == 0

◆ begin() [2/2]

template<std::integral T, size_t N>
requires (N == 1)
IndexRanges< T, N > & tf::IndexRanges< T, N >::begin ( T new_begin)

updates the starting index of the range (only available when N == 1)

Parameters
new_beginthe new starting index of the range
Returns
a reference to *this
tf::IndexRange<int> range(0, 10, 2); // elements: 0, 2, 4, 6, 8
range.begin(4); // elements become: 4, 6, 8

◆ dim() [1/2]

template<std::integral T, size_t N = 1>
std::tuple< T, T, T > & tf::IndexRanges< T, N >::dim ( size_t d)
inline

returns the (begin, end, step) tuple for dimension d (mutable)

Parameters
dzero-based dimension index in [0, N)
Returns
a mutable reference to the std::tuple<T, T, T> for dimension d

Use this to update the bounds of an individual dimension at runtime, for example inside an upstream init task when using stateful ranges:

auto init = taskflow.emplace([&]() {
range.dim(0) = {0, rows, 1}; // set row range at runtime
range.dim(1) = {0, cols, 1}; // set col range at runtime
});
auto loop = taskflow.for_each_by_index(std::ref(range), callable);
init.precede(loop);
const std::tuple< T, T, T > & dim(size_t d) const
returns the (begin, end, step) tuple for dimension d (read-only)
Definition iterator.hpp:297

Native structured bindings can bind directly to the tuple's elements:

// mutate a single field through a structured binding
auto& [beg, end, step] = range.dim(0);
beg = 0; end = rows; step = 1;

◆ dim() [2/2]

template<std::integral T, size_t N = 1>
const std::tuple< T, T, T > & tf::IndexRanges< T, N >::dim ( size_t d) const
inline

returns the (begin, end, step) tuple for dimension d (read-only)

Parameters
dzero-based dimension index in [0, N)
Returns
a const reference to the std::tuple<T, T, T> for dimension d, in (begin, end, step) order
);
auto [beg, end, step] = r.dim(1); // beg=0, end=10, step=2

◆ end() [1/2]

template<std::integral T, size_t N = 1>
T tf::IndexRanges< T, N >::end ( ) const
inline

queries the ending index of the range (only available when N == 1)

Returns
the ending index (exclusive) of the range
tf::IndexRange<int> range(0, 10, 2);
auto e = range.end(); // e == 10

◆ end() [2/2]

template<std::integral T, size_t N>
requires (N == 1)
IndexRanges< T, N > & tf::IndexRanges< T, N >::end ( T new_end)

updates the ending index of the range (only available when N == 1)

Parameters
new_endthe new ending index (exclusive) of the range
Returns
a reference to *this
tf::IndexRange<int> range(0, 10, 2); // elements: 0, 2, 4, 6, 8
range.end(6); // elements become: 0, 2, 4

◆ reset()

template<std::integral T, size_t N>
requires (N == 1)
IndexRanges< T, N > & tf::IndexRanges< T, N >::reset ( T beg,
T end,
T step_size )

updates the range with a new starting index, ending index, and step size (only available when N == 1)

Parameters
begnew starting index of the range
endnew ending index of the range (exclusive)
step_sizenew step size between consecutive indices in the range
Returns
a reference to *this

Use this to rebind a stateful range to new bounds at runtime, for example inside an upstream init task:

auto init = taskflow.emplace([&]() {
range.reset(0, 10, 2); // elements: 0, 2, 4, 6, 8
});
auto loop = taskflow.for_each_by_index(std::ref(range), callable);
init.precede(loop);

◆ size() [1/2]

template<std::integral T, size_t N>
size_t tf::IndexRanges< T, N >::size ( ) const

returns the number of active flat iterations

For N == 1 this is simply the element count of the range. For N > 1 it returns the product of dimension sizes from the outermost dimension inward, stopping before the first zero-size dimension. This matches the behaviour of sequential nested loops: a zero-size dimension prevents its own iterations and those of all deeper dimensions, but outer dimensions are unaffected.

// All non-zero: 4 * 6 * 8 = 192
);
r1.size(); // 192
// Zero in middle (d=1): outer dim only -> 4
tf::IndexRange<int>(0, 0, 1), // stops accumulation here
);
r2.size(); // 4

◆ size() [2/2]

template<std::integral T, size_t N = 1>
size_t tf::IndexRanges< T, N >::size ( size_t d) const
inline

returns the number of iterations along dimension d

Parameters
dzero-based dimension index in [0, N)
Returns
the element count of dimension d

This is a per-dimension count, independent of other dimensions and of the zero-size stopping rule that size() applies.

);
r.size(1); // 5, since the range [0,10) with step 2 has 5 elements

◆ step_size() [1/2]

template<std::integral T, size_t N = 1>
T tf::IndexRanges< T, N >::step_size ( ) const
inline

queries the step size of the range (only available when N == 1)

Returns
the step size between consecutive indices in the range
tf::IndexRange<int> range(0, 10, 2);
auto s = range.step_size(); // s == 2

◆ step_size() [2/2]

template<std::integral T, size_t N>
requires (N == 1)
IndexRanges< T, N > & tf::IndexRanges< T, N >::step_size ( T new_step_size)

updates the step size of the range (only available when N == 1)

Parameters
new_step_sizethe new step size between consecutive indices
Returns
a reference to *this
tf::IndexRange<int> range(0, 10, 1); // elements: 0, 1, 2, ..., 9
range.step_size(3); // elements become: 0, 3, 6, 9

◆ unravel()

template<std::integral T, size_t N>
requires (N == 1)
IndexRanges< T, N > tf::IndexRanges< T, N >::unravel ( size_t part_beg,
size_t part_end ) const

maps a contiguous index partition back to the corresponding subrange (only available when N == 1)

Parameters
part_begbeginning index of the partition (inclusive)
part_endending index of the partition (exclusive)
Returns
a new range covering the elements at positions [part_beg, part_end) in the original range

Each element of the range can be addressed by a zero-based position index from 0 to size()-1. This function unravels a contiguous slice of those position indices back into the original iteration space, returning the sub-range whose elements correspond exactly to positions [part_beg, part_end).

tf::IndexRange<int> range(0, 10, 2); // elements: 0, 2, 4, 6, 8
auto sub = range.unravel(1, 4); // elements at positions [1,4): 2, 4, 6
// sub.begin() == 2, sub.end() == 8, sub.step_size() == 2
Attention
Users must ensure [part_beg, part_end) is a valid partition of [0, size()), i.e., part_end <= size().

The documentation for this class was generated from the following file: