view_interface.hpp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  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. #include <boost/stl_interfaces/fwd.hpp>
  9. namespace boost { namespace stl_interfaces { inline namespace v1 {
  10. /** A CRTP template that one may derive from to make it easier to define
  11. `std::ranges::view`-like types with a container-like interface. This
  12. is a pre-C++20 version of C++20's `view_interface` (see
  13. [view.interface] in the C++ standard).
  14. The template parameter `D` for `view_interface` may be an incomplete
  15. type. Before any member of the resulting specialization of
  16. `view_interface` other than special member functions is referenced,
  17. `D` shall be complete, and model both
  18. `std::derived_from<view_interface<D>>` and `std::view`. */
  19. template<
  20. typename Derived,
  21. element_layout Contiguity = element_layout::discontiguous
  22. #ifndef BOOST_STL_INTERFACES_DOXYGEN
  23. ,
  24. typename E = std::enable_if_t<
  25. std::is_class<Derived>::value &&
  26. std::is_same<Derived, std::remove_cv_t<Derived>>::value>
  27. #endif
  28. >
  29. struct view_interface;
  30. namespace v1_dtl {
  31. template<typename D, element_layout Contiguity>
  32. void derived_view(view_interface<D, Contiguity> const &);
  33. }
  34. template<
  35. typename Derived,
  36. element_layout Contiguity
  37. #ifndef BOOST_STL_INTERFACES_DOXYGEN
  38. ,
  39. typename E
  40. #endif
  41. >
  42. struct view_interface
  43. {
  44. #ifndef BOOST_STL_INTERFACES_DOXYGEN
  45. private:
  46. constexpr Derived & derived() noexcept
  47. {
  48. return static_cast<Derived &>(*this);
  49. }
  50. constexpr const Derived & derived() const noexcept
  51. {
  52. return static_cast<Derived const &>(*this);
  53. }
  54. #endif
  55. public:
  56. template<typename D = Derived>
  57. constexpr auto empty() noexcept(
  58. noexcept(std::declval<D &>().begin() == std::declval<D &>().end()))
  59. -> decltype(
  60. std::declval<D &>().begin() == std::declval<D &>().end())
  61. {
  62. return derived().begin() == derived().end();
  63. }
  64. template<typename D = Derived>
  65. constexpr auto empty() const noexcept(noexcept(
  66. std::declval<D const &>().begin() ==
  67. std::declval<D const &>().end()))
  68. -> decltype(
  69. std::declval<D const &>().begin() ==
  70. std::declval<D const &>().end())
  71. {
  72. return derived().begin() == derived().end();
  73. }
  74. template<
  75. typename D = Derived,
  76. typename R = decltype(std::declval<D &>().empty())>
  77. constexpr explicit
  78. operator bool() noexcept(noexcept(std::declval<D &>().empty()))
  79. {
  80. return !derived().empty();
  81. }
  82. template<
  83. typename D = Derived,
  84. typename R = decltype(std::declval<D const &>().empty())>
  85. constexpr explicit operator bool() const
  86. noexcept(noexcept(std::declval<D const &>().empty()))
  87. {
  88. return !derived().empty();
  89. }
  90. template<
  91. typename D = Derived,
  92. element_layout C = Contiguity,
  93. typename Enable = std::enable_if_t<C == element_layout::contiguous>>
  94. constexpr auto data() noexcept(noexcept(std::declval<D &>().begin()))
  95. -> decltype(std::addressof(*std::declval<D &>().begin()))
  96. {
  97. return std::addressof(*derived().begin());
  98. }
  99. template<
  100. typename D = Derived,
  101. element_layout C = Contiguity,
  102. typename Enable = std::enable_if_t<C == element_layout::contiguous>>
  103. constexpr auto data() const
  104. noexcept(noexcept(std::declval<D const &>().begin()))
  105. -> decltype(std::addressof(*std::declval<D const &>().begin()))
  106. {
  107. return std::addressof(*derived().begin());
  108. }
  109. template<typename D = Derived>
  110. constexpr auto size() noexcept(
  111. noexcept(std::declval<D &>().end() - std::declval<D &>().begin()))
  112. -> decltype(std::declval<D &>().end() - std::declval<D &>().begin())
  113. {
  114. return derived().end() - derived().begin();
  115. }
  116. template<typename D = Derived>
  117. constexpr auto size() const noexcept(noexcept(
  118. std::declval<D const &>().end() -
  119. std::declval<D const &>().begin()))
  120. -> decltype(
  121. std::declval<D const &>().end() -
  122. std::declval<D const &>().begin())
  123. {
  124. return derived().end() - derived().begin();
  125. }
  126. template<typename D = Derived>
  127. constexpr auto front() noexcept(noexcept(*std::declval<D &>().begin()))
  128. -> decltype(*std::declval<D &>().begin())
  129. {
  130. return *derived().begin();
  131. }
  132. template<typename D = Derived>
  133. constexpr auto front() const
  134. noexcept(noexcept(*std::declval<D const &>().begin()))
  135. -> decltype(*std::declval<D const &>().begin())
  136. {
  137. return *derived().begin();
  138. }
  139. template<
  140. typename D = Derived,
  141. typename Enable = std::enable_if_t<
  142. v1_dtl::decrementable_sentinel<D>::value &&
  143. v1_dtl::common_range<D>::value>>
  144. constexpr auto
  145. back() noexcept(noexcept(*std::prev(std::declval<D &>().end())))
  146. -> decltype(*std::prev(std::declval<D &>().end()))
  147. {
  148. return *std::prev(derived().end());
  149. }
  150. template<
  151. typename D = Derived,
  152. typename Enable = std::enable_if_t<
  153. v1_dtl::decrementable_sentinel<D>::value &&
  154. v1_dtl::common_range<D>::value>>
  155. constexpr auto back() const
  156. noexcept(noexcept(*std::prev(std::declval<D const &>().end())))
  157. -> decltype(*std::prev(std::declval<D const &>().end()))
  158. {
  159. return *std::prev(derived().end());
  160. }
  161. template<typename D = Derived>
  162. constexpr auto operator[](v1_dtl::range_difference_t<D> n) noexcept(
  163. noexcept(std::declval<D &>().begin()[n]))
  164. -> decltype(std::declval<D &>().begin()[n])
  165. {
  166. return derived().begin()[n];
  167. }
  168. template<typename D = Derived>
  169. constexpr auto operator[](v1_dtl::range_difference_t<D> n) const
  170. noexcept(noexcept(std::declval<D const &>().begin()[n]))
  171. -> decltype(std::declval<D const &>().begin()[n])
  172. {
  173. return derived().begin()[n];
  174. }
  175. };
  176. /** Implementation of `operator!=()` for all views derived from
  177. `view_interface`. */
  178. template<typename ViewInterface>
  179. constexpr auto operator!=(ViewInterface lhs, ViewInterface rhs) noexcept(
  180. noexcept(lhs == rhs))
  181. -> decltype(v1_dtl::derived_view(lhs), !(lhs == rhs))
  182. {
  183. return !(lhs == rhs);
  184. }
  185. }}}
  186. #if 201703L < __cplusplus && defined(__cpp_lib_concepts) || \
  187. defined(BOOST_STL_INTERFACES_DOXYGEN)
  188. #include <ranges>
  189. namespace boost { namespace stl_interfaces { namespace v2 {
  190. /** A template alias for `std::view_interface`. This only exists to make
  191. migration from Boost.STLInterfaces to C++20 easier; switch to the one
  192. in `std` as soon as you can. */
  193. template<typename D, bool = false>
  194. using view_interface = std::ranges::view_interface<D>;
  195. }}}
  196. #endif
  197. #endif