/// \file // Range v3 library // // Copyright Eric Niebler 2014-present // Copyright Casey Carter 2017 // // 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_ANY_VIEW_HPP #define RANGES_V3_VIEW_ANY_VIEW_HPP #include #include #include #include #include #include #include #include #include #include #include #include RANGES_DIAGNOSTIC_PUSH RANGES_DIAGNOSTIC_IGNORE_INCONSISTENT_OVERRIDE namespace ranges { /// \brief An enum that denotes the supported subset of range concepts supported by a /// range. enum class category { none = 0, ///<\brief No concepts met. input = 1, ///<\brief satisfies ranges::concepts::input_range forward = 3, ///<\brief satisfies ranges::concepts::forward_range bidirectional = 7, ///<\brief satisfies ranges::concepts::bidirectional_range random_access = 15, ///<\brief satisfies ranges::concepts::random_access_range mask = random_access, ///<\brief Mask away any properties other than iterator ///< category sized = 16, ///<\brief satisfies ranges::concepts::sized_range }; /** \name Binary operators for ranges::category * \relates ranges::category * \{ */ constexpr category operator&(category lhs, category rhs) noexcept { return static_cast( static_cast>>(lhs) & static_cast>>(rhs)); } constexpr category operator|(category lhs, category rhs) noexcept { return static_cast( static_cast>>(lhs) | static_cast>>(rhs)); } constexpr category operator^(category lhs, category rhs) noexcept { return static_cast( static_cast>>(lhs) ^ static_cast>>(rhs)); } constexpr category operator~(category lhs) noexcept { return static_cast( ~static_cast>>(lhs)); } constexpr category & operator&=(category & lhs, category rhs) noexcept { return (lhs = lhs & rhs); } constexpr category & operator|=(category & lhs, category rhs) noexcept { return (lhs = lhs | rhs); } constexpr category & operator^=(category & lhs, category rhs) noexcept { return (lhs = lhs ^ rhs); } //!\} /// \brief For a given range, return a ranges::category enum with the satisfied /// concepts. template constexpr category get_categories() noexcept { return (input_range ? category::input : category::none) | (forward_range ? category::forward : category::none) | (bidirectional_range ? category::bidirectional : category::none) | (random_access_range ? category::random_access : category::none) | (sized_range ? category::sized : category::none); } /// \cond namespace detail { // workaround the fact that typeid ignores cv-qualifiers template struct rtti_tag {}; struct any_ref { any_ref() = default; template constexpr any_ref(T & obj) noexcept : obj_(detail::addressof(obj)) #ifndef NDEBUG , info_(&typeid(rtti_tag)) #endif {} template T & get() const noexcept { RANGES_ASSERT(obj_ && info_ && *info_ == typeid(rtti_tag)); return *const_cast(static_cast(obj_)); } private: void const volatile * obj_ = nullptr; #ifndef NDEBUG std::type_info const * info_ = nullptr; #endif }; template struct cloneable : Base { using Base::Base; virtual ~cloneable() = default; cloneable() = default; cloneable(cloneable const &) = delete; cloneable & operator=(cloneable const &) = delete; virtual std::unique_ptr clone() const = 0; }; // clang-format off CPP_def ( template(typename Rng, typename Ref) concept any_compatible_range, convertible_to, Ref> ); // clang-format on template struct any_view_sentinel_impl : private box, any_view_sentinel_impl> { private: using box_t = typename any_view_sentinel_impl::box; public: any_view_sentinel_impl() = default; any_view_sentinel_impl(Rng & rng) : box_t(ranges::end(rng)) {} void init(Rng & rng) noexcept { box_t::get() = ranges::end(rng); } sentinel_t const & get(Rng &) const noexcept { return box_t::get(); } }; template struct any_view_sentinel_impl< Rng, meta::void_()))>> { any_view_sentinel_impl() = default; any_view_sentinel_impl(Rng &) noexcept {} void init(Rng &) noexcept {} sentinel_t get(Rng & rng) const noexcept { return ranges::end(rng); } }; template struct any_input_view_interface { virtual ~any_input_view_interface() = default; virtual void init() = 0; virtual bool done() = 0; virtual Ref read() const = 0; virtual void next() = 0; }; template struct any_input_view_interface : any_input_view_interface { virtual std::size_t size() const = 0; }; template struct any_input_cursor { using single_pass = std::true_type; any_input_cursor() = default; constexpr any_input_cursor(any_input_view_interface & view) noexcept : view_{detail::addressof(view)} {} Ref read() const { return view_->read(); } void next() { view_->next(); } bool equal(any_input_cursor const &) const noexcept { return true; } bool equal(default_sentinel_t) const { return !view_ || view_->done(); } private: any_input_view_interface * view_ = nullptr; }; template struct RANGES_EMPTY_BASES any_input_view_impl : any_input_view_interface , private any_view_sentinel_impl { CPP_assert(any_compatible_range); CPP_assert(!Sized || (bool)sized_range); explicit any_input_view_impl(Rng rng) : rng_{std::move(rng)} {} any_input_view_impl(any_input_view_impl const &) = delete; any_input_view_impl & operator=(any_input_view_impl const &) = delete; private: using sentinel_box_t = any_view_sentinel_impl; virtual void init() override { sentinel_box_t::init(rng_); current_ = ranges::begin(rng_); } virtual bool done() override { return current_ == sentinel_box_t::get(rng_); } virtual Ref read() const override { return *current_; } virtual void next() override { ++current_; } std::size_t size() const // override-ish { return static_cast(ranges::size(rng_)); } RANGES_NO_UNIQUE_ADDRESS Rng rng_; RANGES_NO_UNIQUE_ADDRESS iterator_t current_{}; }; template struct any_cursor_interface; template struct any_cursor_interface< Ref, Cat, meta::if_c<(Cat & category::mask) == category::forward>> { virtual ~any_cursor_interface() = default; virtual any_ref iter() const = 0; // returns a const ref to the cursor's wrapped iterator virtual Ref read() const = 0; virtual bool equal(any_cursor_interface const &) const = 0; virtual void next() = 0; }; template struct any_cursor_interface< Ref, Cat, meta::if_c<(Cat & category::mask) == category::bidirectional>> : any_cursor_interface { virtual void prev() = 0; }; template struct any_cursor_interface< Ref, Cat, meta::if_c<(Cat & category::mask) == category::random_access>> : any_cursor_interface { virtual void advance(std::ptrdiff_t) = 0; virtual std::ptrdiff_t distance_to(any_cursor_interface const &) const = 0; }; template using any_cloneable_cursor_interface = cloneable>; template struct any_cursor_impl : any_cloneable_cursor_interface { CPP_assert(convertible_to, Ref>); CPP_assert((Cat & category::forward) == category::forward); any_cursor_impl() = default; any_cursor_impl(I it) : it_{std::move(it)} {} private: using Forward = any_cursor_interface; I it_; any_ref iter() const override { return it_; } Ref read() const override { return *it_; } bool equal(Forward const & that_) const override { auto & that = polymorphic_downcast(that_); return that.it_ == it_; } void next() override { ++it_; } std::unique_ptr> clone() const override { return detail::make_unique(it_); } void prev() // override (sometimes; it's complicated) { --it_; } void advance(std::ptrdiff_t n) // override-ish { it_ += n; } std::ptrdiff_t distance_to( any_cursor_interface const & that_) const // override-ish { auto & that = polymorphic_downcast(that_); return static_cast(that.it_ - it_); } }; struct fully_erased_view { virtual bool at_end( any_ref) = 0; // any_ref is a const ref to a wrapped iterator // to be compared to the erased view's last sentinel protected: ~fully_erased_view() = default; }; struct any_sentinel { any_sentinel() = default; constexpr explicit any_sentinel(fully_erased_view & view) noexcept : view_{&view} {} private: template friend struct any_cursor; fully_erased_view * view_ = nullptr; }; template struct any_cursor { private: CPP_assert((Cat & category::forward) == category::forward); std::unique_ptr> ptr_; template using impl_t = any_cursor_impl, Ref, Cat>; public: any_cursor() = default; template explicit CPP_ctor(any_cursor)(Rng && rng)( // requires(!ranges::defer::same_as, any_cursor>) && ranges::defer::forward_range && defer::any_compatible_range) : ptr_{detail::make_unique>(begin(rng))} {} any_cursor(any_cursor &&) = default; any_cursor(any_cursor const & that) : ptr_{that.ptr_ ? that.ptr_->clone() : nullptr} {} any_cursor & operator=(any_cursor &&) = default; any_cursor & operator=(any_cursor const & that) { ptr_ = (that.ptr_ ? that.ptr_->clone() : nullptr); return *this; } Ref read() const { RANGES_EXPECT(ptr_); return ptr_->read(); } bool equal(any_cursor const & that) const { RANGES_EXPECT(!ptr_ == !that.ptr_); return !ptr_ || ptr_->equal(*that.ptr_); } bool equal(any_sentinel const & that) const { RANGES_EXPECT(!ptr_ == !that.view_); return !ptr_ || that.view_->at_end(ptr_->iter()); } void next() { RANGES_EXPECT(ptr_); ptr_->next(); } CPP_member auto prev() -> CPP_ret(void)( // requires(category::bidirectional == (Cat & category::bidirectional))) { RANGES_EXPECT(ptr_); ptr_->prev(); } CPP_member auto advance(std::ptrdiff_t n) -> CPP_ret(void)( // requires(category::random_access == (Cat & category::random_access))) { RANGES_EXPECT(ptr_); ptr_->advance(n); } CPP_member auto distance_to(any_cursor const & that) const -> CPP_ret(std::ptrdiff_t)( // requires(category::random_access == (Cat & category::random_access))) { RANGES_EXPECT(!ptr_ == !that.ptr_); return !ptr_ ? 0 : ptr_->distance_to(*that.ptr_); } }; template struct any_view_interface : fully_erased_view { CPP_assert((Cat & category::forward) == category::forward); virtual ~any_view_interface() = default; virtual any_cursor begin_cursor() = 0; }; template struct any_view_interface : any_view_interface { virtual std::size_t size() const = 0; }; template using any_cloneable_view_interface = cloneable>; template struct RANGES_EMPTY_BASES any_view_impl : any_cloneable_view_interface , private box> , private any_view_sentinel_impl { CPP_assert((Cat & category::forward) == category::forward); CPP_assert(any_compatible_range); CPP_assert((Cat & category::sized) == category::none || (bool)sized_range); any_view_impl() = default; any_view_impl(Rng rng) : range_box_t{std::move(rng)} , sentinel_box_t{range_box_t::get()} // NB: initialization order dependence {} private: using range_box_t = box; using sentinel_box_t = any_view_sentinel_impl; any_cursor begin_cursor() override { return any_cursor{range_box_t::get()}; } bool at_end(any_ref it_) override { auto & it = it_.get const>(); return it == sentinel_box_t::get(range_box_t::get()); } std::unique_ptr> clone() const override { return detail::make_unique(range_box_t::get()); } std::size_t size() const // override-ish { return static_cast(ranges::size(range_box_t::get())); } }; } // namespace detail /// \endcond /// \brief A type-erased view /// \ingroup group-views template struct any_view : view_facade, (Cat & category::sized) == category::sized ? finite : unknown> { friend range_access; CPP_assert((Cat & category::forward) == category::forward); any_view() = default; template CPP_ctor(any_view)(Rng && rng)( // requires(!defer::same_as, any_view>) && defer::input_range && detail::defer::any_compatible_range) : any_view(static_cast(rng), meta::bool_<(get_categories() & Cat) == Cat>{}) {} any_view(any_view &&) = default; any_view(any_view const & that) : ptr_{that.ptr_ ? that.ptr_->clone() : nullptr} {} any_view & operator=(any_view &&) = default; any_view & operator=(any_view const & that) { ptr_ = (that.ptr_ ? that.ptr_->clone() : nullptr); return *this; } CPP_member auto size() const -> CPP_ret(std::size_t)( // requires(category::sized == (Cat & category::sized))) { return ptr_ ? ptr_->size() : 0; } private: template using impl_t = detail::any_view_impl, Ref, Cat>; template any_view(Rng && rng, std::true_type) : ptr_{detail::make_unique>(views::all(static_cast(rng)))} {} template any_view(Rng &&, std::false_type) { static_assert( (get_categories() & Cat) == Cat, "The range passed to any_view() does not model the requested category"); } detail::any_cursor begin_cursor() { return ptr_ ? ptr_->begin_cursor() : detail::value_init{}; } detail::any_sentinel end_cursor() noexcept { return detail::any_sentinel{*ptr_}; } std::unique_ptr> ptr_; }; // input and not forward template struct any_view> : view_facade, (Cat & category::sized) == category::sized ? finite : unknown> { friend range_access; any_view() = default; template CPP_ctor(any_view)(Rng && rng)( // requires(!defer::same_as, any_view>) && defer::input_range && detail::defer::any_compatible_range) : ptr_{std::make_shared>(views::all(static_cast(rng)))} {} CPP_member auto size() const -> CPP_ret(std::size_t)( // requires(category::sized == (Cat & category::sized))) { return ptr_ ? ptr_->size() : 0; } private: template using impl_t = detail::any_input_view_impl, Ref, (Cat & category::sized) == category::sized>; detail::any_input_cursor begin_cursor() { if(!ptr_) return {}; ptr_->init(); return detail::any_input_cursor{*ptr_}; } std::shared_ptr> ptr_; }; #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17 CPP_template(typename Rng)( // requires view_) // any_view(Rng &&) ->any_view, get_categories()>; #endif template using any_input_view RANGES_DEPRECATED( "Use any_view instead.") = any_view; template using any_forward_view RANGES_DEPRECATED( "Use any_view instead.") = any_view; template using any_bidirectional_view RANGES_DEPRECATED( "Use any_view instead.") = any_view; template using any_random_access_view RANGES_DEPRECATED( "Use any_view instead.") = any_view; } // namespace ranges #include RANGES_SATISFY_BOOST_RANGE(::ranges::any_view) RANGES_DIAGNOSTIC_POP #endif