Add missing etl::ranges::distance overload (#1569)

* Update _index.md

* Update _index.md

* Cherry pick the Docker fixes for PowerPC (#1563)

Co-authored-by: John Wellbelove <john.wellbelove@etlcpp.com>

* Add missing etl::ranges::distance overload

---------

Co-authored-by: John Wellbelove <jwellbelove@users.noreply.github.com>
Co-authored-by: John Wellbelove <john.wellbelove@etlcpp.com>
This commit is contained in:
Roland Reichwein 2026-08-26 21:16:54 +02:00 committed by GitHub
parent e4fc36d6f2
commit c6c1ee1b28
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 125 additions and 0 deletions

View File

@ -133,6 +133,8 @@ ETL_CONSTEXPR17 typename std::iterator_traits<TIterator>::difference_type
distance(TIterator first, TIterator last)
```
See [Ranges](../../ranges/ranges) for the `etl::ranges` range access primitives, including `etl::ranges::distance`.
## iterator
A base class provided to simplify definitions of the required types for iterators.
https://en.cppreference.com/w/cpp/iterator/iterator

View File

@ -119,6 +119,63 @@ Output:
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.
| 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
```cpp
// 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`.

View File

@ -1656,6 +1656,22 @@ namespace etl
}
return n;
}
// Overload for ranges
template <typename R, typename I = decltype(ETL_OR_STD::begin(etl::declval<R&>()))>
constexpr etl::iter_difference_t<I> operator()(R&& r) const
{
using U = etl::remove_cvref_t<R>;
if constexpr (has_size_member<U>::value)
{
return static_cast<etl::iter_difference_t<I>>(r.size());
}
else
{
return (*this)(ETL_OR_STD::begin(r), ETL_OR_STD::end(r));
}
}
};
struct size

View File

@ -29,6 +29,7 @@ SOFTWARE.
#include "unit_test_framework.h"
#include <algorithm>
#include <forward_list>
#include <list>
#include <queue>
#include <string>
@ -1420,6 +1421,55 @@ namespace
CHECK_EQUAL(1, *result);
}
//*************************************************************************
// etl::ranges::distance(first, last)
//*************************************************************************
TEST(ranges_distance_iterator_sentinel)
{
int data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
CHECK_EQUAL(10, etl::ranges::distance(&data[0], &data[10]));
CHECK_EQUAL(4, etl::ranges::distance(&data[3], &data[7]));
CHECK_EQUAL(0, etl::ranges::distance(&data[3], &data[3]));
non_random_iterator<int> first(&data[0]);
non_random_sentinel<int> last(&data[6]);
CHECK_EQUAL(6, etl::ranges::distance(first, last));
}
//*************************************************************************
// etl::ranges::distance(range)
//*************************************************************************
TEST(ranges_distance_range_with_size_member)
{
std::vector<int> data = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
CHECK_EQUAL(10, etl::ranges::distance(data));
const std::vector<int>& cdata = data;
CHECK_EQUAL(10, etl::ranges::distance(cdata));
std::vector<int> empty_data;
CHECK_EQUAL(0, etl::ranges::distance(empty_data));
}
//*************************************************************************
TEST(ranges_distance_c_array)
{
int data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
CHECK_EQUAL(10, etl::ranges::distance(data));
}
//*************************************************************************
TEST(ranges_distance_range_without_size_member)
{
std::forward_list<int> data = {0, 1, 2, 3, 4};
CHECK_EQUAL(5, etl::ranges::distance(data));
CHECK_EQUAL(etl::ranges::distance(data.begin(), data.end()), etl::ranges::distance(data));
}
TEST(test_is_range)
{
std::vector<int> vec;