Skip to content

Commit c76428a

Browse files
authored
Improve run_length_sequence interface (#80)
2 parents 81d5682 + 42361a9 commit c76428a

3 files changed

Lines changed: 107 additions & 6 deletions

File tree

‎include/iris/error/throwf.hpp‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,12 @@ inline namespace error_functions {
2424
// critical paths as some compilers fail to optimize the plain `throw` statement
2525
// even though the statement itself should imply `[[noreturn]]`.
2626
template<class E>
27+
requires std::is_default_constructible_v<E>
2728
IRIS_CONFIG_THROW_NORETURN void throwf()
2829
{
2930
static_assert(std::is_base_of_v<std::exception, E>);
3031
static_assert(std::is_constructible_v<E>);
31-
IRIS_CONFIG_THROW_IMPL(E{});
32+
IRIS_CONFIG_THROW_IMPL(E());
3233
}
3334

3435
// This function can be used to strongly assume optimization in some performance-
@@ -40,7 +41,7 @@ IRIS_CONFIG_THROW_NORETURN void throwf(Arg&& arg, Rest&&... rest)
4041
{
4142
static_assert(std::is_base_of_v<std::exception, E>);
4243
static_assert(!std::is_base_of_v<std::exception, std::remove_cvref_t<Arg>>, "don't copy/move construct exception types directly");
43-
IRIS_CONFIG_THROW_IMPL(E{std::forward<Arg>(arg), std::forward<Rest>(rest)...});
44+
IRIS_CONFIG_THROW_IMPL(E(std::forward<Arg>(arg), std::forward<Rest>(rest)...));
4445
}
4546

4647
} // error_functions

‎include/iris/error/throwf_format.hpp‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,15 @@ template<class E, class... Args>
3333
IRIS_CONFIG_THROW_NORETURN void throwf(std::format_string<Args...> fmt, Args&&... args)
3434
{
3535
static_assert(std::is_base_of_v<std::exception, E>);
36-
IRIS_CONFIG_THROW_IMPL(E{std::format(std::move(fmt), std::forward<Args>(args)...)});
36+
IRIS_CONFIG_THROW_IMPL(E(std::format(std::move(fmt), std::forward<Args>(args)...)));
3737
}
3838

3939
template<class E, NotStringLike Arg0, class... Args>
4040
requires detail::constructible_from_string_like_types<E, Arg0>
4141
IRIS_CONFIG_THROW_NORETURN void throwf(Arg0&& arg0, std::format_string<Args...> fmt, Args&&... args)
4242
{
4343
static_assert(std::is_base_of_v<std::exception, E>);
44-
IRIS_CONFIG_THROW_IMPL(E{std::forward<Arg0>(arg0), std::format(std::move(fmt), std::forward<Args>(args)...)});
44+
IRIS_CONFIG_THROW_IMPL(E(std::forward<Arg0>(arg0), std::format(std::move(fmt), std::forward<Args>(args)...)));
4545
}
4646

4747
template<class E, NotStringLike Arg0, NotStringLike Arg1, class... Args>
@@ -50,10 +50,10 @@ IRIS_CONFIG_THROW_NORETURN void throwf(Arg0&& arg0, Arg1&& arg1, std::format_str
5050
{
5151
static_assert(std::is_base_of_v<std::exception, E>);
5252
IRIS_CONFIG_THROW_IMPL(
53-
E{
53+
E(
5454
std::forward<Arg0>(arg0), std::forward<Arg1>(arg1),
5555
std::format(std::move(fmt), std::forward<Args>(args)...)
56-
}
56+
)
5757
);
5858
}
5959

‎include/iris/run_length_sequence.hpp‎

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <iris/requirements.hpp>
1616
#include <iris/type_traits.hpp>
1717

18+
#include <functional>
1819
#include <algorithm>
1920
#include <vector>
2021
#include <ranges>
@@ -145,6 +146,23 @@ class run_length_sequence
145146
return {index(), *value_it_};
146147
}
147148

149+
[[nodiscard]] constexpr T const& run_value() const noexcept
150+
{
151+
return *value_it_;
152+
}
153+
154+
constexpr void advance_run() noexcept
155+
{
156+
++ofs_it_;
157+
++value_it_;
158+
rel_pos_ = static_cast<IndexT>(0u);
159+
}
160+
[[nodiscard]] friend constexpr iterator_impl next_run(iterator_impl it) noexcept
161+
{
162+
it.advance_run();
163+
return it;
164+
}
165+
148166
constexpr iterator_impl& operator++() noexcept
149167
{
150168
auto ofs_next = std::next(ofs_it_);
@@ -469,6 +487,88 @@ class run_length_sequence
469487
);
470488
}
471489

