diff --git a/include/seqan3/contrib/std/LICENSE.md b/include/seqan3/contrib/std/LICENSE.md index 1a476688cb..4a99f9dc08 100644 --- a/include/seqan3/contrib/std/LICENSE.md +++ b/include/seqan3/contrib/std/LICENSE.md @@ -1,5 +1,5 @@ -Copyright (c) 2006-2024, Knut Reinert & Freie Universität Berlin -Copyright (c) 2016-2024, Knut Reinert & MPI für molekulare Genetik +Copyright (c) 2006-2025, Knut Reinert & Freie Universität Berlin +Copyright (c) 2016-2025, Knut Reinert & MPI für molekulare Genetik All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/include/seqan3/contrib/std/detail/exposition_only.hpp b/include/seqan3/contrib/std/detail/exposition_only.hpp index 45ef83cae1..3e383c8b47 100644 --- a/include/seqan3/contrib/std/detail/exposition_only.hpp +++ b/include/seqan3/contrib/std/detail/exposition_only.hpp @@ -30,6 +30,11 @@ concept simple_view = std::ranges::view && std::ranges::range using maybe_const = std::conditional_t; +template +concept range_with_movable_references = + std::ranges::input_range && std::move_constructible> + && std::move_constructible>; + } // namespace seqan::stl::detail #endif // SEQAN_STD_DETAIL_EXPOSITION_ONLY diff --git a/include/seqan3/contrib/std/detail/movable_box.hpp b/include/seqan3/contrib/std/detail/movable_box.hpp index 0dbc87047e..7040f60d0c 100644 --- a/include/seqan3/contrib/std/detail/movable_box.hpp +++ b/include/seqan3/contrib/std/detail/movable_box.hpp @@ -77,7 +77,10 @@ class movable_box : public std::optional }; template - requires std::copyable || (std::is_nothrow_move_constructible_v && std::is_nothrow_copy_constructible_v) + requires std::copyable + || (std::is_copy_constructible_v && std::is_nothrow_move_constructible_v + && std::is_nothrow_copy_constructible_v) + || (!std::is_copy_constructible_v && (std::movable || std::is_nothrow_move_constructible_v)) class movable_box { private: @@ -92,13 +95,39 @@ class movable_box constexpr movable_box(movable_box &&) = default; constexpr ~movable_box() = default; - constexpr movable_box & operator=(movable_box const &) = default; + constexpr movable_box & operator=(movable_box const &) + requires std::copyable + = default; - constexpr movable_box & operator=(movable_box &&) = default; + constexpr movable_box & operator=(movable_box &&) + requires std::movable + = default; constexpr explicit movable_box(t const & other) noexcept(std::is_nothrow_copy_constructible_v) : value{other} {} + 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)) + { + value.~t(); + std::construct_at(std::addressof(value), other.value); + } + return *this; + } + + constexpr movable_box & operator=(movable_box && other) noexcept(std::is_nothrow_move_constructible_v) + requires (!std::movable) + { + if (this != std::addressof(other)) + { + value.~t(); + std::construct_at(std::addressof(value), std::move(other.value)); + } + return *this; + } + constexpr explicit movable_box(t && other) noexcept(std::is_nothrow_move_constructible_v) : value{std::move(other)} {} diff --git a/include/seqan3/contrib/std/enumerate_view.hpp b/include/seqan3/contrib/std/enumerate_view.hpp new file mode 100644 index 0000000000..77c2b6f77c --- /dev/null +++ b/include/seqan3/contrib/std/enumerate_view.hpp @@ -0,0 +1,341 @@ +// SPDX-FileCopyrightText: 2006-2025 Knut Reinert & Freie Universität Berlin +// SPDX-FileCopyrightText: 2016-2025 Knut Reinert & MPI für molekulare Genetik +// SPDX-License-Identifier: BSD-3-Clause + +/*!\file + * \author Enrico Seiler + * \brief Provides seqan::stl::views::enumerate. + */ + +// File might be included from multiple libraries. +#ifndef SEQAN_STD_ENUMERATE_VIEW +#define SEQAN_STD_ENUMERATE_VIEW + +#include +#include + +#ifdef __cpp_lib_ranges_enumerate + +namespace seqan::stl::views +{ + +using std::ranges::views::enumerate; + +} // 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/exposition_only.hpp" + +namespace seqan::stl::ranges +{ + +template + requires seqan::stl::detail::range_with_movable_references +class enumerate_view : public std::ranges::view_interface> +{ + // clang-format off +SEQAN_STD_NESTED_VISIBILITY + // clang-format on + V base_ = V(); + + template + class iterator; + + template + class sentinel; + +public: + constexpr enumerate_view() + requires std::default_initializable + = default; + + constexpr explicit enumerate_view(V base) : base_{std::move(base)} + {} + + constexpr auto begin() + requires (!seqan::stl::detail::simple_view) + { + return iterator{std::ranges::begin(base_), 0}; + } + constexpr auto begin() const + requires seqan::stl::detail::range_with_movable_references + { + return iterator{std::ranges::begin(base_), 0}; + } + + constexpr auto end() + requires (!seqan::stl::detail::simple_view) + { + if constexpr (std::ranges::forward_range && std::ranges::common_range && std::ranges::sized_range) + return iterator{std::ranges::end(base_), std::ranges::distance(base_)}; + else + return sentinel{std::ranges::end(base_)}; + } + constexpr auto end() const + requires seqan::stl::detail::range_with_movable_references + { + if constexpr (std::ranges::forward_range && std::ranges::common_range + && std::ranges::sized_range) + return iterator{std::ranges::end(base_), std::ranges::distance(base_)}; + else + return sentinel{std::ranges::end(base_)}; + } + + constexpr auto size() + requires std::ranges::sized_range + { + return std::ranges::size(base_); + } + constexpr auto size() const + requires std::ranges::sized_range + { + return std::ranges::size(base_); + } + + constexpr V base() const & + requires std::copy_constructible + { + return base_; + } + constexpr V base() && + { + return std::move(base_); + } +}; + +template +enumerate_view(R &&) -> enumerate_view>; + +template + requires seqan::stl::detail::range_with_movable_references +template +class enumerate_view::iterator +{ + friend enumerate_view; + using Base = seqan::stl::detail::maybe_const; + +public: + using iterator_category = std::input_iterator_tag; + using iterator_concept = std::conditional_t< + std::ranges::random_access_range, + std::random_access_iterator_tag, + std::conditional_t< + std::ranges::bidirectional_range, + std::bidirectional_iterator_tag, + std::conditional_t, std::forward_iterator_tag, std::input_iterator_tag>>>; + using difference_type = std::ranges::range_difference_t; + using value_type = std::tuple, std::ranges::range_value_t>; + +private: + using reference_type = std::tuple, std::ranges::range_reference_t>; + std::ranges::iterator_t current_ = std::ranges::iterator_t{}; + difference_type pos_ = 0; + + constexpr explicit iterator(std::ranges::iterator_t current, difference_type pos) : + current_{std::move(current)}, + pos_{pos} + {} + +public: + iterator() + requires std::default_initializable> + = default; + constexpr iterator(iterator i) + requires Const && std::convertible_to, std::ranges::iterator_t> + : current_{std::move(i.current_)}, pos_{i.pos_} + {} + + constexpr std::ranges::iterator_t const & base() const & noexcept + { + return current_; + } + constexpr std::ranges::iterator_t base() && + { + return std::move(current_); + } + + constexpr difference_type index() const noexcept + { + return pos_; + } + + constexpr auto operator*() const + { + return reference_type{pos_, *current_}; + } + + constexpr iterator & operator++() + { + ++current_; + ++pos_; + return *this; + } + constexpr void operator++(int) + { + ++*this; + } + constexpr iterator operator++(int) + requires std::ranges::forward_range + { + auto temp = *this; + ++*this; + return temp; + } + + constexpr iterator & operator--() + requires std::ranges::bidirectional_range + { + --current_; + --pos_; + return *this; + } + constexpr iterator operator--(int) + requires std::ranges::bidirectional_range + { + auto temp = *this; + --*this; + return temp; + } + + constexpr iterator & operator+=(difference_type n) + requires std::ranges::random_access_range + { + current_ += n; + pos_ += n; + return *this; + } + constexpr iterator & operator-=(difference_type n) + requires std::ranges::random_access_range + { + current_ -= n; + pos_ -= n; + return *this; + } + + constexpr auto operator[](difference_type x) const + requires std::ranges::random_access_range + { + return reference_type{pos_ + x, current_[x]}; + } + + friend constexpr bool operator==(iterator const & x, iterator const & y) noexcept + { + return x.pos_ == y.pos_; + } +# ifdef __cpp_lib_three_way_comparison + friend constexpr std::strong_ordering operator<=>(iterator const & x, iterator const & y) noexcept + { + return x.pos_ <=> y.pos_; + } +# endif + + friend constexpr iterator operator+(iterator const & x, difference_type y) + requires std::ranges::random_access_range + { + auto temp = x; + temp += y; + return temp; + } + friend constexpr iterator operator+(difference_type x, iterator const & y) + requires std::ranges::random_access_range + { + return y + x; + } + friend constexpr iterator operator-(iterator const & x, difference_type y) + requires std::ranges::random_access_range + { + auto temp = x; + temp -= y; + return temp; + } + friend constexpr difference_type operator-(iterator const & x, iterator const & y) noexcept + { + return x.pos_ - y.pos_; + } + + friend constexpr auto + iter_move(iterator const & i) noexcept(noexcept(std::ranges::iter_move(i.current_)) + && std::is_nothrow_move_constructible_v>) + { + return std::tuple>{ + i.pos_, + std::ranges::iter_move(i.current_)}; + } +}; + +template + requires seqan::stl::detail::range_with_movable_references +template +class enumerate_view::sentinel +{ + friend enumerate_view; + using Base = seqan::stl::detail::maybe_const; + std::ranges::sentinel_t end_ = std::ranges::sentinel_t{}; + constexpr explicit sentinel(std::ranges::sentinel_t end) : end_{std::move(end)} + {} + +public: + sentinel() = default; + constexpr sentinel(sentinel other) + requires Const && std::convertible_to, std::ranges::sentinel_t> + : end_{std::move(other.end_)} + {} + + constexpr std::ranges::sentinel_t base() const + { + return end_; + } + + template + requires std::sentinel_for, + std::ranges::iterator_t>> + friend constexpr bool operator==(iterator const & x, sentinel const & y) noexcept + { + return x.current_ == y.end_; + } + + template + requires std::sentinel_for, + std::ranges::iterator_t>> + friend constexpr std::ranges::range_difference_t> + operator-(iterator const & x, sentinel const & y) + { + return x.current_ - y.end_; + } + + template + requires std::sized_sentinel_for, + std::ranges::iterator_t>> + friend constexpr std::ranges::range_difference_t> + operator-(sentinel const & x, iterator const & y) + { + return x.end_ - y.current_; + } +}; + +struct enumerate_fn +{ + template + constexpr auto operator()(Range && range) const + { + return enumerate_view{std::forward(range)}; + } +}; + +} // namespace seqan::stl::ranges + +namespace seqan::stl::views +{ + +inline constexpr auto enumerate = seqan::stl::ranges::enumerate_fn{}; + +} // namespace seqan::stl::views + +#endif // ifdef __cpp_lib_ranges_enumerate + +#endif // SEQAN_STD_ENUMERATE_VIEW