/// \file // Range v3 library // // Copyright Eric Niebler 2013-present // // Use, modification and distribution is subject to the // Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // // Project home: https://github.com/ericniebler/range-v3 // #ifndef RANGES_V3_VIEW_INTERSPERSE_HPP #define RANGES_V3_VIEW_INTERSPERSE_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include namespace ranges { /// \addtogroup group-views /// @{ template struct intersperse_view : view_adaptor, Rng, (range_cardinality::value > 0) ? static_cast(range_cardinality::value * 2 - 1) : range_cardinality::value> { intersperse_view() = default; constexpr intersperse_view(Rng rng, range_value_t val) : intersperse_view::view_adaptor{detail::move(rng)} , val_(detail::move(val)) {} CPP_member constexpr auto CPP_fun(size)()(const requires sized_range) { auto const n = ranges::size(this->base()); return n ? n * 2 - 1 : 0; } CPP_member constexpr auto CPP_fun(size)()(requires sized_range) { auto const n = ranges::size(this->base()); return n ? n * 2 - 1 : 0; } private: friend range_access; template struct cursor_adaptor : adaptor_base { private: friend struct cursor_adaptor; using CRng = meta::const_if_c; bool toggle_ = false; range_value_t val_; public: cursor_adaptor() = default; explicit constexpr cursor_adaptor(range_value_t const & val) : val_{val} {} CPP_template(bool Other)( // requires Const && (!Other)) cursor_adaptor(cursor_adaptor that) : toggle_(that.toggle_) , val_(std::move(that.val_)) {} template constexpr iterator_t begin(View & view) { auto first = ranges::begin(view.base()); toggle_ = first != ranges::end(view.base()); return first; } constexpr range_value_t read(iterator_t const & it) const { return toggle_ ? *it : val_; } CPP_member constexpr auto equal(iterator_t const & it0, iterator_t const & it1, cursor_adaptor const & other) const -> CPP_ret(bool)( // requires sentinel_for, iterator_t>) { return it0 == it1 && toggle_ == other.toggle_; } constexpr void next(iterator_t & it) { if(toggle_) ++it; toggle_ = !toggle_; } CPP_member constexpr auto prev(iterator_t & it) -> CPP_ret(void)( // requires bidirectional_range) { toggle_ = !toggle_; if(toggle_) --it; } CPP_member constexpr auto distance_to(iterator_t const & it, iterator_t const & other_it, cursor_adaptor const & other) const -> CPP_ret(range_difference_t)( // requires sized_sentinel_for, iterator_t>) { return (other_it - it) * 2 + (other.toggle_ - toggle_); } CPP_member constexpr auto advance(iterator_t & it, range_difference_t n) -> CPP_ret(void)( // requires random_access_range) { ranges::advance(it, n >= 0 ? (n + toggle_) / 2 : (n - !toggle_) / 2); if(n % 2 != 0) toggle_ = !toggle_; } }; template struct sentinel_adaptor : adaptor_base { private: using CRng = meta::const_if_c; public: sentinel_adaptor() = default; CPP_template(bool Other)( // requires Const && (!Other)) sentinel_adaptor(sentinel_adaptor) {} static constexpr bool empty(iterator_t const & it, cursor_adaptor const &, sentinel_t const & sent) { return it == sent; } }; constexpr auto begin_adaptor() -> cursor_adaptor { return cursor_adaptor{val_}; } CPP_member constexpr auto begin_adaptor() const -> CPP_ret(cursor_adaptor)( // requires range) { return cursor_adaptor{val_}; } CPP_member constexpr auto end_adaptor() -> CPP_ret(cursor_adaptor)( // requires common_range && (!single_pass_iterator_>)) { return cursor_adaptor{val_}; } CPP_member constexpr auto end_adaptor() noexcept -> CPP_ret(sentinel_adaptor)( // requires(!common_range) || single_pass_iterator_>) { return {}; } template constexpr auto end_adaptor() const -> CPP_ret(cursor_adaptor)( // requires Const && range> && common_range> && (!single_pass_iterator_>>)) { return cursor_adaptor{val_}; } template constexpr auto end_adaptor() const noexcept -> CPP_ret(sentinel_adaptor)( // requires Const && range> && (!common_range> || single_pass_iterator_>>)) { return {}; } range_value_t val_; }; #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17 template intersperse_view(Rng &&, range_value_t)->intersperse_view>; #endif namespace views { struct intersperse_fn { private: friend view_access; template static constexpr auto CPP_fun(bind)(intersperse_fn intersperse, T t)( // requires copyable) { return make_pipeable(bind_back(intersperse, std::move(t))); } public: template constexpr auto operator()(Rng && rng, range_value_t val) const -> CPP_ret(intersperse_view>)( // requires viewable_range && input_range && convertible_to, range_value_t> && semiregular>) { return {all(static_cast(rng)), std::move(val)}; } }; /// \relates intersperse_fn /// \ingroup group-views RANGES_INLINE_VARIABLE(view, intersperse) } // namespace views } // namespace ranges #include RANGES_SATISFY_BOOST_RANGE(::ranges::intersperse_view) #endif