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> |
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> |
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> |
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> |
87 | 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. |
94 | 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 | |
100 | 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> |
108 | void operator ()(Args const &args) |
109 | { |
110 | this->buffer_.push_back(args[sample]); |
111 | } |
112 | |
113 | 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. |
120 | result_type result(dont_care) const |
121 | { |
122 | return result_type(this->buffer_.begin(), this->buffer_.end()); |
123 | } |
124 | |
125 | template<class Archive> |
126 | 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> |
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 | |
152 | rolling_window_impl(dont_care) |
153 | {} |
154 | |
155 | template<typename Args> |
156 | 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> |
163 | 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 = {}; |
210 | extractor<tag::rolling_window> const = {}; |
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 | |