Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## unreleased

### Progress implementing std::views::X equivalents

| Standard | adaptors |factories | Comment |
|-------------|---------:|---------:|----------------------------|
| C++20 | 14/15 | 5/5 | `lazy_split` not planned |
| C++23 | 2/13 | 1/1 | |
| C++26 | 1/03 | -- | |
| C++29 | 1/?? | -- | |
| extra | 1 | | |

3 changes: 2 additions & 1 deletion docs/feature_table.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

| Range adaptor | $O(n)$ constr | min cat | max cat | sized | common | Remarks |
|----------------------------|:--------------:|---------|----------|:-----:|:---------:|------------------------------------------|
| `radr::all` | | input | contig | = | = | |
| `radr::as_const` | | fwd | contig | = | = | make the range *and* its elements const |
| `radr::as_rvalue` | | input | input/ra | = | = | returns only input ranges in C++20 |
| `radr::drop(n)` | !(ra+sized) | input | contig | = | ⊜ | |
Expand All @@ -16,12 +17,12 @@
| `radr::slice(m, n)` | !(ra+sized) | input | contig | = | = | get subrange between m and n |
| `radr::split(pat)` | always | input | fwd | - | ⊝ | |
| `radr::take(n)` | | input | contig | = | ra+sized | |
| `radr::take_exactly(n)` | | input | contig | + | ra+sized | turns unsized into size of n |
| `radr::take_while(fn)` | | input | contig | - | - | |
| `radr::to_common` | !(common) | fwd | contig | ⊕ | + | |
| `radr::to_single_pass` | | input | input | - | - | demotes range category to single-pass |
| `radr::transform(fn)` | | input | ra | = | = | |
| `radr::values` | | input | ra | = | = | |
| `radr::uncheckd_take(n)` | | input | contig | + | ra+sized | turns unsized into size of n |

**min cat** underlying range required to be at least input (`input_range`), fwd (`forward_range`), bidi (`bidirectional_range`),
ra (`random_access_range`) or contig (`contiguous_range`)<br>
Expand Down
56 changes: 35 additions & 21 deletions docs/implementation_status.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,17 @@ This library is a **work-in-progress**.
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.
The latter will likely change at some point.

### Progress implementing std::views::X equivalents (adaptor objects and factory objects)

| Standard | adaptors |factories | Comment |
|-------------|---------:|---------:|----------------------------|
| C++20 | 14/15 | 5/5 | `lazy_split` not planned |
| C++23 | 2/13 | 1/1 | |
| C++26 | 1/03 | -- | |
| C++29 | 1/?? | -- | |
| extra | 1 | | |

See below for details. Note that the list of adaptors in C++26 and C++29 is not yet final.

## Range adaptor classes

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

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

| Range adaptors (objects) | C++XY | | Equivalent in `std::` | C++XY | Differences of `radr` objects |
|--------------------------|-------|-|--------------------------------|-----------|------------------------------------------|
| `radr::as_const` | C++20 | | `std::views::as_const` | **C++23** | make the range *and* its elements const |
| `radr::as_rvalue` | C++20 | | `std::views::as_rvalue` | **C++23** | *returns only input ranges in C++20 |
| `radr::drop(n)` | C++20 | | `std::views::drop` | C++20 | |
| `radr::drop_while(fn)` | C++20 | | `std::views::drop_while` | C++20 | |
| `radr::elements<I>` | C++20 | | `std::views::elements` | C++20 | |
| `radr::filter(fn)` | C++20 | | `std::views::filter` | C++20 | |
| `radr::join` | C++20 | | `std::views::join` | C++20 | |
| `radr::keys` | C++20 | | `std::views::keys` | C++20 | |
| `radr::reverse` | C++20 | | `std::views::reverse` | C++20 | |
| `radr::slice(m, n)` | C++20 | | *not yet available* | | get subrange between m and n |
| `radr::split(pat)` | C++20 | | `std::views::split` | C++20 | |
| *not planned* | C++20 | | `std::views::lazy_split` | C++20 | use `radr::to_single_pass | radr::split` |
| `radr::take(n)` | C++20 | | `std::views::take` | C++20 | |
| `radr::take_exactly(n)` | C++20 | | *not yet available* | | turns unsized into sized |
| `radr::take_while(fn)` | C++20 | | `std::views::take_while` | C++20 | |
| `radr::to_common` | C++20 | | `std::views::common`[^diff] | C++20 | turns non-common into common |
| `radr::to_single_pass` | C++20 | | `std::views::to_input`[^diff] | **C++26** | demotes range category to input |
| `radr::transform(fn)` | C++20 | | `std::views::transform` | C++20 | |
| `radr::values` | C++20 | | `std::views::values` | C++20 | |
| Range adaptors (objects) | C++XY | | Equivalent in `std::` | C++XY | Differences of `radr` objects |
|---------------------------|-------|-|--------------------------------|-----------|------------------------------------------|
| `radr::all` | C++20 | | `std::views::all` | C++20 | |
| `radr::as_const` | C++20 | | `std::views::as_const` | **C++23** | make the range *and* its elements const |
| `radr::as_rvalue` | C++20 | | `std::views::as_rvalue` | **C++23** | *returns only input ranges in C++20 |
| `radr::drop(n)` | C++20 | | `std::views::drop` | C++20 | |
| `radr::drop_while(fn)` | C++20 | | `std::views::drop_while` | C++20 | |
| `radr::elements<I>` | C++20 | | `std::views::elements` | C++20 | |
| `radr::filter(fn)` | C++20 | | `std::views::filter` | C++20 | |
| `radr::join` | C++20 | | `std::views::join` | C++20 | |
| `radr::keys` | C++20 | | `std::views::keys` | C++20 | |
| `radr::reverse` | C++20 | | `std::views::reverse` | C++20 | |
| `radr::slice(m, n)` | C++20 | | *not yet available* | | get subrange between m and n |
| `radr::split(pat)` | C++20 | | `std::views::split` | C++20 | |
| *not planned* | C++20 | | `std::views::lazy_split` | C++20 | use `radr::to_single_pass ╎ radr::split` |
| `radr::take(n)` | C++20 | | `std::views::take` | C++20 | |
| `radr::take_while(fn)` | C++20 | | `std::views::take_while` | C++20 | |
| `radr::to_common` | C++20 | | `std::views::common`[^diff] | C++20 | turns non-common into common |
| `radr::to_single_pass` | C++20 | | `std::views::to_input`[^diff] | **C++26** | demotes range category to input |
| `radr::transform(fn)` | C++20 | | `std::views::transform` | C++20 | |
| `radr::values` | C++20 | | `std::views::values` | C++20 | |
| `radr::unchecked_take(n)` | C++20 | | `std::views::unchecked_take` | **C++29** | turns unsized into sized |

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

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

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

