Skip to content

Commit f0f4a04

Browse files
committed
[doc] lots of doc and CHANGELOG
1 parent af77e45 commit f0f4a04

File tree

5 files changed

+153
-24
lines changed

5 files changed

+153
-24
lines changed

CHANGELOG.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Changelog
2+
3+
All notable changes to this project will be documented in this file.
4+
5+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7+
8+
## unreleased
9+
10+
### Progress implementing std::views::X equivalents
11+
12+
| Standard | adaptors |factories | Comment |
13+
|-------------|---------:|---------:|----------------------------|
14+
| C++20 | 14/15 | 5/5 | `lazy_split` not planned |
15+
| C++23 | 2/13 | 1/1 | |
16+
| C++26 | 1/03 | -- | |
17+
| C++29 | 1/?? | -- | |
18+
| extra | 1 | | |
19+

docs/feature_table.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
| Range adaptor | $O(n)$ constr | min cat | max cat | sized | common | Remarks |
66
|----------------------------|:--------------:|---------|----------|:-----:|:---------:|------------------------------------------|
7+
| `radr::all` | | input | contig | = | = | |
78
| `radr::as_const` | | fwd | contig | = | = | make the range *and* its elements const |
89
| `radr::as_rvalue` | | input | input/ra | = | = | returns only input ranges in C++20 |
910
| `radr::drop(n)` | !(ra+sized) | input | contig | = || |
@@ -16,12 +17,12 @@
1617
| `radr::slice(m, n)` | !(ra+sized) | input | contig | = | = | get subrange between m and n |
1718
| `radr::split(pat)` | always | input | fwd | - || |
1819
| `radr::take(n)` | | input | contig | = | ra+sized | |
19-
| `radr::take_exactly(n)` | | input | contig | + | ra+sized | turns unsized into size of n |
2020
| `radr::take_while(fn)` | | input | contig | - | - | |
2121
| `radr::to_common` | !(common) | fwd | contig || + | |
2222
| `radr::to_single_pass` | | input | input | - | - | demotes range category to single-pass |
2323
| `radr::transform(fn)` | | input | ra | = | = | |
2424
| `radr::values` | | input | ra | = | = | |
25+
| `radr::uncheckd_take(n)` | | input | contig | + | ra+sized | turns unsized into size of n |
2526

2627
**min cat** underlying range required to be at least input (`input_range`), fwd (`forward_range`), bidi (`bidirectional_range`),
2728
ra (`random_access_range`) or contig (`contiguous_range`)<br>

docs/implementation_status.md

Lines changed: 35 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,17 @@ This library is a **work-in-progress**.
44
We try to stay close to standard library interfaces, but we neither promise full API compatibility with `std::ranges::` nor do we currently promise stability between releases of this library.
55
The latter will likely change at some point.
66

7+
### Progress implementing std::views::X equivalents (adaptor objects and factory objects)
8+
9+
| Standard | adaptors |factories | Comment |
10+
|-------------|---------:|---------:|----------------------------|
11+
| C++20 | 14/15 | 5/5 | `lazy_split` not planned |
12+
| C++23 | 2/13 | 1/1 | |
13+
| C++26 | 1/03 | -- | |
14+
| C++29 | 1/?? | -- | |
15+
| extra | 1 | | |
16+
17+
See below for details. Note that the list of adaptors in C++26 and C++29 is not yet final.
718

819
## Range adaptor classes
920

@@ -22,27 +33,28 @@ Instead all range adaptor objects in this library (see below) return a specialis
2233

2334
We plan to add equivalent objects for all standard library adaptors.
2435

