1 // ----------------------------------------------------------------------------
2 // mbuffer.h
3 //
4 // Copyright (C) 2007
5 // Stelios Bounanos, M0GLD
6 //
7 // This file is part of fldigi.
8 //
9 // fldigi is free software; you can redistribute it and/or modify
10 // it under the terms of the GNU General Public License as published by
11 // the Free Software Foundation; either version 3 of the License, or
12 // (at your option) any later version.
13 //
14 // fldigi is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // GNU General Public License for more details.
18 //
19 // You should have received a copy of the GNU General Public License
20 // along with this program. If not, see <http://www.gnu.org/licenses/>.
21 // ----------------------------------------------------------------------------
22
23
24 // A simple vector wrapper for fldigi's double-buffering needs.
25 // Most vector operations are provided for mbuffers by redirecting them to the
26 // current vector.
27
28 // The template arguments are
29 // 1) T - the type
30 // 2) S - the apparent mbuffer size, i.e., the size of each vector. Defaults to 0.
31 // A mbuffer instantiated with S == 0 is not very useful until resized
32 // with alloc().
33 // 3) N - the number of vectors that we can cycle between. Defaults to 1.
34
35 // Things to note:
36 // 1) There is a T* conversion operator
37 // 2) Operations that modify the length of the container are not provided
38 // 3) Comparison operators are not implemented (but see (1)!)
39 // 4) mbuffer<T, 0, N> is meant to be used when we don't know the size at
40 // compile time, in which case we resize with alloc. The compiler will treat
41 // mbuffers resized to different lengths in this way as objects of the same type.
42
43 #ifndef MBUFFER_H
44 #define MBUFFER_H
45
46 #include <vector>
47 #include <algorithm>
48
49 #ifndef NDEBUG
50 #include <iosfwd>
51 #include <iterator>
52 #endif
53
54 #ifndef NDEBUG
55 template <typename T, std::size_t S, std::size_t N>
56 class mbuffer;
57 template <typename T, std::size_t S, std::size_t N>
58 std::ostream& operator<<(std::ostream& o, const mbuffer<T, S, N>& b);
59 #endif // NDEBUG
60
61 template <typename T, std::size_t S = 0, std::size_t N = 1>
62 class mbuffer
63 {
64 protected:
65 std::vector<T> data[N];
66 mutable std::size_t cur;
67
68 public:
mbuffer(void)69 explicit mbuffer(void)
70 {
71 alloc(S);
72 }
mbuffer(std::size_t n)73 explicit mbuffer(std::size_t n)
74 {
75 alloc(n);
76 }
mbuffer(const std::vector<T> & v)77 mbuffer(const std::vector<T>& v)
78 {
79 data[0] = v;
80 // resize 1 to N only
81 alloc(data[0].size(), 1);
82 }
mbuffer(const T * a,std::size_t n)83 mbuffer(const T* a, std::size_t n)
84 {
85 data[0].assign(a, a + n);
86 // resize 1 to N only
87 alloc(n, 1);
88 }
89 void alloc(std::size_t n, std::size_t start = 0)
90 {
91 for (size_t i = start; i < N; ++i)
92 data[i].resize(n);
93 cur = 0;
94 }
95
96 typedef typename std::vector<T>::iterator iterator;
97 typedef typename std::vector<T>::const_iterator const_iterator;
98
begin(void)99 iterator begin(void) { return data[cur].begin(); }
begin(void)100 const_iterator begin(void) const { return data[cur].begin(); }
end(void)101 iterator end(void) { return data[cur].end(); }
end(void)102 const_iterator end(void) const { return data[cur].end(); }
103
104
105 typedef typename std::vector<T>::reverse_iterator reverse_iterator;
106 typedef typename std::vector<T>::const_reverse_iterator const_reverse_iterator;
107
rbegin(void)108 reverse_iterator rbegin(void) { return reverse_iterator(end()); }
rbegin(void)109 const_reverse_iterator rbegin(void) const { return const_reverse_iterator(end()); }
rend(void)110 reverse_iterator rend(void) { return reverse_iterator(begin()); }
rend(void)111 const_reverse_iterator rend(void) const { return const_reverse_iterator(begin()); }
112
113
114 typedef typename std::vector<T>::value_type value_type;
115 typedef typename std::vector<T>::reference reference;
116 typedef typename std::vector<T>::const_reference const_reference;
117 typedef typename std::vector<T>::size_type size_type;
118 typedef typename std::vector<T>::difference_type difference_type;
119
120 // These should be the same for all vectors in data[]
size(void)121 size_type size(void) { return data[0].size(); }
max_size(void)122 size_type max_size(void) { return data[0].max_size(); }
capacity(void)123 size_type capacity(void) { return data[0].capacity(); }
empty(void)124 bool empty(void) { return data[0].empty(); }
125
126 // Instead of these, we provide a conversion operator for T*
127 // reference operator[](size_type i) { return data[cur][i]; }
128 // const_reference operator[](size_type i) const { return data[cur][i]; }
at(size_type i)129 reference at(size_type i) { return data[cur].at(i); }
at(size_type i)130 const_reference at(size_type i) const { return data[cur].at(i); }
front(void)131 reference front(void) { return data[cur].front(); }
front(void)132 const_reference front(void) const { return data[cur].front(); }
back(void)133 reference back(void) { return data[cur].back(); }
back(void)134 const_reference back(void) const { return data[cur].back(); }
135
136
137 // Operations that modify the size of data[cur] might invalidate
138 // pointers to internal buffers. The rest of the data vectors would need
139 // to be resized, e.g. with check_size below. For this reason these
140 // operations are not provided, but are included here for completeness
141
142 // void check_size(void)
143 // {
144 // for (size_t i = 0; i < N; ++i)
145 // if (data[i].size() != data[cur].size())
146 // data[i].resize(data[cur].size());
147 // }
148
149 // mbuffer<T, S, N>& operator=(const mbuffer<T, S, N>& o)
150 // {
151 // for (int i = 0; i < N; ++i)
152 // std::copy(o.data[i].begin(), o.data[i].end(), data[i].begin());
153 // return *this;
154 // }
155 // std::vector<T>& operator=(const std::vector<T>& o)
156 // {
157 // std::copy(o.begin(), o.end(), data[cur].begin());
158 // check_size();
159 // return data[cur];
160 // }
161
162 // The methods below would modify the length of the vector.
163 // We would need to check_size() before returning from them.
164
165 // There is no vector::assign; the one provided here fills the vector
166 // with copies of the same value without causing a resize.
assign(const_reference v)167 void assign(const_reference v) { std::fill_n(begin(), size(), v); }
168 // template <typename input_iterator>
169 // void assign(input_iterator first, input_iterator last)
170 // {
171 // data[cur].assign(first, last);
172 // }
173
174 // void push_back(const_reference v) { data[cur].push_back(v); }
175 // void pop_back(void) { data[cur].pop_back(); }
176
177 // iterator insert(iterator pos, const_reference v)
178 // {
179 // return data[cur].insert(pos, v);
180 // }
181 // iterator insert(iterator pos, size_type n, const_reference v)
182 // {
183 // return data[cur].insert(pos, n, v);
184 // }
185 // template <typename input_iterator>
186 // void insert(iterator pos, input_iterator first, input_iterator last)
187 // {
188 // data[cur].insert(pos, first, last);
189 // }
190
191 // iterator erase(iterator pos) { return data[cur].erase(pos); }
192 // iterator erase(iterator first, iterator last) { return data[cur].erase(first, last); }
193
194 // void clear(void) { data[cur].clear(); }
195
swap(mbuffer<T,S,N> & o)196 void swap(mbuffer<T, S, N>& o)
197 {
198 for (int i = 0; i < N; ++i)
199 std::swap(data[i].begin(), data[i].end(), o.data[i].begin());
200 }
201 // void swap(std::vector<T>& o)
202 // {
203 // std::swap(data[cur].begin(), data[cur].end(), o.begin());
204 // check_size();
205 // o.check_size();
206 // }
207
208
209 // and now for something completely different
210
next(void)211 void next(void) const { if (++cur == N) cur = 0; }
prev(void)212 void prev(void) const { if (cur > 0) --cur; }
reset(void)213 void reset(void) const { cur = 0; }
214
c_array(void)215 T* c_array(void) { return &data[cur][0]; }
216 operator T*(void) { return c_array(); }
c_array(void)217 const T* c_array(void) const { return &data[cur][0]; }
218 operator const T*(void) const { return c_array(); }
219
vec(void)220 std::vector<T>& vec(void) { return data[cur]; }
vec(void)221 const std::vector<T>& vec(void) const { return data[cur]; }
222 // We also do not provide vector<T> conversions
223 // operator std::vector<T>&(void) { return vec(); }
224 // operator const std::vector<T>&(void) const { return vec(); }
225
idx(void)226 std::size_t idx(void) { return cur; }
nvec(void)227 std::size_t nvec(void) { return N; }
vecp(std::size_t i)228 std::vector<T>* vecp(std::size_t i) { return &data[i]; }
229
230 #ifndef NDEBUG
231 friend std::ostream& operator<<<>(std::ostream& o, const mbuffer<T, S, N>& b);
232 #endif // NDEBUG
233 };
234
235 #ifndef NDEBUG
236 template <typename T, std::size_t S, std::size_t N>
237 std::ostream& operator<<(std::ostream& o, const mbuffer<T, S, N>& b)
238 {
239 for (std::size_t i = 0; i < N; ++i) {
240 o << '<' << i << ">\n";
241 copy(b.data[i].begin(), b.data[i].end(),
242 std::ostream_iterator<T>(o, "\n"));
243 }
244
245 return o;
246 }
247 #endif // NDEBUG
248
249 template <typename T, std::size_t S, std::size_t N>
250 inline
swap(mbuffer<T,S,N> & a,mbuffer<T,S,N> & b)251 void swap(mbuffer<T, S, N>& a, mbuffer<T, S, N>& b) { a.swap(b); }
252
253 #endif // MBUFFER_H
254
255 // Local Variables:
256 // mode: c++
257 // c-file-style: "linux"
258 // End:
259