Audio Processing Framework (APF) version 0.5.0
container.h
Go to the documentation of this file.
1/******************************************************************************
2 Copyright (c) 2012-2016 Institut für Nachrichtentechnik, Universität Rostock
3 Copyright (c) 2006-2012 Quality & Usability Lab
4 Deutsche Telekom Laboratories, TU Berlin
5
6 Permission is hereby granted, free of charge, to any person obtaining a copy
7 of this software and associated documentation files (the "Software"), to deal
8 in the Software without restriction, including without limitation the rights
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 copies of the Software, and to permit persons to whom the Software is
11 furnished to do so, subject to the following conditions:
12
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 THE SOFTWARE.
23*******************************************************************************/
24
25// https://AudioProcessingFramework.github.io/
26
29
30#ifndef APF_CONTAINER_H
31#define APF_CONTAINER_H
32
33#include <memory> // for std::allocator
34#include <vector>
35#include <list>
36#include <stdexcept> // for std::logic_error
37#include <algorithm> // for std::find
38
39#include "apf/iterator.h" // for stride_iterator, ...
40
41namespace apf
42{
43
44// TODO: move metaprogramming stuff into separate file?
45namespace internal
46{
47 template<typename T1, typename...> struct first { using type = T1; };
48
49 // This didn't work with GCC 4.8.2 (segmentation fault during compilation)
50 //template<typename T1, typename...> using first = T1;
51
52 template<typename T1, typename... Ts> struct last : last<Ts...> {};
53 template<typename T1> struct last<T1> { using type = T1; };
54
55 template<typename... Args> using if_first_not_integral
56 = typename std::enable_if<
57 !std::is_integral<typename first<Args...>::type>::value>::type;
58 template<typename X> using if_integral
59 = typename std::enable_if<std::is_integral<X>::value>::type;
60
61 template<typename Arg, typename... Args> using if_last_not_convertible
62 = typename std::enable_if<
63 !std::is_convertible<typename last<Args...>::type, Arg>::value>::type;
64}
65
81template<typename T, typename Allocator = std::allocator<T>>
82class fixed_vector : private std::vector<T, Allocator>
83{
84 private:
85 using _base = typename std::vector<T, Allocator>;
86
87 public:
88 using typename _base::value_type;
89 using typename _base::allocator_type;
90 using typename _base::reference;
91 using typename _base::const_reference;
92 using typename _base::pointer;
93 using typename _base::const_pointer;
94 using typename _base::iterator;
95 using typename _base::const_iterator;
96 using typename _base::reverse_iterator;
97 using typename _base::const_reverse_iterator;
98 using typename _base::difference_type;
99 using typename _base::size_type;
100
101 fixed_vector() = default;
102 fixed_vector(fixed_vector&&) = default;
103 fixed_vector(const fixed_vector&) = delete;
104 fixed_vector& operator=(const fixed_vector&) = delete;
105 fixed_vector& operator=(fixed_vector&&) = delete;
106
108 template<typename... Args, typename =
109 internal::if_first_not_integral<Args...>>
110 explicit fixed_vector(Args&&... args)
111 : _base(std::forward<Args>(args)...)
112 {}
113
114// TODO: constructor from size and allocator is missing in C++11 (but not C++14)
115#if 0
116 // TODO: re-activate with C++14:
117 template<typename Size, typename = internal::if_integral<Size>>
118 fixed_vector(Size n, const Allocator& a = Allocator())
119 : _base(n, a)
120 {}
121#else
122 explicit fixed_vector(size_type n) : _base(n) {}
123#endif
124
125 template<typename Size, typename Arg
126 , typename = internal::if_integral<Size>>
127 fixed_vector(Size n, Arg&& arg, const Allocator& a)
128 : _base(static_cast<size_type>(n), std::forward<Arg>(arg), a)
129 {}
130
133 template<typename Size, typename... Args
134 , typename = internal::if_integral<Size>
135 , typename = internal::if_last_not_convertible<Allocator, Args...>>
136 explicit fixed_vector(Size n, Args&&... args)
137 : _base()
138 {
139 _base::reserve(static_cast<size_type>(n));
140 for (Size i = 0; i < n; ++i)
141 {
142 // Note: std::forward is not used here, because it's called repeatedly
143 _base::emplace_back(args...);
144 }
145 }
146
147 // Perfect forwarding doesn't cover initializer lists:
148 explicit fixed_vector(std::initializer_list<value_type> il
149 , const Allocator& a = Allocator())
150 : _base(il, a)
151 {}
152
159 void resize(size_type n)
160 {
161 if (this->capacity() == 0)
162 {
163 _base::resize(n);
164 }
165 else
166 {
167 throw std::logic_error(
168 "Bug: fixed_vector::resize() is only allowed if capacity == 0!");
169 }
170 }
171
178 void reserve(size_type n)
179 {
180 if (this->capacity() == 0)
181 {
182 _base::reserve(n);
183 }
184 else
185 {
186 throw std::logic_error(
187 "Bug: fixed_vector::reserve() is only allowed if capacity == 0!");
188 }
189 }
190
198 template<typename... Args>
199 void emplace_back(Args&&... args)
200 {
201 if (this->size() < this->capacity())
202 {
203 _base::emplace_back(std::forward<Args>(args)...);
204 }
205 else
206 {
207 throw std::logic_error(
208 "Bug: fixed_vector::emplace_back() "
209 "is only allowed if size < capacity!");
210 }
211 }
212
213 using _base::front;
214 using _base::back;
215 using _base::begin;
216 using _base::end;
217 using _base::rbegin;
218 using _base::rend;
219 using _base::cbegin;
220 using _base::cend;
221 using _base::crbegin;
222 using _base::crend;
223 using _base::size;
224 using _base::max_size;
225 using _base::capacity;
226 using _base::empty;
227 using _base::operator[];
228 using _base::at;
229 using _base::data;
230 using _base::get_allocator;
231
232 // using _base::shrink_to_fit; // This may reallocate!
233};
234
238template<typename T, typename Allocator = std::allocator<T>>
239class fixed_list : private std::list<T, Allocator>
240{
241 private:
242 using _base = typename std::list<T, Allocator>;
243
244 public:
245 using typename _base::value_type;
246 using typename _base::allocator_type;
247 using typename _base::reference;
248 using typename _base::const_reference;
249 using typename _base::pointer;
250 using typename _base::const_pointer;
251 using typename _base::iterator;
252 using typename _base::const_iterator;
253 using typename _base::reverse_iterator;
254 using typename _base::const_reverse_iterator;
255 using typename _base::difference_type;
256 using typename _base::size_type;
257
258 fixed_list() = default;
259 fixed_list(fixed_list&&) = default;
260 fixed_list(const fixed_list&) = delete;
261 fixed_list& operator=(const fixed_list&) = delete;
262 fixed_list& operator=(fixed_list&&) = delete;
263
265 template<typename... Args, typename =
266 internal::if_first_not_integral<Args...>>
267 explicit fixed_list(Args&&... args)
268 : _base(std::forward<Args>(args)...)
269 {}
270
272 template<typename Size, typename... Args, typename =
273 internal::if_integral<Size>>
274 explicit fixed_list(Size n, Args&&... args)
275 : _base()
276 {
277 for (Size i = 0; i < n; ++i)
278 {
279 // Note: std::forward is not used here, because it's called repeatedly
280 _base::emplace_back(args...);
281 }
282 }
283
284 explicit fixed_list(std::initializer_list<value_type> il
285 , const Allocator& a = Allocator())
286 : _base(il, a)
287 {}
288
292 void move(iterator from, iterator to)
293 {
294 _base::splice(to, *this, from);
295 }
296
300 void move(iterator first, iterator last, iterator target)
301 {
302 _base::splice(target, *this, first, last);
303 }
304
305 using _base::begin;
306 using _base::end;
307 using _base::rbegin;
308 using _base::rend;
309 using _base::cbegin;
310 using _base::cend;
311 using _base::crbegin;
312 using _base::crend;
313 using _base::empty;
314 using _base::size;
315 using _base::max_size;
316 using _base::front;
317 using _base::back;
318 using _base::get_allocator;
319 using _base::reverse;
320 using _base::sort;
321};
322
340template<typename T, typename Allocator = std::allocator<T>>
341class fixed_matrix : public fixed_vector<T, Allocator>
342{
343 private:
345
346 public:
347 using typename _base::pointer;
348 using typename _base::size_type;
349
353 using channel_iterator = typename Channel::iterator;
354
358 using slice_iterator = typename Slice::iterator;
359
360 class channels_iterator;
361 class slices_iterator;
362
365 explicit fixed_matrix(const Allocator& a = Allocator())
366 : _base(a)
367 {
368 this->initialize(0, 0);
369 }
370
371 fixed_matrix(fixed_matrix&&) = default;
372 fixed_matrix(const fixed_matrix&) = delete;
373 fixed_matrix& operator=(const fixed_matrix&) = delete;
374 fixed_matrix& operator=(fixed_matrix&&) = delete;
375
381 fixed_matrix(size_type max_channels, size_type max_slices
382 , const Allocator& a = Allocator())
383 : fixed_matrix(a)
384 {
385 this->initialize(max_channels, max_slices);
386 }
387
391 void initialize(size_type max_channels, size_type max_slices)
392 {
393 _base::resize(max_channels * max_slices);
394
395 this->channels = make_begin_and_end(
396 channels_iterator(_base::data(), max_slices), max_channels);
397 this->slices = make_begin_and_end(
398 slices_iterator(_base::data(), max_channels, max_slices), max_slices);
399
400 _channel_ptrs.reserve(max_channels);
401 for (const auto channel: this->channels)
402 {
403 _channel_ptrs.emplace_back(channel.begin());
404 }
405 assert(_channel_ptrs.size() == max_channels);
406 }
407
408 template<typename Ch>
409 void set_channels(const Ch& ch);
410
413 pointer const* get_channel_ptrs() const { return _channel_ptrs.data(); }
414
419
420 private:
421 // Hide functions from fixed_vector:
422 void emplace_back();
423 void reserve();
424 void resize();
425
426 fixed_vector<pointer> _channel_ptrs;
427};
428
430template<typename T, typename Allocator>
431class fixed_matrix<T, Allocator>::channels_iterator
432{
433 private:
434 using self = channels_iterator;
436
438 struct ChannelArrowProxy : Channel
439 {
440 ChannelArrowProxy(const Channel& ch) : Channel(ch) {}
441 Channel* operator->() { return this; }
442 };
443
444 public:
445 using iterator_category = std::random_access_iterator_tag;
446 using value_type = Channel;
447 using reference = Channel;
448 using difference_type = typename _base_type::difference_type;
449 using pointer = ChannelArrowProxy;
450
455 : _size(0)
456 {}
457
459 channels_iterator(channel_iterator base_iterator, size_type step)
460 : _base_iterator(base_iterator, static_cast<difference_type>(step))
461 , _size(step)
462 {}
463
467 {
468 auto temp = _base_iterator.base();
469 assert(apf::no_nullptr(temp));
470 return Channel(temp, temp + _size);
471 }
472
475 pointer operator->() const
476 {
477 return this->operator*();
478 }
479
480 APF_ITERATOR_RANDOMACCESS_EQUAL(_base_iterator)
486 APF_ITERATOR_RANDOMACCESS_LESS(_base_iterator)
492
493 APF_ITERATOR_BASE(_base_type, _base_iterator)
494
495 private:
496 _base_type _base_iterator;
497 size_type _size;
498};
499
501template<typename T, typename Allocator>
502class fixed_matrix<T, Allocator>::slices_iterator
503{
504 private:
505 using self = slices_iterator;
506
508 struct SliceArrowProxy : Slice
509 {
510 SliceArrowProxy(const Slice& sl) : Slice(sl) {}
511 Slice* operator->() { return this; }
512 };
513
514 public:
515 using iterator_category = std::random_access_iterator_tag;
516 using value_type = Slice;
517 using reference = Slice;
518 using pointer = SliceArrowProxy;
519 using difference_type
520 = typename std::iterator_traits<channel_iterator>::difference_type;
521
526 : _max_channels(0)
527 , _max_slices(0)
528 {}
529
532 , size_type max_channels, size_type max_slices)
533 : _base_iterator(base_iterator)
534 , _max_channels(max_channels)
535 , _max_slices(max_slices)
536 {}
537
541 {
542 assert(apf::no_nullptr(_base_iterator));
543 slice_iterator temp{_base_iterator
544 , static_cast<difference_type>(_max_slices)};
545 return Slice(temp, temp + static_cast<difference_type>(_max_channels));
546 }
547
550 pointer operator->() const
551 {
552 return this->operator*();
553 }
554
555 APF_ITERATOR_RANDOMACCESS_EQUAL(_base_iterator)
561 APF_ITERATOR_RANDOMACCESS_LESS(_base_iterator)
567
568 APF_ITERATOR_BASE(channel_iterator, _base_iterator)
569
570 private:
571 channel_iterator _base_iterator;
572 size_type _max_channels;
573 size_type _max_slices;
574};
575
586template<typename T, typename Allocator>
587template<typename Ch>
588void
590{
591 assert(std::distance(ch.begin(), ch.end())
592 == std::distance(this->channels.begin(), this->channels.end()));
593 assert((ch.begin() == ch.end()) ? true :
594 std::distance(ch.begin()->begin(), ch.begin()->end()) ==
595 std::distance(this->channels.begin()->begin()
596 , this->channels.begin()->end()));
597
598 auto target = this->channels.begin();
599
600 for (const auto i: ch)
601 {
602 std::copy(i.begin(), i.end(), target->begin());
603 ++target;
604 }
605}
606
609template<typename L1, typename L2>
610void append_pointers(L1& source, L2& target)
611{
612 for (auto& i: source)
613 {
614 target.push_back(&i);
615 }
616}
617
620template<typename L1, typename L2>
621void append_pointers(const L1& source, L2& target)
622{
623 for (const auto& i: source)
624 {
625 target.push_back(&i);
626 }
627}
628
638template<typename L1, typename L2, typename DataMember>
639void distribute_list(L1& source, L2& target, DataMember member)
640{
641 if (source.size() != target.size())
642 {
643 throw std::logic_error("distribute_list: Different sizes!");
644 }
645
646 auto in = source.begin();
647
648 for (auto& out: target)
649 {
650 (out.*member).splice((out.*member).end(), source, in++);
651 }
652}
653
666// TODO: better name?
667template<typename L1, typename L2, typename DataMember, typename L3>
668void
669undistribute_list(const L1& source, L2& target, DataMember member, L3& garbage)
670{
671 if (source.size() != target.size())
672 {
673 throw std::logic_error("undistribute_list(): Different sizes!");
674 }
675
676 auto in = source.begin();
677
678 for (auto& out: target)
679 {
680 auto delinquent
681 = std::find((out.*member).begin(), (out.*member).end(), *in++);
682 if (delinquent == (out.*member).end())
683 {
684 throw std::logic_error("undistribute_list(): Element not found!");
685 }
686 garbage.splice(garbage.end(), out.*member, delinquent);
687 }
688}
689
690} // namespace apf
691
692#endif
Derived from std::list, but without re-sizing.
Definition: container.h:240
void move(iterator first, iterator last, iterator target)
Move range (from first to last) to target.
Definition: container.h:300
fixed_list(Size n, Args &&... args)
Constructor from size and initialization arguments.
Definition: container.h:274
void move(iterator from, iterator to)
Move list element from one place to another.
Definition: container.h:292
fixed_list(Args &&... args)
Constructor that forwards everything except if first type is integral.
Definition: container.h:267
Iterator over fixed_matrix::Channels.
Definition: container.h:432
channels_iterator()
Default constructor.
Definition: container.h:454
channels_iterator(channel_iterator base_iterator, size_type step)
Constructor.
Definition: container.h:459
reference operator*() const
Dereference operator.
Definition: container.h:466
pointer operator->() const
Arrow operator.
Definition: container.h:475
Iterator over fixed_matrix::Slices.
Definition: container.h:503
slices_iterator(channel_iterator base_iterator, size_type max_channels, size_type max_slices)
Constructor.
Definition: container.h:531
slices_iterator()
Default constructor.
Definition: container.h:525
reference operator*() const
Dereference operator.
Definition: container.h:540
pointer operator->() const
Arrow operator.
Definition: container.h:550
Two-dimensional data storage for row- and column-wise access.
Definition: container.h:342
fixed_matrix(size_type max_channels, size_type max_slices, const Allocator &a=Allocator())
Constructor.
Definition: container.h:381
has_begin_and_end< slices_iterator > slices
Access to Slices; use slices.begin() and slices.end()
Definition: container.h:418
has_begin_and_end< stride_iterator< channel_iterator > > Slice
Proxy class for returning one slice of the fixed_matrix.
Definition: container.h:356
pointer const * get_channel_ptrs() const
Get array of pointers to the channels.
Definition: container.h:413
void initialize(size_type max_channels, size_type max_slices)
Allocate memory for max_channels x max_slices elements and default-construct them.
Definition: container.h:391
typename Channel::iterator channel_iterator
Iterator within a Channel.
Definition: container.h:353
has_begin_and_end< channels_iterator > channels
Access to Channels; use channels.begin() and channels.end()
Definition: container.h:416
void set_channels(const Ch &ch)
Copy channels from another matrix.
Definition: container.h:589
typename Slice::iterator slice_iterator
Iterator within a Slice.
Definition: container.h:358
has_begin_and_end< pointer > Channel
Proxy class for returning one channel of the fixed_matrix.
Definition: container.h:351
fixed_matrix(const Allocator &a=Allocator())
Default constructor.
Definition: container.h:365
Derived from std::vector, but without memory re-allocations.
Definition: container.h:83
void reserve(size_type n)
Reserve space for new elements.
Definition: container.h:178
void emplace_back(Args &&... args)
Construct element at the end.
Definition: container.h:199
fixed_vector(Args &&... args)
Constructor that forwards everything except if first type is integral.
Definition: container.h:110
void resize(size_type n)
Reserve space for new elements and default-construct them.
Definition: container.h:159
fixed_vector(Size n, Args &&... args)
Constructor from size and initialization arguments.
Definition: container.h:136
Convenience class providing begin() and end().
Definition: iterator.h:335
typename std::iterator_traits< channel_iterator >::difference_type difference_type
Definition: iterator.h:1061
#define APF_ITERATOR_RANDOMACCESS_POSTINCREMENT
Postincrement operator (using preincrement operator).
Definition: iterator.h:302
#define APF_ITERATOR_RANDOMACCESS_SUBSCRIPT
Straightforward subscript operator (using + and dereference operator).
Definition: iterator.h:266
#define APF_ITERATOR_RANDOMACCESS_ADDITION_ASSIGNMENT(base_member)
Straightforward addition/assignment operator.
Definition: iterator.h:248
#define APF_ITERATOR_RANDOMACCESS_THE_REST
The rest of the random access iterator requirements.
Definition: iterator.h:314
#define APF_ITERATOR_RANDOMACCESS_PREDECREMENT
Straightforward predecrement operator.
Definition: iterator.h:243
#define APF_ITERATOR_RANDOMACCESS_LESS(base_member)
Straightforward less-than operator.
Definition: iterator.h:274
#define APF_ITERATOR_RANDOMACCESS_PREINCREMENT
Straightforward preincrement operator.
Definition: iterator.h:239
#define APF_ITERATOR_RANDOMACCESS_UNEQUAL
Unequality operator (using equality operator).
Definition: iterator.h:284
#define APF_ITERATOR_RANDOMACCESS_EQUAL
Straightforward equality operator.
Definition: iterator.h:227
#define APF_ITERATOR_RANDOMACCESS_POSTDECREMENT
Postdecrement operator (using predecrement operator)
Definition: iterator.h:306
#define APF_ITERATOR_BASE(base_iterator_type, base_member)
Get the base iterator.
Definition: iterator.h:89
#define APF_ITERATOR_RANDOMACCESS_OTHER_COMPARISONS
Other comparisons (>, <=, >=).
Definition: iterator.h:289
#define APF_ITERATOR_RANDOMACCESS_DIFFERENCE(base_member)
Straightforward difference operator.
Definition: iterator.h:257
Several more or less useful iterators and some macros.
Audio Processing Framework.
Definition: iterator.h:61
void distribute_list(L1 &source, L2 &target, DataMember member)
Splice list elements from source to member lists of target.
Definition: container.h:639
void undistribute_list(const L1 &source, L2 &target, DataMember member, L3 &garbage)
The opposite of distribute_list() – sorry for the strange name!
Definition: container.h:669
bool no_nullptr(T *in)
Check for null-pointer.
Definition: iterator.h:64
void append_pointers(L1 &source, L2 &target)
Append pointers to the elements of the first list to the second list.
Definition: container.h:610