Skip to content

Commit 13be1ee

Browse files
committed
[misc] better handling of infinite ranges
1 parent 3e53180 commit 13be1ee

File tree

9 files changed

+68
-32
lines changed

9 files changed

+68
-32
lines changed

include/radr/concepts.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,13 @@ concept weak_indirect_unary_invocable =
8080
std::invoke_result_t<F &, std::iter_reference_t<I>>>;
8181
//TODO implement P2609
8282

83+
template <typename Rng>
84+
concept infinite_mp_range = mp_range<Rng> && std::same_as<std::ranges::sentinel_t<Rng>, std::unreachable_sentinel_t>;
85+
86+
template <typename Rng>
87+
concept safely_indexable_range =
88+
std::ranges::random_access_range<Rng> && (std::ranges::sized_range<Rng> || infinite_mp_range<Rng>);
89+
8390
} // namespace radr
8491

8592
namespace radr::detail

include/radr/custom/subborrow.hpp

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "../detail/detail.hpp"
1818
#include "../rad_util/borrowing_rad.hpp"
1919
#include "../range_access.hpp"
20+
#include "radr/concepts.hpp"
2021
#include "tags.hpp"
2122

2223
namespace radr::custom
@@ -218,10 +219,13 @@ struct subborrow_impl_t
218219

219220
//!\brief Call tag_invoke if possible; call default otherwise. [i, j]
220221
template <borrowed_mp_range URange>
221-
requires(std::ranges::random_access_range<URange> && std::ranges::sized_range<URange>)
222+
requires(safely_indexable_range<URange>)
222223
constexpr auto operator()(URange && urange, size_t const start, size_t const end) const
223224
{
224-
size_t const e = std::min<size_t>(end, std::ranges::size(urange));
225+
size_t e = end;
226+
if constexpr (std::ranges::sized_range<URange>)
227+
e = std::min<size_t>(e, std::ranges::size(urange));
228+
225229
size_t const b = std::min<size_t>(start, e);
226230

227231
return operator()(std::forward<URange>(urange), radr::begin(urange) + b, radr::begin(urange) + e);
@@ -243,17 +247,10 @@ using subborrow_t = decltype(subborrow(std::declval<Args>()...));
243247
inline constexpr auto borrow =
244248
detail::overloaded{[]<borrowed_mp_range URange>(URange && urange)
245249
{
246-
if constexpr (std::ranges::sized_range<URange>)
247-
{
248-
return subborrow(std::forward<URange>(urange),
249-
radr::begin(urange),
250-
radr::end(urange),
251-
std::ranges::size(urange));
252-
}
253-
else
254-
{
255-
return subborrow(std::forward<URange>(urange), radr::begin(urange), radr::end(urange));
256-
}
250+
return subborrow(std::forward<URange>(urange),
251+
radr::begin(urange),
252+
radr::end(urange),
253+
detail::size_or_not(urange));
257254
},
258255
// if a range is already borrowed and copyable, just copy it (we assume O(1) copy)
259256
// BUT do not do this if a copy would result in a constant_range becoming a mutable range

include/radr/factory/iota.hpp

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -260,17 +260,26 @@ struct iota_fn
260260
static_assert(std::incrementable<Value>, "The Value type to radr::iota needs to satisfy std::incrementable.");
261261
static_assert(weakly_equality_comparable_with<Value, Bound>,
262262
"The Value type to radr::iota needs to be comparable with the Bound type.");
263-
static_assert(std::semiregular<Bound>, "The Bound type to radr::iota needs to satisfy std::regular.");
263+
static_assert(std::semiregular<Bound>, "The Bound type to radr::iota needs to satisfy std::semiregular.");
264264

265-
using It = detail::iota_iterator<Value>;
266-
using Sen = std::conditional_t<std::same_as<Value, Bound>, It, detail::iota_sentinel<Value, Bound>>;
265+
using It = detail::iota_iterator<Value>;
266+
if constexpr (std::same_as<Bound, std::unreachable_sentinel_t>)
267+
{
268+
return borrowing_rad<It, std::unreachable_sentinel_t, It, std::unreachable_sentinel_t>{
269+
It{val},
270+
std::unreachable_sentinel};
271+
}
272+
else
273+
{
274+
using Sen = std::conditional_t<std::same_as<Value, Bound>, It, detail::iota_sentinel<Value, Bound>>;
267275

268-
constexpr borrowing_rad_kind kind =
269-
((std::random_access_iterator<It> && std::same_as<It, Sen>) || std::sized_sentinel_for<Bound, Value>)
270-
? borrowing_rad_kind::sized
271-
: borrowing_rad_kind::unsized;
276+
constexpr borrowing_rad_kind kind =
277+
((std::random_access_iterator<It> && std::same_as<It, Sen>) || std::sized_sentinel_for<Bound, Value>)
278+
? borrowing_rad_kind::sized
279+
: borrowing_rad_kind::unsized;
272280

273-
return borrowing_rad<It, Sen, It, Sen, kind>{It{val}, Sen{bound}};
281+
return borrowing_rad<It, Sen, It, Sen, kind>{It{val}, Sen{bound}};
282+
}
274283
}
275284
};
276285

