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
18namespace 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 {
32 explicit add_ref_visitor(Args const &args)
33 : args_(args)
34 {
35 }
36
37 template<typename Accumulator>
38 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>
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 {
68 explicit drop_visitor(Args const &args)
69 : args_(args)
70 {
71 }
72
73 template<typename Accumulator>
74 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>
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>
112 droppable_accumulator_base(Args const &args)
113 : Accumulator(args)
114 , ref_count_(0)
115 {
116 }
117
118 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>
125 void operator ()(Args const &args)
126 {
127 if(!this->is_dropped())
128 {
129 this->Accumulator::operator ()(args);
130 }
131 }
132
133 template<typename Args>
134 void add_ref(Args const &)
135 {
136 ++this->ref_count_;
137 }
138
139 template<typename Args>
140 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
150 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>
167 droppable_accumulator(Args const &args)
168 : droppable_accumulator::base(args)
169 {
170 }
171
172 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>
187 with_cached_result(Args const &args)
188 : Accumulator(args)
189 , cache()
190 {
191 }
192
193 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
203 ~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>
216 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>
224 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
232 void set(result_type const &r)
233 {
234 ::new(this->cache.address()) result_type(r);
235 }
236
237 result_type const &get() const
238 {
239 return *static_cast<result_type const *>(this->cache.address());
240 }
241
242 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

source code of boost/boost/accumulators/framework/accumulators/droppable_accumulator.hpp