1 // Copyright (C) 2019 T. Zachary Laine 2 // 3 // Distributed under the Boost Software License, Version 1.0. (See 4 // accompanying file LICENSE_1_0.txt or copy at 5 // http://www.boost.org/LICENSE_1_0.txt) 6 #ifndef BOOST_STL_INTERFACES_VIEW_INTERFACE_HPP 7 #define BOOST_STL_INTERFACES_VIEW_INTERFACE_HPP 8 9 #include <boost/stl_interfaces/fwd.hpp> 10 11 12 namespace boost { namespace stl_interfaces { inline namespace v1 { 13 14 /** A CRTP template that one may derive from to make it easier to define 15 `std::ranges::view`-like types with a container-like interface. This 16 is a pre-C++20 version of C++20's `view_interface` (see 17 [view.interface] in the C++ standard). 18 19 The template parameter `D` for `view_interface` may be an incomplete 20 type. Before any member of the resulting specialization of 21 `view_interface` other than special member functions is referenced, 22 `D` shall be complete, and model both 23 `std::derived_from<view_interface<D>>` and `std::view`. */ 24 template< 25 typename Derived, 26 element_layout Contiguity = element_layout::discontiguous 27 #ifndef BOOST_STL_INTERFACES_DOXYGEN 28 , 29 typename E = std::enable_if_t< 30 std::is_class<Derived>::value && 31 std::is_same<Derived, std::remove_cv_t<Derived>>::value> 32 #endif 33 > 34 struct view_interface; 35 36 namespace v1_dtl { 37 template<typename D, element_layout Contiguity> 38 void derived_view(view_interface<D, Contiguity> const &); 39 } 40 41 template< 42 typename Derived, 43 element_layout Contiguity 44 #ifndef BOOST_STL_INTERFACES_DOXYGEN 45 , 46 typename E 47 #endif 48 > 49 struct view_interface 50 { 51 #ifndef BOOST_STL_INTERFACES_DOXYGEN 52 private: derivedboost::stl_interfaces::v1::view_interface53 constexpr Derived & derived() noexcept 54 { 55 return static_cast<Derived &>(*this); 56 } derivedboost::stl_interfaces::v1::view_interface57 constexpr const Derived & derived() const noexcept 58 { 59 return static_cast<Derived const &>(*this); 60 } 61 #endif 62 63 public: 64 template<typename D = Derived> emptyboost::stl_interfaces::v1::view_interface65 constexpr auto empty() noexcept( 66 noexcept(std::declval<D &>().begin() == std::declval<D &>().end())) 67 -> decltype( 68 std::declval<D &>().begin() == std::declval<D &>().end()) 69 { 70 return derived().begin() == derived().end(); 71 } 72 template<typename D = Derived> emptyboost::stl_interfaces::v1::view_interface73 constexpr auto empty() const noexcept(noexcept( 74 std::declval<D const &>().begin() == 75 std::declval<D const &>().end())) 76 -> decltype( 77 std::declval<D const &>().begin() == 78 std::declval<D const &>().end()) 79 { 80 return derived().begin() == derived().end(); 81 } 82 83 template< 84 typename D = Derived, 85 typename R = decltype(std::declval<D &>().empty())> 86 constexpr explicit operator boolboost::stl_interfaces::v1::view_interface87 operator bool() noexcept(noexcept(std::declval<D &>().empty())) 88 { 89 return !derived().empty(); 90 } 91 template< 92 typename D = Derived, 93 typename R = decltype(std::declval<D const &>().empty())> operator boolboost::stl_interfaces::v1::view_interface94 constexpr explicit operator bool() const 95 noexcept(noexcept(std::declval<D const &>().empty())) 96 { 97 return !derived().empty(); 98 } 99 100 template< 101 typename D = Derived, 102 element_layout C = Contiguity, 103 typename Enable = std::enable_if_t<C == element_layout::contiguous>> databoost::stl_interfaces::v1::view_interface104 constexpr auto data() noexcept(noexcept(std::declval<D &>().begin())) 105 -> decltype(std::addressof(*std::declval<D &>().begin())) 106 { 107 return std::addressof(*derived().begin()); 108 } 109 template< 110 typename D = Derived, 111 element_layout C = Contiguity, 112 typename Enable = std::enable_if_t<C == element_layout::contiguous>> databoost::stl_interfaces::v1::view_interface113 constexpr auto data() const 114 noexcept(noexcept(std::declval<D const &>().begin())) 115 -> decltype(std::addressof(*std::declval<D const &>().begin())) 116 { 117 return std::addressof(*derived().begin()); 118 } 119 120 template<typename D = Derived> sizeboost::stl_interfaces::v1::view_interface121 constexpr auto size() noexcept( 122 noexcept(std::declval<D &>().end() - std::declval<D &>().begin())) 123 -> decltype(std::declval<D &>().end() - std::declval<D &>().begin()) 124 { 125 return derived().end() - derived().begin(); 126 } 127 template<typename D = Derived> sizeboost::stl_interfaces::v1::view_interface128 constexpr auto size() const noexcept(noexcept( 129 std::declval<D const &>().end() - 130 std::declval<D const &>().begin())) 131 -> decltype( 132 std::declval<D const &>().end() - 133 std::declval<D const &>().begin()) 134 { 135 return derived().end() - derived().begin(); 136 } 137 138 template<typename D = Derived> frontboost::stl_interfaces::v1::view_interface139 constexpr auto front() noexcept(noexcept(*std::declval<D &>().begin())) 140 -> decltype(*std::declval<D &>().begin()) 141 { 142 return *derived().begin(); 143 } 144 template<typename D = Derived> frontboost::stl_interfaces::v1::view_interface145 constexpr auto front() const 146 noexcept(noexcept(*std::declval<D const &>().begin())) 147 -> decltype(*std::declval<D const &>().begin()) 148 { 149 return *derived().begin(); 150 } 151 152 template< 153 typename D = Derived, 154 typename Enable = std::enable_if_t< 155 v1_dtl::decrementable_sentinel<D>::value && 156 v1_dtl::common_range<D>::value>> 157 constexpr auto backboost::stl_interfaces::v1::view_interface158 back() noexcept(noexcept(*std::prev(std::declval<D &>().end()))) 159 -> decltype(*std::prev(std::declval<D &>().end())) 160 { 161 return *std::prev(derived().end()); 162 } 163 template< 164 typename D = Derived, 165 typename Enable = std::enable_if_t< 166 v1_dtl::decrementable_sentinel<D>::value && 167 v1_dtl::common_range<D>::value>> backboost::stl_interfaces::v1::view_interface168 constexpr auto back() const 169 noexcept(noexcept(*std::prev(std::declval<D const &>().end()))) 170 -> decltype(*std::prev(std::declval<D const &>().end())) 171 { 172 return *std::prev(derived().end()); 173 } 174 175 template<typename D = Derived> operator []boost::stl_interfaces::v1::view_interface176 constexpr auto operator[](v1_dtl::range_difference_t<D> n) noexcept( 177 noexcept(std::declval<D &>().begin()[n])) 178 -> decltype(std::declval<D &>().begin()[n]) 179 { 180 return derived().begin()[n]; 181 } 182 template<typename D = Derived> operator []boost::stl_interfaces::v1::view_interface183 constexpr auto operator[](v1_dtl::range_difference_t<D> n) const 184 noexcept(noexcept(std::declval<D const &>().begin()[n])) 185 -> decltype(std::declval<D const &>().begin()[n]) 186 { 187 return derived().begin()[n]; 188 } 189 }; 190 191 /** Implementation of `operator!=()` for all views derived from 192 `view_interface`. */ 193 template<typename ViewInterface> operator !=(ViewInterface lhs,ViewInterface rhs)194 constexpr auto operator!=(ViewInterface lhs, ViewInterface rhs) noexcept( 195 noexcept(lhs == rhs)) 196 -> decltype(v1_dtl::derived_view(lhs), !(lhs == rhs)) 197 { 198 return !(lhs == rhs); 199 } 200 201 }}} 202 203 204 #if 201703L < __cplusplus && defined(__cpp_lib_concepts) || \ 205 defined(BOOST_STL_INTERFACES_DOXYGEN) 206 207 #include <ranges> 208 209 namespace boost { namespace stl_interfaces { namespace v2 { 210 211 /** A template alias for `std::view_interface`. This only exists to make 212 migration from Boost.STLInterfaces to C++20 easier; switch to the one 213 in `std` as soon as you can. */ 214 template<typename D, bool = false> 215 using view_interface = std::ranges::view_interface<D>; 216 217 }}} 218 219 #endif 220 221 #endif 222