etl/docs/ranges.md
Roland Reichwein 31b87b5419
Add C++ ranges library for C++17 (#1316)
* Add ranges

* Print test names at test time (#1343)

* Fix conflit commit errors

* Cast return value of operator* to value_type

Fixed warning on VS2022

---------

Co-authored-by: John Wellbelove <jwellbelove@users.noreply.github.com>
2026-03-26 08:56:17 +00:00

14 KiB
Raw Permalink Blame History

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.

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 iteratorsentinel 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:

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.