/// \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 #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_auto_member constexpr auto CPP_fun(size)()(const // requires sized_range) { auto const n = ranges::size(this->base()); return n ? n * 2 - 1 : 0; } CPP_auto_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; constexpr explicit cursor_adaptor(range_value_t const & val) : val_{val} {} template(bool Other)( requires Const AND CPP_NOT(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; template(bool Other)( requires Const AND CPP_NOT(Other)) // sentinel_adaptor(sentinel_adaptor) {} static constexpr bool empty(iterator_t const & it, cursor_adaptor const &, sentinel_t const & sent) { return it == sent; } }; constexpr cursor_adaptor begin_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(bool Const = true)( requires Const AND range> AND common_range> AND (!single_pass_iterator_>>)) // constexpr cursor_adaptor end_adaptor() const { return cursor_adaptor{val_}; } template(bool Const = true)( requires Const AND range> AND (!common_range> || single_pass_iterator_>>)) // constexpr sentinel_adaptor end_adaptor() const noexcept { return {}; } range_value_t val_; }; template RANGES_INLINE_VAR constexpr bool enable_borrowed_range> = // enable_borrowed_range; #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17 template intersperse_view(Rng &&, range_value_t) -> intersperse_view>; #endif namespace views { struct intersperse_base_fn { template(typename Rng)( requires viewable_range AND input_range AND convertible_to, range_value_t> AND semiregular>) constexpr intersperse_view> // operator()(Rng && rng, range_value_t val) const { return {all(static_cast(rng)), std::move(val)}; } }; struct intersperse_fn : intersperse_base_fn { using intersperse_base_fn::operator(); template(typename T)( requires copyable) constexpr auto operator()(T t) const { return make_view_closure(bind_back(intersperse_base_fn{}, std::move(t))); } }; /// \relates intersperse_fn /// \ingroup group-views RANGES_INLINE_VARIABLE(intersperse_fn, intersperse) } // namespace views } // namespace ranges #include #include RANGES_SATISFY_BOOST_RANGE(::ranges::intersperse_view) #endif