A C++ template library for embedded applications
MIT licensed
Designed and
maintained by
John Wellbelove
multi_range

Allows the creation of simulated nested ranges at runtime.
Each range is defined as an
etl::multi_range which may be linked to create nested multiple ranges.

template <typename T>
class multi_range

All multi_range<T> classes derive from imulti_range

By default, each call to next() will invoke either the forward_step or reverse_step types.
If the type is an arithmetic or pointer type then the default stepper will be automatically selected, dependent on the first and last parameters. If not, the default will be
forward_step.

If a custom stepper for the type is required, then it may be defined in the constructor.

By default, each call to
completed() will invoke not_equal_compare against the terminating range value. If a custom incrementor for the type is required, then it may be defined in the constructor.
____________________________________________________________________________________________________
Types

value_type
The type of the range.

const_reference
The const reference type of the range.
____________________________________________________________________________________________________
step_type
Pure abstract base.
Inherit from this to define custom step functionality.

forward_step
A pre-defined step type that calls the type's operator++().
This is the default step type if  the type is arithmetic or random access iterator and the range is ascending, or the type is
not an arithmetic or pointer.


forward_step_by
A pre-defined step type that calls the type's operator+=().
The constructor requires the step value to add.

reverse_step
A pre-defined step type that calls the type's operator--().
This is the default step type if  the type is arithmetic or random access iterator and the range is descending.

reverse_step_by
A pre-defined step type that calls the type's operator-=().
The constructor requires the step value to subtract.
____________________________________________________________________________________________________
compare_type
Pure abstract base.
Inherit from this to define custom compare functionality.

not_equal_compare
A pre-defined step type that calls etl::not_equal_to.
This is the default compare type.

less_than_compare
A pre-defined step type that calls etl::less.

greater_than_compare
A pre-defined step type that calls etl::greater.
____________________________________________________________________________________________________
Constructor

multi_range(value_type start,
           
value_type last)
Initialises the loop where start is the initial value and last is the terminate value.
____________________________________________________________________________________________________
multi_range
(value_type first,
           
value_type last,
           
step_type& stepper)
Initialises the loop where start is the initial value and last is the terminate value.
stepper will be called to increment the current range value.
____________________________________________________________________________________________________
multi_range
(value_type    first,
           
value_type    last,
           
compare_type& compare)
Initialises the loop where start is the initial value and last is the terminate value.
compare will be called to compare with the  terminating value.
____________________________________________________________________________________________________
multi_range
(value_type    first,
           
value_type    last,
           
step_type&    stepper,
           
compare_type& compare)
Initialises the loop where start is the initial value and last is the terminate value.
stepper will be called to increment the current range value.
compare will be called to compare with the  terminate value.
____________________________________________________________________________________________________
Modifiers

The nested ranges may be constructed in a variety of ways.

imulti_range& append(imulti_range& inner_ranges)
Appends inner loop(s) to the current range(s).
If the current range,
A,  is linked to ranges B & C in the order A -> B -> C and the new linked ranges are D -> E,
A.append(D) will result in A -> B -> C -> D -> E
____________________________________________________________________________________________________
imulti_range& insert(imulti_range& inner_ranges)
Inserts inner range(s) after the current range.
If the current range,
A,  is linked to ranges B & C in the order A -> B -> C and the new linked ranges are D -> E,
A.insert(D) will result in A -> D -> E -> B -> C
____________________________________________________________________________________________________
void detach()
Unlinks this range from its inner ranges.
____________________________________________________________________________________________________
void detach_all()
Unlinks this range and all its inner ranges from each other.
____________________________________________________________________________________________________
Access

const_reference
value() const;
Gets a const reference to the current value
____________________________________________________________________________________________________
const_reference begin() const;
Gets a const reference to the first value
____________________________________________________________________________________________________
const_reference end() const;
Gets a const reference to the terminate value
____________________________________________________________________________________________________
bool completed() const
Returns true if the range, and all of its inner ranges, have completed.
____________________________________________________________________________________________________
size_t
number_of_ranges() const
Returns the number of linked ranges, starting from this.
For linked ranges
A -> B -> C -> D -> E,
B.number_of_ranges() returns 4.
____________________________________________________________________________________________________
size_t number_of_iterations()
Returns the total number of iterations for all linked ranges, starting from this.
For linked ranges
A -> B -> C -> D -> E, and a range size of 5 for each one,
B.number_of_iterations() returns 625 (5 * 5 * 5 * 5).

This function is not
const as it must simulate the running of all of the nested ranges.
____________________________________________________________________________________________________
Operations

void
start()
Resets the range, and all its linked inner ranges to the starting conditions, with each range reset to its
begin value.
____________________________________________________________________________________________________
void next()
Moves to the next iteration of the nested range.
____________________________________________________________________________________________________
Example

using Iterator = std::forward_list<std::string>::const_iterator;

// Less Than compare type
using LessThanCompare = etl::multi_range<const short*>::less_than_compare;

// Decrementing step type
using DecrementPtr = etl::multi_range<const short*>::reverse_step;

using Outer  = etl::multi_range<int>;          // Incrementing int
using Middle = etl::multi_range<const short*>; // Decrementing const short*
using Inner  = etl::multi_range<Iterator>;     // Incrementing const_iterator

const short data[4] = { 0, 1, 2, 3 };

std::
forward_list<std::string> strings =
{
 
"zero", "one", "two", "three"
};

LessThanCompare lessThan;
DecrementPtr    decrementPtr;

// Setup the loops.
Outer  outer(0, 4, lessThan);
Middle middle(data + 3, data - 1, decrementPtr);
Inner  inner(strings.begin(), strings.end());

outer.append(middle).append(inner);

size_t n_outer_loops  = outer.number_of_loops();  // == 3
size_t n_middle_loops = middle.number_of_loops(); // == 2
size_t n_inner_loops  = inner.number_of_loops();  // == 1

size_t n_outer_iterations  = outer.number_of_iterations();  // == 64
size_t n_middle_iterations = middle.number_of_iterations(); // == 16
size_t n_inner_iterations  = inner.number_of_iterations();  // == 4

// Create const references to the loop values.
const int&      value_outer  = outer.value();
const short*&   value_middle = middle.value();
const Iterator& value_inner  = inner.value();

// Iterate through the nested loops.
int i = 0;

for (outer.start(); !outer.completed(); outer.next())
{
  std::cout <<
"Iteration " << i++ << " : "
            <<
"Outer  = " << value_outer << " : "
            <<
"Middle = " << *value_middle << " : "
            <<
"Inner  = " << *value_inner
            <<
"\n";
}

// Just iterate through the two nested loops.
i = 0;

for (middle.start(); !middle.completed(); middle.next())
{
  std::cout <<
"Iteration " << i++ << " : "
            <<
"Middle = " << *value_middle << " : "
            <<
"Inner  = " << *value_inner
            <<
"\n";
}


multi_range.h