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