HephAudio v3.1.0
A cross-platform C++ library for recording, playing, and processing audio on Windows, Android, Linux, iOS, and macOS.
Loading...
Searching...
No Matches
BufferBase.h
Go to the documentation of this file.
1#pragma once
2#include "HephAudioShared.h"
5#include <cstdlib>
6#include <type_traits>
7
10namespace Heph
11{
13 {
14 None = 0,
21 };
22
29 template <class Tself, typename Tdata>
31 {
32 static_assert(std::is_default_constructible<Tdata>::value, "Tdata must have a default constructor");
33 static_assert(std::is_trivially_destructible<Tdata>::value, "Tdata must be trivially destructible");
34
35 protected:
40 Tdata* pData;
41
46 size_t size;
47
48 protected:
50 BufferBase() : pData(nullptr), size(0) {}
51
57 explicit BufferBase(size_t size) : pData(nullptr), size(size)
58 {
59 if (this->size > 0)
60 {
61 this->pData = BufferBase::Allocate(this->SizeAsByte());
62 }
63 }
64
71 BufferBase(size_t size, BufferFlags flags) : pData(nullptr), size(size)
72 {
73 if (this->size > 0)
74 {
75 if (flags & BufferFlags::AllocUninitialized)
76 this->pData = BufferBase::AllocateUninitialized(this->SizeAsByte());
77 else
78 this->pData = BufferBase::Allocate(this->SizeAsByte());
79 }
80 }
81
87 BufferBase(const std::initializer_list<Tdata>& rhs) : pData(nullptr), size(rhs.size())
88 {
89 if (this->size > 0)
90 {
91 const size_t size_byte = this->SizeAsByte();
92 this->pData = BufferBase::AllocateUninitialized(size_byte);
93 (void)std::memcpy(this->pData, rhs.begin(), size_byte);
94 }
95 }
96
98 BufferBase(const BufferBase& rhs) : pData(nullptr), size(rhs.size)
99 {
100 if (!rhs.IsEmpty())
101 {
102 const size_t size_byte = rhs.SizeAsByte();
103 this->pData = BufferBase::AllocateUninitialized(size_byte);
104 (void)std::memcpy(this->pData, rhs.pData, size_byte);
105 }
106 }
107
109 BufferBase(BufferBase&& rhs) noexcept : pData(rhs.pData), size(rhs.size)
110 {
111 rhs.pData = nullptr;
112 rhs.size = 0;
113 }
114
115 Tself& operator=(const std::initializer_list<Tdata>& rhs)
116 {
117 this->Release();
118
119 this->size = rhs.size();
120 if (this->size > 0)
121 {
122 const size_t size_byte = this->SizeAsByte();
123 this->pData = BufferBase::AllocateUninitialized(size_byte);
124 (void)std::memcpy(this->pData, rhs.begin(), size_byte);
125 }
126
127 return *(Tself*)this;
128 }
129
130 Tself& operator=(const Tself& rhs)
131 {
132 if (this != &rhs)
133 {
134 this->Release();
135
136 if (rhs.size > 0)
137 {
138 const size_t size_byte = rhs.SizeAsByte();
139 this->pData = BufferBase::AllocateUninitialized(size_byte);
140 (void)std::memcpy(this->pData, rhs.pData, size_byte);
141
142 this->size = rhs.size;
143 }
144 }
145
146 return *(Tself*)this;
147 }
148
149 Tself& operator=(Tself&& rhs) noexcept
150 {
151 if (this != &rhs)
152 {
153 this->Release();
154
155 this->pData = rhs.pData;
156 this->size = rhs.size;
157
158 rhs.pData = nullptr;
159 rhs.size = 0;
160 }
161
162 return *(Tself*)this;
163 }
164
165 public:
167 virtual ~BufferBase()
168 {
169 this->Release();
170 }
171
178 virtual Tself operator<<(size_t rhs) const
179 {
180 if (rhs >= this->size)
181 {
182 Tself result{};
183 result.pData = BufferBase::Allocate(this->SizeAsByte());
184 result.size = this->size;
185 return result;
186 }
187
188 const size_t thisSize_byte = this->SizeAsByte();
189 const size_t rhsSize_byte = BufferBase::SizeAsByte(rhs);
190
191 Tself result{};
192 result.pData = BufferBase::AllocateUninitialized(thisSize_byte);
193 result.size = this->size;
194
195 (void)std::memcpy(result.pData, this->pData + rhs, thisSize_byte - rhsSize_byte);
196 if (rhs > 0)
197 {
198 BufferBase::Initialize(result.pData + this->size - rhs, result.pData + this->size);
199 }
200
201 return result;
202 }
203
209 virtual Tself& operator<<=(size_t rhs)
210 {
211 if (rhs >= this->size)
212 {
213 this->Reset();
214 }
215 else if (rhs > 0)
216 {
217 (void)std::memmove(this->pData, this->pData + rhs, this->SizeAsByte() - BufferBase::SizeAsByte(rhs));
218 BufferBase::Initialize(this->pData + this->size - rhs, this->pData + this->size);
219 }
220
221 return *(Tself*)this;
222 }
223
230 virtual Tself operator>>(size_t rhs) const
231 {
232 if (rhs >= this->size)
233 {
234 Tself result{};
235 result.pData = BufferBase::Allocate(this->SizeAsByte());
236 result.size = this->size;
237 return result;
238 }
239
240 const size_t thisSize_byte = this->SizeAsByte();
241
242 Tself result{};
243 result.pData = BufferBase::AllocateUninitialized(thisSize_byte);
244 result.size = this->size;
245
246 (void)std::memcpy(result.pData + rhs, this->pData, thisSize_byte - BufferBase::SizeAsByte(rhs));
247 if (rhs > 0)
248 {
249 BufferBase::Initialize(result.pData, result.pData + rhs);
250 }
251
252 return result;
253 }
254
260 virtual Tself& operator>>=(size_t rhs)
261 {
262 if (rhs >= this->size)
263 {
264 this->Reset();
265 }
266 else if (rhs > 0)
267 {
268 (void)std::memmove(this->pData + rhs, this->pData, this->SizeAsByte() - BufferBase::SizeAsByte(rhs));
269 BufferBase::Initialize(this->pData, this->pData + rhs);
270 }
271 return *(Tself*)this;
272 }
273
274 virtual bool operator==(const Tself& rhs) const
275 {
276 return (this->IsEmpty() && rhs.IsEmpty()) ||
277 (this->size == rhs.size &&
278 std::memcmp(this->pData, rhs.pData, this->SizeAsByte()) == 0);
279 }
280
281 virtual bool operator!=(const Tself& rhs) const
282 {
283 return !((*this) == rhs);
284 }
285
291 Tdata& operator[](size_t index) const
292 {
293 return this->pData[index];
294 }
295
300 size_t Size() const
301 {
302 return this->size;
303 }
304
309 size_t SizeAsByte() const
310 {
311 return this->size * sizeof(Tdata);
312 }
313
318 Tdata& At(size_t index) const
319 {
320 if (index >= this->size)
321 {
323 }
324 return this->pData[index];
325 }
326
332 virtual bool IsEmpty() const
333 {
334 return this->pData == nullptr || this->size == 0;
335 }
336
341 virtual void Reset()
342 {
343 if (!this->IsEmpty())
344 {
345 BufferBase::Initialize(this->pData, this->pData + this->size);
346 }
347 }
348
353 virtual void Release()
354 {
355 if (this->pData != nullptr)
356 {
357 std::free(this->pData);
358 this->pData = nullptr;
359 }
360 this->size = 0;
361 }
362
370 virtual Tself SubBuffer(size_t index, size_t size) const
371 {
372 Tself result{};
373
374 result.pData = BufferBase::SubBuffer(this->pData, this->SizeAsByte(), BufferBase::SizeAsByte(index), BufferBase::SizeAsByte(size));
375 result.size = size;
376
377 return result;
378 }
379
386 virtual void Prepend(const Tself& rhs)
387 {
388 this->pData = BufferBase::Prepend(this->pData, this->SizeAsByte(), rhs.pData,
389 rhs.SizeAsByte());
390 this->size += rhs.size;
391 }
392
399 virtual void Append(const Tself& rhs)
400 {
401 this->pData = BufferBase::Append(this->pData, this->SizeAsByte(), rhs.pData,
402 rhs.SizeAsByte());
403 this->size += rhs.size;
404 }
405
412 virtual void Insert(const Tself& rhs, size_t index)
413 {
414 this->pData = BufferBase::Insert(this->pData, this->SizeAsByte(), rhs.pData,
415 rhs.SizeAsByte(), BufferBase::SizeAsByte(index));
416 this->size += rhs.size;
417 }
418
426 virtual void Cut(size_t index, size_t size)
427 {
428 size_t cutSize_byte = BufferBase::SizeAsByte(size);
429 this->pData = BufferBase::Cut(this->pData, this->SizeAsByte(), BufferBase::SizeAsByte(index), cutSize_byte);
430 this->size -= cutSize_byte / sizeof(Tdata);
431 }
432
440 virtual void Replace(const Tself& rhs, size_t index)
441 {
442 this->Replace(rhs, index, rhs.size);
443 }
444
453 virtual void Replace(const Tself& rhs, size_t index, size_t size)
454 {
455 if (size > rhs.size)
456 {
457 HEPH_RAISE_AND_THROW_EXCEPTION(this, InvalidArgumentException(HEPH_FUNC, "size cannot be greater than the rhs buffer size"))
458 }
459
460 BufferBase::Replace(this->pData, this->SizeAsByte(), rhs.pData,
461 BufferBase::SizeAsByte(size), BufferBase::SizeAsByte(index));
462 }
463
469 virtual void Resize(size_t newSize)
470 {
471 if (this->size != newSize)
472 {
473 if (newSize == 0)
474 {
475 this->Release();
476 }
477 else
478 {
479 Tdata* pTemp = (Tdata*)std::realloc(this->pData, BufferBase::SizeAsByte(newSize));
480 if (pTemp == nullptr)
481 {
483 }
484 if (newSize > this->size)
485 {
486 BufferBase::Initialize(pTemp + this->size, pTemp + newSize);
487 }
488
489 this->pData = pTemp;
490 this->size = newSize;
491 }
492 }
493 }
494
499 virtual void Reverse()
500 {
501 const size_t halfSize = this->size / 2;
502 for (size_t i = 0; i < halfSize; ++i)
503 {
504 std::swap(this->pData[i], this->pData[this->size - i - 1]);
505 }
506 }
507
512 Tdata* begin() const
513 {
514 return this->pData;
515 }
516
521 Tdata* end() const
522 {
523 return this->pData != nullptr
524 ? (this->pData + this->size)
525 : nullptr;
526 }
527
528 protected:
534 static size_t SizeAsByte(size_t size)
535 {
536 return size * sizeof(Tdata);
537 }
538
546 template<typename U = Tdata>
547 static typename std::enable_if<std::is_class<U>::value>::type Initialize(U* pData, U* pDataEnd)
548 {
549 for (; pData < pDataEnd; ++pData)
550 {
551 new (pData) U();
552 }
553 }
554
562 template<typename U = Tdata>
563 static typename std::enable_if<!std::is_class<U>::value>::type Initialize(U* pData, U* pDataEnd)
564 {
565 (void)std::memset(pData, 0, ((uint8_t*)pDataEnd) - ((uint8_t*)pData));
566 }
567
575 static Tdata* Allocate(size_t size_byte)
576 {
577 Tdata* pData = BufferBase::AllocateUninitialized(size_byte);
578 BufferBase::Initialize(pData, (Tdata*)(((uint8_t*)pData) + size_byte));
579 return pData;
580 }
581
589 static Tdata* AllocateUninitialized(size_t size_byte)
590 {
591 Tdata* pData = (Tdata*)std::malloc(size_byte);
592 if (pData == nullptr)
593 {
595 }
596 return pData;
597 }
598
599 static Tdata* SubBuffer(Tdata* pThisData, size_t thisSize_byte, size_t index_byte, size_t subBufferSize_byte)
600 {
601 if (subBufferSize_byte > 0)
602 {
603 if (pThisData == nullptr)
604 {
605 HEPH_RAISE_AND_THROW_EXCEPTION(nullptr, InvalidArgumentException(HEPH_FUNC, "pRhsData cannot be nullptr"));
606 }
607 else if (index_byte >= thisSize_byte)
608 {
609 HEPH_RAISE_AND_THROW_EXCEPTION(nullptr, InvalidArgumentException(HEPH_FUNC, "Index out of bounds"));
610 }
611
612 size_t copySize_byte = subBufferSize_byte;
613 if ((index_byte + copySize_byte) > thisSize_byte)
614 {
615 copySize_byte = thisSize_byte - index_byte;
616 }
617
618 Tdata* pSubBufferData = BufferBase::AllocateUninitialized(subBufferSize_byte);
619 (void)std::memcpy(pSubBufferData, ((uint8_t*)pThisData) + index_byte, copySize_byte);
620
621 if (subBufferSize_byte > copySize_byte)
622 {
623 BufferBase::Initialize((Tdata*)(((uint8_t*)pSubBufferData) + copySize_byte), (Tdata*)(((uint8_t*)pSubBufferData) + subBufferSize_byte));
624 }
625
626 return pSubBufferData;
627 }
628 return nullptr;
629 }
630
631 static Tdata* Prepend(Tdata* pThisData, size_t thisSize_byte, Tdata* pRhsData, size_t rhsSize_byte)
632 {
633 if (rhsSize_byte > 0)
634 {
635 if (pRhsData == nullptr)
636 {
637 HEPH_RAISE_AND_THROW_EXCEPTION(nullptr, InvalidArgumentException(HEPH_FUNC, "pRhsData cannot be nullptr"));
638 }
639
640 Tdata* pResultData = (Tdata*)std::realloc(pThisData, thisSize_byte + rhsSize_byte);
641 if (pResultData == nullptr)
642 {
643 HEPH_RAISE_AND_THROW_EXCEPTION(nullptr, InsufficientMemoryException(HEPH_FUNC, "Insufficient memory"));
644 }
645
646 if (pThisData == pRhsData)
647 {
648 (void)std::memmove(((uint8_t*)pResultData) + rhsSize_byte, pResultData, thisSize_byte);
649 (void)std::memmove(pResultData, ((uint8_t*)pResultData) + rhsSize_byte, rhsSize_byte);
650 }
651 else
652 {
653 (void)std::memmove(((uint8_t*)pResultData) + rhsSize_byte, pResultData, thisSize_byte);
654 (void)std::memcpy(pResultData, pRhsData, rhsSize_byte);
655 }
656
657 return pResultData;
658 }
659 return pThisData;
660 }
661
662 static Tdata* Append(Tdata* pThisData, size_t thisSize_byte, Tdata* pRhsData, size_t rhsSize_byte)
663 {
664 if (rhsSize_byte > 0)
665 {
666 if (pRhsData == nullptr)
667 {
668 HEPH_RAISE_AND_THROW_EXCEPTION(nullptr, InvalidArgumentException(HEPH_FUNC, "pRhsData cannot be nullptr"));
669 }
670
671 Tdata* pResultData = (Tdata*)std::realloc(pThisData, thisSize_byte + rhsSize_byte);
672 if (pResultData == nullptr)
673 {
674 HEPH_RAISE_AND_THROW_EXCEPTION(nullptr, InsufficientMemoryException(HEPH_FUNC, "Insufficient memory"));
675 }
676
677 if (pThisData == pRhsData)
678 {
679 (void)std::memmove(((uint8_t*)pResultData) + thisSize_byte, pResultData, rhsSize_byte);
680 }
681 else
682 {
683 (void)std::memcpy(((uint8_t*)pResultData) + thisSize_byte, pRhsData, rhsSize_byte);
684 }
685
686 return pResultData;
687 }
688 return pThisData;
689 }
690
691 static Tdata* Insert(Tdata* pThisData, size_t thisSize_byte, Tdata* pRhsData, size_t rhsSize_byte, size_t index_byte)
692 {
693 if (rhsSize_byte > 0)
694 {
695 if (pRhsData == nullptr)
696 {
697 HEPH_RAISE_AND_THROW_EXCEPTION(nullptr, InvalidArgumentException(HEPH_FUNC, "pRhsData cannot be nullptr"));
698 }
699 else if (index_byte > thisSize_byte)
700 {
701 HEPH_RAISE_AND_THROW_EXCEPTION(nullptr, InvalidArgumentException(HEPH_FUNC, "Index out of bounds"));
702 }
703 else if (index_byte == thisSize_byte)
704 {
705 return BufferBase::Append(pThisData, thisSize_byte, pRhsData, rhsSize_byte);
706 }
707 else if (index_byte == 0)
708 {
709 return BufferBase::Prepend(pThisData, thisSize_byte, pRhsData, rhsSize_byte);
710 }
711
712 Tdata* pResultData = (Tdata*)std::realloc(pThisData, thisSize_byte + rhsSize_byte);
713 if (pResultData == nullptr)
714 {
715 HEPH_RAISE_AND_THROW_EXCEPTION(nullptr, InsufficientMemoryException(HEPH_FUNC, "Insufficient memory"));
716 }
717
718 if (pThisData == pRhsData)
719 {
720 (void)std::memmove(((uint8_t*)pResultData) + index_byte + rhsSize_byte, ((uint8_t*)pResultData) + index_byte, thisSize_byte - index_byte);
721 if (rhsSize_byte > index_byte)
722 {
723 (void)std::memmove(((uint8_t*)pResultData) + index_byte, pResultData, index_byte);
724 (void)std::memmove(((uint8_t*)pResultData) + 2 * index_byte, ((uint8_t*)pResultData) + index_byte + rhsSize_byte, rhsSize_byte - index_byte);
725 }
726 else
727 {
728 (void)std::memmove(((uint8_t*)pResultData) + index_byte, pResultData, rhsSize_byte);
729 }
730 }
731 else
732 {
733 (void)std::memmove(((uint8_t*)pResultData) + index_byte + rhsSize_byte, ((uint8_t*)pResultData) + index_byte, thisSize_byte - index_byte);
734 (void)std::memcpy(((uint8_t*)pResultData) + index_byte, pRhsData, rhsSize_byte);
735 }
736
737 return pResultData;
738 }
739 return pThisData;
740 }
741
742 static Tdata* Cut(Tdata* pThisData, size_t thisSize_byte, size_t index_byte, size_t& cutSize_byte)
743 {
744 if (thisSize_byte > 0 && cutSize_byte > 0)
745 {
746 if (pThisData == nullptr)
747 {
748 HEPH_RAISE_AND_THROW_EXCEPTION(nullptr, InvalidArgumentException(HEPH_FUNC, "pThisData cannot be nullptr"));
749 }
750 else if (index_byte >= thisSize_byte)
751 {
752 HEPH_RAISE_AND_THROW_EXCEPTION(nullptr, InvalidArgumentException(HEPH_FUNC, "Index out of bounds"));
753 }
754 else if (index_byte == 0 && cutSize_byte >= thisSize_byte)
755 {
756 std::free(pThisData);
757 cutSize_byte = thisSize_byte;
758 return nullptr;
759 }
760
761 if ((index_byte + cutSize_byte) > thisSize_byte)
762 {
763 cutSize_byte = thisSize_byte - index_byte;
764 }
765
766 Tdata* pResultData = BufferBase::AllocateUninitialized(thisSize_byte - cutSize_byte);
767 if (index_byte > 0)
768 {
769 (void)std::memcpy(pResultData, pThisData, index_byte);
770 }
771 if ((index_byte + cutSize_byte) < thisSize_byte)
772 {
773 (void)std::memcpy(((uint8_t*)pResultData) + index_byte, ((uint8_t*)pThisData) + index_byte + cutSize_byte, thisSize_byte - index_byte - cutSize_byte);
774 }
775
776 std::free(pThisData);
777 return pResultData;
778 }
779
780 cutSize_byte = 0;
781 return pThisData;
782 }
783
784 static void Replace(Tdata* pThisData, size_t thisSize_byte, Tdata* pRhsData, size_t rhsSize_byte, size_t index_byte)
785 {
786 if (thisSize_byte > 0 && rhsSize_byte > 0)
787 {
788 if (pThisData == nullptr)
789 {
790 HEPH_RAISE_AND_THROW_EXCEPTION(nullptr, InvalidArgumentException(HEPH_FUNC, "pThisData cannot be nullptr"));
791 }
792 else if (pRhsData == nullptr)
793 {
794 HEPH_RAISE_AND_THROW_EXCEPTION(nullptr, InvalidArgumentException(HEPH_FUNC, "pRhsData cannot be nullptr"));
795 }
796 else if (index_byte >= thisSize_byte)
797 {
798 HEPH_RAISE_AND_THROW_EXCEPTION(nullptr, InvalidArgumentException(HEPH_FUNC, "Index out of bounds"));
799 }
800
801 if ((index_byte + rhsSize_byte) > thisSize_byte)
802 {
803 rhsSize_byte = thisSize_byte - index_byte;
804 }
805 (void)std::memcpy(((uint8_t*)pThisData) + index_byte, pRhsData, rhsSize_byte);
806 }
807 }
808 };
809}
BufferFlags
Definition BufferBase.h:13
@ AllocUninitialized
do not initialize the elements after allocating memory. used in constructors.
Definition BufferBase.h:20
#define HEPH_RAISE_AND_THROW_EXCEPTION(pSender, ex)
Definition Exception.h:27
#define HEPH_FUNC
Definition HephShared.h:137
#define HEPH_API
Definition HephShared.h:124
base class for buffers. Provides basic buffer operations and methods.
Definition BufferBase.h:31
Tdata * begin() const
Definition BufferBase.h:512
virtual ~BufferBase()
Definition BufferBase.h:167
virtual void Append(const Tself &rhs)
Definition BufferBase.h:399
virtual Tself & operator>>=(size_t rhs)
Definition BufferBase.h:260
virtual void Prepend(const Tself &rhs)
Definition BufferBase.h:386
Tdata & operator[](size_t index) const
Definition BufferBase.h:291
virtual Tself operator<<(size_t rhs) const
Definition BufferBase.h:178
virtual bool IsEmpty() const
Definition BufferBase.h:332
BufferBase(BufferBase &&rhs) noexcept
Definition BufferBase.h:109
virtual void Release()
Definition BufferBase.h:353
BufferBase(const BufferBase &rhs)
Definition BufferBase.h:98
virtual Tself operator>>(size_t rhs) const
Definition BufferBase.h:230
static Tdata * AllocateUninitialized(size_t size_byte)
Definition BufferBase.h:589
size_t size
Definition BufferBase.h:46
virtual void Reverse()
Definition BufferBase.h:499
virtual void Resize(size_t newSize)
Definition BufferBase.h:469
size_t Size() const
Definition BufferBase.h:300
virtual void Replace(const Tself &rhs, size_t index, size_t size)
Definition BufferBase.h:453
virtual Tself SubBuffer(size_t index, size_t size) const
Definition BufferBase.h:370
static std::enable_if< std::is_class< U >::value >::type Initialize(U *pData, U *pDataEnd)
Definition BufferBase.h:547
Tdata * pData
Definition BufferBase.h:40
BufferBase(const std::initializer_list< Tdata > &rhs)
Definition BufferBase.h:87
virtual void Reset()
Definition BufferBase.h:341
virtual void Insert(const Tself &rhs, size_t index)
Definition BufferBase.h:412
BufferBase(size_t size)
Definition BufferBase.h:57
virtual void Cut(size_t index, size_t size)
Definition BufferBase.h:426
virtual void Replace(const Tself &rhs, size_t index)
Definition BufferBase.h:440
size_t SizeAsByte() const
Definition BufferBase.h:309
static Tdata * Allocate(size_t size_byte)
Definition BufferBase.h:575
BufferBase()
Definition BufferBase.h:50
Tdata * end() const
Definition BufferBase.h:521
static std::enable_if<!std::is_class< U >::value >::type Initialize(U *pData, U *pDataEnd)
Definition BufferBase.h:563
BufferBase(size_t size, BufferFlags flags)
Definition BufferBase.h:71
Tdata & At(size_t index) const
Definition BufferBase.h:318
static size_t SizeAsByte(size_t size)
Definition BufferBase.h:534
virtual Tself & operator<<=(size_t rhs)
Definition BufferBase.h:209
raised when an allocation fails due to insufficient memory.
Definition InsufficientMemoryException.h:14
raised when an argument passed to a method is invalid.
Definition InvalidArgumentException.h:14