## Notable functions

Expand Down
7 changes: 7 additions & 0 deletions include/radr/concepts.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,13 @@ concept weak_indirect_unary_invocable =
std::invoke_result_t<F &, std::iter_reference_t<I>>>;
//TODO implement P2609

template <typename Rng>
concept infinite_mp_range = mp_range<Rng> && std::same_as<std::ranges::sentinel_t<Rng>, std::unreachable_sentinel_t>;

template <typename Rng>
concept safely_indexable_range =
std::ranges::random_access_range<Rng> && (std::ranges::sized_range<Rng> || infinite_mp_range<Rng>);

} // namespace radr

namespace radr::detail
Expand Down
23 changes: 10 additions & 13 deletions include/radr/custom/subborrow.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "../detail/detail.hpp"
#include "../rad_util/borrowing_rad.hpp"
#include "../range_access.hpp"
#include "radr/concepts.hpp"
#include "tags.hpp"

namespace radr::custom
Expand Down Expand Up @@ -218,10 +219,13 @@ struct subborrow_impl_t

//!\brief Call tag_invoke if possible; call default otherwise. [i, j]
template <borrowed_mp_range URange>
requires(std::ranges::random_access_range<URange> && std::ranges::sized_range<URange>)
requires(safely_indexable_range<URange>)
constexpr auto operator()(URange && urange, size_t const start, size_t const end) const
{
size_t const e = std::min<size_t>(end, std::ranges::size(urange));
size_t e = end;
if constexpr (std::ranges::sized_range<URange>)
e = std::min<size_t>(e, std::ranges::size(urange));

size_t const b = std::min<size_t>(start, e);

return operator()(std::forward<URange>(urange), radr::begin(urange) + b, radr::begin(urange) + e);
Expand All @@ -243,17 +247,10 @@ using subborrow_t = decltype(subborrow(std::declval<Args>()...));
inline constexpr auto borrow =
detail::overloaded{[]<borrowed_mp_range URange>(URange && urange)
{
if constexpr (std::ranges::sized_range<URange>)
{
return subborrow(std::forward<URange>(urange),
radr::begin(urange),
radr::end(urange),
std::ranges::size(urange));
}
else
{
return subborrow(std::forward<URange>(urange), radr::begin(urange), radr::end(urange));
}
return subborrow(std::forward<URange>(urange),
radr::begin(urange),
radr::end(urange),
detail::size_or_not(urange));
},
// if a range is already borrowed and copyable, just copy it (we assume O(1) copy)
// BUT do not do this if a copy would result in a constant_range becoming a mutable range
Expand Down
25 changes: 17 additions & 8 deletions include/radr/factory/iota.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -260,17 +260,26 @@ struct iota_fn
static_assert(std::incrementable<Value>, "The Value type to radr::iota needs to satisfy std::incrementable.");
static_assert(weakly_equality_comparable_with<Value, Bound>,
"The Value type to radr::iota needs to be comparable with the Bound type.");
static_assert(std::semiregular<Bound>, "The Bound type to radr::iota needs to satisfy std::regular.");
static_assert(std::semiregular<Bound>, "The Bound type to radr::iota needs to satisfy std::semiregular.");

using It = detail::iota_iterator<Value>;
using Sen = std::conditional_t<std::same_as<Value, Bound>, It, detail::iota_sentinel<Value, Bound>>;
using It = detail::iota_iterator<Value>;
if constexpr (std::same_as<Bound, std::unreachable_sentinel_t>)
{
return borrowing_rad<It, std::unreachable_sentinel_t, It, std::unreachable_sentinel_t>{
It{val},
std::unreachable_sentinel};
}
else
{
using Sen = std::conditional_t<std::same_as<Value, Bound>, It, detail::iota_sentinel<Value, Bound>>;

constexpr borrowing_rad_kind kind =
((std::random_access_iterator<It> && std::same_as<It, Sen>) || std::sized_sentinel_for<Bound, Value>)
? borrowing_rad_kind::sized
: borrowing_rad_kind::unsized;
constexpr borrowing_rad_kind kind =
((std::random_access_iterator<It> && std::same_as<It, Sen>) || std::sized_sentinel_for<Bound, Value>)
? borrowing_rad_kind::sized
: borrowing_rad_kind::unsized;

return borrowing_rad<It, Sen, It, Sen, kind>{It{val}, Sen{bound}};
return borrowing_rad<It, Sen, It, Sen, kind>{It{val}, Sen{bound}};
}
}
};

