1 //  Copyright (c) 2013-2014 Thomas Heller
2 //  Copyright (c) 2013-2017 Hartmut Kaiser
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 /// \file broadcast.hpp
8 
9 #if defined(DOXYGEN)
10 namespace hpx { namespace lcos
11 {
12     /// \brief Perform a distributed broadcast operation
13     ///
14     /// The function hpx::lcos::broadcast performs a distributed broadcast
15     /// operation resulting in action invocations on a given set
16     /// of global identifiers. The action can be either a plain action (in
17     /// which case the global identifiers have to refer to localities) or a
18     /// component action (in which case the global identifiers have to refer
19     /// to instances of a component type which exposes the action.
20     ///
21     /// The given action is invoked asynchronously on all given identifiers,
22     /// and the arguments ArgN are passed along to those invocations.
23     ///
24     /// \param ids       [in] A list of global identifiers identifying the
25     ///                  target objects for which the given action will be
26     ///                  invoked.
27     /// \param argN      [in] Any number of arbitrary arguments (passed
28     ///                  by const reference) which will be forwarded to the
29     ///                  action invocation.
30     ///
31     /// \returns         This function returns a future representing the result
32     ///                  of the overall reduction operation.
33     ///
34     /// \note            If decltype(Action(...)) is void, then the result of
35     ///                  this function is future<void>.
36     ///
37     template <typename Action, typename ArgN, ...>
38     hpx::future<std::vector<decltype(Action(hpx::id_type, ArgN, ...))> >
39     broadcast(
40         std::vector<hpx::id_type> const & ids
41       , ArgN argN, ...);
42 
43     /// \brief Perform an asynchronous (fire&forget) distributed broadcast operation
44     ///
45     /// The function hpx::lcos::broadcast_apply performs an asynchronous
46     /// (fire&forget) distributed broadcast operation resulting in action
47     /// invocations on a given set of global identifiers. The action can be
48     /// either a plain action (in which case the global identifiers have to
49     /// refer to localities) or a component action (in which case the global
50     /// identifiers have to refer to instances of a component type which
51     /// exposes the action.
52     ///
53     /// The given action is invoked asynchronously on all given identifiers,
54     /// and the arguments ArgN are passed along to those invocations.
55     ///
56     /// \param ids       [in] A list of global identifiers identifying the
57     ///                  target objects for which the given action will be
58     ///                  invoked.
59     /// \param argN      [in] Any number of arbitrary arguments (passed
60     ///                  by const reference) which will be forwarded to the
61     ///                  action invocation.
62     ///
63     template <typename Action, typename ArgN, ...>
64     void
65     broadcast_apply(
66         std::vector<hpx::id_type> const & ids
67       , ArgN argN, ...);
68 
69     /// \brief Perform a distributed broadcast operation
70     ///
71     /// The function hpx::lcos::broadcast_with_index performs a distributed broadcast
72     /// operation resulting in action invocations on a given set
73     /// of global identifiers. The action can be either a plain action (in
74     /// which case the global identifiers have to refer to localities) or a
75     /// component action (in which case the global identifiers have to refer
76     /// to instances of a component type which exposes the action.
77     ///
78     /// The given action is invoked asynchronously on all given identifiers,
79     /// and the arguments ArgN are passed along to those invocations.
80     ///
81     /// The function passes the index of the global identifier in the given
82     /// list of identifiers as the last argument to the action.
83     ///
84     /// \param ids       [in] A list of global identifiers identifying the
85     ///                  target objects for which the given action will be
86     ///                  invoked.
87     /// \param argN      [in] Any number of arbitrary arguments (passed
88     ///                  by const reference) which will be forwarded to the
89     ///                  action invocation.
90     ///
91     /// \returns         This function returns a future representing the result
92     ///                  of the overall reduction operation.
93     ///
94     /// \note            If decltype(Action(...)) is void, then the result of
95     ///                  this function is future<void>.
96     ///
97     template <typename Action, typename ArgN, ...>
98     hpx::future<std::vector<decltype(Action(hpx::id_type, ArgN, ..., std::size_t))> >
99     broadcast_with_index(
100         std::vector<hpx::id_type> const & ids
101       , ArgN argN, ...);
102 
103     /// \brief Perform an asynchronous (fire&forget) distributed broadcast operation
104     ///
105     /// The function hpx::lcos::broadcast_apply_with_index performs an asynchronous
106     /// (fire&forget) distributed broadcast operation resulting in action
107     /// invocations on a given set of global identifiers. The action can be
108     /// either a plain action (in which case the global identifiers have to
109     /// refer to localities) or a component action (in which case the global
110     /// identifiers have to refer to instances of a component type which
111     /// exposes the action.
112     ///
113     /// The given action is invoked asynchronously on all given identifiers,
114     /// and the arguments ArgN are passed along to those invocations.
115     ///
116     /// The function passes the index of the global identifier in the given
117     /// list of identifiers as the last argument to the action.
118     ///
119     /// \param ids       [in] A list of global identifiers identifying the
120     ///                  target objects for which the given action will be
121     ///                  invoked.
122     /// \param argN      [in] Any number of arbitrary arguments (passed
123     ///                  by const reference) which will be forwarded to the
124     ///                  action invocation.
125     ///
126     template <typename Action, typename ArgN, ...>
127     void
128     broadcast_apply_with_index(
129         std::vector<hpx::id_type> const & ids
130       , ArgN argN, ...);
131 }}
132 #else
133 
134 #ifndef HPX_LCOS_BROADCAST_HPP
135 #define HPX_LCOS_BROADCAST_HPP
136 
137 #include <hpx/config.hpp>
138 #include <hpx/apply.hpp>
139 #include <hpx/lcos/detail/async_colocated.hpp>
140 #include <hpx/lcos/future.hpp>
141 #include <hpx/lcos/when_all.hpp>
142 #include <hpx/runtime/actions/plain_action.hpp>
143 #include <hpx/runtime/applier/detail/apply_colocated.hpp>
144 #include <hpx/runtime/naming/name.hpp>
145 #include <hpx/runtime/serialization/vector.hpp>
146 #include <hpx/throw_exception.hpp>
147 #include <hpx/traits/extract_action.hpp>
148 #include <hpx/traits/promise_local_result.hpp>
149 #include <hpx/util/assert.hpp>
150 #include <hpx/util/calculate_fanout.hpp>
151 #include <hpx/util/detail/pack.hpp>
152 #include <hpx/util/detail/pp/cat.hpp>
153 #include <hpx/util/detail/pp/expand.hpp>
154 #include <hpx/util/detail/pp/nargs.hpp>
155 #include <hpx/util/tuple.hpp>
156 
157 #include <cstddef>
158 #include <type_traits>
159 #include <utility>
160 #include <vector>
161 
162 #if !defined(HPX_BROADCAST_FANOUT)
163 #define HPX_BROADCAST_FANOUT 16
164 #endif
165 
166 namespace hpx { namespace lcos
167 {
168     namespace detail
169     {
170         ///////////////////////////////////////////////////////////////////////
171         template <typename Action>
172         struct broadcast_with_index
173         {
174             typedef typename Action::arguments_type arguments_type;
175         };
176 
177         ///////////////////////////////////////////////////////////////////////
178         template <typename Action>
179         struct broadcast_result
180         {
181             typedef
182                 typename traits::promise_local_result<
183                     typename hpx::traits::extract_action<
184                         Action
185                     >::remote_result_type
186                 >::type
187                 action_result;
188             typedef
189                 typename std::conditional<
190                     std::is_same<void, action_result>::value
191                   , void
192                   , std::vector<action_result>
193                 >::type
194                 type;
195         };
196 
197         template <typename Action>
198         struct broadcast_result<broadcast_with_index<Action> >
199           : broadcast_result<Action>
200         {};
201 
202         ///////////////////////////////////////////////////////////////////////
203         template <
204             typename Action
205           , typename ...Ts
206         >
207         //hpx::future<typename broadcast_result<Action>::type>
208         typename broadcast_result<Action>::type
209         broadcast_impl(
210             Action const & act
211           , std::vector<hpx::id_type> const & ids
212           , std::size_t global_idx
213           , std::false_type
214           , Ts const&... vs
215         );
216 
217         template <
218             typename Action
219           , typename ...Ts
220         >
221         //hpx::future<void>
222         void
223         broadcast_impl(
224             Action const & act
225           , std::vector<hpx::id_type> const & ids
226           , std::size_t global_idx
227           , std::true_type
228           , Ts const&... vs
229         );
230 
231         template <
232             typename Action
233           , typename ...Ts
234         >
235         void
236         broadcast_apply_impl(
237             Action const & act
238           , std::vector<hpx::id_type> const & ids
239           , std::size_t global_idx
240           , Ts const&... vs
241         );
242 
243         ///////////////////////////////////////////////////////////////////////
244         template <
245             typename Action
246           , typename Futures
247           , typename ...Ts
248         >
249         void
broadcast_invoke(Action act,Futures & futures,hpx::id_type const & id,std::size_t,Ts const &...vs)250         broadcast_invoke(Action act, Futures& futures, hpx::id_type const& id
251           , std::size_t
252           , Ts const&... vs)
253         {
254             futures.push_back(
255                 hpx::async(
256                     act
257                   , id
258                   , vs...
259                 )
260             );
261         }
262 
263         template <
264             typename Action
265           , typename Futures
266           , typename ...Ts
267         >
268         void
broadcast_invoke(broadcast_with_index<Action>,Futures & futures,hpx::id_type const & id,std::size_t global_idx,Ts const &...vs)269         broadcast_invoke(broadcast_with_index<Action>,
270             Futures& futures, hpx::id_type const& id
271           , std::size_t global_idx
272           , Ts const&... vs)
273         {
274             futures.push_back(
275                 hpx::async(
276                     Action()
277                   , id
278                   , vs...
279                   , global_idx
280                 )
281             );
282         }
283 
284         template <
285             typename Action
286           , typename Futures
287           , typename Cont
288           , typename ...Ts
289         >
290         void
broadcast_invoke(Action act,Futures & futures,Cont && cont,hpx::id_type const & id,std::size_t,Ts const &...vs)291         broadcast_invoke(Action act, Futures& futures, Cont && cont
292           , hpx::id_type const& id
293           , std::size_t
294           , Ts const&... vs)
295         {
296             futures.push_back(
297                 hpx::async(
298                     act
299                   , id
300                   , vs...
301                 ).then(std::forward<Cont>(cont))
302             );
303         }
304 
305         template <
306             typename Action
307           , typename Futures
308           , typename Cont
309           , typename ...Ts
310         >
311         void
broadcast_invoke(broadcast_with_index<Action>,Futures & futures,Cont && cont,hpx::id_type const & id,std::size_t global_idx,Ts const &...vs)312         broadcast_invoke(broadcast_with_index<Action>, Futures& futures
313           , Cont && cont
314           , hpx::id_type const& id
315           , std::size_t global_idx
316           , Ts const&... vs)
317         {
318             futures.push_back(
319                 hpx::async(
320                     Action()
321                   , id
322                   , vs...
323                   , global_idx
324                 ).then(std::forward<Cont>(cont))
325             );
326         }
327 
328         template <
329             typename Action
330           , typename ...Ts
331         >
332         void
broadcast_invoke_apply(Action act,hpx::id_type const & id,std::size_t,Ts const &...vs)333         broadcast_invoke_apply(Action act
334           , hpx::id_type const& id
335           , std::size_t
336           , Ts const&... vs)
337         {
338             hpx::apply(
339                 act
340               , id
341               , vs...
342             );
343         }
344 
345         template <
346             typename Action
347           , typename ...Ts
348         >
349         void
broadcast_invoke_apply(broadcast_with_index<Action>,hpx::id_type const & id,std::size_t global_idx,Ts const &...vs)350         broadcast_invoke_apply(broadcast_with_index<Action>
351           , hpx::id_type const& id
352           , std::size_t global_idx
353           , Ts const&... vs)
354         {
355             hpx::apply(
356                 Action()
357               , id
358               , vs...
359               , global_idx
360             );
361         }
362 
363         ///////////////////////////////////////////////////////////////////////
364         template <
365             typename Action
366           , typename IsVoid
367           , typename ...Ts
368         >
369         struct broadcast_invoker
370         {
371             //static hpx::future<typename broadcast_result<Action>::type>
372             static typename broadcast_result<Action>::type
callhpx::lcos::detail::broadcast_invoker373             call(
374                 Action const & act
375               , std::vector<hpx::id_type> const & ids
376               , std::size_t global_idx
377               , IsVoid
378               , Ts const&... vs
379             )
380             {
381                 return
382                     broadcast_impl(
383                         act
384                       , ids
385                       , global_idx
386                       , IsVoid()
387                       , vs...
388                     );
389             }
390         };
391 
392         template <
393             typename Action
394           , typename ...Ts
395         >
396         struct broadcast_apply_invoker
397         {
398             static void
callhpx::lcos::detail::broadcast_apply_invoker399             call(
400                 Action const & act
401               , std::vector<hpx::id_type> const & ids
402               , std::size_t global_idx
403               , Ts const&... vs
404             )
405             {
406                 return
407                     broadcast_apply_impl(
408                         act
409                       , ids
410                       , global_idx
411                       , vs...
412                     );
413             }
414         };
415 
416         ///////////////////////////////////////////////////////////////////////
417         template <typename Action, typename Is>
418         struct make_broadcast_action_impl;
419 
420         template <typename Action, std::size_t ...Is>
421         struct make_broadcast_action_impl<Action,
422             util::detail::pack_c<std::size_t, Is...> >
423         {
424             typedef
425                 typename broadcast_result<Action>::action_result
426                 action_result;
427 
428             typedef detail::broadcast_invoker<
429                         Action
430                       , typename std::is_void<action_result>::type
431                       , typename util::tuple_element<
432                             Is, typename Action::arguments_type
433                         >::type...
434                     >
435                     broadcast_invoker_type;
436 
437             typedef
438                 typename HPX_MAKE_ACTION(broadcast_invoker_type::call)::type
439                 type;
440         };
441 
442         template <typename Action>
443         struct make_broadcast_action
444           : make_broadcast_action_impl<
445                 Action
446               , typename util::detail::make_index_pack<Action::arity>::type
447             >
448         {};
449 
450         template <typename Action>
451         struct make_broadcast_action<broadcast_with_index<Action> >
452           : make_broadcast_action_impl<
453                 broadcast_with_index<Action>
454               , typename util::detail::make_index_pack<Action::arity - 1>::type
455             >
456         {};
457 
458         template <typename Action, typename Is>
459         struct make_broadcast_apply_action_impl;
460 
461         template <typename Action, std::size_t ...Is>
462         struct make_broadcast_apply_action_impl<Action,
463             util::detail::pack_c<std::size_t, Is...> >
464         {
465             typedef
466                 typename broadcast_result<Action>::action_result
467                 action_result;
468 
469             typedef detail::broadcast_apply_invoker<
470                         Action
471                       , typename util::tuple_element<
472                             Is, typename Action::arguments_type
473                         >::type...
474                     >
475                     broadcast_invoker_type;
476 
477             typedef
478                 typename HPX_MAKE_ACTION(broadcast_invoker_type::call)::type
479                 type;
480         };
481 
482         template <typename Action>
483         struct make_broadcast_apply_action
484           : make_broadcast_apply_action_impl<
485                 Action
486               , typename util::detail::make_index_pack<Action::arity>::type
487             >
488         {};
489 
490         template <typename Action>
491         struct make_broadcast_apply_action<broadcast_with_index<Action> >
492           : make_broadcast_apply_action_impl<
493                 broadcast_with_index<Action>
494               , typename util::detail::make_index_pack<Action::arity - 1>::type
495             >
496         {};
497 
498         ///////////////////////////////////////////////////////////////////////
return_void(hpx::future<std::vector<hpx::future<void>>>)499         inline void return_void(
500             hpx::future<std::vector<hpx::future<void> > >)
501         {
502             // todo: verify validity of all futures in the vector
503         }
504 
505         template <
506             typename Result
507         >
508         std::vector<Result>
wrap_into_vector(hpx::future<Result> r)509         wrap_into_vector(hpx::future<Result> r)
510         {
511             std::vector<Result> result;
512             result.push_back(r.get());
513             return result;
514         }
515 
516         template <
517             typename Result
518         >
519         std::vector<Result>
return_result_type(hpx::future<std::vector<hpx::future<std::vector<Result>>>> r)520         return_result_type(
521             hpx::future<std::vector<hpx::future<std::vector<Result> > > > r)
522         {
523             std::vector<Result> res;
524             std::vector<hpx::future<std::vector<Result> > > fres = std::move(r.get());
525 
526             for (hpx::future<std::vector<Result> >& f : fres)
527             {
528                 std::vector<Result> t = std::move(f.get());
529                 res.reserve(res.capacity() + t.size());
530                 std::move(t.begin(), t.end(), std::back_inserter(res));
531             }
532 
533             return res;
534         }
535 
536         ///////////////////////////////////////////////////////////////////////
537         template <
538             typename Action
539           , typename ...Ts
540         >
541         //hpx::future<void>
542         void
broadcast_impl(Action const & act,std::vector<hpx::id_type> const & ids,std::size_t global_idx,std::true_type,Ts const &...vs)543         broadcast_impl(
544             Action const & act
545           , std::vector<hpx::id_type> const & ids
546           , std::size_t global_idx
547           , std::true_type
548           , Ts const&... vs
549         )
550         {
551             if(ids.empty()) return;// hpx::lcos::make_ready_future();
552 
553             std::size_t const local_fanout = HPX_BROADCAST_FANOUT;
554             std::size_t local_size = (std::min)(ids.size(), local_fanout);
555             std::size_t fanout = util::calculate_fanout(ids.size(), local_fanout);
556 
557             std::vector<hpx::future<void> > broadcast_futures;
558             broadcast_futures.reserve(local_size + (ids.size()/fanout) + 1);
559             for(std::size_t i = 0; i != local_size; ++i)
560             {
561                 broadcast_invoke(
562                     act
563                   , broadcast_futures
564                   , ids[i]
565                   , global_idx + i
566                   , vs...
567                 );
568             }
569 
570             if(ids.size() > local_fanout)
571             {
572                 std::size_t applied = local_fanout;
573                 std::vector<hpx::id_type>::const_iterator it =
574                     ids.begin() + local_fanout;
575 
576                 typedef
577                     typename detail::make_broadcast_action<
578                         Action
579                     >::type
580                     broadcast_impl_action;
581 
582                 while(it != ids.end())
583                 {
584                     HPX_ASSERT(ids.size() >= applied);
585 
586                     std::size_t next_fan = (std::min)(fanout, ids.size() - applied);
587                     std::vector<hpx::id_type> ids_next(it, it + next_fan);
588 
589                     hpx::id_type id(ids_next[0]);
590                     broadcast_futures.push_back(
591                         hpx::detail::async_colocated<broadcast_impl_action>(
592                             id
593                           , act
594                           , std::move(ids_next)
595                           , global_idx + applied
596                           , std::true_type()
597                           , vs...
598                         )
599                     );
600 
601                     applied += next_fan;
602                     it += next_fan;
603                 }
604             }
605 
606             //return hpx::when_all(broadcast_futures).then(&return_void);
607             hpx::when_all(broadcast_futures).then(&return_void).get();
608         }
609 
610         template <
611             typename Action
612           , typename ...Ts
613         >
614         //hpx::future<typename broadcast_result<Action>::type>
615         typename broadcast_result<Action>::type
broadcast_impl(Action const & act,std::vector<hpx::id_type> const & ids,std::size_t global_idx,std::false_type,Ts const &...vs)616         broadcast_impl(
617             Action const & act
618           , std::vector<hpx::id_type> const & ids
619           , std::size_t global_idx
620           , std::false_type
621           , Ts const&... vs
622         )
623         {
624             typedef
625                 typename broadcast_result<Action>::action_result
626                 action_result;
627             typedef
628                 typename broadcast_result<Action>::type
629                 result_type;
630 
631             //if(ids.empty()) return hpx::lcos::make_ready_future(result_type());
632             if(ids.empty()) return result_type();
633 
634             std::size_t const local_fanout = HPX_BROADCAST_FANOUT;
635             std::size_t local_size = (std::min)(ids.size(), local_fanout);
636             std::size_t fanout = util::calculate_fanout(ids.size(), local_fanout);
637 
638             std::vector<hpx::future<result_type> > broadcast_futures;
639             broadcast_futures.reserve(local_size + (ids.size()/fanout) + 1);
640             for(std::size_t i = 0; i != local_size; ++i)
641             {
642                 broadcast_invoke(
643                     act
644                   , broadcast_futures
645                   , &wrap_into_vector<action_result>
646                   , ids[i]
647                   , global_idx + i
648                   , vs...
649                 );
650             }
651 
652             if(ids.size() > local_fanout)
653             {
654                 std::size_t applied = local_fanout;
655                 std::vector<hpx::id_type>::const_iterator it =
656                     ids.begin() + local_fanout;
657 
658                 typedef
659                     typename detail::make_broadcast_action<
660                         Action
661                     >::type
662                     broadcast_impl_action;
663 
664                 while(it != ids.end())
665                 {
666                     HPX_ASSERT(ids.size() >= applied);
667 
668                     std::size_t next_fan = (std::min)(fanout, ids.size() - applied);
669                     std::vector<hpx::id_type> ids_next(it, it + next_fan);
670 
671                     hpx::id_type id(ids_next[0]);
672                     broadcast_futures.push_back(
673                         hpx::detail::async_colocated<broadcast_impl_action>(
674                             id
675                           , act
676                           , std::move(ids_next)
677                           , global_idx + applied
678                           , std::false_type()
679                           , vs...
680                         )
681                     );
682 
683                     applied += next_fan;
684                     it += next_fan;
685                 }
686             }
687 
688             return hpx::when_all(broadcast_futures).
689                 then(&return_result_type<action_result>).get();
690         }
691 
692         ///////////////////////////////////////////////////////////////////////
693         template <
694             typename Action
695           , typename ...Ts
696         >
697         void
broadcast_apply_impl(Action const & act,std::vector<hpx::id_type> const & ids,std::size_t global_idx,Ts const &...vs)698         broadcast_apply_impl(
699             Action const & act
700           , std::vector<hpx::id_type> const & ids
701           , std::size_t global_idx
702           , Ts const&... vs
703         )
704         {
705             if(ids.empty()) return;
706 
707             std::size_t const local_fanout = HPX_BROADCAST_FANOUT;
708             std::size_t local_size = (std::min)(ids.size(), local_fanout);
709 
710             for(std::size_t i = 0; i != local_size; ++i)
711             {
712                 broadcast_invoke_apply(
713                     act
714                   , ids[i]
715                   , global_idx + i
716                   , vs...
717                 );
718             }
719 
720             if(ids.size() > local_fanout)
721             {
722                 std::size_t applied = local_fanout;
723                 std::vector<hpx::id_type>::const_iterator it =
724                     ids.begin() + local_fanout;
725 
726                 typedef
727                     typename detail::make_broadcast_apply_action<
728                         Action
729                     >::type
730                     broadcast_impl_action;
731 
732                 std::size_t fanout = util::calculate_fanout(ids.size(), local_fanout);
733                 while(it != ids.end())
734                 {
735                     HPX_ASSERT(ids.size() >= applied);
736 
737                     std::size_t next_fan = (std::min)(fanout, ids.size() - applied);
738                     std::vector<hpx::id_type> ids_next(it, it + next_fan);
739 
740                     hpx::id_type id(ids_next[0]);
741                     hpx::detail::apply_colocated<broadcast_impl_action>(
742                         id
743                       , act
744                       , std::move(ids_next)
745                       , global_idx + applied
746                       , vs...
747                     );
748 
749                     applied += next_fan;
750                     it += next_fan;
751                 }
752             }
753         }
754     }
755 
756     ///////////////////////////////////////////////////////////////////////////
757     template <
758         typename Action
759       , typename ...Ts
760     >
761     hpx::future<
762         typename detail::broadcast_result<Action>::type
763     >
broadcast(std::vector<hpx::id_type> const & ids,Ts const &...vs)764     broadcast(
765         std::vector<hpx::id_type> const & ids
766       , Ts const&... vs)
767     {
768         typedef
769             typename detail::make_broadcast_action<Action>::type
770             broadcast_impl_action;
771         typedef
772             typename detail::broadcast_result<Action>::action_result
773             action_result;
774 
775         if (ids.empty())
776         {
777             typedef typename detail::broadcast_result<Action>::type
778                 result_type;
779 
780             return hpx::make_exceptional_future<result_type>(
781                 HPX_GET_EXCEPTION(bad_parameter,
782                     "hpx::lcos::broadcast",
783                     "empty list of targets for broadcast operation")
784                 );
785         }
786 
787         return
788             hpx::detail::async_colocated<broadcast_impl_action>(
789                 ids[0]
790               , Action()
791               , ids
792               , std::size_t(0)
793               , std::is_void<action_result>()
794               , vs...
795             );
796     }
797 
798     template <
799         typename Component, typename Signature, typename Derived
800       , typename ...Ts
801     >
802     hpx::future<
803         typename detail::broadcast_result<Derived>::type
804     >
broadcast(hpx::actions::basic_action<Component,Signature,Derived>,std::vector<hpx::id_type> const & ids,Ts const &...vs)805     broadcast(
806         hpx::actions::basic_action<Component, Signature, Derived> /* act */
807       , std::vector<hpx::id_type> const & ids
808       , Ts const&... vs)
809     {
810         return broadcast<Derived>(
811                 ids
812               , vs...
813             );
814     }
815 
816     ///////////////////////////////////////////////////////////////////////////
817     template <
818         typename Action
819       , typename ...Ts
820     >
821     void
broadcast_apply(std::vector<hpx::id_type> const & ids,Ts const &...vs)822     broadcast_apply(
823         std::vector<hpx::id_type> const & ids
824       , Ts const&... vs)
825     {
826         typedef
827             typename detail::make_broadcast_apply_action<Action>::type
828             broadcast_impl_action;
829 
830         if (ids.empty())
831         {
832             HPX_THROW_EXCEPTION(hpx::bad_parameter,
833                 "hpx::lcos::broadcast_apply",
834                 "empty list of targets for broadcast operation");
835             return;
836         }
837 
838         hpx::detail::apply_colocated<broadcast_impl_action>(
839                 ids[0]
840               , Action()
841               , ids
842               , 0
843               , vs...
844             );
845     }
846 
847     template <
848         typename Component, typename Signature, typename Derived
849       , typename ...Ts
850     >
851     void
broadcast_apply(hpx::actions::basic_action<Component,Signature,Derived>,std::vector<hpx::id_type> const & ids,Ts const &...vs)852     broadcast_apply(
853         hpx::actions::basic_action<Component, Signature, Derived> /* act */
854       , std::vector<hpx::id_type> const & ids
855       , Ts const&... vs)
856     {
857         broadcast_apply<Derived>(
858             ids
859           , vs...
860         );
861     }
862 
863     ///////////////////////////////////////////////////////////////////////////
864     template <
865         typename Action
866       , typename ...Ts
867     >
868     hpx::future<
869         typename detail::broadcast_result<Action>::type
870     >
broadcast_with_index(std::vector<hpx::id_type> const & ids,Ts const &...vs)871     broadcast_with_index(
872         std::vector<hpx::id_type> const & ids
873       , Ts const&... vs)
874     {
875         return broadcast<detail::broadcast_with_index<Action> >(
876                 ids
877               , vs...
878             );
879     }
880 
881     template <
882         typename Component, typename Signature, typename Derived
883       , typename ...Ts
884     >
885     hpx::future<
886         typename detail::broadcast_result<Derived>::type
887     >
broadcast_with_index(hpx::actions::basic_action<Component,Signature,Derived>,std::vector<hpx::id_type> const & ids,Ts const &...vs)888     broadcast_with_index(
889         hpx::actions::basic_action<Component, Signature, Derived> /* act */
890       , std::vector<hpx::id_type> const & ids
891       , Ts const&... vs)
892     {
893         return broadcast<detail::broadcast_with_index<Derived> >(
894                 ids
895               , vs...
896             );
897     }
898 
899     ///////////////////////////////////////////////////////////////////////////
900     template <
901         typename Action
902       , typename ...Ts
903     >
904     void
broadcast_apply_with_index(std::vector<hpx::id_type> const & ids,Ts const &...vs)905     broadcast_apply_with_index(
906         std::vector<hpx::id_type> const & ids
907       , Ts const&... vs)
908     {
909         broadcast_apply<detail::broadcast_with_index<Action> >(
910             ids
911           , vs...
912         );
913     }
914 
915     template <
916         typename Component, typename Signature, typename Derived
917       , typename ...Ts
918     >
919     void
broadcast_apply_with_index(hpx::actions::basic_action<Component,Signature,Derived>,std::vector<hpx::id_type> const & ids,Ts const &...vs)920     broadcast_apply_with_index(
921         hpx::actions::basic_action<Component, Signature, Derived> /* act */
922       , std::vector<hpx::id_type> const & ids
923       , Ts const&... vs)
924     {
925         broadcast_apply<detail::broadcast_with_index<Derived> >(
926             ids
927           , vs...
928         );
929     }
930 }}
931 
932 ///////////////////////////////////////////////////////////////////////////////
933 #define HPX_REGISTER_BROADCAST_APPLY_ACTION_DECLARATION(...)                  \
934     HPX_REGISTER_BROADCAST_APPLY_ACTION_DECLARATION_(__VA_ARGS__)             \
935 /**/
936 #define HPX_REGISTER_BROADCAST_APPLY_ACTION_DECLARATION_(...)                 \
937     HPX_PP_EXPAND(HPX_PP_CAT(                                                 \
938         HPX_REGISTER_BROADCAST_APPLY_ACTION_DECLARATION_,                     \
939             HPX_PP_NARGS(__VA_ARGS__)                                         \
940     )(__VA_ARGS__))                                                           \
941 /**/
942 
943 #define HPX_REGISTER_BROADCAST_APPLY_ACTION_DECLARATION_1(Action)             \
944     HPX_REGISTER_BROADCAST_APPLY_ACTION_DECLARATION_2(Action, Action)         \
945 /**/
946 #define HPX_REGISTER_BROADCAST_APPLY_ACTION_DECLARATION_2(Action, Name)       \
947     HPX_REGISTER_ACTION_DECLARATION(                                          \
948         ::hpx::lcos::detail::make_broadcast_apply_action<Action>::type        \
949       , HPX_PP_CAT(broadcast_apply_, Name)                                    \
950     )                                                                         \
951     HPX_REGISTER_APPLY_COLOCATED_DECLARATION(                                 \
952         ::hpx::lcos::detail::make_broadcast_apply_action<Action>::type        \
953       , HPX_PP_CAT(apply_colocated_broadcast_, Name)                          \
954     )                                                                         \
955 /**/
956 
957 ///////////////////////////////////////////////////////////////////////////////
958 #define HPX_REGISTER_BROADCAST_APPLY_ACTION(...)                              \
959     HPX_REGISTER_BROADCAST_APPLY_ACTION_(__VA_ARGS__)                         \
960 /**/
961 #define HPX_REGISTER_BROADCAST_APPLY_ACTION_(...)                             \
962     HPX_PP_EXPAND(HPX_PP_CAT(                                                 \
963         HPX_REGISTER_BROADCAST_APPLY_ACTION_, HPX_PP_NARGS(__VA_ARGS__)       \
964     )(__VA_ARGS__))                                                           \
965 /**/
966 
967 #define HPX_REGISTER_BROADCAST_APPLY_ACTION_1(Action)                         \
968     HPX_REGISTER_BROADCAST_APPLY_ACTION_2(Action, Action)                     \
969 /**/
970 #define HPX_REGISTER_BROADCAST_APPLY_ACTION_2(Action, Name)                   \
971     HPX_REGISTER_ACTION(                                                      \
972         ::hpx::lcos::detail::make_broadcast_apply_action<Action>::type        \
973       , HPX_PP_CAT(broadcast_apply_, Name)                                    \
974     )                                                                         \
975     HPX_REGISTER_APPLY_COLOCATED(                                             \
976         ::hpx::lcos::detail::make_broadcast_apply_action<Action>::type        \
977       , HPX_PP_CAT(apply_colocated_broadcast_, Name)                          \
978     )                                                                         \
979 /**/
980 
981 ///////////////////////////////////////////////////////////////////////////////
982 #define HPX_REGISTER_BROADCAST_APPLY_WITH_INDEX_ACTION_DECLARATION(...)       \
983     HPX_REGISTER_BROADCAST_APPLY_WITH_INDEX_ACTION_DECLARATION_(__VA_ARGS__)  \
984 /**/
985 #define HPX_REGISTER_BROADCAST_APPLY_WITH_INDEX_ACTION_DECLARATION_(...)      \
986     HPX_PP_EXPAND(HPX_PP_CAT(                                                 \
987         HPX_REGISTER_BROADCAST_APPLY_WITH_INDEX_ACTION_DECLARATION_,          \
988             HPX_PP_NARGS(__VA_ARGS__)                                         \
989     )(__VA_ARGS__))                                                           \
990 /**/
991 
992 #define HPX_REGISTER_BROADCAST_APPLY_WITH_INDEX_ACTION_DECLARATION_1(Action)  \
993     HPX_REGISTER_BROADCAST_APPLY_WITH_INDEX_ACTION_DECLARATION_2(             \
994         Action, Action)                                                       \
995 /**/
996 #define HPX_REGISTER_BROADCAST_APPLY_WITH_INDEX_ACTION_DECLARATION_2(         \
997         Action, Name)                                                         \
998     HPX_REGISTER_ACTION_DECLARATION(                                          \
999         ::hpx::lcos::detail::make_broadcast_apply_action<                     \
1000             ::hpx::lcos::detail::broadcast_with_index<Action>                 \
1001         >::type                                                               \
1002       , HPX_PP_CAT(broadcast_apply_with_index_, Name)                         \
1003     )                                                                         \
1004     HPX_REGISTER_APPLY_COLOCATED_DECLARATION(                                 \
1005         ::hpx::lcos::detail::make_broadcast_apply_action<                     \
1006             ::hpx::lcos::detail::broadcast_with_index<Action>                 \
1007         >::type                                                               \
1008       , HPX_PP_CAT(apply_colocated_broadcast_with_index_, Name)               \
1009     )                                                                         \
1010 /**/
1011 
1012 ///////////////////////////////////////////////////////////////////////////////
1013 #define HPX_REGISTER_BROADCAST_APPLY_WITH_INDEX_ACTION(...)                   \
1014     HPX_REGISTER_BROADCAST_APPLY_WITH_INDEX_ACTION_(__VA_ARGS__)              \
1015 /**/
1016 #define HPX_REGISTER_BROADCAST_APPLY_WITH_INDEX_ACTION_(...)                  \
1017     HPX_PP_EXPAND(HPX_PP_CAT(                                                 \
1018         HPX_REGISTER_BROADCAST_APPLY_WITH_INDEX_ACTION_,                      \
1019             HPX_PP_NARGS(__VA_ARGS__)                                         \
1020     )(__VA_ARGS__))                                                           \
1021 /**/
1022 
1023 #define HPX_REGISTER_BROADCAST_APPLY_WITH_INDEX_ACTION_1(Action)              \
1024     HPX_REGISTER_BROADCAST_APPLY_WITH_INDEX_ACTION_2(Action, Action)          \
1025 /**/
1026 #define HPX_REGISTER_BROADCAST_APPLY_WITH_INDEX_ACTION_2(Action, Name)        \
1027     HPX_REGISTER_ACTION(                                                      \
1028         ::hpx::lcos::detail::make_broadcast_apply_action<                     \
1029             ::hpx::lcos::detail::broadcast_with_index<Action>                 \
1030         >::type                                                               \
1031       , HPX_PP_CAT(broadcast_apply_with_index_, Name)                         \
1032     )                                                                         \
1033     HPX_REGISTER_APPLY_COLOCATED(                                             \
1034         ::hpx::lcos::detail::make_broadcast_apply_action<                     \
1035             ::hpx::lcos::detail::broadcast_with_index<Action>                 \
1036         >::type                                                               \
1037       , HPX_PP_CAT(apply_colocated_broadcast_with_index_, Name)               \
1038     )                                                                         \
1039 /**/
1040 
1041 ///////////////////////////////////////////////////////////////////////////////
1042 #define HPX_REGISTER_BROADCAST_ACTION_DECLARATION(...)                        \
1043     HPX_REGISTER_BROADCAST_ACTION_DECLARATION_(__VA_ARGS__)                   \
1044 /**/
1045 #define HPX_REGISTER_BROADCAST_ACTION_DECLARATION_(...)                       \
1046     HPX_PP_EXPAND(HPX_PP_CAT(                                                 \
1047         HPX_REGISTER_BROADCAST_ACTION_DECLARATION_,                           \
1048             HPX_PP_NARGS(__VA_ARGS__)                                         \
1049     )(__VA_ARGS__))                                                           \
1050 /**/
1051 
1052 #define HPX_REGISTER_BROADCAST_ACTION_DECLARATION_1(Action)                   \
1053     HPX_REGISTER_BROADCAST_ACTION_DECLARATION_2(Action, Action)               \
1054 /**/
1055 #define HPX_REGISTER_BROADCAST_ACTION_DECLARATION_2(Action, Name)             \
1056     HPX_REGISTER_ACTION_DECLARATION(                                          \
1057         ::hpx::lcos::detail::make_broadcast_action<Action>::type              \
1058       , HPX_PP_CAT(broadcast_, Name)                                          \
1059     )                                                                         \
1060     HPX_REGISTER_ASYNC_COLOCATED_DECLARATION(                                 \
1061         ::hpx::lcos::detail::make_broadcast_action<Action>::type              \
1062       , HPX_PP_CAT(async_colocated_broadcast_, Name)                          \
1063     )                                                                         \
1064 /**/
1065 
1066 ///////////////////////////////////////////////////////////////////////////////
1067 #define HPX_REGISTER_BROADCAST_ACTION(...)                                    \
1068     HPX_REGISTER_BROADCAST_ACTION_(__VA_ARGS__)                               \
1069 /**/
1070 #define HPX_REGISTER_BROADCAST_ACTION_(...)                                   \
1071     HPX_PP_EXPAND(HPX_PP_CAT(                                                 \
1072         HPX_REGISTER_BROADCAST_ACTION_, HPX_PP_NARGS(__VA_ARGS__)             \
1073     )(__VA_ARGS__))                                                           \
1074 /**/
1075 
1076 #define HPX_REGISTER_BROADCAST_ACTION_1(Action)                               \
1077     HPX_REGISTER_BROADCAST_ACTION_2(Action, Action)                           \
1078 /**/
1079 #define HPX_REGISTER_BROADCAST_ACTION_2(Action, Name)                         \
1080     HPX_REGISTER_ACTION(                                                      \
1081         ::hpx::lcos::detail::make_broadcast_action<Action>::type              \
1082       , HPX_PP_CAT(broadcast_, Name)                                          \
1083     )                                                                         \
1084     HPX_REGISTER_ASYNC_COLOCATED(                                             \
1085         ::hpx::lcos::detail::make_broadcast_action<Action>::type              \
1086       , HPX_PP_CAT(async_colocated_broadcast_, Name)                          \
1087     )                                                                         \
1088 /**/
1089 #define HPX_REGISTER_BROADCAST_ACTION_ID(Action, Name, Id)                    \
1090     HPX_REGISTER_ACTION_ID(                                                   \
1091         ::hpx::lcos::detail::make_broadcast_action<Action>::type              \
1092       , HPX_PP_CAT(broadcast_, Name)                                          \
1093       , Id                                                                    \
1094     )                                                                         \
1095     HPX_REGISTER_ASYNC_COLOCATED(                                             \
1096         ::hpx::lcos::detail::make_broadcast_action<Action>::type              \
1097       , HPX_PP_CAT(async_colocated_broadcast_, Name)                          \
1098     )                                                                         \
1099 /**/
1100 
1101 ///////////////////////////////////////////////////////////////////////////////
1102 #define HPX_REGISTER_BROADCAST_WITH_INDEX_ACTION_DECLARATION(...)             \
1103     HPX_REGISTER_BROADCAST_WITH_INDEX_ACTION_DECLARATION_(__VA_ARGS__)        \
1104 /**/
1105 #define HPX_REGISTER_BROADCAST_WITH_INDEX_ACTION_DECLARATION_(...)            \
1106     HPX_PP_EXPAND(HPX_PP_CAT(                                                 \
1107         HPX_REGISTER_BROADCAST_WITH_INDEX_ACTION_DECLARATION_,                \
1108             HPX_PP_NARGS(__VA_ARGS__)                                         \
1109     )(__VA_ARGS__))                                                           \
1110 /**/
1111 
1112 #define HPX_REGISTER_BROADCAST_WITH_INDEX_ACTION_DECLARATION_1(Action)        \
1113     HPX_REGISTER_BROADCAST_WITH_INDEX_ACTION_DECLARATION_2(Action, Action)    \
1114 /**/
1115 #define HPX_REGISTER_BROADCAST_WITH_INDEX_ACTION_DECLARATION_2(Action, Name)  \
1116     HPX_REGISTER_ACTION_DECLARATION(                                          \
1117         ::hpx::lcos::detail::make_broadcast_action<                           \
1118             ::hpx::lcos::detail::broadcast_with_index<Action>                 \
1119         >::type                                                               \
1120       , HPX_PP_CAT(broadcast_with_index_, Name)                               \
1121     )                                                                         \
1122     HPX_REGISTER_ASYNC_COLOCATED_DECLARATION(                                 \
1123         ::hpx::lcos::detail::make_broadcast_action<                           \
1124             ::hpx::lcos::detail::broadcast_with_index<Action>                 \
1125         >::type                                                               \
1126       , HPX_PP_CAT(async_colocated_broadcast_with_index_, Name)               \
1127     )                                                                         \
1128 /**/
1129 
1130 ///////////////////////////////////////////////////////////////////////////////
1131 #define HPX_REGISTER_BROADCAST_WITH_INDEX_ACTION(...)                         \
1132     HPX_REGISTER_BROADCAST_WITH_INDEX_ACTION_(__VA_ARGS__)                    \
1133 /**/
1134 #define HPX_REGISTER_BROADCAST_WITH_INDEX_ACTION_(...)                        \
1135     HPX_PP_EXPAND(HPX_PP_CAT(                                                 \
1136         HPX_REGISTER_BROADCAST_WITH_INDEX_ACTION_,                            \
1137             HPX_PP_NARGS(__VA_ARGS__)                                         \
1138     )(__VA_ARGS__))                                                           \
1139 /**/
1140 
1141 #define HPX_REGISTER_BROADCAST_WITH_INDEX_ACTION_1(Action)                    \
1142     HPX_REGISTER_BROADCAST_WITH_INDEX_ACTION_2(Action, Action)                \
1143 /**/
1144 #define HPX_REGISTER_BROADCAST_WITH_INDEX_ACTION_2(Action, Name)              \
1145     HPX_REGISTER_ACTION(                                                      \
1146         ::hpx::lcos::detail::make_broadcast_action<                           \
1147             ::hpx::lcos::detail::broadcast_with_index<Action>                 \
1148         >::type                                                               \
1149       , HPX_PP_CAT(broadcast_with_index_, Name)                               \
1150     )                                                                         \
1151     HPX_REGISTER_ASYNC_COLOCATED(                                             \
1152         ::hpx::lcos::detail::make_broadcast_action<                           \
1153             ::hpx::lcos::detail::broadcast_with_index<Action>                 \
1154         >::type                                                               \
1155       , HPX_PP_CAT(async_colocated_broadcast_with_index_, Name)               \
1156     )                                                                         \
1157 /**/
1158 #define HPX_REGISTER_BROADCAST_WITH_INDEX_ACTION_ID(Action, Name, Id)         \
1159     HPX_REGISTER_ACTION_ID(                                                   \
1160         ::hpx::lcos::detail::make_broadcast_action<                           \
1161             ::hpx::lcos::detail::broadcast_with_index<Action>                 \
1162         >::type                                                               \
1163       , HPX_PP_CAT(broadcast_with_index_, Name)                               \
1164       , Id                                                                    \
1165     )                                                                         \
1166     HPX_REGISTER_ASYNC_COLOCATED(                                             \
1167         ::hpx::lcos::detail::make_broadcast_action<                           \
1168             ::hpx::lcos::detail::broadcast_with_index<Action>                 \
1169         >::type                                                               \
1170       , HPX_PP_CAT(async_colocated_broadcast_with_index_, Name)               \
1171     )                                                                         \
1172 /**/
1173 
1174 #endif
1175 
1176 #endif // DOXYGEN
1177