• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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