1 /*  _________________________________________________________________________
2  *
3  *  Acro: A Common Repository for Optimizers
4  *  Copyright (c) 2008 Sandia Corporation.
5  *  This software is distributed under the BSD License.
6  *  Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
7  *  the U.S. Government retains certain rights in this software.
8  *  For more information, see the README.txt file in the top Acro directory.
9  *  _________________________________________________________________________
10  */
11 
12 /**
13  * \file BoostExtras.h
14  *
15  * Declares supplemental utility functions for use with Boost template
16  * definitions.
17  */
18 
19 #ifndef colin_BoostExtras_h
20 #define colin_BoostExtras_h
21 
22 #include <acro_config.h>
23 #include <boost/signals2/last_value.hpp>
24 
25 namespace colin
26 {
27 
28 namespace boost_extras {
29 
30 /** Special variant of boost::signal that calls slots in the reverse
31  *  order from which they were registered (i.e. Last in, First out).
32  */
33 template<typename Signature, // function type R (T1, T2, ..., TN)
34          typename Combiner = boost::signals2::last_value
35              <typename boost::function_traits<Signature>::result_type>,
36          typename Group = int,
37          typename GroupCompare = std::less<Group>,
38          typename SlotFunction = boost::function<Signature>
39 >
40 class lifo_signal : public boost::signals2::signal<Signature, Combiner, Group,
41                                          GroupCompare, SlotFunction>
42 {
43    typedef boost::signals2::signal<Signature, Combiner, Group,
44                          GroupCompare, SlotFunction>  signal_t;
45 
46 public:
47    explicit lifo_signal(const Combiner& combiner = Combiner(),
48                         const GroupCompare& group_compare = GroupCompare())
signal_t(combiner,group_compare)49       : signal_t(combiner, group_compare)
50    {}
51 
52    // Connect a slot to this signal
53    boost::signals2::connection
connect(const typename signal_t::slot_type & fcn)54    connect(const typename signal_t::slot_type& fcn)
55    {
56       return signal_t::connect(fcn, boost::signals2::at_front);
57    }
58 
59    boost::signals2::connection
connect(const typename signal_t::group_type & group,const typename signal_t::slot_type & fcn)60    connect(const typename signal_t::group_type& group,
61            const typename signal_t::slot_type& fcn)
62    {
63       return signal_t::connect(group, fcn, boost::signals2::at_front);
64    }
65 };
66 
67 
68 /** A Combiner class that will sum the return values from all of the slots.
69  */
70 template<typename T>
71 struct sum {
72    typedef T result_type;
73 
74    template<typename InputIterator>
operatorsum75    T operator()(InputIterator first, InputIterator last) const
76    {
77       T value = T();
78       while (first != last)
79          value = value + *first++;
80       return value;
81    }
82 };
83 
84 template<>
85 struct sum<void> {
86    struct unusable {};
87 
88    typedef unusable result_type;
89 
90    template<typename InputIterator>
91    result_type
92    operator()(InputIterator first, InputIterator last) const
93    {
94       while (first != last)
95          *first++;
96       return result_type();
97    }
98 };
99 
100 
101 
102 /** A Combiner class that will call slots until each slot returns true.
103  *  The return value is the number of slots that never returned true
104  *  (after the first complete pass through the slots where no new slots
105  *  returned true).
106  */
107 struct call_until_pass {
108    typedef size_t result_type;
109 
110    template<typename InputIterator>
111    size_t operator()(InputIterator first, InputIterator last) const
112    {
113       if (first == last)
114          return 0;
115 
116       // an absurdly large number just to prevent infinite loops
117       size_t maxPasses = 100;
118 
119       bool slotPassed = false;
120       std::list<InputIterator> pending;
121       for( ; first != last; ++first )
122       {
123          int ans = *first;
124          if ( ans != 0 )
125             slotPassed = true;
126          if ( ans >= 0 )
127             pending.push_back(first);
128       }
129 
130       while ( slotPassed && ! pending.empty() && --maxPasses )
131       {
132          slotPassed = false;
133          std::list<InputIterator> active;
134          active.swap(pending);
135          while ( ! active.empty() )
136          {
137             int ans = *active.front();
138             if ( ans != 0 )
139                slotPassed = true;
140             if ( ans >= 0 )
141                pending.splice(pending.end(), active, active.begin());
142             else
143                active.pop_front();
144          }
145       }
146 
147       return pending.size();
148    }
149 };
150 
151 
152 } // namespace colin::boost_extras
153 } // namespace colin
154 
155 #endif // defined colin_BoostExtras_h
156