| 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 | |