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

2 | // associated_executor.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_EXECUTOR_HPP |

12 | #define BOOST_ASIO_ASSOCIATED_EXECUTOR_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 <boost/asio/associator.hpp> |

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

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

22 | #include <boost/asio/execution/executor.hpp> |

23 | #include <boost/asio/is_executor.hpp> |

24 | #include <boost/asio/system_executor.hpp> |

25 | |

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

27 | |

28 | namespace boost { |

29 | namespace asio { |

30 | |

31 | template <typename T, typename Executor> |

32 | struct associated_executor; |

33 | |

34 | namespace detail { |

35 | |

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

37 | struct has_executor_type : false_type |

38 | { |

39 | }; |

40 | |

41 | template <typename T> |

42 | struct has_executor_type<T, void_t<typename T::executor_type>> |

43 | : true_type |

44 | { |

45 | }; |

46 | |

47 | template <typename T, typename E, typename = void, typename = void> |

48 | struct associated_executor_impl |

49 | { |

50 | typedef void asio_associated_executor_is_unspecialised; |

51 | |

52 | typedef E type; |

53 | |

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

55 | { |

56 | return type(); |

57 | } |

58 | |

59 | static const type& get(const T&, const E& e) noexcept |

60 | { |

61 | return e; |

62 | } |

63 | }; |

64 | |

65 | template <typename T, typename E> |

66 | struct associated_executor_impl<T, E, void_t<typename T::executor_type>> |

67 | { |

68 | typedef typename T::executor_type type; |

69 | |

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

71 | -> decltype(t.get_executor()) |

72 | { |

73 | return t.get_executor(); |

74 | } |

75 | |

76 | static auto get(const T& t, const E&) noexcept |

77 | -> decltype(t.get_executor()) |

78 | { |

79 | return t.get_executor(); |

80 | } |

81 | }; |

82 | |

83 | template <typename T, typename E> |

84 | struct associated_executor_impl<T, E, |

85 | enable_if_t< |

86 | !has_executor_type<T>::value |

87 | >, |

88 | void_t< |

89 | typename associator<associated_executor, T, E>::type |

90 | >> : associator<associated_executor, T, E> |

91 | { |

92 | }; |

93 | |

94 | } // namespace detail |

95 | |

96 | /// Traits type used to obtain the executor associated with an object. |

97 | /** |

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

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

100 | * Executor shall be a type meeting the Executor requirements. |

101 | * |

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

103 | * reference to an object of type @c T, and @c e is an object of type @c |

104 | * Executor. |

105 | * |

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

107 | * Executor requirements. |

108 | * |

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

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

111 | * type. |

112 | * |

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

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

115 | * type. |

116 | */ |

117 | template <typename T, typename Executor = system_executor> |

118 | struct associated_executor |

119 | #if !defined(GENERATING_DOCUMENTATION) |

120 | : detail::associated_executor_impl<T, Executor> |

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

122 | { |

123 | #if defined(GENERATING_DOCUMENTATION) |

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

125 | /// Otherwise @c Executor. |

126 | typedef see_below type; |

127 | |

128 | /// If @c T has a nested type @c executor_type, returns |

129 | /// <tt>t.get_executor()</tt>. Otherwise returns @c type(). |

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

131 | |

132 | /// If @c T has a nested type @c executor_type, returns |

133 | /// <tt>t.get_executor()</tt>. Otherwise returns @c ex. |

134 | static decltype(auto) get(const T& t, const Executor& ex) noexcept; |

135 | #endif // defined(GENERATING_DOCUMENTATION) |

136 | }; |

137 | |

138 | /// Helper function to obtain an object's associated executor. |

139 | /** |

140 | * @returns <tt>associated_executor<T>::get(t)</tt> |

141 | */ |

142 | template <typename T> |

143 | BOOST_ASIO_NODISCARD inline typename associated_executor<T>::type |

144 | get_associated_executor(const T& t) noexcept |

145 | { |

146 | return associated_executor<T>::get(t); |

147 | } |

148 | |

149 | /// Helper function to obtain an object's associated executor. |

150 | /** |

151 | * @returns <tt>associated_executor<T, Executor>::get(t, ex)</tt> |

152 | */ |

153 | template <typename T, typename Executor> |

154 | BOOST_ASIO_NODISCARD inline auto get_associated_executor( |

155 | const T& t, const Executor& ex, |

156 | constraint_t< |

157 | is_executor<Executor>::value || execution::is_executor<Executor>::value |

158 | > = 0) noexcept |

159 | -> decltype(associated_executor<T, Executor>::get(t, ex)) |

160 | { |

161 | return associated_executor<T, Executor>::get(t, ex); |

162 | } |

163 | |

164 | /// Helper function to obtain an object's associated executor. |

165 | /** |

166 | * @returns <tt>associated_executor<T, typename |

167 | * ExecutionContext::executor_type>::get(t, ctx.get_executor())</tt> |

168 | */ |

169 | template <typename T, typename ExecutionContext> |

170 | BOOST_ASIO_NODISCARD inline typename associated_executor<T, |

171 | typename ExecutionContext::executor_type>::type |

172 | get_associated_executor(const T& t, ExecutionContext& ctx, |

173 | constraint_t<is_convertible<ExecutionContext&, |

174 | execution_context&>::value> = 0) noexcept |

175 | { |

176 | return associated_executor<T, |

177 | typename ExecutionContext::executor_type>::get(t, ctx.get_executor()); |

178 | } |

179 | |

180 | template <typename T, typename Executor = system_executor> |

181 | using associated_executor_t = typename associated_executor<T, Executor>::type; |

182 | |

183 | namespace detail { |

184 | |

185 | template <typename T, typename E, typename = void> |

186 | struct associated_executor_forwarding_base |

187 | { |

188 | }; |

189 | |

190 | template <typename T, typename E> |

191 | struct associated_executor_forwarding_base<T, E, |

192 | enable_if_t< |

193 | is_same< |

194 | typename associated_executor<T, |

195 | E>::asio_associated_executor_is_unspecialised, |

196 | void |

197 | >::value |

198 | >> |

199 | { |

200 | typedef void asio_associated_executor_is_unspecialised; |

201 | }; |

202 | |

203 | } // namespace detail |

204 | |

205 | /// Specialisation of associated_executor for @c std::reference_wrapper. |

206 | template <typename T, typename Executor> |

207 | struct associated_executor<reference_wrapper<T>, Executor> |

208 | #if !defined(GENERATING_DOCUMENTATION) |

209 | : detail::associated_executor_forwarding_base<T, Executor> |

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

211 | { |

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

213 | /// @c T. |

214 | typedef typename associated_executor<T, Executor>::type type; |

215 | |

216 | /// Forwards the request to get the executor to the associator specialisation |

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

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

219 | { |

220 | return associated_executor<T, Executor>::get(t.get()); |

221 | } |

222 | |

223 | /// Forwards the request to get the executor to the associator specialisation |

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

225 | static auto get(reference_wrapper<T> t, const Executor& ex) noexcept |

226 | -> decltype(associated_executor<T, Executor>::get(t.get(), ex)) |

227 | { |

228 | return associated_executor<T, Executor>::get(t.get(), ex); |

229 | } |

230 | }; |

231 | |

232 | } // namespace asio |

233 | } // namespace boost |

234 | |

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

236 | |

237 | #endif // BOOST_ASIO_ASSOCIATED_EXECUTOR_HPP |

238 |