1 // Copyright (c) 2007-2017 Hartmut Kaiser 2 // Copyright (c) 2012-2017 Thomas Heller 3 // 4 // Distributed under the Boost Software License, Version 1.0. (See accompanying 5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 7 #ifndef HPX_LCOS_BASE_LCO_WITH_VALUE_HPP 8 #define HPX_LCOS_BASE_LCO_WITH_VALUE_HPP 9 10 #include <hpx/config.hpp> 11 #include <hpx/throw_exception.hpp> 12 #include <hpx/lcos/base_lco.hpp> 13 #include <hpx/plugins/parcel/coalescing_message_handler_registration.hpp> 14 #include <hpx/runtime/actions/basic_action.hpp> 15 #include <hpx/runtime/actions/component_action.hpp> 16 #include <hpx/runtime/components/component_type.hpp> 17 #include <hpx/runtime/components/server/managed_component_base.hpp> 18 #include <hpx/runtime/components/server/component_base.hpp> 19 #include <hpx/runtime/components/server/component_heap.hpp> 20 #include <hpx/runtime/components_fwd.hpp> 21 #include <hpx/runtime/naming/id_type.hpp> 22 #include <hpx/traits/is_component.hpp> 23 #include <hpx/util/assert.hpp> 24 #include <hpx/util/detail/pp/cat.hpp> 25 #include <hpx/util/detail/pp/expand.hpp> 26 #include <hpx/util/detail/pp/nargs.hpp> 27 #include <hpx/util/ini.hpp> 28 #include <hpx/util/unused.hpp> 29 #include <hpx/util/void_guard.hpp> 30 31 #include <cstddef> 32 #include <cstdint> 33 #include <string> 34 #include <type_traits> 35 #include <utility> 36 #include <vector> 37 38 namespace hpx { namespace lcos 39 { 40 namespace detail 41 { 42 /// \cond NOINTERNAL 43 template <typename ComponentTag, typename BaseLco> 44 struct base_lco_wrapping_type; 45 46 template <typename BaseLco> 47 struct base_lco_wrapping_type<traits::detail::component_tag, BaseLco> 48 { 49 typedef components::component<BaseLco> type; 50 }; 51 52 template <typename BaseLco> 53 struct base_lco_wrapping_type<traits::detail::managed_component_tag, BaseLco> 54 { 55 typedef components::managed_component<BaseLco> type; 56 }; 57 /// \endcond 58 } 59 60 /// The \a base_lco_with_value class is the common base class for all LCO's 61 /// synchronizing on a value. 62 /// The \a RemoteResult template argument should be set to the type of the 63 /// argument expected for the set_value action. 64 /// 65 /// \tparam RemoteResult The type of the result value to be carried back 66 /// to the LCO instance. 67 /// \tparam ComponentTag The tag type representing the type of the component 68 /// (either component_tag or managed_component_tag). 69 template <typename Result, typename RemoteResult, typename ComponentTag> 70 class base_lco_with_value : public base_lco, public ComponentTag 71 { 72 protected: 73 typedef typename std::conditional< 74 std::is_void<Result>::value, util::unused_type, Result 75 >::type result_type; 76 77 /// Destructor, needs to be virtual to allow for clean destruction of 78 /// derived objects ~base_lco_with_value()79 virtual ~base_lco_with_value() noexcept {} 80 set_event()81 virtual void set_event() 82 { 83 set_event_nonvirt(std::is_default_constructible<RemoteResult>()); 84 } 85 set_event_nonvirt(std::false_type)86 void set_event_nonvirt(std::false_type) 87 { 88 // this shouldn't ever be called 89 HPX_THROW_EXCEPTION(invalid_status, 90 "base_lco_with_value::set_event_nonvirt", 91 "attempt to use a non-default-constructible return type with " 92 "an action in a context where default-construction would be " 93 "required"); 94 } 95 set_event_nonvirt(std::true_type)96 void set_event_nonvirt(std::true_type) 97 { 98 set_value(RemoteResult()); 99 } 100 101 virtual void set_value (RemoteResult && result) = 0; 102 103 virtual result_type get_value() = 0; get_value(error_code &)104 virtual result_type get_value(error_code& /*ec*/) 105 { 106 return get_value(); 107 } 108 109 public: 110 // components must contain a typedef for wrapping_type defining the 111 // managed_component type used to encapsulate instances of this 112 // component 113 typedef typename detail::base_lco_wrapping_type< 114 ComponentTag, base_lco_with_value 115 >::type wrapping_type; 116 117 typedef base_lco_with_value base_type_holder; 118 get_component_type()119 static components::component_type get_component_type() 120 { 121 return components::get_component_type<base_lco_with_value>(); 122 } set_component_type(components::component_type type)123 static void set_component_type(components::component_type type) 124 { 125 components::set_component_type<base_lco_with_value>(type); 126 } 127 128 /// The \a function set_value_nonvirt is called whenever a 129 /// \a set_value_action is applied on this LCO instance. This 130 /// function just forwards to the virtual function \a set_value, which 131 /// is overloaded by the derived concrete LCO. 132 /// 133 /// \param result [in] The result value to be transferred from the 134 /// remote operation back to this LCO instance. 135 set_value_nonvirt(RemoteResult && result)136 void set_value_nonvirt (RemoteResult&& result) 137 { 138 set_value(std::move(result)); 139 } 140 141 /// The \a function get_result_nonvirt is called whenever a 142 /// \a get_result_action is applied on this LCO instance. This 143 /// function just forwards to the virtual function \a get_result, which 144 /// is overloaded by the derived concrete LCO. 145 get_value_nonvirt()146 Result get_value_nonvirt() 147 { 148 return util::void_guard<Result>(), get_value(); 149 } 150 151 public: 152 /// The \a set_value_action may be used to trigger any LCO instances 153 /// while carrying an additional parameter of any type. 154 /// 155 /// RemoteResult is taken by rvalue ref. This allows for perfect forwarding. 156 /// When the action thread function is created, the values are moved into 157 /// the calling function. If we took it by const lvalue reference, we 158 /// would disable the possibility to further move the result to the 159 /// designated destination. 160 /// 161 /// \param RemoteResult [in] The type of the result to be transferred 162 /// back to this LCO instance. 163 HPX_DEFINE_COMPONENT_DIRECT_ACTION(base_lco_with_value, 164 set_value_nonvirt, set_value_action); 165 166 /// The \a get_value_action may be used to query the value this LCO 167 /// instance exposes as its 'result' value. 168 HPX_DEFINE_COMPONENT_DIRECT_ACTION(base_lco_with_value, 169 get_value_nonvirt, get_value_action); 170 }; 171 172 /// The base_lco<void> specialization is used whenever the set_event action 173 /// for a particular LCO doesn't carry any argument. 174 /// 175 /// \tparam void This specialization expects no result value and is almost 176 /// completely equivalent to the plain \a base_lco. 177 template <typename ComponentTag> 178 class base_lco_with_value<void, void, ComponentTag> 179 : public base_lco, public ComponentTag 180 { 181 protected: 182 /// Destructor, needs to be virtual to allow for clean destruction of 183 /// derived objects ~base_lco_with_value()184 virtual ~base_lco_with_value() {} 185 186 public: 187 // components must contain a typedef for wrapping_type defining the 188 // managed_component type used to encapsulate instances of this 189 // component 190 typedef typename detail::base_lco_wrapping_type<ComponentTag, 191 base_lco_with_value>::type wrapping_type; 192 typedef base_lco_with_value base_type_holder; 193 194 // refer to base type for the corresponding implementation 195 typedef typename base_lco::set_event_action set_value_action; 196 197 // dummy action definition get_value()198 void get_value() {} 199 200 HPX_DEFINE_COMPONENT_DIRECT_ACTION(base_lco_with_value, 201 get_value, get_value_action); 202 }; 203 }} 204 205 namespace hpx { namespace traits 206 { 207 // define component type data base entry generator 208 template <typename Result, typename RemoteResult, typename Enable> 209 struct component_type_database< 210 hpx::lcos::base_lco_with_value< 211 Result, RemoteResult, traits::detail::managed_component_tag 212 >, Enable> 213 { gethpx::traits::component_type_database214 static components::component_type get() 215 { 216 return components::component_base_lco_with_value; 217 } 218 sethpx::traits::component_type_database219 static void set(components::component_type) 220 { 221 HPX_ASSERT(false); 222 } 223 }; 224 225 template <typename Result, typename RemoteResult, typename Enable> 226 struct component_type_database< 227 hpx::lcos::base_lco_with_value< 228 Result, RemoteResult, traits::detail::component_tag 229 >, Enable> 230 { gethpx::traits::component_type_database231 static components::component_type get() 232 { 233 return components::component_base_lco_with_value_unmanaged; 234 } 235 sethpx::traits::component_type_database236 static void set(components::component_type) 237 { 238 HPX_ASSERT(false); 239 } 240 }; 241 }} 242 namespace hpx { namespace components { 243 namespace detail { 244 template <typename Result, typename RemoteResult> 245 struct component_heap_impl< 246 hpx::components::managed_component<hpx::lcos::base_lco_with_value< 247 Result, RemoteResult, traits::detail::managed_component_tag>>> 248 { 249 typedef void valid; 250 typedef hpx::components::managed_component<hpx::lcos::base_lco_with_value< 251 Result, RemoteResult, traits::detail::managed_component_tag>> 252 component_type; callhpx::components::detail::component_heap_impl253 HPX_ALWAYS_EXPORT static typename component_type::heap_type& call() 254 { 255 util::reinitializable_static<typename component_type::heap_type> 256 heap; 257 return heap.get(); 258 } 259 }; 260 template <typename Result, typename RemoteResult> 261 struct component_heap_impl< 262 hpx::components::managed_component<hpx::lcos::base_lco_with_value< 263 Result, RemoteResult, traits::detail::component_tag>>> 264 { 265 typedef void valid; 266 typedef hpx::components::managed_component<hpx::lcos::base_lco_with_value< 267 Result, RemoteResult, traits::detail::component_tag>> 268 component_type; 269 HPX_ALWAYS_EXPORT static callhpx::components::detail::component_heap_impl270 typename component_type::heap_type& call() 271 { 272 util::reinitializable_static<typename component_type::heap_type> 273 heap; 274 return heap.get(); 275 } 276 }; 277 } 278 }} 279 280 /////////////////////////////////////////////////////////////////////////////// 281 #define HPX_REGISTER_BASE_LCO_WITH_VALUE_DECLARATION(...) \ 282 HPX_REGISTER_BASE_LCO_WITH_VALUE_DECLARATION_(__VA_ARGS__) \ 283 /**/ 284 #define HPX_REGISTER_BASE_LCO_WITH_VALUE_DECLARATION_(...) \ 285 HPX_PP_EXPAND(HPX_PP_CAT( \ 286 HPX_REGISTER_BASE_LCO_WITH_VALUE_DECLARATION_, \ 287 HPX_PP_NARGS(__VA_ARGS__) \ 288 )(__VA_ARGS__)) \ 289 /**/ 290 291 // obsolete 292 #define HPX_REGISTER_BASE_LCO_WITH_VALUE_DECLARATION2(Value, RemoteValue, Name)\ 293 HPX_REGISTER_BASE_LCO_WITH_VALUE_DECLARATION_3(Value, RemoteValue, Name) \ 294 /**/ 295 296 #define HPX_REGISTER_BASE_LCO_WITH_VALUE_DECLARATION_1(Value) \ 297 HPX_REGISTER_BASE_LCO_WITH_VALUE_DECLARATION_4( \ 298 Value, Value, Value, managed_component_tag) \ 299 /**/ 300 301 #define HPX_REGISTER_BASE_LCO_WITH_VALUE_DECLARATION_2(Value, Name) \ 302 HPX_REGISTER_BASE_LCO_WITH_VALUE_DECLARATION_4( \ 303 Value, Value, Name, managed_component_tag) \ 304 /**/ 305 306 #define HPX_REGISTER_BASE_LCO_WITH_VALUE_DECLARATION_3( \ 307 Value, RemoteValue, Name) \ 308 HPX_REGISTER_BASE_LCO_WITH_VALUE_DECLARATION_4( \ 309 Value, RemoteValue, Name, managed_component_tag) \ 310 /**/ 311 312 #define HPX_REGISTER_BASE_LCO_WITH_VALUE_DECLARATION_4( \ 313 Value, RemoteValue, Name, Tag) \ 314 typedef ::hpx::lcos::base_lco_with_value<Value, RemoteValue, \ 315 ::hpx::traits::detail::Tag> \ 316 HPX_PP_CAT(HPX_PP_CAT(base_lco_with_value_, Name), Tag); \ 317 HPX_REGISTER_ACTION_DECLARATION( \ 318 HPX_PP_CAT(HPX_PP_CAT(base_lco_with_value_, Name), Tag) \ 319 ::set_value_action, \ 320 HPX_PP_CAT(HPX_PP_CAT(set_value_action_, Name), Tag)) \ 321 HPX_REGISTER_ACTION_DECLARATION( \ 322 HPX_PP_CAT(HPX_PP_CAT(base_lco_with_value_, Name), Tag) \ 323 ::get_value_action, \ 324 HPX_PP_CAT(HPX_PP_CAT(get_value_action_, Name), Tag)) \ 325 HPX_ACTION_USES_MESSAGE_COALESCING_NOTHROW_DECLARATION( \ 326 HPX_PP_CAT(HPX_PP_CAT(base_lco_with_value_, Name), Tag) \ 327 ::set_value_action, \ 328 "lco_set_value_action", std::size_t(-1), std::size_t(-1)) \ 329 /**/ 330 331 /////////////////////////////////////////////////////////////////////////////// 332 #define HPX_REGISTER_BASE_LCO_WITH_VALUE(...) \ 333 HPX_REGISTER_BASE_LCO_WITH_VALUE_(__VA_ARGS__) \ 334 /**/ 335 #define HPX_REGISTER_BASE_LCO_WITH_VALUE_(...) \ 336 HPX_PP_EXPAND(HPX_PP_CAT( \ 337 HPX_REGISTER_BASE_LCO_WITH_VALUE_, \ 338 HPX_PP_NARGS(__VA_ARGS__) \ 339 )(__VA_ARGS__)) \ 340 /**/ 341 342 #define HPX_REGISTER_BASE_LCO_WITH_VALUE_1(Value) \ 343 HPX_REGISTER_BASE_LCO_WITH_VALUE_4( \ 344 Value, Value, Value, managed_component_tag) \ 345 /**/ 346 347 #define HPX_REGISTER_BASE_LCO_WITH_VALUE_2(Value, Name) \ 348 HPX_REGISTER_BASE_LCO_WITH_VALUE_4( \ 349 Value, Value, Name, managed_component_tag) \ 350 /**/ 351 352 #define HPX_REGISTER_BASE_LCO_WITH_VALUE_3(Value, RemoteValue, Name) \ 353 HPX_REGISTER_BASE_LCO_WITH_VALUE_4( \ 354 Value, RemoteValue, Name, managed_component_tag) \ 355 /**/ 356 357 #define HPX_REGISTER_BASE_LCO_WITH_VALUE_4(Value, RemoteValue, Name, Tag) \ 358 typedef ::hpx::lcos::base_lco_with_value<Value, RemoteValue, \ 359 ::hpx::traits::detail::Tag> \ 360 HPX_PP_CAT(HPX_PP_CAT(base_lco_with_value_, Name), Tag); \ 361 HPX_REGISTER_ACTION( \ 362 HPX_PP_CAT(HPX_PP_CAT(base_lco_with_value_, Name), Tag) \ 363 ::set_value_action, \ 364 HPX_PP_CAT(HPX_PP_CAT(set_value_action_, Name), Tag)) \ 365 HPX_REGISTER_ACTION( \ 366 HPX_PP_CAT(HPX_PP_CAT(base_lco_with_value_, Name), Tag):: \ 367 get_value_action, \ 368 HPX_PP_CAT(HPX_PP_CAT(get_value_action_, Name), Tag)) \ 369 HPX_ACTION_USES_MESSAGE_COALESCING_NOTHROW_DEFINITION( \ 370 HPX_PP_CAT(HPX_PP_CAT(base_lco_with_value_, Name), Tag) \ 371 ::set_value_action, \ 372 "lco_set_value_action", std::size_t(-1), std::size_t(-1)) \ 373 /**/ 374 375 /////////////////////////////////////////////////////////////////////////////// 376 #define HPX_REGISTER_BASE_LCO_WITH_VALUE_ID(...) \ 377 HPX_REGISTER_BASE_LCO_WITH_VALUE_ID_(__VA_ARGS__) \ 378 /**/ 379 #define HPX_REGISTER_BASE_LCO_WITH_VALUE_ID_(...) \ 380 HPX_PP_EXPAND(HPX_PP_CAT( \ 381 HPX_REGISTER_BASE_LCO_WITH_VALUE_ID_, \ 382 HPX_PP_NARGS(__VA_ARGS__) \ 383 )(__VA_ARGS__)) \ 384 /**/ 385 386 // obsolete 387 #define HPX_REGISTER_BASE_LCO_WITH_VALUE_ID2( \ 388 Value, RemoteValue, Name, ActionIdGet, ActionIdSet) \ 389 HPX_REGISTER_BASE_LCO_WITH_VALUE_ID_6( \ 390 Value, RemoteValue, Name, ActionIdGet, ActionIdSet, \ 391 managed_component_tag) \ 392 /**/ 393 394 #define HPX_REGISTER_BASE_LCO_WITH_VALUE_ID_4( \ 395 Value, Name, ActionIdGet, ActionIdSet) \ 396 HPX_REGISTER_BASE_LCO_WITH_VALUE_ID_6(Value, Value, Name, \ 397 ActionIdGet, ActionIdSet, managed_component_tag) \ 398 /**/ 399 400 #define HPX_REGISTER_BASE_LCO_WITH_VALUE_ID_5( \ 401 Value, RemoteValue, Name, ActionIdGet, ActionIdSet) \ 402 HPX_REGISTER_BASE_LCO_WITH_VALUE_ID_6(Value, RemoteValue, Name, \ 403 ActionIdGet, ActionIdSet, managed_component_tag) \ 404 /**/ 405 406 #define HPX_REGISTER_BASE_LCO_WITH_VALUE_ID_6( \ 407 Value, RemoteValue, Name, ActionIdGet, ActionIdSet, Tag) \ 408 typedef ::hpx::lcos::base_lco_with_value<Value, RemoteValue, \ 409 ::hpx::traits::detail::Tag> \ 410 HPX_PP_CAT(HPX_PP_CAT(base_lco_with_value_, Name), Tag); \ 411 HPX_REGISTER_ACTION_ID( \ 412 HPX_PP_CAT(HPX_PP_CAT(base_lco_with_value_, Name), Tag) \ 413 ::set_value_action, \ 414 HPX_PP_CAT(HPX_PP_CAT(set_value_action_, Name), Tag), ActionIdSet) \ 415 HPX_REGISTER_ACTION_ID( \ 416 HPX_PP_CAT(HPX_PP_CAT(base_lco_with_value_, Name), Tag) \ 417 ::get_value_action, \ 418 HPX_PP_CAT(HPX_PP_CAT(get_value_action_, Name), Tag), ActionIdGet) \ 419 HPX_ACTION_USES_MESSAGE_COALESCING_NOTHROW_DEFINITION( \ 420 HPX_PP_CAT(HPX_PP_CAT(base_lco_with_value_, Name), Tag) \ 421 ::set_value_action, \ 422 "lco_set_value_action", std::size_t(-1), std::size_t(-1)) \ 423 /**/ 424 425 /////////////////////////////////////////////////////////////////////////////// 426 HPX_REGISTER_BASE_LCO_WITH_VALUE_DECLARATION(hpx::naming::gid_type, gid_type) 427 HPX_REGISTER_BASE_LCO_WITH_VALUE_DECLARATION( 428 std::vector<hpx::naming::gid_type>, vector_gid_type) 429 HPX_REGISTER_BASE_LCO_WITH_VALUE_DECLARATION( 430 hpx::naming::id_type, hpx::naming::gid_type, id_type) 431 HPX_REGISTER_BASE_LCO_WITH_VALUE_DECLARATION( 432 hpx::naming::id_type, naming_id_type) 433 HPX_REGISTER_BASE_LCO_WITH_VALUE_DECLARATION( 434 std::vector<hpx::naming::id_type>, std::vector<hpx::naming::gid_type>, 435 vector_id_gid_type) 436 HPX_REGISTER_BASE_LCO_WITH_VALUE_DECLARATION( 437 std::vector<hpx::naming::id_type>, vector_id_type) 438 HPX_REGISTER_BASE_LCO_WITH_VALUE_DECLARATION( 439 hpx::util::unused_type, hpx_unused_type) 440 HPX_REGISTER_BASE_LCO_WITH_VALUE_DECLARATION(float) 441 HPX_REGISTER_BASE_LCO_WITH_VALUE_DECLARATION(double) 442 HPX_REGISTER_BASE_LCO_WITH_VALUE_DECLARATION(std::int8_t, int8_t) 443 HPX_REGISTER_BASE_LCO_WITH_VALUE_DECLARATION(std::uint8_t, uint8_t) 444 HPX_REGISTER_BASE_LCO_WITH_VALUE_DECLARATION(std::int16_t, int16_t) 445 HPX_REGISTER_BASE_LCO_WITH_VALUE_DECLARATION(std::uint16_t, uint16_t) 446 HPX_REGISTER_BASE_LCO_WITH_VALUE_DECLARATION(std::int32_t, int32_t) 447 HPX_REGISTER_BASE_LCO_WITH_VALUE_DECLARATION(std::uint32_t, uint32_t) 448 HPX_REGISTER_BASE_LCO_WITH_VALUE_DECLARATION(std::int64_t, int64_t) 449 HPX_REGISTER_BASE_LCO_WITH_VALUE_DECLARATION(std::uint64_t, uint64_t) 450 HPX_REGISTER_BASE_LCO_WITH_VALUE_DECLARATION(bool) 451 HPX_REGISTER_BASE_LCO_WITH_VALUE_DECLARATION(std::vector<bool>, vector_bool_type) 452 HPX_REGISTER_BASE_LCO_WITH_VALUE_DECLARATION( 453 std::vector<std::uint32_t>, vector_std_uint32_type) 454 HPX_REGISTER_BASE_LCO_WITH_VALUE_DECLARATION(hpx::util::section, hpx_section) 455 HPX_REGISTER_BASE_LCO_WITH_VALUE_DECLARATION(std::string, std_string) 456 457 #endif /*HPX_LCOS_BASE_LCO_WITH_VALUE_HPP*/ 458