HephAudio v3.1.0
A cross-platform C++ library for recording, playing, and processing audio on Windows, Android, Linux, iOS, and macOS.
All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
BufferOperators.h
Go to the documentation of this file.
1#pragma once
2#include "HephShared.h"
3#include "BufferBase.h"
4#include "HephTypeTraits.h"
5#include "Event.h"
7
10namespace Heph
11{
12#pragma region Event
17 template<typename Lhs, typename Rhs>
19 {
20 const Lhs& lhs;
21 const Rhs& rhs;
22 Lhs& result;
23 BufferOperatorResultCreatedEventArgs(const Lhs& lhs, const Rhs& rhs, Lhs& result) : lhs(lhs), rhs(rhs), result(result) {}
24 };
25
26 template<typename Lhs, typename Rhs>
28 {
33 static inline Event OnResultCreated = Event();
34 };
35#pragma endregion
36#pragma region Addition
41 template<class Lhs, typename LhsData, typename Rhs = LhsData, typename RhsData = Rhs>
43 {
44 static constexpr bool DEFINE_RHS_LHS_OPERATOR = !has_addition_operator<Rhs, Lhs, Lhs>::value && !has_addition_operator<Rhs, Lhs, Rhs>::value;
45
46 public:
48 {
49 static_assert(std::is_default_constructible<Lhs>::value, "Lhs must have a default constructor");
50 static_assert(std::is_base_of<BufferBase<Lhs, LhsData>, Lhs>::value, "Lhs must derive from BufferBase<Lhs, LhsData>");
51 static_assert(
52 std::is_base_of<BufferBase<Rhs, RhsData>, Rhs>::value || std::is_same<Rhs, RhsData>::value,
53 "Rhs must derive from BufferBase<Rhs, RhsData> or RhsData must be the same type as Rhs"
54 );
55 static_assert(
56 has_addition_operator<LhsData, RhsData>::value && has_addition_assignment_operator<LhsData, RhsData>::value,
57 "LhsData must have operator+(RhsData) and operator+=(RhsData)"
58 );
59 }
61 BufferAdditionOperator& operator=(const BufferAdditionOperator&) = delete;
62
63 public:
64 friend inline Lhs operator+(const Lhs& lhs, const Rhs& rhs)
65 {
66 return Impl<Rhs, RhsData>(lhs, rhs);
67 }
68
69 friend inline Lhs& operator+=(Lhs& lhs, const Rhs& rhs)
70 {
71 return ImplAssign<Rhs, RhsData>(lhs, rhs);
72 }
73
74 template<typename Ret = Lhs>
75 friend inline typename std::enable_if<DEFINE_RHS_LHS_OPERATOR, Ret>::type operator+(const Rhs& rhs, const Lhs& lhs)
76 {
77 return lhs + rhs;
78 }
79
80 template<typename Ret>
81 friend inline typename std::enable_if<!DEFINE_RHS_LHS_OPERATOR, Ret>::type operator+(const Rhs& rhs, const Lhs& lhs);
82
83 private:
84 template<typename U = Rhs, typename V = RhsData>
85 static inline typename std::enable_if<std::is_same<U, V>::value, Lhs>::type Impl(const Lhs& lhs, const U& rhs)
86 {
87 Lhs result{};
90 {
91 HEPH_RAISE_AND_THROW_EXCEPTION(&lhs, InvalidOperationException(HEPH_FUNC, "BufferOperatorEvents::OnResultCreated event must be handled"));
92 }
94
95 const size_t size = lhs.Size();
96 for (size_t i = 0; i < size; ++i)
97 {
98 result.begin()[i] = lhs.begin()[i] + rhs;
99 }
100 return result;
101 }
102
103 template<typename U = Rhs, typename V = RhsData>
104 static inline typename std::enable_if<std::is_same<U, V>::value, Lhs&>::type ImplAssign(Lhs& lhs, const U& rhs)
105 {
106 const size_t size = lhs.Size();
107 for (size_t i = 0; i < size; ++i)
108 {
109 lhs.begin()[i] += rhs;
110 }
111 return lhs;
112 }
113
114 template<typename U = Rhs, typename V = RhsData>
115 static inline typename std::enable_if<std::is_base_of<BufferBase<U, V>, U>::value, Lhs>::type Impl(const Lhs& lhs, const U& rhs)
116 {
117 if (lhs.Size() != rhs.Size())
118 {
119 HEPH_RAISE_AND_THROW_EXCEPTION(&lhs, InvalidArgumentException(HEPH_FUNC, "Both operands must have the same size"));
120 }
121
122 Lhs result{};
125 {
127 "BufferOperatorEvents::OnResultCreated event must be handled"));
128 }
130
131 const size_t size = lhs.Size();
132 for (size_t i = 0; i < size; ++i)
133 {
134 result.begin()[i] = lhs.begin()[i] + rhs.begin()[i];
135 }
136 return result;
137 }
138
139 template<typename U = Rhs, typename V = RhsData>
140 static inline typename std::enable_if<std::is_base_of<BufferBase<U, V>, U>::value, Lhs&>::type ImplAssign(Lhs& lhs, const U& rhs)
141 {
142 const size_t minSize = HEPH_MATH_MIN(lhs.Size(), rhs.Size());
143 for (size_t i = 0; i < minSize; ++i)
144 {
145 lhs.begin()[i] += rhs.begin()[i];
146 }
147 return lhs;
148 }
149 };
150#pragma endregion
151#pragma region Subtraction
156 template<class Lhs, typename LhsData, typename Rhs = LhsData, typename RhsData = Rhs>
158 {
159 static constexpr bool DEFINE_RHS_LHS_OPERATOR = !has_subtraction_operator<Rhs, Lhs, Lhs>::value && !has_subtraction_operator<Rhs, Lhs, Rhs>::value;
160
161 public:
163 {
164 static_assert(std::is_default_constructible<Lhs>::value, "Lhs must have a default constructor");
165 static_assert(std::is_base_of<BufferBase<Lhs, LhsData>, Lhs>::value, "Lhs must derive from BufferBase<Lhs, LhsData>");
166 static_assert(
167 std::is_base_of<BufferBase<Rhs, RhsData>, Rhs>::value || std::is_same<Rhs, RhsData>::value,
168 "Rhs must derive from BufferBase<Rhs, RhsData> or RhsData must be the same type as Rhs"
169 );
170 static_assert(
171 has_subtraction_operator<LhsData, RhsData>::value && has_subtraction_assignment_operator<LhsData, RhsData>::value,
172 "LhsData must have operator-(RhsData) and operator-=(RhsData)"
173 );
174 }
176 BufferSubtractionOperator& operator=(const BufferSubtractionOperator&) = delete;
177
178 public:
179 friend inline Lhs operator-(const Lhs& lhs, const Rhs& rhs)
180 {
181 return Impl<Rhs, RhsData>(lhs, rhs);
182 }
183
184 friend inline Lhs& operator-=(Lhs& lhs, const Rhs& rhs)
185 {
186 return ImplAssign<Rhs, RhsData>(lhs, rhs);
187 }
188
189 template<typename Ret = Lhs>
190 friend inline typename std::enable_if<DEFINE_RHS_LHS_OPERATOR, Ret>::type operator-(const Rhs& rhs, const Lhs& lhs)
191 {
192 return ImplRhs<Rhs, RhsData>(rhs, lhs);
193 }
194
195 template<typename Ret>
196 friend inline typename std::enable_if<!DEFINE_RHS_LHS_OPERATOR, Ret>::type operator-(const Rhs& rhs, const Lhs& lhs);
197
198 private:
199 template<typename U = Rhs, typename V = RhsData>
200 static inline typename std::enable_if<std::is_same<U, V>::value, Lhs>::type Impl(const Lhs& lhs, const U& rhs)
201 {
202 Lhs result{};
205 {
206 HEPH_RAISE_AND_THROW_EXCEPTION(&lhs, InvalidOperationException(HEPH_FUNC, "BufferOperatorEvents::OnResultCreated event must be handled"));
207 }
209
210 const size_t size = lhs.Size();
211 for (size_t i = 0; i < size; ++i)
212 {
213 result.begin()[i] = lhs.begin()[i] - rhs;
214 }
215 return result;
216 }
217
218 template<typename U = Rhs, typename V = RhsData>
219 static inline typename std::enable_if<DEFINE_RHS_LHS_OPERATOR&& std::is_same<U, V>::value, Lhs>::type ImplRhs(const U& rhs, const Lhs& lhs)
220 {
221 Lhs result{};
224 {
225 HEPH_RAISE_AND_THROW_EXCEPTION(&lhs, InvalidOperationException(HEPH_FUNC, "BufferOperatorEvents::OnResultCreated event must be handled"));
226 }
228
229 const size_t size = lhs.Size();
230 for (size_t i = 0; i < size; ++i)
231 {
232 result.begin()[i] = rhs - lhs.begin()[i];
233 }
234 return result;
235 }
236
237 template<typename U = Rhs, typename V = RhsData>
238 static inline typename std::enable_if<std::is_same<U, V>::value, Lhs&>::type ImplAssign(Lhs& lhs, const U& rhs)
239 {
240 const size_t size = lhs.Size();
241 for (size_t i = 0; i < size; ++i)
242 {
243 lhs.begin()[i] -= rhs;
244 }
245 return lhs;
246 }
247
248 template<typename U = Rhs, typename V = RhsData>
249 static inline typename std::enable_if<std::is_base_of<BufferBase<U, V>, U>::value, Lhs>::type Impl(const Lhs& lhs, const U& rhs)
250 {
251 if (lhs.Size() != rhs.Size())
252 {
253 HEPH_RAISE_AND_THROW_EXCEPTION(&lhs, InvalidArgumentException(HEPH_FUNC, "Both operands must have the same size"));
254 }
255
256 Lhs result{};
259 {
261 "BufferOperatorEvents::OnResultCreated event must be handled"));
262 }
264
265 const size_t size = lhs.Size();
266 for (size_t i = 0; i < size; ++i)
267 {
268 result.begin()[i] = lhs.begin()[i] - rhs.begin()[i];
269 }
270 return result;
271 }
272
273 template<typename U = Rhs, typename V = RhsData>
274 static inline typename std::enable_if<DEFINE_RHS_LHS_OPERATOR&& std::is_base_of<BufferBase<U, V>, U>::value, Lhs>::type ImplRhs(const U& rhs, const Lhs& lhs)
275 {
276 if (lhs.Size() != rhs.Size())
277 {
278 HEPH_RAISE_AND_THROW_EXCEPTION(&lhs, InvalidArgumentException(HEPH_FUNC, "Both operands must have the same size"));
279 }
280
281 Lhs result{};
284 {
286 "BufferOperatorEvents::OnResultCreated event must be handled"));
287 }
289
290 const size_t size = lhs.Size();
291 for (size_t i = 0; i < size; ++i)
292 {
293 result.begin()[i] = rhs.begin()[i] - lhs.begin()[i];
294 }
295 return result;
296 }
297
298 template<typename U = Rhs, typename V = RhsData>
299 static inline typename std::enable_if<std::is_base_of<BufferBase<U, V>, U>::value, Lhs&>::type ImplAssign(Lhs& lhs, const U& rhs)
300 {
301 const size_t minSize = HEPH_MATH_MIN(lhs.Size(), rhs.Size());
302 for (size_t i = 0; i < minSize; ++i)
303 {
304 lhs.begin()[i] -= rhs.begin()[i];
305 }
306 return lhs;
307 }
308 };
309#pragma endregion
310#pragma region Multiplication
315 template<class Lhs, typename LhsData, typename Rhs = LhsData, typename RhsData = Rhs>
317 {
318 static constexpr bool DEFINE_RHS_LHS_OPERATOR = !has_multiplication_operator<Rhs, Lhs, Lhs>::value && !has_multiplication_operator<Rhs, Lhs, Rhs>::value;
319
320 public:
322 {
323 static_assert(std::is_default_constructible<Lhs>::value, "Lhs must have a default constructor");
324 static_assert(std::is_base_of<BufferBase<Lhs, LhsData>, Lhs>::value, "Lhs must derive from BufferBase<Lhs, LhsData>");
325 static_assert(
326 std::is_base_of<BufferBase<Rhs, RhsData>, Rhs>::value || std::is_same<Rhs, RhsData>::value,
327 "Rhs must derive from BufferBase<Rhs, RhsData> or RhsData must be the same type as Rhs"
328 );
329 static_assert(
330 has_multiplication_operator<LhsData, RhsData>::value && has_multiplication_operator<LhsData, RhsData>::value,
331 "LhsData must have operator*(RhsData) and operator*=(RhsData)"
332 );
333 }
336
337 public:
338 friend inline Lhs operator*(const Lhs& lhs, const Rhs& rhs)
339 {
340 return Impl<Rhs, RhsData>(lhs, rhs);
341 }
342
343 friend inline Lhs& operator*=(Lhs& lhs, const Rhs& rhs)
344 {
345 return ImplAssign<Rhs, RhsData>(lhs, rhs);
346 }
347
348 template<typename Ret = Lhs>
349 friend inline typename std::enable_if<DEFINE_RHS_LHS_OPERATOR, Ret>::type operator*(const Rhs& rhs, const Lhs& lhs)
350 {
351 return lhs * rhs;
352 }
353
354 template<typename Ret>
355 friend inline typename std::enable_if<!DEFINE_RHS_LHS_OPERATOR, Ret>::type operator*(const Rhs& rhs, const Lhs& lhs);
356
357 private:
358 template<typename U = Rhs, typename V = RhsData>
359 static inline typename std::enable_if<std::is_same<U, V>::value, Lhs>::type Impl(const Lhs& lhs, const U& rhs)
360 {
361 Lhs result{};
364 {
365 HEPH_RAISE_AND_THROW_EXCEPTION(&lhs, InvalidOperationException(HEPH_FUNC, "BufferOperatorEvents::OnResultCreated event must be handled"));
366 }
368
369 const size_t size = lhs.Size();
370 for (size_t i = 0; i < size; ++i)
371 {
372 result.begin()[i] = lhs.begin()[i] * rhs;
373 }
374 return result;
375 }
376
377 template<typename U = Rhs, typename V = RhsData>
378 static inline typename std::enable_if<std::is_same<U, V>::value, Lhs&>::type ImplAssign(Lhs& lhs, const U& rhs)
379 {
380 const size_t size = lhs.Size();
381 for (size_t i = 0; i < size; ++i)
382 {
383 lhs.begin()[i] *= rhs;
384 }
385 return lhs;
386 }
387
388 template<typename U = Rhs, typename V = RhsData>
389 static inline typename std::enable_if<std::is_base_of<BufferBase<U, V>, U>::value, Lhs>::type Impl(const Lhs& lhs, const U& rhs)
390 {
391 if (lhs.Size() != rhs.Size())
392 {
393 HEPH_RAISE_AND_THROW_EXCEPTION(&lhs, InvalidArgumentException(HEPH_FUNC, "Both operands must have the same size"));
394 }
395
396 Lhs result{};
399 {
401 "BufferOperatorEvents::OnResultCreated event must be handled"));
402 }
404
405 const size_t size = lhs.Size();
406 for (size_t i = 0; i < size; ++i)
407 {
408 result.begin()[i] = lhs.begin()[i] * rhs.begin()[i];
409 }
410 return result;
411 }
412
413 template<typename U = Rhs, typename V = RhsData>
414 static inline typename std::enable_if<std::is_base_of<BufferBase<U, V>, U>::value, Lhs&>::type ImplAssign(Lhs& lhs, const U& rhs)
415 {
416 const size_t minSize = HEPH_MATH_MIN(lhs.Size(), rhs.Size());
417 for (size_t i = 0; i < minSize; ++i)
418 {
419 lhs.begin()[i] *= rhs.begin()[i];
420 }
421 return lhs;
422 }
423 };
424#pragma endregion
425#pragma region Division
430 template<class Lhs, typename LhsData, typename Rhs = LhsData, typename RhsData = Rhs>
432 {
433 static constexpr bool DEFINE_RHS_LHS_OPERATOR = !has_division_operator<Rhs, Lhs, Lhs>::value && !has_division_operator<Rhs, Lhs, Rhs>::value;
434
435 public:
437 {
438 static_assert(std::is_default_constructible<Lhs>::value, "Lhs must have a default constructor");
439 static_assert(std::is_base_of<BufferBase<Lhs, LhsData>, Lhs>::value, "Lhs must derive from BufferBase<Lhs, LhsData>");
440 static_assert(
441 std::is_base_of<BufferBase<Rhs, RhsData>, Rhs>::value || std::is_same<Rhs, RhsData>::value,
442 "Rhs must derive from BufferBase<Rhs, RhsData> or RhsData must be the same type as Rhs"
443 );
444 static_assert(
445 has_division_operator<LhsData, RhsData>::value && has_division_assignment_operator<LhsData, RhsData>::value,
446 "LhsData must have operator/(RhsData) and operator/=(RhsData)"
447 );
448 }
450 BufferDivisionOperator& operator=(const BufferDivisionOperator&) = delete;
451
452 public:
453 friend inline Lhs operator/(const Lhs& lhs, const Rhs& rhs)
454 {
455 return Impl<Rhs, RhsData>(lhs, rhs);
456 }
457
458 friend inline Lhs& operator/=(Lhs& lhs, const Rhs& rhs)
459 {
460 return ImplAssign<Rhs, RhsData>(lhs, rhs);
461 }
462
463 template<typename Ret = Lhs>
464 friend inline typename std::enable_if<DEFINE_RHS_LHS_OPERATOR, Ret>::type operator/(const Rhs& rhs, const Lhs& lhs)
465 {
466 return ImplRhs<Rhs, RhsData>(rhs, lhs);
467 }
468
469 template<typename Ret>
470 friend inline typename std::enable_if<!DEFINE_RHS_LHS_OPERATOR, Ret>::type operator/(const Rhs& rhs, const Lhs& lhs);
471
472 private:
473 template<typename U = Rhs, typename V = RhsData>
474 static inline typename std::enable_if<std::is_same<U, V>::value, Lhs>::type Impl(const Lhs& lhs, const U& rhs)
475 {
476 Lhs result{};
479 {
480 HEPH_RAISE_AND_THROW_EXCEPTION(&lhs, InvalidOperationException(HEPH_FUNC, "BufferOperatorEvents::OnResultCreated event must be handled"));
481 }
483
484 const size_t size = lhs.Size();
485 for (size_t i = 0; i < size; ++i)
486 {
487 result.begin()[i] = lhs.begin()[i] / rhs;
488 }
489 return result;
490 }
491
492 template<typename U = Rhs, typename V = RhsData>
493 static inline typename std::enable_if<DEFINE_RHS_LHS_OPERATOR&& std::is_same<U, V>::value, Lhs>::type ImplRhs(const U& rhs, const Lhs& lhs)
494 {
495 Lhs result{};
498 {
499 HEPH_RAISE_AND_THROW_EXCEPTION(&lhs, InvalidOperationException(HEPH_FUNC, "BufferOperatorEvents::OnResultCreated event must be handled"));
500 }
502
503 const size_t size = lhs.Size();
504 for (size_t i = 0; i < size; ++i)
505 {
506 result.begin()[i] = rhs / lhs.begin()[i];
507 }
508 return result;
509 }
510
511 template<typename U = Rhs, typename V = RhsData>
512 static inline typename std::enable_if<std::is_same<U, V>::value, Lhs&>::type ImplAssign(Lhs& lhs, const U& rhs)
513 {
514 const size_t size = lhs.Size();
515 for (size_t i = 0; i < size; ++i)
516 {
517 lhs.begin()[i] /= rhs;
518 }
519 return lhs;
520 }
521
522 template<typename U = Rhs, typename V = RhsData>
523 static inline typename std::enable_if<std::is_base_of<BufferBase<U, V>, U>::value, Lhs>::type Impl(const Lhs& lhs, const U& rhs)
524 {
525 if (lhs.Size() != rhs.Size())
526 {
527 HEPH_RAISE_AND_THROW_EXCEPTION(&lhs, InvalidArgumentException(HEPH_FUNC, "Both operands must have the same size"));
528 }
529
530 Lhs result{};
533 {
535 "BufferOperatorEvents::OnResultCreated event must be handled"));
536 }
538
539 const size_t size = lhs.Size();
540 for (size_t i = 0; i < size; ++i)
541 {
542 result.begin()[i] = lhs.begin()[i] / rhs.begin()[i];
543 }
544 return result;
545 }
546
547 template<typename U = Rhs, typename V = RhsData>
548 static inline typename std::enable_if<DEFINE_RHS_LHS_OPERATOR&& std::is_base_of<BufferBase<U, V>, U>::value, Lhs>::type ImplRhs(const U& rhs, const Lhs& lhs)
549 {
550 if (lhs.Size() != rhs.Size())
551 {
552 HEPH_RAISE_AND_THROW_EXCEPTION(&lhs, InvalidArgumentException(HEPH_FUNC, "Both operands must have the same size"));
553 }
554
555 Lhs result{};
558 {
560 "BufferOperatorEvents::OnResultCreated event must be handled"));
561 }
563
564 const size_t size = lhs.Size();
565 for (size_t i = 0; i < size; ++i)
566 {
567 result.begin()[i] = rhs.begin()[i] / lhs.begin()[i];
568 }
569 return result;
570 }
571
572 template<typename U = Rhs, typename V = RhsData>
573 static inline typename std::enable_if<std::is_base_of<BufferBase<U, V>, U>::value, Lhs&>::type ImplAssign(Lhs& lhs, const U& rhs)
574 {
575 const size_t minSize = HEPH_MATH_MIN(lhs.Size(), rhs.Size());
576 for (size_t i = 0; i < minSize; ++i)
577 {
578 lhs.begin()[i] /= rhs.begin()[i];
579 }
580 return lhs;
581 }
582 };
583#pragma endregion
584#pragma region Arithmetic
589 template<class Lhs, typename LhsData, typename Rhs = LhsData, typename RhsData = Rhs>
591 public BufferAdditionOperator<Lhs, LhsData, Rhs, RhsData>,
592 public BufferSubtractionOperator<Lhs, LhsData, Rhs, RhsData>,
593 public BufferMultiplicationOperator<Lhs, LhsData, Rhs, RhsData>,
594 public BufferDivisionOperator<Lhs, LhsData, Rhs, RhsData>
595 {
596 public:
597 BufferArithmeticOperators() = default;
599 BufferArithmeticOperators& operator=(const BufferArithmeticOperators&) = delete;
600 };
601#pragma endregion
602#pragma region Unary Minus
607 template<class Lhs, typename LhsData>
609 {
610 public:
612 {
613 static_assert(std::is_default_constructible<Lhs>::value, "Lhs must have a default constructor");
614 static_assert(std::is_base_of<BufferBase<Lhs, LhsData>, Lhs>::value, "Lhs must derive from BufferBase<Lhs, LhsData>");
615 static_assert(has_unary_minus_operator<LhsData>::value, "LhsData must have operator-()");
616 }
618 BufferUnaryMinusOperator& operator=(const BufferUnaryMinusOperator&) = delete;
619
620 public:
621 friend inline Lhs operator-(const Lhs& lhs)
622 {
623 Lhs result{};
626 {
627 HEPH_RAISE_AND_THROW_EXCEPTION(&lhs, InvalidOperationException(HEPH_FUNC, "BufferUnaryMinusOperator::OnResultCreated event must be handled"));
628 }
630
631 const size_t size = lhs.Size();
632 for (size_t i = 0; i < size; ++i)
633 {
634 result.begin()[i] = -lhs.begin()[i];
635 }
636
637 return result;
638 }
639 };
640#pragma endregion
641}
#define HEPH_RAISE_AND_THROW_EXCEPTION(pSender, ex)
Definition Exception.h:27
#define HEPH_MATH_MIN(a, b)
Definition HephMath.h:35
#define HEPH_FUNC
Definition HephShared.h:137
#define HEPH_API
Definition HephShared.h:124
provides + and += operators to the buffer.
Definition BufferOperators.h:43
provides arithmetic operators to the buffer.
Definition BufferOperators.h:595
provides / and /= operators to the buffer.
Definition BufferOperators.h:432
provides * and *= operators to the buffer.
Definition BufferOperators.h:317
provides - and -= operators to the buffer.
Definition BufferOperators.h:158
provides unary minus operator to the buffer.
Definition BufferOperators.h:609
class for managing callback functions.
Definition Event.h:25
raised when an argument passed to a method is invalid.
Definition InvalidArgumentException.h:14
raised when an operation is invalid.
Definition InvalidOperationException.h:14
Definition BufferOperators.h:28
contains the results of the BufferOperatorEvents::OnResultCreated event.
Definition BufferOperators.h:19
base class for storing arguments for an event .
Definition EventArgs.h:13