Imported Upstream version 1.57.0
[platform/upstream/boost.git] / boost / accumulators / framework / accumulators / droppable_accumulator.hpp
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         {
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