1 /////////////////////////////////////////////////////////////////////////////// 2 // droppable_accumulator.hpp 3 // 4 // Copyright 2005 Eric Niebler. Distributed under the Boost 5 // Software License, Version 1.0. (See accompanying file 6 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 7 8 #ifndef BOOST_ACCUMULATORS_FRAMEWORK_ACCUMULATORS_DROPPABLE_ACCUMULATOR_HPP_EAN_13_12_2005 9 #define BOOST_ACCUMULATORS_FRAMEWORK_ACCUMULATORS_DROPPABLE_ACCUMULATOR_HPP_EAN_13_12_2005 10 11 #include <new> 12 #include <boost/assert.hpp> 13 #include <boost/mpl/apply.hpp> 14 #include <boost/aligned_storage.hpp> 15 #include <boost/accumulators/framework/depends_on.hpp> // for feature_of 16 #include <boost/accumulators/framework/parameters/accumulator.hpp> // for accumulator 17 18 namespace boost { namespace accumulators 19 { 20 21 template<typename Accumulator> 22 struct droppable_accumulator; 23 24 namespace detail 25 { 26 /////////////////////////////////////////////////////////////////////////////// 27 // add_ref_visitor 28 // a fusion function object for add_ref'ing accumulators 29 template<typename Args> 30 struct add_ref_visitor 31 { add_ref_visitorboost::accumulators::detail::add_ref_visitor32 explicit add_ref_visitor(Args const &args) 33 : args_(args) 34 { 35 } 36 37 template<typename Accumulator> operator ()boost::accumulators::detail::add_ref_visitor38 void operator ()(Accumulator &acc) const 39 { 40 typedef typename Accumulator::feature_tag::dependencies dependencies; 41 42 acc.add_ref(this->args_); 43 44 // Also add_ref accumulators that this feature depends on 45 this->args_[accumulator].template 46 visit_if<detail::contains_feature_of_<dependencies> >( 47 *this 48 ); 49 } 50 51 private: 52 add_ref_visitor &operator =(add_ref_visitor const &); 53 Args const &args_; 54 }; 55 56 template<typename Args> make_add_ref_visitor(Args const & args)57 add_ref_visitor<Args> make_add_ref_visitor(Args const &args) 58 { 59 return add_ref_visitor<Args>(args); 60 } 61 62 /////////////////////////////////////////////////////////////////////////////// 63 // drop_visitor 64 // a fusion function object for dropping accumulators 65 template<typename Args> 66 struct drop_visitor 67 { drop_visitorboost::accumulators::detail::drop_visitor68 explicit drop_visitor(Args const &args) 69 : args_(args) 70 { 71 } 72 73 template<typename Accumulator> operator ()boost::accumulators::detail::drop_visitor74 void operator ()(Accumulator &acc) const 75 { 76 if(typename Accumulator::is_droppable()) 77 { 78 typedef typename Accumulator::feature_tag::dependencies dependencies; 79 80 acc.drop(this->args_); 81 // Also drop accumulators that this feature depends on 82 this->args_[accumulator].template 83 visit_if<detail::contains_feature_of_<dependencies> >( 84 *this 85 ); 86 } 87 } 88 89 private: 90 drop_visitor &operator =(drop_visitor const &); 91 Args const &args_; 92 }; 93 94 template<typename Args> make_drop_visitor(Args const & args)95 drop_visitor<Args> make_drop_visitor(Args const &args) 96 { 97 return drop_visitor<Args>(args); 98 } 99 } 100 101 ////////////////////////////////////////////////////////////////////////// 102 // droppable_accumulator_base 103 template<typename Accumulator> 104 struct droppable_accumulator_base 105 : Accumulator 106 { 107 typedef droppable_accumulator_base base; 108 typedef mpl::true_ is_droppable; 109 typedef typename Accumulator::result_type result_type; 110 111 template<typename Args> droppable_accumulator_baseboost::accumulators::droppable_accumulator_base112 droppable_accumulator_base(Args const &args) 113 : Accumulator(args) 114 , ref_count_(0) 115 { 116 } 117 droppable_accumulator_baseboost::accumulators::droppable_accumulator_base118 droppable_accumulator_base(droppable_accumulator_base const &that) 119 : Accumulator(*static_cast<Accumulator const *>(&that)) 120 , ref_count_(that.ref_count_) 121 { 122 } 123 124 template<typename Args> operator ()boost::accumulators::droppable_accumulator_base125 void operator ()(Args const &args) 126 { 127 if(!this->is_dropped()) 128 { 129 this->Accumulator::operator ()(args); 130 } 131 } 132 133 template<typename Args> add_refboost::accumulators::droppable_accumulator_base134 void add_ref(Args const &) 135 { 136 ++this->ref_count_; 137 } 138 139 template<typename Args> dropboost::accumulators::droppable_accumulator_base140 void drop(Args const &args) 141 { 142 BOOST_ASSERT(0 < this->ref_count_); 143 if(1 == this->ref_count_) 144 { 145 static_cast<droppable_accumulator<Accumulator> *>(this)->on_drop(args); 146 } 147 --this->ref_count_; 148 } 149 is_droppedboost::accumulators::droppable_accumulator_base150 bool is_dropped() const 151 { 152 return 0 == this->ref_count_; 153 } 154 155 private: 156 int ref_count_; 157 }; 158 159 ////////////////////////////////////////////////////////////////////////// 160 // droppable_accumulator 161 // this can be specialized for any type that needs special handling 162 template<typename Accumulator> 163 struct droppable_accumulator 164 : droppable_accumulator_base<Accumulator> 165 { 166 template<typename Args> droppable_accumulatorboost::accumulators::droppable_accumulator167 droppable_accumulator(Args const &args) 168 : droppable_accumulator::base(args) 169 { 170 } 171 droppable_accumulatorboost::accumulators::droppable_accumulator172 droppable_accumulator(droppable_accumulator const &that) 173 : droppable_accumulator::base(*static_cast<typename droppable_accumulator::base const *>(&that)) 174 { 175 } 176 }; 177 178 ////////////////////////////////////////////////////////////////////////// 179 // with_cached_result 180 template<typename Accumulator> 181 struct with_cached_result 182 : Accumulator 183 { 184 typedef typename Accumulator::result_type result_type; 185 186 template<typename Args> with_cached_resultboost::accumulators::with_cached_result187 with_cached_result(Args const &args) 188 : Accumulator(args) 189 , cache() 190 { 191 } 192 with_cached_resultboost::accumulators::with_cached_result193 with_cached_result(with_cached_result const &that) 194 : Accumulator(*static_cast<Accumulator const *>(&that)) 195 , cache() 196 { 197 if(that.has_result()) 198 { 199 this->set(that.get()); 200 } 201 } 202 ~with_cached_resultboost::accumulators::with_cached_result203 ~with_cached_result() 204 { 205 // Since this is a base class of droppable_accumulator_base, 206 // this destructor is called before any of droppable_accumulator_base's 207 // members get cleaned up, including is_dropped, so the following 208 // call to has_result() is valid. 209 if(this->has_result()) 210 { 211 this->get().~result_type(); 212 } 213 } 214 215 template<typename Args> on_dropboost::accumulators::with_cached_result216 void on_drop(Args const &args) 217 { 218 // cache the result at the point this calculation was dropped 219 BOOST_ASSERT(!this->has_result()); 220 this->set(this->Accumulator::result(args)); 221 } 222 223 template<typename Args> resultboost::accumulators::with_cached_result224 result_type result(Args const &args) const 225 { 226 return this->has_result() ? this->get() : this->Accumulator::result(args); 227 } 228 229 private: 230 with_cached_result &operator =(with_cached_result const &); 231 setboost::accumulators::with_cached_result232 void set(result_type const &r) 233 { 234 ::new(this->cache.address()) result_type(r); 235 } 236 getboost::accumulators::with_cached_result237 result_type const &get() const 238 { 239 return *static_cast<result_type const *>(this->cache.address()); 240 } 241 has_resultboost::accumulators::with_cached_result242 bool has_result() const 243 { 244 typedef with_cached_result<Accumulator> this_type; 245 typedef droppable_accumulator_base<this_type> derived_type; 246 return static_cast<derived_type const *>(this)->is_dropped(); 247 } 248 249 aligned_storage<sizeof(result_type)> cache; 250 }; 251 252 namespace tag 253 { 254 template<typename Feature> 255 struct as_droppable 256 { 257 typedef droppable<Feature> type; 258 }; 259 260 template<typename Feature> 261 struct as_droppable<droppable<Feature> > 262 { 263 typedef droppable<Feature> type; 264 }; 265 266 ////////////////////////////////////////////////////////////////////////// 267 // droppable 268 template<typename Feature> 269 struct droppable 270 : as_feature<Feature>::type 271 { 272 typedef typename as_feature<Feature>::type feature_type; 273 typedef typename feature_type::dependencies tmp_dependencies_; 274 275 typedef 276 typename mpl::transform< 277 typename feature_type::dependencies 278 , as_droppable<mpl::_1> 279 >::type 280 dependencies; 281 282 struct impl 283 { 284 template<typename Sample, typename Weight> 285 struct apply 286 { 287 typedef 288 droppable_accumulator< 289 typename mpl::apply2<typename feature_type::impl, Sample, Weight>::type 290 > 291 type; 292 }; 293 }; 294 }; 295 } 296 297 // make droppable<tag::feature(modifier)> work 298 template<typename Feature> 299 struct as_feature<tag::droppable<Feature> > 300 { 301 typedef tag::droppable<typename as_feature<Feature>::type> type; 302 }; 303 304 // make droppable<tag::mean> work with non-void weights (should become 305 // droppable<tag::weighted_mean> 306 template<typename Feature> 307 struct as_weighted_feature<tag::droppable<Feature> > 308 { 309 typedef tag::droppable<typename as_weighted_feature<Feature>::type> type; 310 }; 311 312 // for the purposes of feature-based dependency resolution, 313 // droppable<Foo> provides the same feature as Foo 314 template<typename Feature> 315 struct feature_of<tag::droppable<Feature> > 316 : feature_of<Feature> 317 { 318 }; 319 320 // Note: Usually, the extractor is pulled into the accumulators namespace with 321 // a using directive, not the tag. But the droppable<> feature doesn't have an 322 // extractor, so we can put the droppable tag in the accumulators namespace 323 // without fear of a name conflict. 324 using tag::droppable; 325 326 }} // namespace boost::accumulators 327 328 #endif 329