Ranges
ETL C++17 Ranges Implementation
Overview
The Embedded Template Library provides a C++17-compatible implementation of ranges, inspired by the C++20 ranges library. This implementation enables range-based algorithms and views for embedded and resource-constrained environments where full C++20 support may not be available.
Features
- Ranges: Provides range types and iterator wrappers for composing operations over sequences.
- Views: Includes lightweight, composable views such as
filter_view,transform_view, andsubrange. - Algorithms: Supports range-based algorithms compatible with ETL containers and standard containers.
- Compatibility: Designed for C++17, with minimal dependencies and no reliance on C++20 features.
Getting Started
Include the main header in your project:
#include <etl/ranges.h>Example Usage
Using Ranges
#include <etl/print.h>
#include <etl/ranges.h>
#include <etl/vector.h>
...
etl::vector<int, 10> data = {6, 1, 3, 3, 2};
etl::ranges::sort(data);
etl::ranges::for_each(data, [](const int& i){etl::print(" {}", i);});Output:
1 2 3 3 6Using Views
#include <etl/print.h>
#include <etl/ranges.h>
#include <etl/vector.h>
...
etl::vector<int, 10> data = {1, 2, 3, 4, 5};
auto even = [](int v) { return v % 2 == 0; };
auto filtered = etl::ranges::filter_view(data, even);
etl::ranges::for_each(filtered, [](const int& i){etl::print(" {}", i);});Output:
2 4Transforming Elements
#include <etl/print.h>
#include <etl/ranges.h>
#include <etl/vector.h>
...
etl::vector<int, 10> data = {1, 2, 3, 4, 5};
auto squared = etl::ranges::transform_view(data, [](int v) { return v * v; });
etl::ranges::for_each(squared, [](const int& i){etl::print(" {}", i);});Output:
1 4 9 16 25Composition
Views can be composed using the pipe (|) operator, allowing you to chain multiple transformations in a readable, left-to-right style:
#include <etl/print.h>
#include <etl/ranges.h>
#include <etl/vector.h>
namespace views = etl::ranges::views;
...
etl::vector<int, 10> data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
auto result = data
| views::filter([](const int& v) { return v % 2 == 0; })
| views::transform([](const int& v) { return v * v; });
etl::ranges::for_each(result, [](const int& i){ etl::print(" {}", i); });Output:
4 16 36 64 100This first filters the even numbers and then squares them. Each | passes the result of the previous stage as input to the next view adaptor.
Range Access and Primitives
These are declared in the etl::ranges namespace in iterator.h, which is included by ranges.h.
Range access
Function objects, equivalent to their std::ranges counterparts.
| Name | Description |
|---|---|
begin, end | The iterator to the first element, and the sentinel. |
cbegin, cend | The const iterator to the first element, and the const sentinel. |
rbegin, rend | The reverse iterator to the last element in forward order, and the past-the-end reverse iterator. |
crbegin, crend | The const reverse iterator to the last element in forward order, and the const past-the-end reverse iterator. |
size | The number of elements, as a size_t. |
ssize | The number of elements, as a ptrdiff_t. |
empty | Whether the range has no elements. |
data, cdata | A pointer to the first element. |
distance | The number of elements between two iterators, or in a range. |
advance | Advances an iterator by a given distance and/or to a bound. |
next, prev | An iterator advanced forwards or backwards by a given distance and/or to a bound. |
size and ssize use the range’s size() member if it has one; otherwise they count the elements by traversing the range, which requires at least a forward range.
distance
// Iterator and sentinel of the same type.
template <typename I>
constexpr etl::iter_difference_t<I> distance(I first, I last)
// Iterator and sentinel of different types.
template <typename I, typename S>
constexpr etl::iter_difference_t<I> distance(I first, S last)
// Range.
template <typename R>
constexpr etl::iter_difference_t<etl::ranges::iterator_t<R>> distance(R&& r)The range overload uses the range’s size() member if it has one; otherwise it counts the elements by traversing from begin() to end().
Range primitives
Alias templates that give the associated types of a range.
| Name | Description |
|---|---|
iterator_t<R> | The iterator type. |
const_iterator_t<R> | The const iterator type. |
sentinel_t<R> | The sentinel type. |
const_sentinel_t<R> | The const sentinel type. |
range_size_t<R> | The size type. |
range_difference_t<R> | The difference type. |
range_value_t<R> | The element value type. |
range_reference_t<R> | The element reference type. |
Supported Views
All views are in the etl::ranges namespace. Corresponding range adaptor objects are available in etl::ranges::views.
Range Factories
| View | views:: adaptor | Description |
|---|---|---|
empty_view<T> | views::empty<T> | A view with no elements. |
single_view | views::single | A view containing exactly one element. |
iota_view | views::iota | A view of sequentially increasing values. |
repeat_view | views::repeat | A view that repeats a value a given number of times. |
Range Adaptors
| View | views:: adaptor | Description |
|---|---|---|
ref_view | views::ref | A non-owning view that wraps a reference to a range. |
owning_view | views::owning | A view that takes ownership of a range via move. |
| — | views::all | Returns the range itself (if already a view), a ref_view, or an owning_view. |
filter_view | views::filter | Filters elements based on a predicate. |
transform_view | views::transform | Applies a transformation to each element. |
as_rvalue_view | views::as_rvalue | Casts each element to an rvalue reference. |
as_const_view | views::as_const | Provides a const view of the elements. |
cache_latest_view | views::cache_latest | Caches the most recently accessed element (avoids recomputation). |
reverse_view | views::reverse | Reverses the order of elements. |
drop_view | views::drop | Skips the first n elements. |
drop_while_view | views::drop_while | Skips leading elements while a predicate is true. |
take_view | views::take | Takes the first n elements. |
take_while_view | views::take_while | Takes leading elements while a predicate is true. |
join_view | views::join | Flattens a range of ranges into a single range. |
join_with_view | views::join_with | Flattens a range of ranges, inserting a delimiter between each. |
split_view | views::split | Splits a range into subranges around a delimiter pattern. |
lazy_split_view | views::lazy_split | Lazily splits a range by a pattern (inner ranges discovered on iteration). |
| — | views::counted | Creates a view of n elements starting from an iterator. |
concat_view | views::concat | Concatenates multiple ranges into a single view. |
zip_view | views::zip | Zips multiple ranges into a view of tuples (length of shortest range). |
zip_transform_view | views::zip_transform | Zips multiple ranges and applies a function to each tuple of elements. |
common_view | views::common | Adapts a view so that its iterator and sentinel types are the same. |
enumerate_view | views::enumerate | Pairs each element with its index, producing tuples of (index, value). |
elements_view | views::elements | Extracts the N-th element from each tuple-like value. |
keys_view | views::keys | Alias for elements_view with N=0 (extracts first element of pairs/tuples). |
values_view | views::values | Alias for elements_view with N=1 (extracts second element of pairs/tuples). |
adjacent_view | views::adjacent | Produces a view of tuples of N adjacent elements (sliding window of tuples). |
| — | views::pairwise | Alias for views::adjacent<2>. |
adjacent_transform_view | views::adjacent_transform | Applies a function to each group of N adjacent elements. |
| — | views::pairwise_transform | Alias for views::adjacent_transform<2>. |
chunk_view | views::chunk | Splits a range into non-overlapping chunks of a given size. |
slide_view | views::slide | Produces overlapping subranges (sliding windows) of a given size. |
chunk_by_view | views::chunk_by | Splits a range into subranges between adjacent elements where a predicate is false. |
stride_view | views::stride | Yields every N-th element from the underlying range. |
cartesian_product_view | views::cartesian_product | Produces the Cartesian product of multiple ranges as a view of tuples. |
to_input_view | views::to_input | Downgrades iterator category to input iterator while preserving elements and order. |
subrange | — | Represents a sub-range defined by an iterator–sentinel pair. |
All views support range-based for-loop iteration and can be composed with the pipe (|) operator.
Supported Algorithms
All algorithms are callable objects in the etl::ranges namespace. Each supports both an iterator-pair overload and a range overload (where applicable), and most accept optional projection and comparator arguments.
Non-modifying Sequence Operations
| Algorithm | Description |
|---|---|
for_each | Applies a function to each element in a range. |
for_each_n | Applies a function to the first n elements. |
find | Finds the first element equal to a value. |
find_if | Finds the first element satisfying a predicate. |
find_if_not | Finds the first element not satisfying a predicate. |
find_end | Finds the last occurrence of a subsequence. |
find_first_of | Finds the first element matching any in a second range. |
adjacent_find | Finds the first pair of adjacent equal elements. |
count | Counts elements equal to a value. |
count_if | Counts elements satisfying a predicate. |
all_of | Checks if all elements satisfy a predicate. |
any_of | Checks if any element satisfies a predicate. |
none_of | Checks if no elements satisfy a predicate. |
mismatch | Finds the first position where two ranges differ. |
equal | Checks if two ranges are equal. |
is_permutation | Checks if one range is a permutation of another. |
search | Searches for the first occurrence of a subsequence. |
search_n | Searches for n consecutive copies of a value. |
starts_with | Checks if a range starts with another range. |
ends_with | Checks if a range ends with another range. |
lexicographical_compare | Compares two ranges lexicographically. |
Fold Operations
| Algorithm | Description |
|---|---|
fold_left | Left-folds elements with a binary operation. |
fold_left_with_iter | Left-folds, returning both the result and an iterator. |
fold_left_first | Left-folds using the first element as the initial value. |
fold_left_first_with_iter | Like fold_left_first, also returning an iterator. |
fold_right | Right-folds elements with a binary operation. |
fold_right_last | Right-folds using the last element as the initial value. |
Modifying Sequence Operations
| Algorithm | Description |
|---|---|
copy | Copies elements to a destination range. |
copy_n | Copies n elements to a destination range. |
copy_if | Copies elements satisfying a predicate. |
copy_backward | Copies elements backwards to a destination range. |
move | Moves elements to a destination range. |
move_backward | Moves elements backwards to a destination range. |
swap_ranges | Swaps elements between two ranges. |
replace | Replaces elements equal to a value. |
replace_if | Replaces elements satisfying a predicate. |
replace_copy | Copies, replacing elements equal to a value. |
replace_copy_if | Copies, replacing elements satisfying a predicate. |
remove | Removes elements equal to a value. |
remove_if | Removes elements satisfying a predicate. |
remove_copy | Copies, omitting elements equal to a value. |
fill | Fills a range with a value. |
fill_n | Fills n elements with a value. |
generate | Assigns each element the result of a generator function. |
generate_n | Assigns n elements the result of a generator function. |
iota | Fills a range with sequentially increasing values. |
unique | Removes consecutive duplicate elements. |
unique_copy | Copies, removing consecutive duplicates. |
transform | Applies a transformation to each element. |
reverse | Reverses the order of elements. |
reverse_copy | Copies elements in reverse order. |
rotate | Rotates elements in a range. |
rotate_copy | Copies elements with rotation. |
shift_left | Shifts elements to the left. |
shift_right | Shifts elements to the right. |
shuffle | Randomly reorders elements. |
sample | Selects n random elements from a range. |
Sorting Operations
| Algorithm | Description |
|---|---|
sort | Sorts elements in a range. |
stable_sort | Sorts elements preserving relative order of equivalent elements. |
partial_sort | Partially sorts a range so that the first n elements are sorted. |
partial_sort_copy | Copies and partially sorts elements. |
nth_element | Partially sorts so that the n-th element is in its sorted position. |
is_sorted | Checks if a range is sorted. |
is_sorted_until | Finds the first unsorted element. |
Partitioning Operations
| Algorithm | Description |
|---|---|
partition | Partitions elements by a predicate. |
stable_partition | Partitions elements, preserving relative order. |
is_partitioned | Checks if a range is partitioned. |
partition_copy | Copies elements into two ranges based on a predicate. |
partition_point | Finds the partition point. |
Binary Search (on sorted ranges)
| Algorithm | Description |
|---|---|
lower_bound | Finds the first element not less than a value. |
upper_bound | Finds the first element greater than a value. |
equal_range | Returns the range of elements equal to a value. |
binary_search | Checks if a sorted range contains a value. |
Set Operations (on sorted ranges)
| Algorithm | Description |
|---|---|
includes | Checks if one sorted range includes another. |
merge | Merges two sorted ranges. |
inplace_merge | Merges two consecutive sorted sub-ranges in place. |
set_union | Computes the union of two sorted ranges. |
set_intersection | Computes the intersection of two sorted ranges. |
set_difference | Computes the difference of two sorted ranges. |
set_symmetric_difference | Computes the symmetric difference of two sorted ranges. |
Heap Operations
| Algorithm | Description |
|---|---|
make_heap | Creates a heap from a range. |
push_heap | Pushes an element onto a heap. |
pop_heap | Pops the top element from a heap. |
sort_heap | Sorts a heap into a sorted range. |
is_heap | Checks if a range is a heap. |
is_heap_until | Finds the first element that breaks the heap property. |
Min/Max Operations
| Algorithm | Description |
|---|---|
min | Returns the smaller of two values or the smallest in an initializer list. |
min_element | Finds the smallest element in a range. |
max | Returns the larger of two values or the largest in an initializer list. |
max_element | Finds the largest element in a range. |
minmax | Returns the smaller and larger of two values. |
minmax_element | Finds both the smallest and largest elements in a range. |
clamp | Clamps a value between a minimum and maximum. |
Permutation Operations
| Algorithm | Description |
|---|---|
next_permutation | Generates the next lexicographic permutation. |
prev_permutation | Generates the previous lexicographic permutation. |
Reference
For reference to the STD implementation, see also:
- Algorithms: https://en.cppreference.com/w/cpp/algorithm.html
- Ranges/Views: https://en.cppreference.com/w/cpp/ranges.html
Limitations
- Not all C++20 range features are available due to limitation to C++17. Especially C++20 concepts are not used.
- Designed for ETL containers but can work with standard containers if compatible with ETL’s iterator requirements.