associated_allocator.hpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. //
  2. // associated_allocator.hpp
  3. // ~~~~~~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
  6. //
  7. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  8. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  9. //
  10. #ifndef ASIO_ASSOCIATED_ALLOCATOR_HPP
  11. #define ASIO_ASSOCIATED_ALLOCATOR_HPP
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. # pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include "asio/detail/config.hpp"
  16. #include <memory>
  17. #include "asio/associator.hpp"
  18. #include "asio/detail/functional.hpp"
  19. #include "asio/detail/type_traits.hpp"
  20. #include "asio/detail/push_options.hpp"
  21. namespace asio {
  22. template <typename T, typename Allocator>
  23. struct associated_allocator;
  24. namespace detail {
  25. template <typename T, typename = void>
  26. struct has_allocator_type : false_type
  27. {
  28. };
  29. template <typename T>
  30. struct has_allocator_type<T, void_t<typename T::allocator_type>> : true_type
  31. {
  32. };
  33. template <typename T, typename A, typename = void, typename = void>
  34. struct associated_allocator_impl
  35. {
  36. typedef void asio_associated_allocator_is_unspecialised;
  37. typedef A type;
  38. static type get(const T&) noexcept
  39. {
  40. return type();
  41. }
  42. static const type& get(const T&, const A& a) noexcept
  43. {
  44. return a;
  45. }
  46. };
  47. template <typename T, typename A>
  48. struct associated_allocator_impl<T, A, void_t<typename T::allocator_type>>
  49. {
  50. typedef typename T::allocator_type type;
  51. static auto get(const T& t) noexcept
  52. -> decltype(t.get_allocator())
  53. {
  54. return t.get_allocator();
  55. }
  56. static auto get(const T& t, const A&) noexcept
  57. -> decltype(t.get_allocator())
  58. {
  59. return t.get_allocator();
  60. }
  61. };
  62. template <typename T, typename A>
  63. struct associated_allocator_impl<T, A,
  64. enable_if_t<
  65. !has_allocator_type<T>::value
  66. >,
  67. void_t<
  68. typename associator<associated_allocator, T, A>::type
  69. >> : associator<associated_allocator, T, A>
  70. {
  71. };
  72. } // namespace detail
  73. /// Traits type used to obtain the allocator associated with an object.
  74. /**
  75. * A program may specialise this traits type if the @c T template parameter in
  76. * the specialisation is a user-defined type. The template parameter @c
  77. * Allocator shall be a type meeting the Allocator requirements.
  78. *
  79. * Specialisations shall meet the following requirements, where @c t is a const
  80. * reference to an object of type @c T, and @c a is an object of type @c
  81. * Allocator.
  82. *
  83. * @li Provide a nested typedef @c type that identifies a type meeting the
  84. * Allocator requirements.
  85. *
  86. * @li Provide a noexcept static member function named @c get, callable as @c
  87. * get(t) and with return type @c type or a (possibly const) reference to @c
  88. * type.
  89. *
  90. * @li Provide a noexcept static member function named @c get, callable as @c
  91. * get(t,a) and with return type @c type or a (possibly const) reference to @c
  92. * type.
  93. */
  94. template <typename T, typename Allocator = std::allocator<void>>
  95. struct associated_allocator
  96. #if !defined(GENERATING_DOCUMENTATION)
  97. : detail::associated_allocator_impl<T, Allocator>
  98. #endif // !defined(GENERATING_DOCUMENTATION)
  99. {
  100. #if defined(GENERATING_DOCUMENTATION)
  101. /// If @c T has a nested type @c allocator_type, <tt>T::allocator_type</tt>.
  102. /// Otherwise @c Allocator.
  103. typedef see_below type;
  104. /// If @c T has a nested type @c allocator_type, returns
  105. /// <tt>t.get_allocator()</tt>. Otherwise returns @c type().
  106. static decltype(auto) get(const T& t) noexcept;
  107. /// If @c T has a nested type @c allocator_type, returns
  108. /// <tt>t.get_allocator()</tt>. Otherwise returns @c a.
  109. static decltype(auto) get(const T& t, const Allocator& a) noexcept;
  110. #endif // defined(GENERATING_DOCUMENTATION)
  111. };
  112. /// Helper function to obtain an object's associated allocator.
  113. /**
  114. * @returns <tt>associated_allocator<T>::get(t)</tt>
  115. */
  116. template <typename T>
  117. ASIO_NODISCARD inline typename associated_allocator<T>::type
  118. get_associated_allocator(const T& t) noexcept
  119. {
  120. return associated_allocator<T>::get(t);
  121. }
  122. /// Helper function to obtain an object's associated allocator.
  123. /**
  124. * @returns <tt>associated_allocator<T, Allocator>::get(t, a)</tt>
  125. */
  126. template <typename T, typename Allocator>
  127. ASIO_NODISCARD inline auto get_associated_allocator(
  128. const T& t, const Allocator& a) noexcept
  129. -> decltype(associated_allocator<T, Allocator>::get(t, a))
  130. {
  131. return associated_allocator<T, Allocator>::get(t, a);
  132. }
  133. template <typename T, typename Allocator = std::allocator<void>>
  134. using associated_allocator_t
  135. = typename associated_allocator<T, Allocator>::type;
  136. namespace detail {
  137. template <typename T, typename A, typename = void>
  138. struct associated_allocator_forwarding_base
  139. {
  140. };
  141. template <typename T, typename A>
  142. struct associated_allocator_forwarding_base<T, A,
  143. enable_if_t<
  144. is_same<
  145. typename associated_allocator<T,
  146. A>::asio_associated_allocator_is_unspecialised,
  147. void
  148. >::value
  149. >>
  150. {
  151. typedef void asio_associated_allocator_is_unspecialised;
  152. };
  153. } // namespace detail
  154. /// Specialisation of associated_allocator for @c std::reference_wrapper.
  155. template <typename T, typename Allocator>
  156. struct associated_allocator<reference_wrapper<T>, Allocator>
  157. #if !defined(GENERATING_DOCUMENTATION)
  158. : detail::associated_allocator_forwarding_base<T, Allocator>
  159. #endif // !defined(GENERATING_DOCUMENTATION)
  160. {
  161. /// Forwards @c type to the associator specialisation for the unwrapped type
  162. /// @c T.
  163. typedef typename associated_allocator<T, Allocator>::type type;
  164. /// Forwards the request to get the allocator to the associator specialisation
  165. /// for the unwrapped type @c T.
  166. static type get(reference_wrapper<T> t) noexcept
  167. {
  168. return associated_allocator<T, Allocator>::get(t.get());
  169. }
  170. /// Forwards the request to get the allocator to the associator specialisation
  171. /// for the unwrapped type @c T.
  172. static auto get(reference_wrapper<T> t, const Allocator& a) noexcept
  173. -> decltype(associated_allocator<T, Allocator>::get(t.get(), a))
  174. {
  175. return associated_allocator<T, Allocator>::get(t.get(), a);
  176. }
  177. };
  178. } // namespace asio
  179. #include "asio/detail/pop_options.hpp"
  180. #endif // ASIO_ASSOCIATED_ALLOCATOR_HPP