Skip to content

Ranges

Header: ranges.h
Since: 20.46.2
Similar to: std::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, and subrange.
  • 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 6

Using 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 4

Transforming 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 25

Composition

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 100

This 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.

NameDescription
begin, endThe iterator to the first element, and the sentinel.
cbegin, cendThe const iterator to the first element, and the const sentinel.
rbegin, rendThe reverse iterator to the last element in forward order, and the past-the-end reverse iterator.
crbegin, crendThe const reverse iterator to the last element in forward order, and the const past-the-end reverse iterator.
sizeThe number of elements, as a size_t.
ssizeThe number of elements, as a ptrdiff_t.
emptyWhether the range has no elements.
data, cdataA pointer to the first element.
distanceThe number of elements between two iterators, or in a range.
advanceAdvances an iterator by a given distance and/or to a bound.
next, prevAn 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.

NameDescription
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

Viewviews:: adaptorDescription
empty_view<T>views::empty<T>A view with no elements.
single_viewviews::singleA view containing exactly one element.
iota_viewviews::iotaA view of sequentially increasing values.
repeat_viewviews::repeatA view that repeats a value a given number of times.

Range Adaptors

Viewviews:: adaptorDescription
ref_viewviews::refA non-owning view that wraps a reference to a range.
owning_viewviews::owningA view that takes ownership of a range via move.
—views::allReturns the range itself (if already a view), a ref_view, or an owning_view.
filter_viewviews::filterFilters elements based on a predicate.
transform_viewviews::transformApplies a transformation to each element.
as_rvalue_viewviews::as_rvalueCasts each element to an rvalue reference.
as_const_viewviews::as_constProvides a const view of the elements.
cache_latest_viewviews::cache_latestCaches the most recently accessed element (avoids recomputation).
reverse_viewviews::reverseReverses the order of elements.
drop_viewviews::dropSkips the first n elements.
drop_while_viewviews::drop_whileSkips leading elements while a predicate is true.
take_viewviews::takeTakes the first n elements.
take_while_viewviews::take_whileTakes leading elements while a predicate is true.
join_viewviews::joinFlattens a range of ranges into a single range.
join_with_viewviews::join_withFlattens a range of ranges, inserting a delimiter between each.
split_viewviews::splitSplits a range into subranges around a delimiter pattern.
lazy_split_viewviews::lazy_splitLazily splits a range by a pattern (inner ranges discovered on iteration).
—views::countedCreates a view of n elements starting from an iterator.
concat_viewviews::concatConcatenates multiple ranges into a single view.
zip_viewviews::zipZips multiple ranges into a view of tuples (length of shortest range).
zip_transform_viewviews::zip_transformZips multiple ranges and applies a function to each tuple of elements.
common_viewviews::commonAdapts a view so that its iterator and sentinel types are the same.
enumerate_viewviews::enumeratePairs each element with its index, producing tuples of (index, value).
elements_viewviews::elementsExtracts the N-th element from each tuple-like value.
keys_viewviews::keysAlias for elements_view with N=0 (extracts first element of pairs/tuples).
values_viewviews::valuesAlias for elements_view with N=1 (extracts second element of pairs/tuples).
adjacent_viewviews::adjacentProduces a view of tuples of N adjacent elements (sliding window of tuples).
—views::pairwiseAlias for views::adjacent<2>.
adjacent_transform_viewviews::adjacent_transformApplies a function to each group of N adjacent elements.
—views::pairwise_transformAlias for views::adjacent_transform<2>.
chunk_viewviews::chunkSplits a range into non-overlapping chunks of a given size.
slide_viewviews::slideProduces overlapping subranges (sliding windows) of a given size.
chunk_by_viewviews::chunk_bySplits a range into subranges between adjacent elements where a predicate is false.
stride_viewviews::strideYields every N-th element from the underlying range.
cartesian_product_viewviews::cartesian_productProduces the Cartesian product of multiple ranges as a view of tuples.
to_input_viewviews::to_inputDowngrades 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

AlgorithmDescription
for_eachApplies a function to each element in a range.
for_each_nApplies a function to the first n elements.
findFinds the first element equal to a value.
find_ifFinds the first element satisfying a predicate.
find_if_notFinds the first element not satisfying a predicate.
find_endFinds the last occurrence of a subsequence.
find_first_ofFinds the first element matching any in a second range.
adjacent_findFinds the first pair of adjacent equal elements.
countCounts elements equal to a value.
count_ifCounts elements satisfying a predicate.
all_ofChecks if all elements satisfy a predicate.
any_ofChecks if any element satisfies a predicate.
none_ofChecks if no elements satisfy a predicate.
mismatchFinds the first position where two ranges differ.
equalChecks if two ranges are equal.
is_permutationChecks if one range is a permutation of another.
searchSearches for the first occurrence of a subsequence.
search_nSearches for n consecutive copies of a value.
starts_withChecks if a range starts with another range.
ends_withChecks if a range ends with another range.
lexicographical_compareCompares two ranges lexicographically.