Expand Down
2 changes: 1 addition & 1 deletion include/radr/factory/repeat.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ using constant_t = std::integral_constant<decltype(v), v>;
* dimensions: \p Bound and \p storage.
*
* All instantiations of `repeat_rng` model at least std::semiregular, std::ranges::random_access_range and
* radr::const_iterable.
* radr::mp_range.
*
* ## Bound
*
Expand Down
54 changes: 54 additions & 0 deletions include/radr/rad/all.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// Copyright (c) 2023-2025 Hannes Hauswedell
//
// Licensed under the Apache License v2.0 with LLVM Exceptions.
// See the LICENSE file for details.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#pragma once

#include "radr/custom/subborrow.hpp"
#include "radr/detail/pipe.hpp"
#include "radr/rad/to_single_pass.hpp"

namespace radr
{

inline namespace cpo
{
/*!\brief A NOOP range adaptor provided for compatibility.
* \param urange The underlying range.
*
* This range adaptor is semantically a NOOP, i.e. the returned range has the same elements
* and generally satisfies the same concepts. However, the actual range type will be different
* (and may be customised).
*
* ### Multi-pass adaptor
*
* Requirements:
* * `radr::mp_range<URange>`
*
* Calls radr::borrow on \p urange which may result in a customised range type being returned.
*
* Unless customised otherwise, preserves all range concepts and is transparant (preserves iterator and
* sentinel types).
*
* ### Single-pass adaptor
*
* Requirements:
* * `std::ranges::input_range<URange>`
*
* Returns the range as-is.
*/
#ifndef RADR_ALL_NO_DEPRECATED
[[deprecated(
"radr::all is provided as a (mostly) NOOP adaptor. You probably want radr::borrow instead.\n"
"You can silence this warning by defining RADR_ALL_NO_DEPRECATED.")]]
#endif
inline constexpr auto all = detail::pipe_without_args_fn<decltype(detail::to_single_pass_coro), decltype(borrow)>{};
} // namespace cpo
} // namespace radr
10 changes: 2 additions & 8 deletions include/radr/rad/as_const.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,14 @@
#include "../custom/subborrow.hpp"
#include "../detail/detail.hpp"
#include "../detail/pipe.hpp"
#include "radr/range_access.hpp"

namespace radr::detail
{

inline constexpr auto as_const_borrow = []<borrowed_mp_range URange>(URange && urange)
{
if constexpr (std::ranges::sized_range<URange>)
{
return radr::subborrow(urange, radr::cbegin(urange), radr::cend(urange), std::ranges::size(urange));
}
else
{
return radr::subborrow(urange, radr::cbegin(urange), radr::cend(urange));
}
return radr::subborrow(urange, radr::cbegin(urange), radr::cend(urange), detail::size_or_not(urange));
};

} // namespace radr::detail
Expand Down
2 changes: 1 addition & 1 deletion include/radr/rad/slice.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ namespace radr::detail
inline constexpr auto slice_borrow =
[]<std::ranges::borrowed_range URange>(URange && urange, size_t const start, size_t const end)
{
if constexpr (std::ranges::random_access_range<URange> && std::ranges::sized_range<URange>)
if constexpr (safely_indexable_range<URange>)
{
return subborrow(std::forward<URange>(urange), start, end);
}
Expand Down
Loading