VCTR
Loading...
Searching...
No Matches
VctrBase.h
1/*
2 ==============================================================================
3 DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
5 Copyright 2022- by sonible GmbH.
6
7 This file is part of VCTR - Versatile Container Templates Reconceptualized.
8
9 VCTR is free software: you can redistribute it and/or modify
10 it under the terms of the GNU Lesser General Public License version 3
11 only, as published by the Free Software Foundation.
12
13 VCTR is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU Lesser General Public License version 3 for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 version 3 along with VCTR. If not, see <https://www.gnu.org/licenses/>.
20 ==============================================================================
21*/
22
23// clang-format off
24// Disable MSVC warning C4324 "structure was padded due to alignment specifier"
25#if VCTR_MSVC
26__pragma (warning (push))
27__pragma (warning (disable : 4324))
28#endif
29// clang-format on
30
31namespace vctr
32{
33
35template <class ElementType, class StorageType, size_t extent, class StorageInfoType = StorageInfo<StorageType>>
36class VctrBase : private Config,
37 private StorageInfoType
38{
39public:
40 //==============================================================================
41 using value_type = std::remove_cv_t<ElementType>;
42
43 //==============================================================================
44 // Retrieving size related information.
45 //==============================================================================
46
47 // clang-format off
48
55 static consteval size_t getExtent (size_t amountToShrink = 0)
56 {
57 return extent == std::dynamic_extent ? std::dynamic_extent : (extent - amountToShrink);
58 }
59
61 [[nodiscard]] constexpr size_t size() const noexcept requires (extent == std::dynamic_extent) { return storage.size(); }
62
64 static constexpr size_t size() noexcept requires (extent != std::dynamic_extent) { return extent; }
65
67 [[nodiscard]] constexpr bool empty() const noexcept { return storage.empty(); }
68
73 [[nodiscard]] constexpr size_t sizeInBytes() const noexcept requires (extent == std::dynamic_extent) { return size() * sizeof (value_type); }
74
79 [[nodiscard]] static constexpr size_t sizeInBytes() noexcept requires (extent != std::dynamic_extent) { return size() * sizeof (value_type); }
80
85 [[nodiscard]] constexpr size_t backIdx() const noexcept requires (extent == std::dynamic_extent) { return size() - 1; }
86
91 static constexpr size_t backIdx() noexcept requires (extent != std::dynamic_extent) { return size() - 1; }
92
93 //==============================================================================
94 // Accessing elements.
95 //==============================================================================
97 constexpr auto& operator[] (size_t i) { VCTR_ASSERT (i < size()); return storage[i]; }
98
100 constexpr auto& operator[] (size_t i) const { VCTR_ASSERT (i < size()); return storage[i]; }
101
103 constexpr auto& at (size_t i) { throwIfOutOfRange (i); return storage[i]; }
104
106 constexpr auto& at (size_t i) const { throwIfOutOfRange (i); return storage[i]; }
107
108 // clang-format on
109
111 constexpr auto&& front() { return storage.front(); }
112
114 constexpr auto&& front() const { return storage.front(); }
115
117 constexpr auto&& back() { return storage[backIdx()]; }
118
120 constexpr auto&& back() const { return storage[backIdx()]; }
121
123 VCTR_FORCEDINLINE constexpr auto* data()
124 {
125 if constexpr (requires { typename RequireConstexpr<StorageInfoType::dataIsSIMDAligned>; } && StorageInfoType::dataIsSIMDAligned)
126 return assumeAlignedToMaxSIMDRegisterSize (storage.data());
127
128 return storage.data();
129 }
130
132 VCTR_FORCEDINLINE constexpr auto* data() const
133 {
134 if constexpr (requires { typename RequireConstexpr<StorageInfoType::dataIsSIMDAligned>; } && StorageInfoType::dataIsSIMDAligned)
135 return assumeAlignedToMaxSIMDRegisterSize (storage.data());
136
137 return storage.data();
138 }
139
141 constexpr auto begin() { return storage.begin(); }
142
144 constexpr auto begin() const { return storage.begin(); }
145
147 constexpr auto end() { return is::stdArray<StorageType> ? storage.begin() + extent : storage.end(); }
148
150 constexpr auto end() const { return is::stdArray<StorageType> ? storage.begin() + extent : storage.end(); }
151
153 constexpr auto rbegin() { return std::reverse_iterator (end()); }
154
156 constexpr auto rbegin() const { return std::reverse_iterator (end()); }
157
159 constexpr auto rend() { return std::reverse_iterator (begin()); }
160
162 constexpr auto rend() const { return std::reverse_iterator (begin()); }
163
164 //==============================================================================
165 // Accessing sub spans.
166 //==============================================================================
172 template <size_t startIdx>
173 constexpr auto subSpan()
174 {
175 assertIsInRange<startIdx>();
176 return constCorrectSpan<getExtent (startIdx)> (data() + startIdx, size() - startIdx);
177 }
178
184 template <size_t startIdx>
185 constexpr auto subSpan() const
186 {
187 assertIsInRange<startIdx>();
188 return constCorrectSpan<getExtent (startIdx)> (data() + startIdx, size() - startIdx);
189 }
190
195 constexpr auto subSpan (size_t startIdx)
196 {
197 VCTR_ASSERT (startIdx < size());
198 return constCorrectSpan<std::dynamic_extent> (data() + startIdx, size() - startIdx);
199 }
200
205 constexpr auto subSpan (size_t startIdx) const
206 {
207 VCTR_ASSERT (startIdx < size());
208 return constCorrectSpan<std::dynamic_extent> (data() + startIdx, size() - startIdx);
209 }
210
215 template <size_t startIdx, size_t numElements>
216 constexpr auto subSpan()
217 {
218 VCTR_ASSERT (int64_t (size()) - int64_t (startIdx) >= int64_t (numElements));
219 return constCorrectSpan<numElements> (data() + startIdx, numElements);
220 }
221
226 template <size_t startIdx, size_t numElements>
227 constexpr auto subSpan() const
228 {
229 VCTR_ASSERT (int64_t (size()) - int64_t (startIdx) >= int64_t (numElements));
230 return constCorrectSpan<numElements> (data() + startIdx, numElements);
231 }
232
237 constexpr auto subSpan (size_t startIdx, size_t numElements)
238 {
239 VCTR_ASSERT (int64_t (size()) - int64_t (startIdx) >= int64_t (numElements));
240 return constCorrectSpan<std::dynamic_extent> (data() + startIdx, numElements);
241 }
242
247 constexpr auto subSpan (size_t startIdx, size_t numElements) const
248 {
249 VCTR_ASSERT (int64_t (size()) - int64_t (startIdx) >= int64_t (numElements));
250 return constCorrectSpan<std::dynamic_extent> (data() + startIdx, numElements);
251 }
252
253 //==============================================================================
254 // Assign data.
255 //==============================================================================
256
262 constexpr void assign (std::initializer_list<ElementType> elements)
263 {
264 if constexpr (has::resize<StorageType>)
265 {
266 storage.resize (elements.size());
267 }
268 else
269 {
270 VCTR_ASSERT (elements.size() == size());
271 }
272
273 std::copy (elements.begin(), elements.end(), begin());
274 }
275
281 constexpr void copyFrom (const ElementType* otherData, size_t otherSize)
283 {
284 resizeOrAssertSizeMatches (otherSize);
285
287 {
288 if (! std::is_constant_evaluated())
289 {
290 std::memcpy (data(), otherData, sizeof (ElementType) * otherSize);
291 return;
292 }
293 }
294
295 std::copy_n (otherData, otherSize, begin());
296 }
297
299 constexpr void fill (const value_type& value) { std::fill (begin(), end(), value); }
300
301 //==============================================================================
302 // Generators
303 //==============================================================================
316 constexpr void fillLinspace (ElementType start, ElementType stop, bool includeEnd = true)
317 requires is::realNumber<ElementType>
318 {
319 const auto num = size();
320
321 VCTR_ASSERT (num > 0);
322 VCTR_ASSERT (! includeEnd || num != 1); // a num-one range cannot include the end
323
324 const auto increment = (stop - start) / double (num - size_t (includeEnd));
325
326#if VCTR_USE_GCEM
327 [[maybe_unused]] const auto isIntegerIncrement = increment - gcem::floor (increment) == ElementType (0);
328#else
329 [[maybe_unused]] const auto isIntegerIncrement = increment - std::floor (increment) == ElementType (0);
330#endif
331 VCTR_ASSERT (std::is_floating_point_v<ElementType> || isIntegerIncrement);
332
333 auto value = double (start);
334
335 for (int i = 0; i < num; ++i)
336 {
337 storage[i] = ElementType (value);
338 value += increment;
339 };
340 }
341
342 //==============================================================================
343 // For each functionality.
344 //==============================================================================
349 template <is::functionWithSignatureOrImplicitlyConvertible<void (value_type&)> Fn>
350 constexpr void forEach (Fn&& fn)
351 {
352 for (auto& e : *this)
353 fn (e);
354 }
355
360 template <is::functionWithSignatureOrImplicitlyConvertible<void (const value_type&)> Fn>
361 constexpr void forEach (Fn&& fn) const
362 {
363 for (const auto& e : *this)
364 fn (e);
365 }
366
371 template <is::functionWithSignatureOrImplicitlyConvertible<value_type (const value_type&)> Fn>
372 constexpr void forEach (Fn&& fn)
373 {
374 for (auto& e : *this)
375 e = fn (e);
376 }
377
382 template <is::functionWithSignatureOrImplicitlyConvertible<void (value_type&, size_t)> Fn>
383 constexpr void forEach (Fn&& fn)
384 {
385 const auto s = size();
386 for (size_t i = 0; i < s; ++i)
387 fn (storage[i], i);
388 }
389
394 template <is::functionWithSignatureOrImplicitlyConvertible<void (const value_type&, size_t)> Fn>
395 constexpr void forEach (Fn&& fn) const
396 {
397 const auto s = size();
398 for (size_t i = 0; i < s; ++i)
399 fn (storage[i], i);
400 }
401
406 template <is::functionWithSignatureOrImplicitlyConvertible<value_type (const value_type&, size_t)> Fn>
407 constexpr void forEach (Fn&& fn)
408 {
409 const auto s = size();
410 for (size_t i = 0; i < s; ++i)
411 storage[i] = fn (storage[i], i);
412 }
413
418 template <class... Args, is::functionWithSignatureOrImplicitlyConvertible<void (value_type&, Args&&...)> Fn>
419 constexpr void forEach (Fn&& fn, Args&&... fnArgs)
420 {
421 for (auto& e : *this)
422 fn (e, std::forward<Args> (fnArgs)...);
423 }
424
429 template <class... Args, is::functionWithSignatureOrImplicitlyConvertible<void (const value_type&, Args&&...)> Fn>
430 constexpr void forEach (Fn&& fn, Args&&... fnArgs) const
431 {
432 for (const auto& e : *this)
433 fn (e, std::forward<Args> (fnArgs)...);
434 }
435
440 template <class... Args, is::functionWithSignatureOrImplicitlyConvertible<value_type (const value_type&, Args&&...)> Fn>
441 constexpr void forEach (Fn&& fn, Args&&... fnArgs)
442 {
443 for (auto& e : *this)
444 e = fn (e, std::forward<Args> (fnArgs)...);
445 }
446
447 //==============================================================================
448 // Finding elements and manipulating them.
449 //==============================================================================
451 template <std::equality_comparable_with<ElementType> T>
452 constexpr auto find (const T& valueToLookFor)
453 {
454 return std::find (begin(), end(), valueToLookFor);
455 }
456
458 template <std::equality_comparable_with<ElementType> T>
459 constexpr auto find (const T& valueToLookFor) const
460 {
461 return std::find (begin(), end(), valueToLookFor);
462 }
463
465 template <std::equality_comparable_with<ElementType> T>
466 constexpr auto findReverse (const T& valueToLookFor)
467 {
468 return std::find (rbegin(), rend(), valueToLookFor);
469 }
470
472 template <std::equality_comparable_with<ElementType> T>
473 constexpr auto findReverse (const T& valueToLookFor) const
474 {
475 return std::find (rbegin(), rend(), valueToLookFor);
476 }
477
479 template <is::functionWithSignatureOrImplicitlyConvertible<bool (const ElementType&)> Fn>
480 constexpr auto findIf (Fn&& predicate)
481 {
482 return std::find_if (begin(), end(), std::forward<Fn> (predicate));
483 }
484
486 template <is::functionWithSignatureOrImplicitlyConvertible<bool (const ElementType&)> Fn>
487 constexpr auto findIf (Fn&& predicate) const
488 {
489 return std::find_if (begin(), end(), std::forward<Fn> (predicate));
490 }
491
493 template <is::functionWithSignatureOrImplicitlyConvertible<bool (const ElementType&)> Fn>
494 constexpr auto findIfReverse (Fn&& predicate)
495 {
496 return std::find_if (rbegin(), rend(), std::forward<Fn> (predicate));
497 }
498
500 template <is::functionWithSignatureOrImplicitlyConvertible<bool (const ElementType&)> Fn>
501 constexpr auto findIfReverse (Fn&& predicate) const
502 {
503 return std::find_if (rbegin(), rend(), std::forward<Fn> (predicate));
504 }
505
507 constexpr size_t count (const ElementType& valueToLookFor) const
508 {
509 return std::count (begin(), end(), valueToLookFor);
510 }
511
513 template <is::functionWithSignatureOrImplicitlyConvertible<bool (const ElementType&)> Fn>
514 constexpr size_t countIf (Fn&& predicate) const
515 {
516 return std::count_if (begin(), end(), std::forward<Fn> (predicate));
517 }
518
520 template <is::functionWithSignatureOrImplicitlyConvertible<bool (const ElementType&)> Fn>
521 constexpr bool all (Fn&& predicate) const
522 {
523 return std::all_of (begin(), end(), std::forward<Fn> (predicate));
524 }
525
527 template <is::functionWithSignatureOrImplicitlyConvertible<bool (const ElementType&)> Fn>
528 constexpr bool any (Fn&& predicate) const
529 {
530 return std::any_of (begin(), end(), std::forward<Fn> (predicate));
531 }
532
534 template <std::equality_comparable_with<ElementType> T>
535 constexpr bool allElementsEqual (const T& value) const
536 {
537 return all ([&] (const auto& e) { return e == value; });
538 }
539
541 [[nodiscard]] constexpr bool allElementsEqual() const
542 requires std::equality_comparable<ElementType>
543 {
544 if (size() < 2)
545 return true;
546
547 return std::all_of (begin() + 1, end(), [&v = storage[0]] (const auto& e) { return v == e; });
548 }
549
551 template <std::equality_comparable_with<ElementType> T>
552 constexpr bool contains (const T& value) const
553 {
554 return find (value) != end();
555 }
556
561 template <is::contiguousIteratorWithValueTypeSameAs<ElementType> It>
562 constexpr bool contains (It it) const
563 {
564 const auto* address = std::to_address (it);
565 const auto* first = std::to_address (begin());
566 const auto* last = std::to_address (end() - 1);
567
568 return address >= first && address <= last;
569 }
570
572 template <std::equality_comparable_with<ElementType> T>
573 constexpr std::optional<size_t> indexOf (const T& value) const
574 {
575 auto it = find (value);
576 return it == end() ? std::nullopt : std::optional<size_t> (std::distance (begin(), it));
577 }
578
580 template <std::equality_comparable_with<ElementType> T>
581 constexpr std::optional<size_t> indexOfReverse (const T& value) const
582 {
583 auto it = findReverse (value);
584 return it == rend() ? std::nullopt : std::optional<size_t> (std::distance (it, rend()) - 1);
585 }
586
588 template <is::functionWithSignatureOrImplicitlyConvertible<bool (const ElementType&)> Fn>
589 constexpr std::optional<size_t> indexIf (Fn&& predicate) const
590 {
591 auto it = findIf (predicate);
592 return it == end() ? std::nullopt : std::optional<size_t> (std::distance (begin(), it));
593 }
594
596 template <is::functionWithSignatureOrImplicitlyConvertible<bool (const ElementType&)> Fn>
597 constexpr std::optional<size_t> indexIfReverse (Fn&& predicate) const
598 {
599 auto it = findIfReverse (predicate);
600 return it == rend() ? std::nullopt : std::optional<size_t> (std::distance (it, rend()) - 1);
601 }
602
608 constexpr std::optional<value_type> firstValueGreaterThanOrEqualTo (const value_type& valueToLookFor) const
609 requires std::totally_ordered<value_type>
610 {
611 VCTR_ASSERT (elementsAreSorted());
612 auto it = std::lower_bound (begin(), end(), valueToLookFor);
613 return it == end() ? std::nullopt : std::optional<value_type> (*it);
614 }
615
621 constexpr std::optional<value_type> firstValueGreaterThan (const value_type& valueToLookFor) const
622 requires std::totally_ordered<value_type>
623 {
624 VCTR_ASSERT (elementsAreSorted());
625 auto it = std::upper_bound (begin(), end(), valueToLookFor);
626 return it == end() ? std::nullopt : std::optional<value_type> (*it);
627 }
628
629 //==============================================================================
630 // Shuffling and sorting elements
631 //==============================================================================
633 constexpr void reverse()
634 {
635 std::reverse (begin(), end());
636 }
637
641 constexpr void rotate (size_t newFirstElementIdx)
642 {
643 VCTR_ASSERT (newFirstElementIdx < size());
644 std::rotate (begin(), begin() + newFirstElementIdx, end());
645 }
646
654 void shiftLeft (size_t n, bool clearFreeSpaceAfterShiftedRegion)
655 requires std::is_trivially_copyable_v<ElementType>
656 {
657 if (n == size())
658 {
659 if (clearFreeSpaceAfterShiftedRegion)
660 clear (data(), size());
661
662 return;
663 }
664
665 VCTR_ASSERT (n < size());
666
667 auto numElementsToMove = size() - n;
668 memMove (data() + n, data(), numElementsToMove);
669
670 if (clearFreeSpaceAfterShiftedRegion)
671 clear (data() + numElementsToMove, n);
672 }
673
681 void shiftRight (size_t n, bool clearFreeSpaceBeforeShiftedRegion)
682 requires std::is_trivially_copyable_v<ElementType>
683 {
684 if (n == size())
685 {
686 if (clearFreeSpaceBeforeShiftedRegion)
687 clear (data(), size());
688
689 return;
690 }
691
692 VCTR_ASSERT (n < size());
693
694 const auto numElementsToMove = size() - n;
695 memMove (data(), data() + n, numElementsToMove);
696
697 if (clearFreeSpaceBeforeShiftedRegion)
698 clear (data(), n);
699 }
700
702 constexpr void sort()
703 requires std::totally_ordered<value_type>
704 {
705 std::sort (begin(), end());
706 }
707
712 template <is::functionWithSignatureOrImplicitlyConvertible<bool (const value_type&, const value_type&)> ComparatorFn>
713 constexpr void sort (ComparatorFn&& compare)
714 {
715 std::sort (begin(), end(), compare);
716 }
717
719 [[nodiscard]] constexpr bool elementsAreSorted() const
720 requires std::totally_ordered<value_type>
721 {
722 return std::is_sorted (begin(), end());
723 }
724
725 //==============================================================================
726 // SIMD Register Access
727 //==============================================================================
729 requires archARM && is::realNumber<ElementType>
730 {
731 VCTR_ASSERT (i % NeonRegister<std::remove_const_t<ElementType>>::numElements == 0);
733 }
734
735 VCTR_TARGET ("avx")
736 AVXRegister<std::remove_const_t<ElementType>> getAVX (size_t i) const
737 requires archX64 && is::realNumber<ElementType>
738 {
739 VCTR_ASSERT (i % AVXRegister<std::remove_const_t<ElementType>>::numElements == 0);
740 if (StorageInfoType::dataIsSIMDAligned)
741 return AVXRegister<std::remove_const_t<ElementType>>::loadAligned (data() + i);
742 else
743 return AVXRegister<std::remove_const_t<ElementType>>::loadUnaligned (data() + i);
744 }
745
746 VCTR_TARGET ("sse4.1")
747 SSERegister<std::remove_const_t<ElementType>> getSSE (size_t i) const
748 requires archX64 && is::realNumber<ElementType>
749 {
750 VCTR_ASSERT (i % SSERegister<std::remove_const_t<ElementType>>::numElements == 0);
751 if (StorageInfoType::dataIsSIMDAligned)
752 return SSERegister<std::remove_const_t<ElementType>>::loadAligned (data() + i);
753 else
754 return SSERegister<std::remove_const_t<ElementType>>::loadUnaligned (data() + i);
755 }
756
757 //==============================================================================
758 // Expression chain related functions
759 //==============================================================================
763 template <is::expressionChainBuilder ExpressionChain>
764 void evalInPlace (const ExpressionChain& expression)
765 {
766 assignExpressionTemplate (expression << *this);
767 }
768
769 constexpr bool isNotAliased (const void*) const { return true; }
770
771 VCTR_FORCEDINLINE const ElementType* evalNextVectorOpInExpressionChain (void*) const { return data(); }
772
773 constexpr const StorageInfoType& getStorageInfo() const { return *this; }
774
775 //==============================================================================
776 // Math operators.
777 //==============================================================================
779 template <is::anyVctrOrExpression V>
780 constexpr void operator*= (const V& v);
781
783 constexpr void operator*= (value_type c);
784
786 template <is::anyVctrOrExpression V>
787 constexpr void operator/= (const V& v);
788
790 constexpr void operator/= (value_type c);
791
811 template <is::anyVctrOrExpression V>
812 constexpr void operator+= (const V& v);
813
815 constexpr void operator+= (value_type c);
816
818 template <is::anyVctrOrExpression V>
819 constexpr void operator-= (const V& v);
820
822 constexpr void operator-= (value_type c);
823
824 //==============================================================================
825 // Math reduction operations.
826 //==============================================================================
828 constexpr ElementType min() const requires std::totally_ordered<ElementType>;
829
831 constexpr ElementType minAbs() const requires is::number<ElementType>;
832
834 constexpr ElementType max() const requires std::totally_ordered<ElementType>;
835
837 constexpr ElementType maxAbs() const requires is::number<ElementType>;
838
840 constexpr ElementType mean() const requires is::number<ElementType>;
841
843 constexpr ElementType meanSquare() const requires is::number<ElementType>;
844
846 constexpr ElementType rms() const requires is::number<ElementType>;
847
849 constexpr ElementType sum() const requires has::operatorPlusEquals<std::remove_cv_t<ElementType>>;
850
851 //==============================================================================
852 // Math sanity checks.
853 //==============================================================================
855 constexpr bool allElementsAreFinite() requires std::floating_point<ElementType>;
856
858 constexpr bool allElementsAreFinite() requires is::complexFloatNumber<ElementType>;
859
861 constexpr bool anyElementIsNaN() requires std::floating_point<ElementType>;
862
864 constexpr bool anyElementIsNaN() requires is::complexFloatNumber<ElementType>;
865
866protected:
867 //==============================================================================
868 constexpr VctrBase()
869 {
870 if constexpr (has::init<StorageInfoType>)
871 StorageInfoType::init (storage.data(), storage.size());
872 }
873
874 constexpr VctrBase (StorageType&& s)
875 : storage (std::move (s))
876 {
877 if constexpr (has::init<StorageInfoType>)
878 StorageInfoType::init (storage.data(), storage.size());
879 }
880
881 template <is::storageInfo OtherStorageInfoType>
882 constexpr VctrBase (StorageType&& s, const OtherStorageInfoType& otherInfo)
883 : StorageInfoType (otherInfo),
884 storage (std::move (s))
885 {}
886
887 //==============================================================================
889 constexpr void resizeOrAssertSizeMatches (size_t desiredSize)
890 requires has::resize<StorageType>
891 {
892 storage.resize (desiredSize);
893 }
894
896 constexpr void resizeOrAssertSizeMatches ([[maybe_unused]] size_t desiredSize) const
897 {
898 VCTR_ASSERT (size() == desiredSize);
899 }
900
902 template <size_t i>
903 constexpr void assertIsInRange() const
904 requires (extent == std::dynamic_extent)
905 {
906 VCTR_ASSERT (i < size());
907 }
908
910 template <size_t i>
911 constexpr void assertIsInRange() const
912 requires (extent != std::dynamic_extent)
913 {
914 static_assert (i < extent);
915 }
916
918 void throwIfOutOfRange (size_t i) const
919 {
920 if (i >= size())
921 {
922 VCTR_ASSERT (false);
923 throw std::out_of_range ("Vctr of size " + std::to_string (size()) + ": Element " + std::to_string (i) + " is out of range.");
924 }
925 }
926
927 //==============================================================================
928 template <is::expression Expression>
929 VCTR_FORCEDINLINE constexpr void assignExpressionTemplate (const Expression& e)
930 {
931 if (! std::is_constant_evaluated())
932 {
933 if constexpr (has::evalNextVectorOpInExpressionChain<Expression, ElementType>)
934 {
935 if (e.isNotAliased (data()))
936 {
937 e.evalNextVectorOpInExpressionChain (data());
938 return;
939 }
940 }
941
942 if constexpr (has::getNeon<Expression>)
943 {
944 assignExpressionTemplateNeon (e);
945 return;
946 }
947
948 if constexpr (has::getAVX<Expression>)
949 {
950 if constexpr (is::realFloatNumber<ElementType>)
951 {
952 if (supportsAVX)
953 {
954 assignExpressionTemplateAVX (e);
955 return;
956 }
957 }
958 else
959 {
960 if (supportsAVX2)
961 {
962 assignExpressionTemplateAVX2 (e);
963 return;
964 }
965 }
966 }
967
968 if constexpr (has::getSSE<Expression>)
969 {
970 if (highestSupportedCPUInstructionSet != CPUInstructionSet::fallback)
971 {
972 assignExpressionTemplateSSE4_1 (e);
973 return;
974 }
975 }
976 }
977
978 const auto n = size();
979
980 for (size_t i = 0; i < n; ++i)
981 storage[i] = e[i];
982 }
983
985 template <class OtherContainer>
986 static constexpr bool shouldMoveFromOtherContainer = has::begin<OtherContainer> &&
987 has::end<OtherContainer> &&
988 (! is::view<OtherContainer>) &&
989 (! std::is_reference_v<OtherContainer>) &&
990 (! std::is_trivially_copyable_v<ElementType>);
991
992 //==============================================================================
993 alignas (StorageInfoType::memberAlignment) StorageType storage = StorageType {};
994
995private:
996 //==============================================================================
997 template <class Expression>
998 void assignExpressionTemplateNeon (const Expression& e)
999 requires archARM
1000 {
1001 constexpr auto inc = NeonRegister<ElementType>::numElements;
1002 const bool hasExtendedSIMDStorage = e.getStorageInfo().hasSIMDExtendedStorage && StorageInfoType::hasSIMDExtendedStorage;
1003 const auto n = storage.size();
1004 const auto nSIMD = hasExtendedSIMDStorage ? detail::nextMultipleOf<inc> (n) : detail::previousMultipleOf<inc> (n);
1005
1006 auto* d = data();
1007
1008 size_t i = 0;
1009 for (; i < nSIMD; i += inc, d += inc)
1010 e.getNeon (i).store (d);
1011
1012 for (; i < n; ++i, ++d)
1013 storage[i] = e[i];
1014 }
1015
1016 template <class Expression>
1017 VCTR_TARGET ("avx2")
1018 void assignExpressionTemplateAVX2 (const Expression& e)
1019 requires archX64
1020 {
1021 constexpr auto inc = AVXRegister<ElementType>::numElements;
1022 const bool hasExtendedSIMDStorage = e.getStorageInfo().hasSIMDExtendedStorage && StorageInfoType::hasSIMDExtendedStorage;
1023 const auto n = storage.size();
1024 const auto nSIMD = hasExtendedSIMDStorage ? detail::nextMultipleOf<inc> (n) : detail::previousMultipleOf<inc> (n);
1025
1026 auto* d = data();
1027
1028 if (StorageInfoType::dataIsSIMDAligned)
1029 {
1030 size_t i = 0;
1031 for (; i < nSIMD; i += inc, d += inc)
1032 e.getAVX (i).storeAligned (d);
1033
1034 for (; i < n; ++i, ++d)
1035 storage[i] = e[i];
1036 }
1037 else
1038 {
1039 size_t i = 0;
1040 for (; i < nSIMD; i += inc, d += inc)
1041 e.getAVX (i).storeUnaligned (d);
1042
1043 for (; i < n; ++i, ++d)
1044 storage[i] = e[i];
1045 }
1046 }
1047
1048 template <class Expression>
1049 VCTR_TARGET ("avx")
1050 void assignExpressionTemplateAVX (const Expression& e)
1051 requires archX64
1052 {
1053 constexpr auto inc = AVXRegister<ElementType>::numElements;
1054 const bool hasExtendedSIMDStorage = e.getStorageInfo().hasSIMDExtendedStorage && StorageInfoType::hasSIMDExtendedStorage;
1055 const auto n = storage.size();
1056 const auto nSIMD = hasExtendedSIMDStorage ? detail::nextMultipleOf<inc> (n) : detail::previousMultipleOf<inc> (n);
1057
1058 auto* d = data();
1059
1060 if (StorageInfoType::dataIsSIMDAligned)
1061 {
1062 size_t i = 0;
1063 for (; i < nSIMD; i += inc, d += inc)
1064 e.getAVX (i).storeAligned (d);
1065
1066 for (; i < n; ++i, ++d)
1067 storage[i] = e[i];
1068 }
1069 else
1070 {
1071 size_t i = 0;
1072 for (; i < nSIMD; i += inc, d += inc)
1073 e.getAVX (i).storeUnaligned (d);
1074
1075 for (; i < n; ++i, ++d)
1076 storage[i] = e[i];
1077 }
1078 }
1079
1080 template <class Expression>
1081 VCTR_TARGET ("sse4.1")
1082 void assignExpressionTemplateSSE4_1 (const Expression& e)
1083 requires archX64
1084 {
1085 constexpr auto inc = SSERegister<ElementType>::numElements;
1086 const bool hasExtendedSIMDStorage = e.getStorageInfo().hasSIMDExtendedStorage && StorageInfoType::hasSIMDExtendedStorage;
1087 const auto n = storage.size();
1088 const auto nSIMD = hasExtendedSIMDStorage ? detail::nextMultipleOf<inc> (n) : detail::previousMultipleOf<inc> (n);
1089
1090 auto* d = data();
1091
1092 if (StorageInfoType::dataIsSIMDAligned)
1093 {
1094 size_t i = 0;
1095 for (; i < nSIMD; i += inc, d += inc)
1096 e.getSSE (i).storeAligned (d);
1097
1098 for (; i < n; ++i, ++d)
1099 storage[i] = e[i];
1100 }
1101 else
1102 {
1103 size_t i = 0;
1104 for (; i < nSIMD; i += inc, d += inc)
1105 e.getSSE (i).storeUnaligned (d);
1106
1107 for (; i < n; ++i, ++d)
1108 storage[i] = e[i];
1109 }
1110 }
1111
1112 //==============================================================================
1113 template <size_t spanExtent>
1114 constexpr auto constCorrectSpan (ElementType* data, size_t spanSize);
1115
1116 template <size_t spanExtent>
1117 constexpr auto constCorrectSpan (const ElementType* data, size_t spanSize) const
1118 requires (! is::stdSpan<StorageType>);
1119
1120 template <size_t spanExtent>
1121 constexpr auto constCorrectSpan (ElementType* data, size_t spanSize) const
1122 requires is::stdSpan<StorageType>;
1123
1124 //==============================================================================
1126 static void clear (ElementType* ptr, size_t numElements)
1127 {
1128 std::memset (ptr, 0, numElements * sizeof (ElementType));
1129 }
1130
1132 static void memMove (const ElementType* src, ElementType* dst, size_t numElements)
1133 requires std::is_trivially_copyable_v<ElementType>
1134 {
1135 std::memmove (dst, src, numElements * sizeof (ElementType));
1136 }
1137
1139 template <class T>
1140 VCTR_FORCEDINLINE constexpr static T* assumeAlignedToMaxSIMDRegisterSize (T* ptr)
1141 {
1142 if (std::is_constant_evaluated())
1143 return ptr;
1144
1145 #if __cpp_lib_assume_aligned
1146 return std::assume_aligned<maxSIMDRegisterSize> (ptr);
1147 #elif VCTR_CLANG
1148 return static_cast<T*> (__builtin_assume_aligned (ptr, maxSIMDRegisterSize));
1149 #else
1150 return ptr;
1151 #endif
1152 }
1153};
1154
1160template <is::anyVctr Lhs, is::anyVctr Rhs>
1161requires std::same_as<ValueType<Lhs>, ValueType<Rhs>>
1162constexpr bool operator== (const Lhs& lhs, const Rhs& rhs)
1163{
1164 return std::equal (lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
1165}
1166
1167} // namespace vctr
1168
1169#if VCTR_MSVC
1170__pragma (warning (pop))
1171#endif
The base class to all one dimensional containers and views in the VCTR project.
Definition: VctrBase.h:38
void shiftRight(size_t n, bool clearFreeSpaceBeforeShiftedRegion)
Shifts all elements to the right by n.
Definition: VctrBase.h:681
constexpr size_t count(const ElementType &valueToLookFor) const
Returns the number of elements that are equal to valueToLookFor.
Definition: VctrBase.h:507
constexpr bool contains(It it) const
Returns true if the iterator refers to an element inside this container or span.
Definition: VctrBase.h:562
constexpr void sort(ComparatorFn &&compare)
Sorts all elements in this vector according to the compare function.
Definition: VctrBase.h:713
static consteval size_t getExtent(size_t amountToShrink=0)
Returns the extent of this instance, optionally shrank by a certain amount.
Definition: VctrBase.h:55
constexpr size_t size() const noexcept
Returns the number of elements.
Definition: VctrBase.h:61
constexpr auto findReverse(const T &valueToLookFor)
Returns a reverse iterator to the last element in this vector that equals valueToLookFor or rend() if...
Definition: VctrBase.h:466
constexpr std::optional< size_t > indexIfReverse(Fn &&predicate) const
Returns the index of the last element that satisfies the predicate or std::nullopt if none is found.
Definition: VctrBase.h:597
constexpr void fillLinspace(ElementType start, ElementType stop, bool includeEnd=true)
Fills the vector with evenly spaced numbers between start and stop.
Definition: VctrBase.h:316
constexpr void rotate(size_t newFirstElementIdx)
Rotates the elements so that the element with the index newFirstElementIdx becomes the first element ...
Definition: VctrBase.h:641
constexpr void forEach(Fn &&fn) const
Calls a function on each element.
Definition: VctrBase.h:361
constexpr auto subSpan() const
Returns a Span that views a portion of this instance, starting at startIdx with a length of numElemen...
Definition: VctrBase.h:227
constexpr auto subSpan()
Returns a Span that views a portion of this instance, starting at startIdx with a length of size() - ...
Definition: VctrBase.h:173
constexpr auto subSpan(size_t startIdx) const
Returns a Span that views a portion of this instance, starting at startIdx with a length of size() - ...
Definition: VctrBase.h:205
VCTR_FORCEDINLINE constexpr auto * data() const
Returns a raw pointer to the underlying storage.
Definition: VctrBase.h:132
constexpr void operator-=(const V &v)
Subtracts a vector or expression from this in place.
constexpr void operator+=(const V &v)
Adds a vector or expression to this in place.
constexpr ElementType min() const
Returns the minimal value of all elements.
constexpr auto find(const T &valueToLookFor)
Returns an iterator to the first element that equals valueToLookFor or end() if none was found.
Definition: VctrBase.h:452
constexpr void operator/=(const V &v)
Divides this by a vector or expression in place.
constexpr auto find(const T &valueToLookFor) const
Returns a const iterator to the first element that equals valueToLookFor or end() if none was found.
Definition: VctrBase.h:459
static constexpr size_t sizeInBytes() noexcept
Returns the container size in bytes.
Definition: VctrBase.h:79
constexpr bool all(Fn &&predicate) const
Returns true if all elements satisfy the predicate or if the container is empty.
Definition: VctrBase.h:521
constexpr auto begin()
Returns an iterator to the begin of the storage.
Definition: VctrBase.h:141
constexpr std::optional< size_t > indexOfReverse(const T &value) const
Returns the index of the last element that compares true to value or std::nullopt if none is found.
Definition: VctrBase.h:581
constexpr auto subSpan(size_t startIdx, size_t numElements) const
Returns a Span that views a portion of this instance, starting at startIdx with a length of numElemen...
Definition: VctrBase.h:247
constexpr void assign(std::initializer_list< ElementType > elements)
Assigns elements from the initializer list to this instance.
Definition: VctrBase.h:262
constexpr ElementType maxAbs() const
Returns the maximum absolute value of all elements.
constexpr size_t countIf(Fn &&predicate) const
Returns the number of elements that satisfy predicate.
Definition: VctrBase.h:514
constexpr auto subSpan(size_t startIdx, size_t numElements)
Returns a Span that views a portion of this instance, starting at startIdx with a length of numElemen...
Definition: VctrBase.h:237
constexpr void sort()
Sorts all elements in an ascending order using operator <=>.
Definition: VctrBase.h:702
constexpr void forEach(Fn &&fn, Args &&... fnArgs)
Calls a function on each element and forwards fnArgs to the function after the value.
Definition: VctrBase.h:419
constexpr size_t sizeInBytes() const noexcept
Returns the container size in bytes.
Definition: VctrBase.h:73
constexpr auto findReverse(const T &valueToLookFor) const
Returns a const reverse iterator to the last element in this vector that equals valueToLookFor or ren...
Definition: VctrBase.h:473
constexpr void copyFrom(const ElementType *otherData, size_t otherSize)
Copies the content from otherData to this instance.
Definition: VctrBase.h:281
VCTR_FORCEDINLINE constexpr auto * data()
Returns a raw pointer to the underlying storage.
Definition: VctrBase.h:123
constexpr bool anyElementIsNaN()
Returns true if any element is NaN.
static constexpr size_t backIdx() noexcept
Returns the index referring to the last element in the vector.
Definition: VctrBase.h:91
constexpr auto subSpan()
Returns a Span that views a portion of this instance, starting at startIdx with a length of numElemen...
Definition: VctrBase.h:216
NeonRegister< std::remove_const_t< ElementType > > getNeon(size_t i) const &&is
Evaluates a certain expression in place on this vector, e.g.
Definition: VctrBase.h:728
constexpr void forEach(Fn &&fn)
Calls a function on each element.
Definition: VctrBase.h:350
constexpr std::optional< size_t > indexOf(const T &value) const
Returns the index of the first element that compares true to value or std::nullopt if none is found.
Definition: VctrBase.h:573
constexpr auto findIf(Fn &&predicate)
Returns an iterator to the first element in this vector for which predicate returns true or end() if ...
Definition: VctrBase.h:480
constexpr auto subSpan() const
Returns a Span that views a portion of this instance, starting at startIdx with a length of size() - ...
Definition: VctrBase.h:185
constexpr auto end() const
Returns a const iterator to the first element behind the storage.
Definition: VctrBase.h:150
constexpr auto subSpan(size_t startIdx)
Returns a Span that views a portion of this instance, starting at startIdx with a length of size() - ...
Definition: VctrBase.h:195
constexpr auto & at(size_t i) const
Returns a reference to element i.
Definition: VctrBase.h:106
constexpr auto findIfReverse(Fn &&predicate) const
Returns a const reverse iterator to the last element in this vector for which predicate returns true ...
Definition: VctrBase.h:501
constexpr auto && front() const
Returns a reference to the first element.
Definition: VctrBase.h:114
constexpr ElementType rms() const
Returns the square root of the mean value across all squared elements.
constexpr auto findIfReverse(Fn &&predicate)
Returns a reverse iterator to the last element in this vector for which predicate returns true or ren...
Definition: VctrBase.h:494
constexpr void reverse()
Reverses the order of all elements.
Definition: VctrBase.h:633
constexpr bool allElementsEqual() const
Returns true if all elements are equal to themselves.
Definition: VctrBase.h:541
constexpr std::optional< value_type > firstValueGreaterThan(const value_type &valueToLookFor) const
Returns a std::optional holding a copy of the first element value which is greater than valueToLookFo...
Definition: VctrBase.h:621
constexpr auto && front()
Returns a reference to the first element.
Definition: VctrBase.h:111
constexpr bool allElementsAreFinite()
Returns true if all elements are finite.
constexpr auto rend() const
Returns a const reverse iterator to the element before the first element in the storage.
Definition: VctrBase.h:162
constexpr auto & operator[](size_t i)
Returns a reference to element i.
Definition: VctrBase.h:97
constexpr auto && back()
Returns a reference to the last element.
Definition: VctrBase.h:117
constexpr bool allElementsEqual(const T &value) const
Returns true if all elements are equal to value or if the container is empty.
Definition: VctrBase.h:535
constexpr bool elementsAreSorted() const
Returns true if all elements are sorted.
Definition: VctrBase.h:719
constexpr size_t backIdx() const noexcept
Returns the index referring to the last element in the vector.
Definition: VctrBase.h:85
constexpr std::optional< value_type > firstValueGreaterThanOrEqualTo(const value_type &valueToLookFor) const
Returns a std::optional holding a copy of the first element value which is greater or equal to valueT...
Definition: VctrBase.h:608
constexpr ElementType minAbs() const
Returns the minimal absolute value of all elements.
constexpr ElementType max() const
Returns the maximum value of all elements.
constexpr auto findIf(Fn &&predicate) const
Returns a const iterator to the first element in this vector for which predicate returns true or end(...
Definition: VctrBase.h:487
constexpr void forEach(Fn &&fn, Args &&... fnArgs) const
Calls a function on each element and forwards fnArgs to the function after the value.
Definition: VctrBase.h:430
constexpr auto rend()
Returns a reverse iterator to the element before the first element in the storage.
Definition: VctrBase.h:159
constexpr auto & at(size_t i)
Returns a reference to element i.
Definition: VctrBase.h:103
constexpr bool empty() const noexcept
Checks whether the container is empty.
Definition: VctrBase.h:67
constexpr void fill(const value_type &value)
Fills the container with the given value.
Definition: VctrBase.h:299
constexpr ElementType mean() const
Returns the mean value across all elements.
constexpr bool any(Fn &&predicate) const
Returns true if one or more elements satisfy the predicate.
Definition: VctrBase.h:528
constexpr ElementType sum() const
Returns the sum of all elements.
constexpr auto && back() const
Returns a reference to the last element.
Definition: VctrBase.h:120
constexpr auto begin() const
Returns a const iterator to the begin of the storage.
Definition: VctrBase.h:144
constexpr auto end()
Returns an iterator to the first element behind the storage.
Definition: VctrBase.h:147
constexpr ElementType meanSquare() const
Returns the mean value across all squared elements.
static constexpr size_t size() noexcept
Returns the number of elements.
Definition: VctrBase.h:64
constexpr bool contains(const T &value) const
Returns true if at least one element is equal to value.
Definition: VctrBase.h:552
constexpr std::optional< size_t > indexIf(Fn &&predicate) const
Returns the index of the first element that satisfies the predicate or std::nullopt if none is found.
Definition: VctrBase.h:589
void shiftLeft(size_t n, bool clearFreeSpaceAfterShiftedRegion)
Shifts all elements to the left by n.
Definition: VctrBase.h:654
constexpr auto rbegin() const
Returns a const reverse iterator to the last element in the storage.
Definition: VctrBase.h:156
constexpr void operator*=(const V &v)
Multiplies this by a vector or expression in place.
constexpr auto rbegin()
Returns a reverse iterator to the last element in the storage.
Definition: VctrBase.h:153
Constrains the type to have a member function init that takes a void pointer and a size_t.
Definition: GenericConcepts.h:32
Constrains a type to have a function resize (size_t).
Definition: ContainerAndExpressionConcepts.h:146
Constrains Fn to be a function with the specified function signature or some signature with implicitl...
Definition: FunctionConcepts.h:89
Constrains a type to be non const.
Definition: GenericConcepts.h:88
Constrains a type to represent a real valued number.
Definition: NumericTypeConcepts.h:75
Constrains a type to be any instance of std::array.
Definition: ContainerAndExpressionConcepts.h:216
Constrains a type to be trivially copyable.
Definition: GenericConcepts.h:84
The main namespace of the VCTR project.
Definition: Array.h:24
typename detail::StorageInfoType< std::remove_cvref_t< T > >::Type StorageInfoType
If t is a type derived from VctrBase, this will equal the return value of T::getStorageInfo,...
Definition: Traits.h:227
constexpr bool operator==(const Lhs &lhs, const Rhs &rhs)
Compares lhs and rhs for equality.
Definition: VctrBase.h:1162
Definition: AVXRegister.h:28
Definition: Config.h:290
Definition: NeonRegister.h:28
A helper struct intended to check if a value is a constexpr.
Definition: Traits.h:279