// Copyright (C) 2019 T. Zachary Laine // // Distributed under 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) #ifndef BOOST_STL_INTERFACES_VIEW_INTERFACE_HPP #define BOOST_STL_INTERFACES_VIEW_INTERFACE_HPP #include namespace boost { namespace stl_interfaces { BOOST_STL_INTERFACES_NAMESPACE_V1 { /** A CRTP template that one may derive from to make it easier to define `std::ranges::view`-like types with a container-like interface. This is a pre-C++20 version of C++20's `view_interface` (see [view.interface] in the C++ standard). The template parameter `D` for `view_interface` may be an incomplete type. Before any member of the resulting specialization of `view_interface` other than special member functions is referenced, `D` shall be complete, and model both `std::derived_from>` and `std::view`. */ template< typename Derived, element_layout Contiguity = element_layout::discontiguous #ifndef BOOST_STL_INTERFACES_DOXYGEN , typename E = std::enable_if_t< std::is_class::value && std::is_same>::value> #endif > struct view_interface; namespace v1_dtl { template void derived_view(view_interface const &); } template< typename Derived, element_layout Contiguity #ifndef BOOST_STL_INTERFACES_DOXYGEN , typename E #endif > struct view_interface { #ifndef BOOST_STL_INTERFACES_DOXYGEN private: constexpr Derived & derived() noexcept { return static_cast(*this); } constexpr const Derived & derived() const noexcept { return static_cast(*this); } #endif public: template constexpr auto empty() noexcept( noexcept(std::declval().begin() == std::declval().end())) -> decltype( std::declval().begin() == std::declval().end()) { return derived().begin() == derived().end(); } template constexpr auto empty() const noexcept(noexcept( std::declval().begin() == std::declval().end())) -> decltype( std::declval().begin() == std::declval().end()) { return derived().begin() == derived().end(); } template< typename D = Derived, typename R = decltype(std::declval().empty())> constexpr explicit operator bool() noexcept(noexcept(std::declval().empty())) { return !derived().empty(); } template< typename D = Derived, typename R = decltype(std::declval().empty())> constexpr explicit operator bool() const noexcept(noexcept(std::declval().empty())) { return !derived().empty(); } template< typename D = Derived, element_layout C = Contiguity, typename Enable = std::enable_if_t> constexpr auto data() noexcept(noexcept(std::declval().begin())) -> decltype(std::addressof(*std::declval().begin())) { return std::addressof(*derived().begin()); } template< typename D = Derived, element_layout C = Contiguity, typename Enable = std::enable_if_t> constexpr auto data() const noexcept(noexcept(std::declval().begin())) -> decltype(std::addressof(*std::declval().begin())) { return std::addressof(*derived().begin()); } template constexpr auto size() noexcept( noexcept(std::declval().end() - std::declval().begin())) -> decltype(std::declval().end() - std::declval().begin()) { return derived().end() - derived().begin(); } template constexpr auto size() const noexcept(noexcept( std::declval().end() - std::declval().begin())) -> decltype( std::declval().end() - std::declval().begin()) { return derived().end() - derived().begin(); } template constexpr auto front() noexcept(noexcept(*std::declval().begin())) -> decltype(*std::declval().begin()) { return *derived().begin(); } template constexpr auto front() const noexcept(noexcept(*std::declval().begin())) -> decltype(*std::declval().begin()) { return *derived().begin(); } template< typename D = Derived, typename Enable = std::enable_if_t< v1_dtl::decrementable_sentinel::value && v1_dtl::common_range::value>> constexpr auto back() noexcept(noexcept(*std::prev(std::declval().end()))) -> decltype(*std::prev(std::declval().end())) { return *std::prev(derived().end()); } template< typename D = Derived, typename Enable = std::enable_if_t< v1_dtl::decrementable_sentinel::value && v1_dtl::common_range::value>> constexpr auto back() const noexcept(noexcept(*std::prev(std::declval().end()))) -> decltype(*std::prev(std::declval().end())) { return *std::prev(derived().end()); } template constexpr auto operator[](v1_dtl::range_difference_t n) noexcept( noexcept(std::declval().begin()[n])) -> decltype(std::declval().begin()[n]) { return derived().begin()[n]; } template constexpr auto operator[](v1_dtl::range_difference_t n) const noexcept(noexcept(std::declval().begin()[n])) -> decltype(std::declval().begin()[n]) { return derived().begin()[n]; } }; /** Implementation of `operator!=()` for all views derived from `view_interface`. */ template constexpr auto operator!=(ViewInterface lhs, ViewInterface rhs) noexcept( noexcept(lhs == rhs)) -> decltype(v1_dtl::derived_view(lhs), !(lhs == rhs)) { return !(lhs == rhs); } }}} #if defined(BOOST_STL_INTERFACES_DOXYGEN) || BOOST_STL_INTERFACES_USE_CONCEPTS namespace boost { namespace stl_interfaces { BOOST_STL_INTERFACES_NAMESPACE_V2 { /** A template alias for `std::ranges::view_interface`. This only exists to make migration from Boost.STLInterfaces to C++20 easier; switch to the one in `std` as soon as you can. */ template using view_interface = std::ranges::view_interface; }}} namespace boost { namespace stl_interfaces { BOOST_STL_INTERFACES_NAMESPACE_V3 { /** A template alias for `std::ranges::view_interface`. This only exists to make migration from Boost.STLInterfaces to C++20 easier; switch to the one in `std` as soon as you can. */ template using view_interface = std::ranges::view_interface; }}} #endif #endif