From d9c3bc6345839f51495c240fcf68f6a989bf476c Mon Sep 17 00:00:00 2001 From: Enrico Seiler Date: Thu, 19 Oct 2023 17:17:24 +0200 Subject: [PATCH] Squashed 'include/hibf/contrib/std/' changes from 7292933..57a41f7 57a41f7 [FIX] chunk_by_view detection 9892f34 [FEATURE] chunk_by_view git-subtree-dir: include/hibf/contrib/std git-subtree-split: 57a41f7a99df9ff6679af166842a716db5ad8f15 --- chunk_by_view.hpp | 232 +++++++++++++++++++++++++++++++++++++++++ detail/movable_box.hpp | 161 ++++++++++++++++++++++++++++ 2 files changed, 393 insertions(+) create mode 100644 chunk_by_view.hpp create mode 100644 detail/movable_box.hpp diff --git a/chunk_by_view.hpp b/chunk_by_view.hpp new file mode 100644 index 00000000..5367a03d --- /dev/null +++ b/chunk_by_view.hpp @@ -0,0 +1,232 @@ +// SPDX-FileCopyrightText: 2006-2023, Knut Reinert & Freie Universität Berlin +// SPDX-FileCopyrightText: 2016-2023, Knut Reinert & MPI für molekulare Genetik +// SPDX-License-Identifier: BSD-3-Clause + +/*!\file + * \author Enrico Seiler + * \brief Provides seqan::stl::views::chunk_by. + */ + +// File might be included from multiple libraries. +#ifndef SEQAN_STD_CHUNK_BY_VIEW +#define SEQAN_STD_CHUNK_BY_VIEW + +#include +#include +#include + +#ifdef __cpp_lib_ranges_chunk_by + +namespace seqan::stl::views +{ + +using std::ranges::views::chunk_by; + +} // namespace seqan::stl::views + +#else + +# include "all_view.hpp" +# include "concepts.hpp" +# include "detail/adaptor_from_functor.hpp" +# include "detail/compiler_definitions.hpp" +# include "detail/movable_box.hpp" +# include "detail/non_propagating_cache.hpp" + +namespace seqan::stl::ranges +{ + +template , std::ranges::iterator_t> Pred> + requires std::ranges::view && std::is_object_v +class chunk_by_view : public std::ranges::view_interface> +{ +private: + V base_ = V(); + seqan::stl::detail::movable_box pred_; + class iterator; + + seqan::stl::detail::non_propagating_cache> current_; + + constexpr std::ranges::iterator_t find_next(std::ranges::iterator_t current) + { + assert(pred_.has_value()); + auto pred = [this](lhs_t && lhs, rhs_t && rhs) + { + // Call pred with two arguments, return logical not. + return !bool((*pred_)(std::forward(lhs), std::forward(rhs))); + }; + auto it = std::ranges::adjacent_find(current, std::ranges::end(base_), pred); + return std::ranges::next(it, 1, std::ranges::end(base_)); + } + + constexpr std::ranges::iterator_t find_prev(std::ranges::iterator_t current) + requires std::ranges::bidirectional_range + { + assert(pred_.has_value()); + auto pred = [this](lhs_t && lhs, rhs_t && rhs) + { + // Call pred with two (reversed) arguments, return logical not. + return !bool((*pred_)(std::forward(rhs), std::forward(lhs))); + }; + auto rbegin = std::make_reverse_iterator(current); + auto rend = std::make_reverse_iterator(std::ranges::begin(base_)); + assert(rbegin != rend); + auto it = std::ranges::adjacent_find(rbegin, rend, pred).base(); + return std::ranges::prev(it, 1, std::ranges::begin(base_)); + } + +public: + chunk_by_view() + requires std::default_initializable && std::default_initializable + = default; + + constexpr explicit chunk_by_view(V base, Pred pred) : base_{std::move(base)}, pred_{std::move(pred)} + {} + + constexpr V base() const & + requires std::copy_constructible + { + return base_; + } + constexpr V base() && + { + return std::move(base_); + } + + constexpr Pred const & pred() const + { + return *pred_; + } + + constexpr iterator begin() + { + assert(pred_.has_value()); + std::ranges::iterator_t it; + if (current_.has_value()) + { + it = current_.value(); + } + else + { + it = find_next(std::ranges::begin(base_)); + current_ = it; + } + + return iterator{*this, std::ranges::begin(base_), it}; + } + constexpr auto end() + { + if constexpr (std::ranges::common_range) + { + return iterator{*this, std::ranges::end(base_), std::ranges::end(base_)}; + } + else + { + return std::default_sentinel; + } + } +}; + +template +chunk_by_view(R &&, Pred) -> chunk_by_view, Pred>; + +template , std::ranges::iterator_t> Pred> + requires std::ranges::view && std::is_object_v +class chunk_by_view::iterator +{ +private: + chunk_by_view * parent_ = nullptr; + std::ranges::iterator_t current_ = std::ranges::iterator_t{}; + std::ranges::iterator_t next_ = std::ranges::iterator_t{}; + + constexpr iterator(chunk_by_view & parent, std::ranges::iterator_t current, std::ranges::iterator_t next) : + parent_{std::addressof(parent)}, + current_{std::move(current)}, + next_{std::move(next)} + {} + + friend chunk_by_view; + +public: + using value_type = std::ranges::subrange>; + using difference_type = std::ranges::range_difference_t; + using iterator_category = std::input_iterator_tag; + using iterator_concept = std::conditional_t, // + std::bidirectional_iterator_tag, + std::forward_iterator_tag>; + + iterator() = default; + + constexpr value_type operator*() const + { + assert(current_ != next_); + return std::ranges::subrange{current_, next_}; + } + constexpr iterator & operator++() + { + assert(current_ != next_); + current_ = next_; + next_ = parent_->find_next(current_); + return *this; + } + constexpr iterator operator++(int) + { + auto tmp = *this; + ++*this; + return tmp; + } + + constexpr iterator & operator--() + requires std::ranges::bidirectional_range + { + next_ = current_; + current_ = parent_->find_prev(next_); + return *this; + } + constexpr iterator operator--(int) + requires std::ranges::bidirectional_range + { + auto tmp = *this; + --*this; + return tmp; + } + + friend constexpr bool operator==(iterator const & x, iterator const & y) + { + return x.current_ == y.current_; + } + friend constexpr bool operator==(iterator const & x, std::default_sentinel_t) + { + return x.current_ == x.next_; + } +}; + +struct chunk_by_fn +{ + template + constexpr auto operator()(Predicate && pred) const + { + return seqan::stl::detail::adaptor_from_functor{*this, std::forward(pred)}; + } + + template + constexpr auto operator()(Range && range, Predicate && pred) const + { + return chunk_by_view{std::forward(range), std::forward(pred)}; + } +}; + +} // namespace seqan::stl::ranges + +namespace seqan::stl::views +{ + +inline constexpr auto chunk_by = seqan::stl::ranges::chunk_by_fn{}; + +} // namespace seqan::stl::views + +#endif // ifdef __cpp_lib_ranges_chunk_by + +#endif // SEQAN_STD_CHUNK_BY_VIEW diff --git a/detail/movable_box.hpp b/detail/movable_box.hpp new file mode 100644 index 00000000..a9daca2a --- /dev/null +++ b/detail/movable_box.hpp @@ -0,0 +1,161 @@ +// SPDX-FileCopyrightText: 2006-2023, Knut Reinert & Freie Universität Berlin +// SPDX-FileCopyrightText: 2016-2023, Knut Reinert & MPI für molekulare Genetik +// SPDX-License-Identifier: BSD-3-Clause + +/*!\file + * \author Enrico Seiler + * \brief Provides seqan::stl::detail::movable_box. + */ + +// File might be included from multiple libraries. +#ifndef SEQAN_STD_DETAIL_MOVABLE_BOX +#define SEQAN_STD_DETAIL_MOVABLE_BOX + +#include +#include + +namespace seqan::stl::detail +{ + +template +concept boxable = std::move_constructible && std::is_object_v; + +template +class movable_box : public std::optional +{ +public: + using std::optional::optional; + using std::optional::operator=; + constexpr movable_box(movable_box const &) = default; + constexpr movable_box(movable_box &&) = default; + constexpr ~movable_box() = default; + + constexpr movable_box() noexcept(std::is_nothrow_default_constructible_v) + requires std::default_initializable + : movable_box{std::in_place} + {} + + constexpr movable_box & operator=(movable_box const & other) noexcept(std::is_nothrow_copy_constructible_v) + requires (!std::copyable && std::copy_constructible) + { + if (this != std::addressof(other)) + { + if (other) + this->emplace(*other); + else + this->reset(); + } + return *this; + } + + constexpr movable_box & operator=(movable_box && other) noexcept(std::is_nothrow_move_constructible_v) + requires (!std::movable) + { + if (this != std::addressof(other)) + { + if (other) + this->emplace(std::move(*other)); + else + this->reset(); + } + return *this; + } + + template + requires std::invocable + constexpr decltype(auto) operator()(args_t... args) noexcept(std::is_nothrow_invocable_v) + { + return std::invoke(this->value(), std::forward(args)...); + } + + template + requires std::invocable + constexpr decltype(auto) operator()(args_t... args) const noexcept(std::is_nothrow_invocable_v) + { + return std::invoke(this->value(), std::forward(args)...); + } +}; + +template + requires std::copyable || (std::is_nothrow_move_constructible_v && std::is_nothrow_copy_constructible_v) +class movable_box +{ +private: + t value{}; + +public: + constexpr movable_box() + requires std::default_initializable + = default; + + constexpr movable_box(movable_box const &) = default; + constexpr movable_box(movable_box &&) = default; + constexpr ~movable_box() = default; + + constexpr movable_box & operator=(movable_box const &) = default; + + constexpr movable_box & operator=(movable_box &&) = default; + + constexpr explicit movable_box(t const & other) noexcept(std::is_nothrow_copy_constructible_v) : value{other} + {} + + constexpr explicit movable_box(t && other) noexcept(std::is_nothrow_move_constructible_v) : + value{std::move(other)} + {} + + template + requires std::constructible_from + constexpr explicit movable_box(std::in_place_t, + args_t... args) noexcept(std::is_nothrow_constructible_v) : + value{std::forward(args)...} + {} + + constexpr bool has_value() const noexcept + { + return true; // t is copyable, hence we always store a value. + } + + constexpr t & operator*() noexcept + { + return value; + } + + constexpr t const & operator*() const noexcept + { + return value; + } + + constexpr t * operator->() noexcept + { + return std::addressof(value); + } + + constexpr t const * operator->() const noexcept + { + return std::addressof(value); + } + + template + requires std::invocable + constexpr decltype(auto) operator()(args_t... args) noexcept(std::is_nothrow_invocable_v) + { + return std::invoke(value, std::forward(args)...); + } + + template + requires std::invocable + constexpr decltype(auto) operator()(args_t... args) const noexcept(std::is_nothrow_invocable_v) + { + return std::invoke(value, std::forward(args)...); + } +}; + +template +movable_box(t) -> movable_box>; + +template +using movable_box_t = movable_box>; + +} // namespace seqan::stl::detail + +#endif // SEQAN_STD_DETAIL_MOVABLE_BOX