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