1 ///////////////////////////////////////////////////////////////////////////////
2 // rolling_window.hpp
3 //
4 // Copyright 2008 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_STATISTICS_ROLLING_WINDOW_HPP_EAN_26_12_2008
9 #define BOOST_ACCUMULATORS_STATISTICS_ROLLING_WINDOW_HPP_EAN_26_12_2008
10 
11 #include <cstddef>
12 #include <boost/version.hpp>
13 #include <boost/assert.hpp>
14 #include <boost/circular_buffer.hpp>
15 #include <boost/range/iterator_range.hpp>
16 #include <boost/accumulators/accumulators_fwd.hpp>
17 #include <boost/accumulators/framework/extractor.hpp>
18 #include <boost/accumulators/framework/depends_on.hpp>
19 #include <boost/accumulators/framework/accumulator_base.hpp>
20 #include <boost/accumulators/framework/parameters/sample.hpp>
21 #include <boost/accumulators/framework/parameters/accumulator.hpp>
22 #include <boost/accumulators/numeric/functional.hpp>
23 #include <boost/accumulators/statistics_fwd.hpp>
24 #include <boost/serialization/split_free.hpp>
25 
26 namespace boost { namespace serialization {
27 
28 // implement serialization for boost::circular_buffer
29 template <class Archive, class T>
save(Archive & ar,const circular_buffer<T> & b,const unsigned int)30 void save(Archive& ar, const circular_buffer<T>& b, const unsigned int /* version */)
31 {
32     typename circular_buffer<T>::size_type size = b.size();
33     ar << b.capacity();
34     ar << size;
35     const typename circular_buffer<T>::const_array_range one = b.array_one();
36     const typename circular_buffer<T>::const_array_range two = b.array_two();
37     ar.save_binary(one.first, one.second*sizeof(T));
38     ar.save_binary(two.first, two.second*sizeof(T));
39 }
40 
41 template <class Archive, class T>
load(Archive & ar,circular_buffer<T> & b,const unsigned int)42 void load(Archive& ar, circular_buffer<T>& b, const unsigned int /* version */)
43 {
44     typename circular_buffer<T>::capacity_type capacity;
45     typename circular_buffer<T>::size_type size;
46     ar >> capacity;
47     b.set_capacity(capacity);
48     ar >> size;
49     b.clear();
50     const typename circular_buffer<T>::pointer buff = new T[size*sizeof(T)];
51     ar.load_binary(buff, size*sizeof(T));
52     b.insert(b.begin(), buff, buff+size);
53     delete[] buff;
54 }
55 
56 template<class Archive, class T>
serialize(Archive & ar,circular_buffer<T> & b,const unsigned int version)57 inline void serialize(Archive & ar, circular_buffer<T>& b, const unsigned int version)
58 {
59     split_free(ar, b, version);
60 }
61 
62 } } // end namespace boost::serialization
63 
64 namespace boost { namespace accumulators
65 {
66 
67 ///////////////////////////////////////////////////////////////////////////////
68 // tag::rolling_window::size named parameter
69 BOOST_PARAMETER_NESTED_KEYWORD(tag, rolling_window_size, window_size)
70 
71 BOOST_ACCUMULATORS_IGNORE_GLOBAL(rolling_window_size)
72 
73 namespace impl
74 {
75     ///////////////////////////////////////////////////////////////////////////////
76     // rolling_window_plus1_impl
77     //    stores the latest N+1 samples, where N is specified at construction time
78     //    with the rolling_window_size named parameter
79     template<typename Sample>
80     struct rolling_window_plus1_impl
81       : accumulator_base
82     {
83         typedef typename circular_buffer<Sample>::const_iterator const_iterator;
84         typedef iterator_range<const_iterator> result_type;
85 
86         template<typename Args>
rolling_window_plus1_implboost::accumulators::impl::rolling_window_plus1_impl87         rolling_window_plus1_impl(Args const & args)
88           : buffer_(args[rolling_window_size] + 1)
89         {}
90 
91         #if BOOST_VERSION < 103600
92         // Before Boost 1.36, copying a circular buffer didn't copy
93         // it's capacity, and we need that behavior.
rolling_window_plus1_implboost::accumulators::impl::rolling_window_plus1_impl94         rolling_window_plus1_impl(rolling_window_plus1_impl const &that)
95           : buffer_(that.buffer_)
96         {
97             this->buffer_.set_capacity(that.buffer_.capacity());
98         }
99 
operator =boost::accumulators::impl::rolling_window_plus1_impl100         rolling_window_plus1_impl &operator =(rolling_window_plus1_impl const &that)
101         {
102             this->buffer_ = that.buffer_;
103             this->buffer_.set_capacity(that.buffer_.capacity());
104         }
105         #endif
106 
107         template<typename Args>
operator ()boost::accumulators::impl::rolling_window_plus1_impl108         void operator ()(Args const &args)
109         {
110             this->buffer_.push_back(args[sample]);
111         }
112 
fullboost::accumulators::impl::rolling_window_plus1_impl113         bool full() const
114         {
115             return this->buffer_.full();
116         }
117 
118         // The result of a shifted rolling window is the range including
119         // everything except the most recently added element.
resultboost::accumulators::impl::rolling_window_plus1_impl120         result_type result(dont_care) const
121         {
122             return result_type(this->buffer_.begin(), this->buffer_.end());
123         }
124 
125         template<class Archive>
serializeboost::accumulators::impl::rolling_window_plus1_impl126         void serialize(Archive & ar, const unsigned int version)
127         {
128             ar & buffer_;
129         }
130 
131     private:
132         circular_buffer<Sample> buffer_;
133     };
134 
135     template<typename Args>
is_rolling_window_plus1_full(Args const & args)136     bool is_rolling_window_plus1_full(Args const &args)
137     {
138         return find_accumulator<tag::rolling_window_plus1>(args[accumulator]).full();
139     }
140 
141     ///////////////////////////////////////////////////////////////////////////////
142     // rolling_window_impl
143     //    stores the latest N samples, where N is specified at construction type
144     //    with the rolling_window_size named parameter
145     template<typename Sample>
146     struct rolling_window_impl
147       : accumulator_base
148     {
149         typedef typename circular_buffer<Sample>::const_iterator const_iterator;
150         typedef iterator_range<const_iterator> result_type;
151 
rolling_window_implboost::accumulators::impl::rolling_window_impl152         rolling_window_impl(dont_care)
153         {}
154 
155         template<typename Args>
resultboost::accumulators::impl::rolling_window_impl156         result_type result(Args const &args) const
157         {
158             return rolling_window_plus1(args).advance_begin(is_rolling_window_plus1_full(args));
159         }
160 
161         // serialization is done by accumulators it depends on
162         template<class Archive>
serializeboost::accumulators::impl::rolling_window_impl163         void serialize(Archive & ar, const unsigned int file_version) {}
164     };
165 
166 } // namespace impl
167 
168 ///////////////////////////////////////////////////////////////////////////////
169 // tag::rolling_window_plus1
170 // tag::rolling_window
171 //
172 namespace tag
173 {
174     struct rolling_window_plus1
175       : depends_on<>
176       , tag::rolling_window_size
177     {
178         /// INTERNAL ONLY
179         ///
180         typedef accumulators::impl::rolling_window_plus1_impl< mpl::_1 > impl;
181 
182         #ifdef BOOST_ACCUMULATORS_DOXYGEN_INVOKED
183         /// tag::rolling_window::size named parameter
184         static boost::parameter::keyword<tag::rolling_window_size> const window_size;
185         #endif
186     };
187 
188     struct rolling_window
189       : depends_on< rolling_window_plus1 >
190     {
191         /// INTERNAL ONLY
192         ///
193         typedef accumulators::impl::rolling_window_impl< mpl::_1 > impl;
194 
195         #ifdef BOOST_ACCUMULATORS_DOXYGEN_INVOKED
196         /// tag::rolling_window::size named parameter
197         static boost::parameter::keyword<tag::rolling_window_size> const window_size;
198         #endif
199     };
200 
201 } // namespace tag
202 
203 ///////////////////////////////////////////////////////////////////////////////
204 // extract::rolling_window_plus1
205 // extract::rolling_window
206 //
207 namespace extract
208 {
209     extractor<tag::rolling_window_plus1> const rolling_window_plus1 = {};
210     extractor<tag::rolling_window> const rolling_window = {};
211 
212     BOOST_ACCUMULATORS_IGNORE_GLOBAL(rolling_window_plus1)
213     BOOST_ACCUMULATORS_IGNORE_GLOBAL(rolling_window)
214 }
215 
216 using extract::rolling_window_plus1;
217 using extract::rolling_window;
218 
219 }} // namespace boost::accumulators
220 
221 #endif
222