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 
25 namespace boost { namespace accumulators
26 {
27 
28 ///////////////////////////////////////////////////////////////////////////////
29 // tag::rolling_window::size named parameter
30 BOOST_PARAMETER_NESTED_KEYWORD(tag, rolling_window_size, window_size)
31 
32 BOOST_ACCUMULATORS_IGNORE_GLOBAL(rolling_window_size)
33 
34 namespace impl
35 {
36     ///////////////////////////////////////////////////////////////////////////////
37     // rolling_window_plus1_impl
38     //    stores the latest N+1 samples, where N is specified at construction time
39     //    with the rolling_window_size named parameter
40     template<typename Sample>
41     struct rolling_window_plus1_impl
42       : accumulator_base
43     {
44         typedef typename circular_buffer<Sample>::const_iterator const_iterator;
45         typedef iterator_range<const_iterator> result_type;
46 
47         template<typename Args>
rolling_window_plus1_implboost::accumulators::impl::rolling_window_plus1_impl48         rolling_window_plus1_impl(Args const & args)
49           : buffer_(args[rolling_window_size] + 1)
50         {}
51 
52         #if BOOST_VERSION < 103600
53         // Before Boost 1.36, copying a circular buffer didn't copy
54         // it's capacity, and we need that behavior.
rolling_window_plus1_implboost::accumulators::impl::rolling_window_plus1_impl55         rolling_window_plus1_impl(rolling_window_plus1_impl const &that)
56           : buffer_(that.buffer_)
57         {
58             this->buffer_.set_capacity(that.buffer_.capacity());
59         }
60 
operator =boost::accumulators::impl::rolling_window_plus1_impl61         rolling_window_plus1_impl &operator =(rolling_window_plus1_impl const &that)
62         {
63             this->buffer_ = that.buffer_;
64             this->buffer_.set_capacity(that.buffer_.capacity());
65         }
66         #endif
67 
68         template<typename Args>
operator ()boost::accumulators::impl::rolling_window_plus1_impl69         void operator ()(Args const &args)
70         {
71             this->buffer_.push_back(args[sample]);
72         }
73 
fullboost::accumulators::impl::rolling_window_plus1_impl74         bool full() const
75         {
76             return this->buffer_.full();
77         }
78 
79         // The result of a shifted rolling window is the range including
80         // everything except the most recently added element.
resultboost::accumulators::impl::rolling_window_plus1_impl81         result_type result(dont_care) const
82         {
83             return result_type(this->buffer_.begin(), this->buffer_.end());
84         }
85 
86     private:
87         circular_buffer<Sample> buffer_;
88     };
89 
90     template<typename Args>
is_rolling_window_plus1_full(Args const & args)91     bool is_rolling_window_plus1_full(Args const &args)
92     {
93         return find_accumulator<tag::rolling_window_plus1>(args[accumulator]).full();
94     }
95 
96     ///////////////////////////////////////////////////////////////////////////////
97     // rolling_window_impl
98     //    stores the latest N samples, where N is specified at construction type
99     //    with the rolling_window_size named parameter
100     template<typename Sample>
101     struct rolling_window_impl
102       : accumulator_base
103     {
104         typedef typename circular_buffer<Sample>::const_iterator const_iterator;
105         typedef iterator_range<const_iterator> result_type;
106 
rolling_window_implboost::accumulators::impl::rolling_window_impl107         rolling_window_impl(dont_care)
108         {}
109 
110         template<typename Args>
resultboost::accumulators::impl::rolling_window_impl111         result_type result(Args const &args) const
112         {
113             return rolling_window_plus1(args).advance_begin(is_rolling_window_plus1_full(args));
114         }
115     };
116 
117 } // namespace impl
118 
119 ///////////////////////////////////////////////////////////////////////////////
120 // tag::rolling_window_plus1
121 // tag::rolling_window
122 //
123 namespace tag
124 {
125     struct rolling_window_plus1
126       : depends_on<>
127       , tag::rolling_window_size
128     {
129         /// INTERNAL ONLY
130         ///
131         typedef accumulators::impl::rolling_window_plus1_impl< mpl::_1 > impl;
132 
133         #ifdef BOOST_ACCUMULATORS_DOXYGEN_INVOKED
134         /// tag::rolling_window::size named parameter
135         static boost::parameter::keyword<tag::rolling_window_size> const window_size;
136         #endif
137     };
138 
139     struct rolling_window
140       : depends_on< rolling_window_plus1 >
141     {
142         /// INTERNAL ONLY
143         ///
144         typedef accumulators::impl::rolling_window_impl< mpl::_1 > impl;
145 
146         #ifdef BOOST_ACCUMULATORS_DOXYGEN_INVOKED
147         /// tag::rolling_window::size named parameter
148         static boost::parameter::keyword<tag::rolling_window_size> const window_size;
149         #endif
150     };
151 
152 } // namespace tag
153 
154 ///////////////////////////////////////////////////////////////////////////////
155 // extract::rolling_window_plus1
156 // extract::rolling_window
157 //
158 namespace extract
159 {
160     extractor<tag::rolling_window_plus1> const rolling_window_plus1 = {};
161     extractor<tag::rolling_window> const rolling_window = {};
162 
163     BOOST_ACCUMULATORS_IGNORE_GLOBAL(rolling_window_plus1)
164     BOOST_ACCUMULATORS_IGNORE_GLOBAL(rolling_window)
165 }
166 
167 using extract::rolling_window_plus1;
168 using extract::rolling_window;
169 
170 }} // namespace boost::accumulators
171 
172 #endif
173