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