HephAudio v3.0.6
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
179 virtual Tself operator<<(size_t rhs) const
180 {
181 if (rhs >= this->size)
182 {
183 Tself result{};
184 result.pData = BufferBase::Allocate(this->SizeAsByte());
185 result.size = this->size;
186 return result;
187 }
188
189 const size_t thisSize_byte = this->SizeAsByte();
190 const size_t rhsSize_byte = BufferBase::SizeAsByte(rhs);
191
192 Tself result{};
193 result.pData = BufferBase::AllocateUninitialized(thisSize_byte);
194 result.size = this->size;
195
196 (void)std::memcpy(result.pData, this->pData + rhs, thisSize_byte - rhsSize_byte);
197 if (rhs > 0)
198 {
199 BufferBase::Initialize(result.pData + this->size - rhs, result.pData + this->size);
200 }
201
202 return result;
203 }
204
210 virtual Tself& operator<<=(size_t rhs)
211 {
212 if (rhs >= this->size)
213 {
214 this->Reset();
215 }
216 else if (rhs > 0)
217 {
218 (void)std::memcpy(this->pData, this->pData + rhs, this->SizeAsByte() - BufferBase::SizeAsByte(rhs));
219 BufferBase::Initialize(this->pData + this->size - rhs, this->pData + this->size);
220 }
221
222 return *(Tself*)this;
223 }
224
232 virtual Tself operator>>(size_t rhs) const
233 {
234 if (rhs >= this->size)
235 {
236 Tself result{};
237 result.pData = BufferBase::Allocate(this->SizeAsByte());
238 result.size = this->size;
239 return result;
240 }
241
242 const size_t thisSize_byte = this->SizeAsByte();
243
244 Tself result{};
245 result.pData = BufferBase::AllocateUninitialized(thisSize_byte);
246 result.size = this->size;
247
248 (void)std::memcpy(result.pData + rhs, this->pData, thisSize_byte - BufferBase::SizeAsByte(rhs));
249 if (rhs > 0)
250 {
251 BufferBase::Initialize(result.pData, result.pData + rhs);
252 }
253
254 return result;
255 }
256
262 virtual Tself& operator>>=(size_t rhs)
263 {
264 if (rhs >= this->size)
265 {
266 this->Reset();
267 }
268 else if (rhs > 0)
269 {
270 (void)std::memcpy(this->pData + rhs, this->pData, this->SizeAsByte() - BufferBase::SizeAsByte(rhs));
271 BufferBase::Initialize(this->pData, this->pData + rhs);
272 }
273 return *(Tself*)this;
274 }
275
276 virtual bool operator==(const Tself& rhs) const
277 {
278 return (this->IsEmpty() && rhs.IsEmpty()) ||
279 (this->size == rhs.size &&
280 std::memcmp(this->pData, rhs.pData, this->SizeAsByte()) == 0);
281 }
282
283 virtual bool operator!=(const Tself& rhs) const
284 {
285 return !((*this) == rhs);
286 }
287
293 Tdata& operator[](size_t index) const
294 {
295 return this->pData[index];
296 }
297
302 size_t Size() const
303 {
304 return this->size;
305 }
306
311 size_t SizeAsByte() const
312 {
313 return this->size * sizeof(Tdata);
314 }
315
321 Tdata& At(size_t index) const
322 {
323 if (index >= this->size)
324 {
326 }
327 return this->pData[index];
328 }
329
335 virtual bool IsEmpty() const
336 {
337 return this->pData == nullptr || this->size == 0;
338 }
339
344 virtual void Reset()
345 {
346 if (!this->IsEmpty())
347 {
348 BufferBase::Initialize(this->pData, this->pData + this->size);
349 }
350 }
351
356 virtual void Release()
357 {
358 if (this->pData != nullptr)
359 {
360 std::free(this->pData);
361 this->pData = nullptr;
362 }
363 this->size = 0;
364 }
365
375 virtual Tself SubBuffer(size_t index, size_t size) const
376 {
377 Tself result{};
378
379 result.pData = BufferBase::SubBuffer(this->pData, this->SizeAsByte(), BufferBase::SizeAsByte(index), BufferBase::SizeAsByte(size));
380 result.size = size;
381
382 return result;
383 }
384
393 virtual void Prepend(const Tself& rhs)
394 {
395 this->pData = BufferBase::Prepend(this->pData, this->SizeAsByte(), rhs.pData,
396 rhs.SizeAsByte());
397 this->size += rhs.size;
398 }
399
408 virtual void Append(const Tself& rhs)
409 {
410 this->pData = BufferBase::Append(this->pData, this->SizeAsByte(), rhs.pData,
411 rhs.SizeAsByte());
412 this->size += rhs.size;
413 }
414
423 virtual void Insert(const Tself& rhs, size_t index)
424 {
425 this->pData = BufferBase::Insert(this->pData, this->SizeAsByte(), rhs.pData,
426 rhs.SizeAsByte(), BufferBase::SizeAsByte(index));
427 this->size += rhs.size;
428 }
429
438 virtual void Cut(size_t index, size_t size)
439 {
440 size_t cutSize_byte = BufferBase::SizeAsByte(size);
441 this->pData = BufferBase::Cut(this->pData, this->SizeAsByte(), BufferBase::SizeAsByte(index), cutSize_byte);
442 this->size -= cutSize_byte / sizeof(Tdata);
443 }
444
453 virtual void Replace(const Tself& rhs, size_t index)
454 {
455 this->Replace(rhs, index, rhs.size);
456 }
457
467 virtual void Replace(const Tself& rhs, size_t index, size_t size)
468 {
469 if (size > rhs.size)
470 {
471 HEPH_RAISE_AND_THROW_EXCEPTION(this, InvalidArgumentException(HEPH_FUNC, "size cannot be greater than the rhs buffer size"))
472 }
473
474 BufferBase::Replace(this->pData, this->SizeAsByte(), rhs.pData,
475 BufferBase::SizeAsByte(size), BufferBase::SizeAsByte(index));
476 }
477
484 virtual void Resize(size_t newSize)
485 {
486 if (this->size != newSize)
487 {
488 if (newSize == 0)
489 {
490 this->Release();
491 }
492 else
493 {
494 Tdata* pTemp = (Tdata*)std::realloc(this->pData, BufferBase::SizeAsByte(newSize));
495 if (pTemp == nullptr)
496 {
498 }
499 if (newSize > this->size)
500 {
501 BufferBase::Initialize(pTemp + this->size, pTemp + newSize);
502 }
503
504 this->pData = pTemp;
505 this->size = newSize;
506 }
507 }
508 }
509
514 virtual void Reverse()
515 {
516 const size_t halfSize = this->size / 2;
517 for (size_t i = 0; i < halfSize; ++i)
518 {
519 std::swap(this->pData[i], this->pData[this->size - i - 1]);
520 }
521 }
522
527 Tdata* begin() const
528 {
529 return this->pData;
530 }
531
536 Tdata* end() const
537 {
538 return this->pData != nullptr
539 ? (this->pData + this->size)
540 : nullptr;
541 }
542
543 protected:
549 static size_t SizeAsByte(size_t size)
550 {
551 return size * sizeof(Tdata);
552 }
553
561 template<typename U = Tdata>
562 static typename std::enable_if<std::is_class<U>::value>::type Initialize(U* pData, U* pDataEnd)
563 {
564 for (; pData < pDataEnd; ++pData)
565 {
566 new (pData) U();
567 }
568 }
569
577 template<typename U = Tdata>
578 static typename std::enable_if<!std::is_class<U>::value>::type Initialize(U* pData, U* pDataEnd)
579 {
580 (void)std::memset(pData, 0, ((uint8_t*)pDataEnd) - ((uint8_t*)pData));
581 }
582
591 static Tdata* Allocate(size_t size_byte)
592 {
593 Tdata* pData = BufferBase::AllocateUninitialized(size_byte);
594 BufferBase::Initialize(pData, (Tdata*)(((uint8_t*)pData) + size_byte));
595 return pData;
596 }
597
606 static Tdata* AllocateUninitialized(size_t size_byte)
607 {
608 Tdata* pData = (Tdata*)std::malloc(size_byte);
609 if (pData == nullptr)
610 {
612 }
613 return pData;
614 }
615
616 static Tdata* SubBuffer(Tdata* pThisData, size_t thisSize_byte, size_t index_byte, size_t subBufferSize_byte)
617 {
618 if (subBufferSize_byte > 0)
619 {
620 if (pThisData == nullptr)
621 {
622 HEPH_RAISE_AND_THROW_EXCEPTION(nullptr, InvalidArgumentException(HEPH_FUNC, "pRhsData cannot be nullptr"));
623 }
624 else if (index_byte >= thisSize_byte)
625 {
626 HEPH_RAISE_AND_THROW_EXCEPTION(nullptr, InvalidArgumentException(HEPH_FUNC, "Index out of bounds"));
627 }
628
629 size_t copySize_byte = subBufferSize_byte;
630 if ((index_byte + copySize_byte) > thisSize_byte)
631 {
632 copySize_byte = thisSize_byte - index_byte;
633 }
634
635 Tdata* pSubBufferData = BufferBase::AllocateUninitialized(subBufferSize_byte);
636 (void)std::memcpy(pSubBufferData, ((uint8_t*)pThisData) + index_byte, copySize_byte);
637
638 if (subBufferSize_byte > copySize_byte)
639 {
640 BufferBase::Initialize((Tdata*)(((uint8_t*)pSubBufferData) + copySize_byte), (Tdata*)(((uint8_t*)pSubBufferData) + subBufferSize_byte));
641 }
642
643 return pSubBufferData;
644 }
645 return nullptr;
646 }
647
648 static Tdata* Prepend(Tdata* pThisData, size_t thisSize_byte, Tdata* pRhsData, size_t rhsSize_byte)
649 {
650 if (rhsSize_byte > 0)
651 {
652 if (pRhsData == nullptr)
653 {
654 HEPH_RAISE_AND_THROW_EXCEPTION(nullptr, InvalidArgumentException(HEPH_FUNC, "pRhsData cannot be nullptr"));
655 }
656
657 Tdata* pResultData = (Tdata*)std::realloc(pThisData, thisSize_byte + rhsSize_byte);
658 if (pResultData == nullptr)
659 {
660 HEPH_RAISE_AND_THROW_EXCEPTION(nullptr, InsufficientMemoryException(HEPH_FUNC, "Insufficient memory"));
661 }
662
663 if (pThisData == pRhsData)
664 {
665 (void)std::memcpy(((uint8_t*)pResultData) + rhsSize_byte, pResultData, thisSize_byte);
666 (void)std::memcpy(pResultData, ((uint8_t*)pResultData) + rhsSize_byte, rhsSize_byte);
667 }
668 else
669 {
670 (void)std::memcpy(((uint8_t*)pResultData) + rhsSize_byte, pThisData, thisSize_byte);
671 (void)std::memcpy(pResultData, pRhsData, rhsSize_byte);
672 }
673
674 return pResultData;
675 }
676 return pThisData;
677 }
678
679 static Tdata* Append(Tdata* pThisData, size_t thisSize_byte, Tdata* pRhsData, size_t rhsSize_byte)
680 {
681 if (rhsSize_byte > 0)
682 {
683 if (pRhsData == nullptr)
684 {
685 HEPH_RAISE_AND_THROW_EXCEPTION(nullptr, InvalidArgumentException(HEPH_FUNC, "pRhsData cannot be nullptr"));
686 }
687
688 Tdata* pResultData = (Tdata*)std::realloc(pThisData, thisSize_byte + rhsSize_byte);
689 if (pResultData == nullptr)
690 {
691 HEPH_RAISE_AND_THROW_EXCEPTION(nullptr, InsufficientMemoryException(HEPH_FUNC, "Insufficient memory"));
692 }
693
694 if (pThisData == pRhsData)
695 {
696 (void)std::memcpy(((uint8_t*)pResultData) + thisSize_byte, pResultData, rhsSize_byte);
697 }
698 else
699 {
700 (void)std::memcpy(((uint8_t*)pResultData) + thisSize_byte, pRhsData, rhsSize_byte);
701 }
702
703 return pResultData;
704 }
705 return pThisData;
706 }
707
708 static Tdata* Insert(Tdata* pThisData, size_t thisSize_byte, Tdata* pRhsData, size_t rhsSize_byte, size_t index_byte)
709 {
710 if (rhsSize_byte > 0)
711 {
712 if (pRhsData == nullptr)
713 {
714 HEPH_RAISE_AND_THROW_EXCEPTION(nullptr, InvalidArgumentException(HEPH_FUNC, "pRhsData cannot be nullptr"));
715 }
716 else if (index_byte > thisSize_byte)
717 {
718 HEPH_RAISE_AND_THROW_EXCEPTION(nullptr, InvalidArgumentException(HEPH_FUNC, "Index out of bounds"));
719 }
720 else if (index_byte == thisSize_byte)
721 {
722 return BufferBase::Append(pThisData, thisSize_byte, pRhsData, rhsSize_byte);
723 }
724 else if (index_byte == 0)
725 {
726 return BufferBase::Prepend(pThisData, thisSize_byte, pRhsData, rhsSize_byte);
727 }
728
729 Tdata* pResultData = (Tdata*)std::realloc(pThisData, thisSize_byte + rhsSize_byte);
730 if (pResultData == nullptr)
731 {
732 HEPH_RAISE_AND_THROW_EXCEPTION(nullptr, InsufficientMemoryException(HEPH_FUNC, "Insufficient memory"));
733 }
734
735 if (pThisData == pRhsData)
736 {
737 (void)std::memcpy(((uint8_t*)pResultData) + index_byte + rhsSize_byte, ((uint8_t*)pResultData) + index_byte, thisSize_byte - index_byte);
738 if (rhsSize_byte > index_byte)
739 {
740 (void)std::memcpy(((uint8_t*)pResultData) + index_byte, pResultData, index_byte);
741 (void)std::memcpy(((uint8_t*)pResultData) + 2 * index_byte, ((uint8_t*)pResultData) + index_byte + rhsSize_byte, rhsSize_byte - index_byte);
742 }
743 else
744 {
745 (void)std::memcpy(((uint8_t*)pResultData) + index_byte, pResultData, rhsSize_byte);
746 }
747 }
748 else
749 {
750 (void)std::memcpy(((uint8_t*)pResultData) + index_byte + rhsSize_byte, ((uint8_t*)pResultData) + index_byte, thisSize_byte - index_byte);
751 (void)std::memcpy(((uint8_t*)pResultData) + index_byte, pRhsData, rhsSize_byte);
752 }
753
754 return pResultData;
755 }
756 return pThisData;
757 }
758
759 static Tdata* Cut(Tdata* pThisData, size_t thisSize_byte, size_t index_byte, size_t& cutSize_byte)
760 {
761 if (thisSize_byte > 0 && cutSize_byte > 0)
762 {
763 if (pThisData == nullptr)
764 {
765 HEPH_RAISE_AND_THROW_EXCEPTION(nullptr, InvalidArgumentException(HEPH_FUNC, "pThisData cannot be nullptr"));
766 }
767 else if (index_byte >= thisSize_byte)
768 {
769 HEPH_RAISE_AND_THROW_EXCEPTION(nullptr, InvalidArgumentException(HEPH_FUNC, "Index out of bounds"));
770 }
771 else if (index_byte == 0 && cutSize_byte >= thisSize_byte)
772 {
773 std::free(pThisData);
774 cutSize_byte = thisSize_byte;
775 return nullptr;
776 }
777
778 if ((index_byte + cutSize_byte) > thisSize_byte)
779 {
780 cutSize_byte = thisSize_byte - index_byte;
781 }
782
783 Tdata* pResultData = BufferBase::AllocateUninitialized(thisSize_byte - cutSize_byte);
784 if (index_byte > 0)
785 {
786 (void)std::memcpy(pResultData, pThisData, index_byte);
787 }
788 if ((index_byte + cutSize_byte) < thisSize_byte)
789 {
790 (void)std::memcpy(((uint8_t*)pResultData) + index_byte, ((uint8_t*)pThisData) + index_byte + cutSize_byte, thisSize_byte - index_byte - cutSize_byte);
791 }
792
793 std::free(pThisData);
794 return pResultData;
795 }
796
797 cutSize_byte = 0;
798 return pThisData;
799 }
800
801 static void Replace(Tdata* pThisData, size_t thisSize_byte, Tdata* pRhsData, size_t rhsSize_byte, size_t index_byte)
802 {
803 if (thisSize_byte > 0 && rhsSize_byte > 0)
804 {
805 if (pThisData == nullptr)
806 {
807 HEPH_RAISE_AND_THROW_EXCEPTION(nullptr, InvalidArgumentException(HEPH_FUNC, "pThisData cannot be nullptr"));
808 }
809 else if (pRhsData == nullptr)
810 {
811 HEPH_RAISE_AND_THROW_EXCEPTION(nullptr, InvalidArgumentException(HEPH_FUNC, "pRhsData cannot be nullptr"));
812 }
813 else if (index_byte >= thisSize_byte)
814 {
815 HEPH_RAISE_AND_THROW_EXCEPTION(nullptr, InvalidArgumentException(HEPH_FUNC, "Index out of bounds"));
816 }
817
818 if ((index_byte + rhsSize_byte) > thisSize_byte)
819 {
820 rhsSize_byte = thisSize_byte - index_byte;
821 }
822 (void)std::memcpy(((uint8_t*)pThisData) + index_byte, pRhsData, rhsSize_byte);
823 }
824 }
825 };
826}
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:145
#define HEPH_API
Definition HephShared.h:132
base class for buffers. Provides basic buffer operations and methods.
Definition BufferBase.h:31
Tdata * begin() const
Definition BufferBase.h:527
virtual ~BufferBase()
Definition BufferBase.h:167
virtual void Append(const Tself &rhs)
Definition BufferBase.h:408
virtual Tself & operator>>=(size_t rhs)
Definition BufferBase.h:262
virtual void Prepend(const Tself &rhs)
Definition BufferBase.h:393
Tdata & operator[](size_t index) const
Definition BufferBase.h:293
virtual Tself operator<<(size_t rhs) const
Definition BufferBase.h:179
virtual bool IsEmpty() const
Definition BufferBase.h:335
BufferBase(BufferBase &&rhs) noexcept
Definition BufferBase.h:109
virtual void Release()
Definition BufferBase.h:356
BufferBase(const BufferBase &rhs)
Definition BufferBase.h:98
virtual Tself operator>>(size_t rhs) const
Definition BufferBase.h:232
static Tdata * AllocateUninitialized(size_t size_byte)
Definition BufferBase.h:606
size_t size
Definition BufferBase.h:46
virtual void Reverse()
Definition BufferBase.h:514
virtual void Resize(size_t newSize)
Definition BufferBase.h:484
size_t Size() const
Definition BufferBase.h:302
virtual void Replace(const Tself &rhs, size_t index, size_t size)
Definition BufferBase.h:467
virtual Tself SubBuffer(size_t index, size_t size) const
Definition BufferBase.h:375
static std::enable_if< std::is_class< U >::value >::type Initialize(U *pData, U *pDataEnd)
Definition BufferBase.h:562
Tdata * pData
Definition BufferBase.h:40
BufferBase(const std::initializer_list< Tdata > &rhs)
Definition BufferBase.h:87
virtual void Reset()
Definition BufferBase.h:344
virtual void Insert(const Tself &rhs, size_t index)
Definition BufferBase.h:423
BufferBase(size_t size)
Definition BufferBase.h:57
virtual void Cut(size_t index, size_t size)
Definition BufferBase.h:438
virtual void Replace(const Tself &rhs, size_t index)
Definition BufferBase.h:453
size_t SizeAsByte() const
Definition BufferBase.h:311
static Tdata * Allocate(size_t size_byte)
Definition BufferBase.h:591
BufferBase()
Definition BufferBase.h:50
Tdata * end() const
Definition BufferBase.h:536
static std::enable_if<!std::is_class< U >::value >::type Initialize(U *pData, U *pDataEnd)
Definition BufferBase.h:578
BufferBase(size_t size, BufferFlags flags)
Definition BufferBase.h:71
Tdata & At(size_t index) const
Definition BufferBase.h:321
static size_t SizeAsByte(size_t size)
Definition BufferBase.h:549
virtual Tself & operator<<=(size_t rhs)
Definition BufferBase.h:210
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