include/radr/factory/repeat.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ using constant_t = std::integral_constant<decltype(v), v>;
226226
* dimensions: \p Bound and \p storage.
227227
*
228228
* All instantiations of `repeat_rng` model at least std::semiregular, std::ranges::random_access_range and
229-
* radr::const_iterable.
229+
* radr::mp_range.
230230
*
231231
* ## Bound
232232
*

include/radr/rad/as_const.hpp

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,14 @@
1717
#include "../custom/subborrow.hpp"
1818
#include "../detail/detail.hpp"
1919
#include "../detail/pipe.hpp"
20+
#include "radr/range_access.hpp"
2021

2122
namespace radr::detail
2223
{
2324

2425
inline constexpr auto as_const_borrow = []<borrowed_mp_range URange>(URange && urange)
2526
{
26-
if constexpr (std::ranges::sized_range<URange>)
27-
{
28-
return radr::subborrow(urange, radr::cbegin(urange), radr::cend(urange), std::ranges::size(urange));
29-
}
30-
else
31-
{
32-
return radr::subborrow(urange, radr::cbegin(urange), radr::cend(urange));
33-
}
27+
return radr::subborrow(urange, radr::cbegin(urange), radr::cend(urange), detail::size_or_not(urange));
3428
};
3529

3630
} // namespace radr::detail

include/radr/rad/slice.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ namespace radr::detail
2424
inline constexpr auto slice_borrow =
2525
[]<std::ranges::borrowed_range URange>(URange && urange, size_t const start, size_t const end)
2626
{
27-
if constexpr (std::ranges::random_access_range<URange> && std::ranges::sized_range<URange>)
27+
if constexpr (safely_indexable_range<URange>)
2828
{
2929
return subborrow(std::forward<URange>(urange), start, end);
3030
}

include/radr/rad/take.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "../detail/pipe.hpp"
1717
#include "../generator.hpp"
1818
#include "../rad_util/borrowing_rad.hpp"
19+
#include "radr/concepts.hpp"
1920

2021
namespace radr::detail
2122
{
@@ -99,7 +100,7 @@ inline constexpr auto take_borrow =
99100
}
100101
},
101102
[]<borrowed_mp_range URange>(URange && urange, range_size_t_or_size_t<URange> n)
102-
requires(std::ranges::random_access_range<URange> && std::ranges::sized_range<URange>)
103+
requires(safely_indexable_range<URange>)
103104
{
104105
return subborrow(std::forward<URange>(urange), 0ull, n);
105106
}};

tests/unit/factory/iota.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <radr/test/gtest_helpers.hpp>
99

1010
#include <radr/factory/iota.hpp>
11+
#include <radr/rad/take.hpp>
1112
#include <radr/rad/take_while.hpp>
1213
#include <radr/rad/transform.hpp>
1314

@@ -74,6 +75,20 @@ TEST(iota, InfiniteRange)
7475
EXPECT_TRUE(std::ranges::borrowed_range<decltype(v)>);
7576
}
7677

78+
TEST(iota, InfiniteRangeTake)
79+
{
80+
auto v = radr::iota(0) | radr::take(5);
81+
auto it = v.begin();
82+
EXPECT_EQ(*it, 0);
83+
EXPECT_EQ(*(++it), 1);
84+
EXPECT_EQ(*(++it), 2);
85+
86+
EXPECT_TRUE(std::ranges::sized_range<decltype(v)>);
87+
EXPECT_TRUE(std::ranges::random_access_range<decltype(v)>);
88+
EXPECT_TRUE(std::ranges::common_range<decltype(v)>);
89+
EXPECT_TRUE(std::ranges::borrowed_range<decltype(v)>);
90+
}
91+
7792
TEST(iota, IotaWithCharType)
7893
{
7994
auto v = radr::iota('a', 'f');

tests/unit/factory/repeat.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,3 +395,16 @@ TYPED_TEST(repeat_rng, subborrow_infinite_size)
395395
}
396396
}
397397
}
398+
399+
TYPED_TEST(repeat_rng, take)
400+
{
401+
int i = 3;
402+
403+
TypeParam r{i, TestFixture::get_bound()};
404+
405+
auto rad = std::move(r) | radr::take(2);
406+
407+
EXPECT_TRUE(std::ranges::sized_range<decltype(rad)>);
408+
EXPECT_TRUE(radr::common_range<decltype(rad)>);
409+
EXPECT_EQ(std::ranges::size(rad), 2);
410+
}

0 commit comments

Comments
 (0)