490+
template<class Pred>
491+
requires std::predicate<Pred&, T const&>
492+
[[nodiscard]] constexpr const_iterator find_run_if(const_iterator from, Pred&& pred) const
493+
noexcept(std::is_nothrow_invocable_v<Pred&, T const&>)
494+
{
495+
auto const last = this->end();
496+
for (; from != last; from.advance_run()) {
497+
if (std::invoke(pred, from.run_value())) {
498+
return from;
499+
}
500+
}
501+
return last;
502+
}
503+
504+
template<class Pred>
505+
requires std::predicate<Pred&, T const&>
506+
[[nodiscard]] constexpr const_iterator find_run_if_not(const_iterator from, Pred&& pred) const
507+
noexcept(std::is_nothrow_invocable_v<Pred&, T const&>)
508+
{
509+
auto const last = this->end();
510+
for (; from != last; from.advance_run()) {
511+
if (!std::invoke(pred, from.run_value())) {
512+
return from;
513+
}
514+
}
515+
return last;
516+
}
517+
518+
template<class U>
519+
requires req::half_equality_comparable<T, U>
520+
[[nodiscard]] constexpr const_iterator find_run(const_iterator from, U const& value) const
521+
noexcept(noexcept(std::declval<T const&>() == value))
522+
{
523+
return this->find_run_if(std::move(from), [&](T const& e) noexcept(noexcept(e == value)) {
524+
return e == value;
525+
});
526+
}
527+
528+
template<class U>
529+
requires req::half_equality_comparable<T, U>
530+
[[nodiscard]] constexpr const_iterator find_run_not(const_iterator from, U const& value) const
531+
noexcept(noexcept(std::declval<T const&>() != value))
532+
{
533+
return this->find_run_if(std::move(from), [&](T const& e) noexcept(noexcept(e != value)) {
534+
return e != value;
535+
});
536+
}
537+
538+
// ---------------------------------------------------------------------
539+
540+
template<class Pred>
541+
requires std::predicate<Pred&, T const&>
542+
[[nodiscard]] constexpr const_iterator find_run_if(Pred&& pred) const
543+
noexcept(noexcept(this->find_run_if(begin(), std::forward<Pred>(pred))))
544+
{
545+
return this->find_run_if(begin(), std::forward<Pred>(pred));
546+
}
547+
548+
template<class Pred>
549+
requires std::predicate<Pred&, T const&>
550+
[[nodiscard]] constexpr const_iterator find_run_if_not(Pred&& pred) const
551+
noexcept(noexcept(this->find_run_if_not(begin(), std::forward<Pred>(pred))))
552+
{
553+
return this->find_run_if_not(begin(), std::forward<Pred>(pred));
554+
}
555+
556+
template<class U>
557+
requires req::half_equality_comparable<T, U>
558+
[[nodiscard]] constexpr const_iterator find_run(U const& value) const
559+
noexcept(noexcept(this->find_run(begin(), value)))
560+
{
561+
return this->find_run(begin(), value);
562+
}
563+
564+
template<class U>
565+
requires req::half_equality_comparable<T, U>
566+
[[nodiscard]] constexpr const_iterator find_run_not(U const& value) const
567+
noexcept(noexcept(this->find_run_not(begin(), value)))
568+
{
569+
return this->find_run_not(begin(), value);
570+
}
571+
472572
// ---------------------------------------------------------------------
473573

474574
// Returns an iterator to the element at logical position `pos`, or `end()`

0 commit comments

Comments
 (0)