25-
| Range adaptors (objects) | C++XY | | Equivalent in `std::` | C++XY | Differences of `radr` objects |
26-
|--------------------------|-------|-|--------------------------------|-----------|------------------------------------------|
27-
| `radr::as_const` | C++20 | | `std::views::as_const` | **C++23** | make the range *and* its elements const |
28-
| `radr::as_rvalue` | C++20 | | `std::views::as_rvalue` | **C++23** | *returns only input ranges in C++20 |
29-
| `radr::drop(n)` | C++20 | | `std::views::drop` | C++20 | |
30-
| `radr::drop_while(fn)` | C++20 | | `std::views::drop_while` | C++20 | |
31-
| `radr::elements<I>` | C++20 | | `std::views::elements` | C++20 | |
32-
| `radr::filter(fn)` | C++20 | | `std::views::filter` | C++20 | |
33-
| `radr::join` | C++20 | | `std::views::join` | C++20 | |
34-
| `radr::keys` | C++20 | | `std::views::keys` | C++20 | |
35-
| `radr::reverse` | C++20 | | `std::views::reverse` | C++20 | |
36-
| `radr::slice(m, n)` | C++20 | | *not yet available* | | get subrange between m and n |
37-
| `radr::split(pat)` | C++20 | | `std::views::split` | C++20 | |
38-
| *not planned* | C++20 | | `std::views::lazy_split` | C++20 | use `radr::to_single_pass | radr::split` |
39-
| `radr::take(n)` | C++20 | | `std::views::take` | C++20 | |
40-
| `radr::take_exactly(n)` | C++20 | | *not yet available* | | turns unsized into sized |
41-
| `radr::take_while(fn)` | C++20 | | `std::views::take_while` | C++20 | |
42-
| `radr::to_common` | C++20 | | `std::views::common`[^diff] | C++20 | turns non-common into common |
43-
| `radr::to_single_pass` | C++20 | | `std::views::to_input`[^diff] | **C++26** | demotes range category to input |
44-
| `radr::transform(fn)` | C++20 | | `std::views::transform` | C++20 | |
45-
| `radr::values` | C++20 | | `std::views::values` | C++20 | |
36+
| Range adaptors (objects) | C++XY | | Equivalent in `std::` | C++XY | Differences of `radr` objects |
37+
|---------------------------|-------|-|--------------------------------|-----------|------------------------------------------|
38+
| `radr::all` | C++20 | | `std::views::all` | C++20 | |
39+
| `radr::as_const` | C++20 | | `std::views::as_const` | **C++23** | make the range *and* its elements const |
40+
| `radr::as_rvalue` | C++20 | | `std::views::as_rvalue` | **C++23** | *returns only input ranges in C++20 |
41+
| `radr::drop(n)` | C++20 | | `std::views::drop` | C++20 | |
42+
| `radr::drop_while(fn)` | C++20 | | `std::views::drop_while` | C++20 | |
43+
| `radr::elements<I>` | C++20 | | `std::views::elements` | C++20 | |
44+
| `radr::filter(fn)` | C++20 | | `std::views::filter` | C++20 | |
45+
| `radr::join` | C++20 | | `std::views::join` | C++20 | |
46+
| `radr::keys` | C++20 | | `std::views::keys` | C++20 | |
47+
| `radr::reverse` | C++20 | | `std::views::reverse` | C++20 | |
48+
| `radr::slice(m, n)` | C++20 | | *not yet available* | | get subrange between m and n |
49+
| `radr::split(pat)` | C++20 | | `std::views::split` | C++20 | |
50+
| *not planned* | C++20 | | `std::views::lazy_split` | C++20 | use `radr::to_single_pass ╎ radr::split` |
51+
| `radr::take(n)` | C++20 | | `std::views::take` | C++20 | |
52+
| `radr::take_while(fn)` | C++20 | | `std::views::take_while` | C++20 | |
53+
| `radr::to_common` | C++20 | | `std::views::common`[^diff] | C++20 | turns non-common into common |
54+
| `radr::to_single_pass` | C++20 | | `std::views::to_input`[^diff] | **C++26** | demotes range category to input |
55+
| `radr::transform(fn)` | C++20 | | `std::views::transform` | C++20 | |
56+
| `radr::values` | C++20 | | `std::views::values` | C++20 | |
57+
| `radr::unchecked_take(n)` | C++20 | | `std::views::unchecked_take` | **C++29** | turns unsized into sized |
4658

4759
All range adaptors from this library are available in C++20, although `radr::as_rvalue` behaves slightly different between modes.
4860