Fold Operations

AlgorithmDescription
fold_leftLeft-folds elements with a binary operation.
fold_left_with_iterLeft-folds, returning both the result and an iterator.
fold_left_firstLeft-folds using the first element as the initial value.
fold_left_first_with_iterLike fold_left_first, also returning an iterator.
fold_rightRight-folds elements with a binary operation.
fold_right_lastRight-folds using the last element as the initial value.

Modifying Sequence Operations

AlgorithmDescription
copyCopies elements to a destination range.
copy_nCopies n elements to a destination range.
copy_ifCopies elements satisfying a predicate.
copy_backwardCopies elements backwards to a destination range.
moveMoves elements to a destination range.
move_backwardMoves elements backwards to a destination range.
swap_rangesSwaps elements between two ranges.
replaceReplaces elements equal to a value.
replace_ifReplaces elements satisfying a predicate.
replace_copyCopies, replacing elements equal to a value.
replace_copy_ifCopies, replacing elements satisfying a predicate.
removeRemoves elements equal to a value.
remove_ifRemoves elements satisfying a predicate.
remove_copyCopies, omitting elements equal to a value.
fillFills a range with a value.
fill_nFills n elements with a value.
generateAssigns each element the result of a generator function.
generate_nAssigns n elements the result of a generator function.
iotaFills a range with sequentially increasing values.
uniqueRemoves consecutive duplicate elements.
unique_copyCopies, removing consecutive duplicates.
transformApplies a transformation to each element.
reverseReverses the order of elements.
reverse_copyCopies elements in reverse order.
rotateRotates elements in a range.
rotate_copyCopies elements with rotation.
shift_leftShifts elements to the left.
shift_rightShifts elements to the right.
shuffleRandomly reorders elements.
sampleSelects n random elements from a range.

Sorting Operations

AlgorithmDescription
sortSorts elements in a range.
stable_sortSorts elements preserving relative order of equivalent elements.
partial_sortPartially sorts a range so that the first n elements are sorted.
partial_sort_copyCopies and partially sorts elements.
nth_elementPartially sorts so that the n-th element is in its sorted position.
is_sortedChecks if a range is sorted.
is_sorted_untilFinds the first unsorted element.

Partitioning Operations

AlgorithmDescription
partitionPartitions elements by a predicate.
stable_partitionPartitions elements, preserving relative order.
is_partitionedChecks if a range is partitioned.
partition_copyCopies elements into two ranges based on a predicate.
partition_pointFinds the partition point.

Binary Search (on sorted ranges)

AlgorithmDescription
lower_boundFinds the first element not less than a value.
upper_boundFinds the first element greater than a value.
equal_rangeReturns the range of elements equal to a value.
binary_searchChecks if a sorted range contains a value.

Set Operations (on sorted ranges)

AlgorithmDescription
includesChecks if one sorted range includes another.
mergeMerges two sorted ranges.
inplace_mergeMerges two consecutive sorted sub-ranges in place.
set_unionComputes the union of two sorted ranges.
set_intersectionComputes the intersection of two sorted ranges.
set_differenceComputes the difference of two sorted ranges.
set_symmetric_differenceComputes the symmetric difference of two sorted ranges.

Heap Operations

AlgorithmDescription
make_heapCreates a heap from a range.
push_heapPushes an element onto a heap.
pop_heapPops the top element from a heap.
sort_heapSorts a heap into a sorted range.
is_heapChecks if a range is a heap.
is_heap_untilFinds the first element that breaks the heap property.

Min/Max Operations

AlgorithmDescription
minReturns the smaller of two values or the smallest in an initializer list.
min_elementFinds the smallest element in a range.
maxReturns the larger of two values or the largest in an initializer list.
max_elementFinds the largest element in a range.
minmaxReturns the smaller and larger of two values.
minmax_elementFinds both the smallest and largest elements in a range.
clampClamps a value between a minimum and maximum.

Permutation Operations

AlgorithmDescription
next_permutationGenerates the next lexicographic permutation.
prev_permutationGenerates the previous lexicographic permutation.

Reference

For reference to the STD implementation, see also:

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.