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