1 | // |
---|---|

2 | // associated_allocator.hpp |

3 | // ~~~~~~~~~~~~~~~~~~~~~~~~ |

4 | // |

5 | // Copyright (c) 2003-2024 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 | |

11 | #ifndef BOOST_ASIO_ASSOCIATED_ALLOCATOR_HPP |

12 | #define BOOST_ASIO_ASSOCIATED_ALLOCATOR_HPP |

13 | |

14 | #if defined(_MSC_VER) && (_MSC_VER >= 1200) |

15 | # pragma once |

16 | #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) |

17 | |

18 | #include <boost/asio/detail/config.hpp> |

19 | #include <memory> |

20 | #include <boost/asio/associator.hpp> |

21 | #include <boost/asio/detail/functional.hpp> |

22 | #include <boost/asio/detail/type_traits.hpp> |

23 | |

24 | #include <boost/asio/detail/push_options.hpp> |

25 | |

26 | namespace boost { |

27 | namespace asio { |

28 | |

29 | template <typename T, typename Allocator> |

30 | struct associated_allocator; |

31 | |

32 | namespace detail { |

33 | |

34 | template <typename T, typename = void> |

35 | struct has_allocator_type : false_type |

36 | { |

37 | }; |

38 | |

39 | template <typename T> |

40 | struct has_allocator_type<T, void_t<typename T::allocator_type>> : true_type |

41 | { |

42 | }; |

43 | |

44 | template <typename T, typename A, typename = void, typename = void> |

45 | struct associated_allocator_impl |

46 | { |

47 | typedef void asio_associated_allocator_is_unspecialised; |

48 | |

49 | typedef A type; |

50 | |

51 | static type get(const T&) noexcept |

52 | { |

53 | return type(); |

54 | } |

55 | |

56 | static const type& get(const T&, const A& a) noexcept |

57 | { |

58 | return a; |

59 | } |

60 | }; |

61 | |

62 | template <typename T, typename A> |

63 | struct associated_allocator_impl<T, A, void_t<typename T::allocator_type>> |

64 | { |

65 | typedef typename T::allocator_type type; |

66 | |

67 | static auto get(const T& t) noexcept |

68 | -> decltype(t.get_allocator()) |

69 | { |

70 | return t.get_allocator(); |

71 | } |

72 | |

73 | static auto get(const T& t, const A&) noexcept |

74 | -> decltype(t.get_allocator()) |

75 | { |

76 | return t.get_allocator(); |

77 | } |

78 | }; |

79 | |

80 | template <typename T, typename A> |

81 | struct associated_allocator_impl<T, A, |

82 | enable_if_t< |

83 | !has_allocator_type<T>::value |

84 | >, |

85 | void_t< |

86 | typename associator<associated_allocator, T, A>::type |

87 | >> : associator<associated_allocator, T, A> |

88 | { |

89 | }; |

90 | |

91 | } // namespace detail |

92 | |

93 | /// Traits type used to obtain the allocator associated with an object. |

94 | /** |

95 | * A program may specialise this traits type if the @c T template parameter in |

96 | * the specialisation is a user-defined type. The template parameter @c |

97 | * Allocator shall be a type meeting the Allocator requirements. |

98 | * |

99 | * Specialisations shall meet the following requirements, where @c t is a const |

100 | * reference to an object of type @c T, and @c a is an object of type @c |

101 | * Allocator. |

102 | * |

103 | * @li Provide a nested typedef @c type that identifies a type meeting the |

104 | * Allocator requirements. |

105 | * |

106 | * @li Provide a noexcept static member function named @c get, callable as @c |

107 | * get(t) and with return type @c type or a (possibly const) reference to @c |

108 | * type. |

109 | * |

110 | * @li Provide a noexcept static member function named @c get, callable as @c |

111 | * get(t,a) and with return type @c type or a (possibly const) reference to @c |

112 | * type. |

113 | */ |

114 | template <typename T, typename Allocator = std::allocator<void>> |

115 | struct associated_allocator |

116 | #if !defined(GENERATING_DOCUMENTATION) |

117 | : detail::associated_allocator_impl<T, Allocator> |

118 | #endif // !defined(GENERATING_DOCUMENTATION) |

119 | { |

120 | #if defined(GENERATING_DOCUMENTATION) |

121 | /// If @c T has a nested type @c allocator_type, <tt>T::allocator_type</tt>. |

122 | /// Otherwise @c Allocator. |

123 | typedef see_below type; |

124 | |

125 | /// If @c T has a nested type @c allocator_type, returns |

126 | /// <tt>t.get_allocator()</tt>. Otherwise returns @c type(). |

127 | static decltype(auto) get(const T& t) noexcept; |

128 | |

129 | /// If @c T has a nested type @c allocator_type, returns |

130 | /// <tt>t.get_allocator()</tt>. Otherwise returns @c a. |

131 | static decltype(auto) get(const T& t, const Allocator& a) noexcept; |

132 | #endif // defined(GENERATING_DOCUMENTATION) |

133 | }; |

134 | |

135 | /// Helper function to obtain an object's associated allocator. |

136 | /** |

137 | * @returns <tt>associated_allocator<T>::get(t)</tt> |

138 | */ |

139 | template <typename T> |

140 | BOOST_ASIO_NODISCARD inline typename associated_allocator<T>::type |

141 | get_associated_allocator(const T& t) noexcept |

142 | { |

143 | return associated_allocator<T>::get(t); |

144 | } |

145 | |

146 | /// Helper function to obtain an object's associated allocator. |

147 | /** |

148 | * @returns <tt>associated_allocator<T, Allocator>::get(t, a)</tt> |

149 | */ |

150 | template <typename T, typename Allocator> |

151 | BOOST_ASIO_NODISCARD inline auto get_associated_allocator( |

152 | const T& t, const Allocator& a) noexcept |

153 | -> decltype(associated_allocator<T, Allocator>::get(t, a)) |

154 | { |

155 | return associated_allocator<T, Allocator>::get(t, a); |

156 | } |

157 | |

158 | template <typename T, typename Allocator = std::allocator<void>> |

159 | using associated_allocator_t |

160 | = typename associated_allocator<T, Allocator>::type; |

161 | |

162 | namespace detail { |

163 | |

164 | template <typename T, typename A, typename = void> |

165 | struct associated_allocator_forwarding_base |

166 | { |

167 | }; |

168 | |

169 | template <typename T, typename A> |

170 | struct associated_allocator_forwarding_base<T, A, |

171 | enable_if_t< |

172 | is_same< |

173 | typename associated_allocator<T, |

174 | A>::asio_associated_allocator_is_unspecialised, |

175 | void |

176 | >::value |

177 | >> |

178 | { |

179 | typedef void asio_associated_allocator_is_unspecialised; |

180 | }; |

181 | |

182 | } // namespace detail |

183 | |

184 | /// Specialisation of associated_allocator for @c std::reference_wrapper. |

185 | template <typename T, typename Allocator> |

186 | struct associated_allocator<reference_wrapper<T>, Allocator> |

187 | #if !defined(GENERATING_DOCUMENTATION) |

188 | : detail::associated_allocator_forwarding_base<T, Allocator> |

189 | #endif // !defined(GENERATING_DOCUMENTATION) |

190 | { |

191 | /// Forwards @c type to the associator specialisation for the unwrapped type |

192 | /// @c T. |

193 | typedef typename associated_allocator<T, Allocator>::type type; |

194 | |

195 | /// Forwards the request to get the allocator to the associator specialisation |

196 | /// for the unwrapped type @c T. |

197 | static type get(reference_wrapper<T> t) noexcept |

198 | { |

199 | return associated_allocator<T, Allocator>::get(t.get()); |

200 | } |

201 | |

202 | /// Forwards the request to get the allocator to the associator specialisation |

203 | /// for the unwrapped type @c T. |

204 | static auto get(reference_wrapper<T> t, const Allocator& a) noexcept |

205 | -> decltype(associated_allocator<T, Allocator>::get(t.get(), a)) |

206 | { |

207 | return associated_allocator<T, Allocator>::get(t.get(), a); |

208 | } |

209 | }; |

210 | |

211 | } // namespace asio |

212 | } // namespace boost |

213 | |

214 | #include <boost/asio/detail/pop_options.hpp> |

215 | |

216 | #endif // BOOST_ASIO_ASSOCIATED_ALLOCATOR_HPP |

217 |