1 ///////////////////////////////////////////////////////////////////////////////
2 // droppable_accumulator.hpp
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)
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
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
18 namespace boost { namespace accumulators
21 template<typename Accumulator>
22 struct droppable_accumulator;
26 ///////////////////////////////////////////////////////////////////////////////
28 // a fusion function object for add_ref'ing accumulators
29 template<typename Args>
30 struct add_ref_visitor
32 explicit add_ref_visitor(Args const &args)
37 template<typename Accumulator>
38 void operator ()(Accumulator &acc) const
40 typedef typename Accumulator::feature_tag::dependencies dependencies;
42 acc.add_ref(this->args_);
44 // Also add_ref accumulators that this feature depends on
45 this->args_[accumulator].template
46 visit_if<detail::contains_feature_of_<dependencies> >(
52 add_ref_visitor &operator =(add_ref_visitor const &);
56 template<typename Args>
57 add_ref_visitor<Args> make_add_ref_visitor(Args const &args)
59 return add_ref_visitor<Args>(args);
62 ///////////////////////////////////////////////////////////////////////////////
64 // a fusion function object for dropping accumulators
65 template<typename Args>
68 explicit drop_visitor(Args const &args)
73 template<typename Accumulator>
74 void operator ()(Accumulator &acc) const
76 if(typename Accumulator::is_droppable())
78 typedef typename Accumulator::feature_tag::dependencies dependencies;
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> >(
90 drop_visitor &operator =(drop_visitor const &);
94 template<typename Args>
95 drop_visitor<Args> make_drop_visitor(Args const &args)
97 return drop_visitor<Args>(args);
101 //////////////////////////////////////////////////////////////////////////
102 // droppable_accumulator_base
103 template<typename Accumulator>
104 struct droppable_accumulator_base
107 typedef droppable_accumulator_base base;
108 typedef mpl::true_ is_droppable;
109 typedef typename Accumulator::result_type result_type;
111 template<typename Args>
112 droppable_accumulator_base(Args const &args)
118 droppable_accumulator_base(droppable_accumulator_base const &that)
119 : Accumulator(*static_cast<Accumulator const *>(&that))
120 , ref_count_(that.ref_count_)
124 template<typename Args>
125 void operator ()(Args const &args)
127 if(!this->is_dropped())
129 this->Accumulator::operator ()(args);
133 template<typename Args>
134 void add_ref(Args const &)
139 template<typename Args>
140 void drop(Args const &args)
142 BOOST_ASSERT(0 < this->ref_count_);
143 if(1 == this->ref_count_)
145 static_cast<droppable_accumulator<Accumulator> *>(this)->on_drop(args);
150 bool is_dropped() const
152 return 0 == this->ref_count_;
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>
166 template<typename Args>
167 droppable_accumulator(Args const &args)
168 : droppable_accumulator::base(args)
172 droppable_accumulator(droppable_accumulator const &that)
173 : droppable_accumulator::base(*static_cast<typename droppable_accumulator::base const *>(&that))
178 //////////////////////////////////////////////////////////////////////////
179 // with_cached_result
180 template<typename Accumulator>
181 struct with_cached_result
184 typedef typename Accumulator::result_type result_type;
186 template<typename Args>
187 with_cached_result(Args const &args)
193 with_cached_result(with_cached_result const &that)
194 : Accumulator(*static_cast<Accumulator const *>(&that))
197 if(that.has_result())
199 this->set(that.get());
203 ~with_cached_result()
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())
211 this->get().~result_type();
215 template<typename Args>
216 void on_drop(Args const &args)
218 // cache the result at the point this calculation was dropped
219 BOOST_ASSERT(!this->has_result());
220 this->set(this->Accumulator::result(args));
223 template<typename Args>
224 result_type result(Args const &args) const
226 return this->has_result() ? this->get() : this->Accumulator::result(args);
230 with_cached_result &operator =(with_cached_result const &);
232 void set(result_type const &r)
234 ::new(this->cache.address()) result_type(r);
237 result_type const &get() const
239 return *static_cast<result_type const *>(this->cache.address());
242 bool has_result() const
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();
249 aligned_storage<sizeof(result_type)> cache;
254 template<typename Feature>
257 typedef droppable<Feature> type;
260 template<typename Feature>
261 struct as_droppable<droppable<Feature> >
263 typedef droppable<Feature> type;
266 //////////////////////////////////////////////////////////////////////////
268 template<typename Feature>
270 : as_feature<Feature>::type
272 typedef typename as_feature<Feature>::type feature_type;
273 typedef typename feature_type::dependencies tmp_dependencies_;
276 typename mpl::transform<
277 typename feature_type::dependencies
278 , as_droppable<mpl::_1>
284 template<typename Sample, typename Weight>
288 droppable_accumulator<
289 typename mpl::apply2<typename feature_type::impl, Sample, Weight>::type
297 // make droppable<tag::feature(modifier)> work
298 template<typename Feature>
299 struct as_feature<tag::droppable<Feature> >
301 typedef tag::droppable<typename as_feature<Feature>::type> type;
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> >
309 typedef tag::droppable<typename as_weighted_feature<Feature>::type> type;
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>
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;
326 }} // namespace boost::accumulators