@@ -62,6 +74,8 @@ All range adaptors from this library are available in C++20, although `radr::as_
6274
| `radr::repeat(val[, bound])` | C++20 | | `std::views::repeat` | **C++23** | allows indirect storage and static bounds |
6375
| `radr::single(val)` | C++20 | | `std::views::single` | C++20 | allows indirect storage |
6476

77+
The standard library groups `counted` with "range adaptors" and not "range factories",
78+
although you create it on an iterator and not a range.
6579

6680
## Notable functions
6781

include/radr/rad/split.hpp

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,14 @@
1313
#pragma once
1414

1515
#include <iterator>
16+
#include <ranges>
1617

1718
#include "radr/custom/subborrow.hpp"
1819
#include "radr/detail/detail.hpp"
1920
#include "radr/detail/pipe.hpp"
2021
#include "radr/factory/single.hpp"
2122
#include "radr/rad/as_const.hpp"
23+
#include "radr/rad/to_single_pass.hpp"
2224
#include "radr/range_access.hpp"
2325

2426
namespace radr::detail
@@ -305,25 +307,71 @@ inline namespace cpo
305307
{
306308

307309
/*!\brief radr::split(urange, pattern)
310+
* \tparam URange Type of \p urange.
311+
* \tparam Patttern Type of \p pattern.
308312
* \param urange The underlying range.
309313
* \param pattern The pattern to split by.
310314
* \details
311315
*
316+
* Turns a range into a range-of-ranges, by splitting on the provided pattern.
317+
* The pattern will not be included in the output.
318+
*
312319
* ## Multi-pass ranges
313320
*
314321
* The pattern can be one of:
315322
* * a std::ref-wrapped lvalue of a range whose elements are comparable to the underlying range.
316323
* * an rvalue of a range whose elements are comparable to the underlying range (only if the pattern is a borrowed_mp_range).
317324
* * a std::ref-wrapped lvalue of a delimiter element that is comparable to elements of the underlying range.
318325
* * an rvalue of a delimiter element that is comparable to elements of the underlying range (only if that value is default constructible and copyable without throwing).
326+
* * Note that string-literal patterns (`"foobar"`) are not supported. Use string_views instead (`"foobar"sv`).
327+
*
328+
* Requirements:
329+
* * `radr::mp_range<URange>`
330+
* * for Pattern, see above.
331+
*
332+
* The returned "outer range"-type models radr::mp_range and preserves std::ranges::borrowed_range.
333+
* It is never bidirectional, common, sized or mutable.
334+
*
335+
* The returned "inner range"-type is created via the radr::subborrow customisation point.
336+
* Unless customised otherwise, it always models:
337+
* * std::ranges::borrowed_range
338+
* * std::ranges::sized_range
339+
* * radr::common_range
340+
*
341+
* It preserves from the underlying range:
342+
* * categories up to std::ranges::contiguous_range
343+
* * radr::mutable_range
344+
* * radr::constant_range
345+
*
346+
* Construction of the adaptor is in O(n), because the first inner range is searched on construction
347+
* (which could be the full range).
319348
*
320-
* Note that string-literal patterns (`"foobar"`) are not supported. Use string_views instead (`"foobar"sv`).
349+
* ### Notable differences to std::views::split
350+
*
351+
* Due to radr::subborrow being used, splitting a string_view results in string_views:
352+
*
353+
* ```cpp
354+
* auto subs = "foo bar bax"sv | radr::split(' ');
355+
* auto frst = *subs.begin(); // this is a string_view, too
356+
* ```
321357
*
322358
* ## Single-pass ranges
323359
*
324-
* The pattern can be delimiter element (rvalue or lvalue) comparable to the elements of the underlying range.
360+
* The pattern must be delimiter element (rvalue or lvalue) comparable to the elements of the underlying range.
361+
* Ranges as patterns are not supported for single-pass inputs.
362+
*
363+
* Requirements:
364+
* * `std::ranges::input_range<URange>`
365+
* * `std::equality_comparable_with<std::ranges::range_reference_t<URange>, Pattern>`
366+
*
367+
* Both, the "outer range"-type and the "inner range"-type are a radr::generator.
368+
* This design is fully lazy; no read-ahead happens.
325369
*
326370
*/
327371
inline constexpr auto split = detail::pipe_with_args_fn{detail::split_coro, detail::split_borrow};
372+
373+
[[deprecated(
374+
"Instead of radr::lazy_split, just use radr::split. Or use `radr::to_single_pass | radr::split` which is lazier, but "
375+
"does not support range-as-a-pattern.")]] inline constexpr auto lazy_split = split;
328376
} // namespace cpo
329377
} // namespace radr

include/radr/rad/take.hpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,53 @@ namespace radr
142142

143143
inline namespace cpo
144144
{
145+
/*!\brief Take up to n elements from the underlying range.
146+
* \param[in] urange The underlying range.
147+
* \param[in] n Number of elements.
148+
* \tparam URange Type of \p urange.
149+
* \details
150+
*
151+
* Takes \p n elements from \p urange, or all elements if \p urange is smaller than \p n.
152+
*
153+
* ## Multi-pass ranges
154+
*
155+
* Requirements:
156+
* * `radr::mp_range<URange>`
157+
*
158+
* For underlying ranges that are radr::safely_indexable_range, this adaptor invokes the radr::subborrow
159+
* customisation point.
160+
* Unless customised otherwise and if the range was sized, it will preserve all range concepts and be
161+
* transparent (same iterator and senintel types as \p urange).
162+
* If it was infinite, it will become sized and common.
163+
*
164+
* For underlying ranges that are not radr::safely_indexable_range, this adaptors preserves:
165+
* * categories up to std::ranges::contiguous_range
166+
* * std::ranges::borrowed_range
167+
* * radr::mutable_range
168+
* * radr::constant_range
169+
* * std::ranges::sized_range
170+
*
171+
* It does not preserve:
172+
* * radr::common_range
173+
*
174+
* ### Notable differences to std::views::take
175+
*
176+
* * Subrange customisation through radr::subborrow.
177+
* * Returns sized, common ranges for infinite inputs like radr::iota and radr::repeat.
178+
*
179+
* ## Single-pass ranges
180+
*
181+
* Requirements:
182+
* * `std::ranges::input_range<URange>`
183+
*
184+
* ### Notable difference std::views::take
185+
*
186+
* std::views::take takes \p n elements from the underlying range but then silently advances over the `n+1`-th element,
187+
* resulting in unexpected behaviour (e.g. skipped/missing elements in a stream).
188+
* See https://www.youtube.com/watch?v=dvi0cl8ccNQ for an explenation.
189+
*
190+
* We **fixed this bug** for radr::take on single-pass ranges.
191+
*/
145192
inline constexpr auto take = detail::pipe_with_args_fn{detail::take_coro, detail::take_borrow};
146193
} // namespace cpo
147194
} // namespace radr

0 commit comments

Comments
 (0)