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 (startIdx < size());
219 VCTR_ASSERT (startIdx + numElements <= size());
220 return constCorrectSpan<numElements> (data() + startIdx, numElements);
221 }
222
227 template <size_t startIdx, size_t numElements>
228 constexpr auto subSpan() const
229 {
230 VCTR_ASSERT (startIdx < size());
231 VCTR_ASSERT (startIdx + numElements <= size());
232 return constCorrectSpan<numElements> (data() + startIdx, numElements);
233 }
234
239 constexpr auto subSpan (size_t startIdx, size_t numElements)
240 {
241 VCTR_ASSERT (startIdx < size());
242 VCTR_ASSERT (startIdx + numElements <= size());
243 return constCorrectSpan<std::dynamic_extent> (data() + startIdx, numElements);
244 }
245
250 constexpr auto subSpan (size_t startIdx, size_t numElements) const
251 {
252 VCTR_ASSERT (startIdx < size());
253 VCTR_ASSERT (startIdx + numElements <= size());
254 return constCorrectSpan<std::dynamic_extent> (data() + startIdx, numElements);
255 }
256
257 //==============================================================================
258 // Assign data.
259 //==============================================================================
260
266 constexpr void assign (std::initializer_list<ElementType> elements)
267 {
268 if constexpr (has::resize<StorageType>)
269 {
270 storage.resize (elements.size());
271 }
272 else
273 {
274 VCTR_ASSERT (elements.size() == size());
275 }
276
277 std::copy (elements.begin(), elements.end(), begin());
278 }
279
285 constexpr void copyFrom (const ElementType* otherData, size_t otherSize)
287 {
288 resizeOrAssertSizeMatches (otherSize);
289
291 {
292 if (! std::is_constant_evaluated())
293 {
294 std::memcpy (data(), otherData, sizeof (ElementType) * otherSize);
295 return;
296 }
297 }
298
299 std::copy_n (otherData, otherSize, begin());
300 }
301
303 constexpr void fill (const value_type& value) { std::fill (begin(), end(), value); }
304
305 //==============================================================================
306 // Generators
307 //==============================================================================
320 constexpr void fillLinspace (ElementType start, ElementType stop, bool includeEnd = true)
321 requires is::realNumber<ElementType>
322 {
323 const auto num = size();
324
325 VCTR_ASSERT (num > 0);
326 VCTR_ASSERT (! includeEnd || num != 1); // a num-one range cannot include the end
327
328 const auto increment = (stop - start) / double (num - size_t (includeEnd));
329
330#if VCTR_USE_GCEM
331 [[maybe_unused]] const auto isIntegerIncrement = increment - gcem::floor (increment) == ElementType (0);
332#else
333 [[maybe_unused]] const auto isIntegerIncrement = increment - std::floor (increment) == ElementType (0);
334#endif
335 VCTR_ASSERT (std::is_floating_point_v<ElementType> || isIntegerIncrement);
336
337 auto value = double (start);
338
339 for (int i = 0; i < num; ++i)
340 {
341 storage[i] = ElementType (value);
342 value += increment;
343 };
344 }
345
346 //==============================================================================
347 // For each functionality.
348 //==============================================================================
353 template <is::functionWithSignatureOrImplicitlyConvertible<void (value_type&)> Fn>
354 constexpr void forEach (Fn&& fn)
355 {
356 for (auto& e : *this)
357 fn (e);
358 }
359
364 template <is::functionWithSignatureOrImplicitlyConvertible<void (const value_type&)> Fn>
365 constexpr void forEach (Fn&& fn) const
366 {
367 for (const auto& e : *this)
368 fn (e);
369 }
370
375 template <is::functionWithSignatureOrImplicitlyConvertible<value_type (const value_type&)> Fn>
376 constexpr void forEach (Fn&& fn)
377 {
378 for (auto& e : *this)
379 e = fn (e);
380 }
381
386 template <is::functionWithSignatureOrImplicitlyConvertible<void (value_type&, size_t)> Fn>
387 constexpr void forEach (Fn&& fn)
388 {
389 const auto s = size();
390 for (size_t i = 0; i < s; ++i)
391 fn (storage[i], i);
392 }
393
398 template <is::functionWithSignatureOrImplicitlyConvertible<void (const value_type&, size_t)> Fn>
399 constexpr void forEach (Fn&& fn) const
400 {
401 const auto s = size();
402 for (size_t i = 0; i < s; ++i)
403 fn (storage[i], i);
404 }
405
410 template <is::functionWithSignatureOrImplicitlyConvertible<value_type (const value_type&, size_t)> Fn>
411 constexpr void forEach (Fn&& fn)
412 {
413 const auto s = size();
414 for (size_t i = 0; i < s; ++i)
415 storage[i] = fn (storage[i], i);
416 }
417
422 template <class... Args, is::functionWithSignatureOrImplicitlyConvertible<void (value_type&, Args&&...)> Fn>
423 constexpr void forEach (Fn&& fn, Args&&... fnArgs)
424 {
425 for (auto& e : *this)
426 fn (e, std::forward<Args> (fnArgs)...);
427 }
428
433 template <class... Args, is::functionWithSignatureOrImplicitlyConvertible<void (const value_type&, Args&&...)> Fn>
434 constexpr void forEach (Fn&& fn, Args&&... fnArgs) const
435 {
436 for (const auto& e : *this)
437 fn (e, std::forward<Args> (fnArgs)...);
438 }
439
444 template <class... Args, is::functionWithSignatureOrImplicitlyConvertible<value_type (const value_type&, Args&&...)> Fn>
445 constexpr void forEach (Fn&& fn, Args&&... fnArgs)
446 {
447 for (auto& e : *this)
448 e = fn (e, std::forward<Args> (fnArgs)...);
449 }
450
451 //==============================================================================
452 // Finding elements and manipulating them.
453 //==============================================================================
455 template <std::equality_comparable_with<ElementType> T>
456 constexpr auto find (const T& valueToLookFor)
457 {
458 return std::find (begin(), end(), valueToLookFor);
459 }
460
462 template <std::equality_comparable_with<ElementType> T>
463 constexpr auto find (const T& valueToLookFor) const
464 {
465 return std::find (begin(), end(), valueToLookFor);
466 }
467
469 template <std::equality_comparable_with<ElementType> T>
470 constexpr auto findReverse (const T& valueToLookFor)
471 {
472 return std::find (rbegin(), rend(), valueToLookFor);
473 }
474
476 template <std::equality_comparable_with<ElementType> T>
477 constexpr auto findReverse (const T& valueToLookFor) const
478 {
479 return std::find (rbegin(), rend(), valueToLookFor);
480 }
481
483 template <is::functionWithSignatureOrImplicitlyConvertible<bool (const ElementType&)> Fn>
484 constexpr auto findIf (Fn&& predicate)
485 {
486 return std::find_if (begin(), end(), std::forward<Fn> (predicate));
487 }
488
490 template <is::functionWithSignatureOrImplicitlyConvertible<bool (const ElementType&)> Fn>
491 constexpr auto findIf (Fn&& predicate) const
492 {
493 return std::find_if (begin(), end(), std::forward<Fn> (predicate));
494 }
495
497 template <is::functionWithSignatureOrImplicitlyConvertible<bool (const ElementType&)> Fn>
498 constexpr auto findIfReverse (Fn&& predicate)
499 {
500 return std::find_if (rbegin(), rend(), std::forward<Fn> (predicate));
501 }
502
504 template <is::functionWithSignatureOrImplicitlyConvertible<bool (const ElementType&)> Fn>
505 constexpr auto findIfReverse (Fn&& predicate) const
506 {
507 return std::find_if (rbegin(), rend(), std::forward<Fn> (predicate));
508 }
509
511 constexpr size_t count (const ElementType& valueToLookFor) const
512 {
513 return std::count (begin(), end(), valueToLookFor);
514 }
515
517 template <is::functionWithSignatureOrImplicitlyConvertible<bool (const ElementType&)> Fn>
518 constexpr size_t countIf (Fn&& predicate) const
519 {
520 return std::count_if (begin(), end(), std::forward<Fn> (predicate));
521 }
522
524 template <is::functionWithSignatureOrImplicitlyConvertible<bool (const ElementType&)> Fn>
525 constexpr bool all (Fn&& predicate) const
526 {
527 return std::all_of (begin(), end(), std::forward<Fn> (predicate));
528 }
529
531 template <is::functionWithSignatureOrImplicitlyConvertible<bool (const ElementType&)> Fn>
532 constexpr bool any (Fn&& predicate) const
533 {
534 return std::any_of (begin(), end(), std::forward<Fn> (predicate));
535 }
536
538 template <std::equality_comparable_with<ElementType> T>
539 constexpr bool allElementsEqual (const T& value) const
540 {
541 return all ([&] (const auto& e) { return e == value; });
542 }
543
545 [[nodiscard]] constexpr bool allElementsEqual() const
546 requires std::equality_comparable<ElementType>
547 {
548 if (size() < 2)
549 return true;
550
551 return std::all_of (begin() + 1, end(), [&v = storage[0]] (const auto& e) { return v == e; });
552 }
553
555 template <std::equality_comparable_with<ElementType> T>
556 constexpr bool contains (const T& value) const
557 {
558 return find (value) != end();
559 }
560
565 template <is::contiguousIteratorWithValueTypeSameAs<ElementType> It>
566 constexpr bool contains (It it) const
567 {
568 const auto* address = std::to_address (it);
569 const auto* first = std::to_address (begin());
570 const auto* last = std::to_address (end() - 1);
571
572 return address >= first && address <= last;
573 }
574
576 template <std::equality_comparable_with<ElementType> T>
577 constexpr std::optional<size_t> indexOf (const T& value) const
578 {
579 auto it = find (value);
580 return it == end() ? std::nullopt : std::optional<size_t> (std::distance (begin(), it));
581 }
582
584 template <std::equality_comparable_with<ElementType> T>
585 constexpr std::optional<size_t> indexOfReverse (const T& value) const
586 {
587 auto it = findReverse (value);
588 return it == rend() ? std::nullopt : std::optional<size_t> (std::distance (it, rend()) - 1);
589 }
590
592 template <is::functionWithSignatureOrImplicitlyConvertible<bool (const ElementType&)> Fn>
593 constexpr std::optional<size_t> indexIf (Fn&& predicate) const
594 {
595 auto it = findIf (predicate);
596 return it == end() ? std::nullopt : std::optional<size_t> (std::distance (begin(), it));
597 }
598
600 template <is::functionWithSignatureOrImplicitlyConvertible<bool (const ElementType&)> Fn>
601 constexpr std::optional<size_t> indexIfReverse (Fn&& predicate) const
602 {
603 auto it = findIfReverse (predicate);
604 return it == rend() ? std::nullopt : std::optional<size_t> (std::distance (it, rend()) - 1);
605 }
606
612 [[nodiscard]] auto findMaxElement()
613 requires std::totally_ordered<value_type>
614 {
615 return std::max_element (begin(), end());
616 }
617
623 [[nodiscard]] auto findMaxElement() const
624 requires std::totally_ordered<value_type>
625 {
626 return std::max_element (begin(), end());
627 }
628
634 [[nodiscard]] auto findMinElement()
635 requires std::totally_ordered<value_type>
636 {
637 return std::min_element (begin(), end());
638 }
639
645 [[nodiscard]] auto findMinElement() const
646 requires std::totally_ordered<value_type>
647 {
648 return std::min_element (begin(), end());
649 }
650
652 [[nodiscard]] size_t indexOfMaxElement() const
653 requires std::totally_ordered<value_type>
654 {
655 return std::distance (begin(), findMaxElement());
656 }
657
659 [[nodiscard]] size_t indexOfMinElement() const
660 requires std::totally_ordered<value_type>
661 {
662 return std::distance (begin(), findMinElement());
663 }
664
670 constexpr std::optional<value_type> firstValueGreaterThanOrEqualTo (const value_type& valueToLookFor) const
671 requires std::totally_ordered<value_type>
672 {
673 VCTR_ASSERT (elementsAreSorted());
674 auto it = std::lower_bound (begin(), end(), valueToLookFor);
675 return it == end() ? std::nullopt : std::optional<value_type> (*it);
676 }
677
683 constexpr std::optional<value_type> firstValueGreaterThan (const value_type& valueToLookFor) const
684 requires std::totally_ordered<value_type>
685 {
686 VCTR_ASSERT (elementsAreSorted());
687 auto it = std::upper_bound (begin(), end(), valueToLookFor);
688 return it == end() ? std::nullopt : std::optional<value_type> (*it);
689 }
690
691 //==============================================================================
692 // Shuffling and sorting elements
693 //==============================================================================
695 constexpr void reverse()
696 {
697 std::reverse (begin(), end());
698 }
699
703 constexpr void rotate (size_t newFirstElementIdx)
704 {
705 VCTR_ASSERT (newFirstElementIdx < size());
706 std::rotate (begin(), begin() + newFirstElementIdx, end());
707 }
708
716 void shiftLeft (size_t n, bool clearFreeSpaceAfterShiftedRegion)
717 requires std::is_trivially_copyable_v<ElementType>
718 {
719 if (n == size())
720 {
721 if (clearFreeSpaceAfterShiftedRegion)
722 clear (data(), size());
723
724 return;
725 }
726
727 VCTR_ASSERT (n < size());
728
729 auto numElementsToMove = size() - n;
730 memMove (data() + n, data(), numElementsToMove);
731
732 if (clearFreeSpaceAfterShiftedRegion)
733 clear (data() + numElementsToMove, n);
734 }
735
743 void shiftRight (size_t n, bool clearFreeSpaceBeforeShiftedRegion)
744 requires std::is_trivially_copyable_v<ElementType>
745 {
746 if (n == size())
747 {
748 if (clearFreeSpaceBeforeShiftedRegion)
749 clear (data(), size());
750
751 return;
752 }
753
754 VCTR_ASSERT (n < size());
755
756 const auto numElementsToMove = size() - n;
757 memMove (data(), data() + n, numElementsToMove);
758
759 if (clearFreeSpaceBeforeShiftedRegion)
760 clear (data(), n);
761 }
762
764 constexpr void sort()
765 requires std::totally_ordered<value_type>
766 {
767 std::sort (begin(), end());
768 }
769
774 template <is::functionWithSignatureOrImplicitlyConvertible<bool (const value_type&, const value_type&)> ComparatorFn>
775 constexpr void sort (ComparatorFn&& compare)
776 {
777 std::sort (begin(), end(), compare);
778 }
779
781 [[nodiscard]] constexpr bool elementsAreSorted() const
782 requires std::totally_ordered<value_type>
783 {
784 return std::is_sorted (begin(), end());
785 }
786
787 //==============================================================================
788 // SIMD Register Access
789 //==============================================================================
790 void prepareNeonEvaluation() const {}
791
793 requires archARM && is::realNumber<ElementType>
794 {
795 VCTR_ASSERT (i % NeonRegister<std::remove_const_t<ElementType>>::numElements == 0);
797 }
798
799 void prepareAVXEvaluation() const {}
800
801 VCTR_TARGET ("avx")
802 AVXRegister<std::remove_const_t<ElementType>> getAVX (size_t i) const
803 requires archX64 && is::realNumber<ElementType>
804 {
805 VCTR_ASSERT (i % AVXRegister<std::remove_const_t<ElementType>>::numElements == 0);
806 if (StorageInfoType::dataIsSIMDAligned)
807 return AVXRegister<std::remove_const_t<ElementType>>::loadAligned (data() + i);
808 else
809 return AVXRegister<std::remove_const_t<ElementType>>::loadUnaligned (data() + i);
810 }
811
812 void prepareSSEEvaluation() const {}
813
814 VCTR_TARGET ("sse4.1")
815 SSERegister<std::remove_const_t<ElementType>> getSSE (size_t i) const
816 requires archX64 && is::realNumber<ElementType>
817 {
818 VCTR_ASSERT (i % SSERegister<std::remove_const_t<ElementType>>::numElements == 0);
819 if (StorageInfoType::dataIsSIMDAligned)
820 return SSERegister<std::remove_const_t<ElementType>>::loadAligned (data() + i);
821 else
822 return SSERegister<std::remove_const_t<ElementType>>::loadUnaligned (data() + i);
823 }
824
825 //==============================================================================
826 // Expression chain related functions
827 //==============================================================================
831 template <is::expressionChainBuilder ExpressionChain>
832 void evalInPlace (const ExpressionChain& expression)
833 {
834 assignExpressionTemplate (expression << *this);
835 }
836
837 constexpr bool isNotAliased (const void*) const { return true; }
838
839 VCTR_FORCEDINLINE const ElementType* evalNextVectorOpInExpressionChain (void*) const { return data(); }
840
841 constexpr const StorageInfoType& getStorageInfo() const { return *this; }
842
843 //==============================================================================
844 // Math operators.
845 //==============================================================================
847 template <is::anyVctrOrExpression V>
848 constexpr void operator*= (const V& v);
849
851 constexpr void operator*= (value_type c);
852
854 template <is::anyVctrOrExpression V>
855 constexpr void operator/= (const V& v);
856
858 constexpr void operator/= (value_type c);
859
879 template <is::anyVctrOrExpression V>
880 constexpr void operator+= (const V& v);
881
883 constexpr void operator+= (value_type c);
884
886 template <is::anyVctrOrExpression V>
887 constexpr void operator-= (const V& v);
888
890 constexpr void operator-= (value_type c);
891
892 //==============================================================================
893 // Math reduction operations.
894 //==============================================================================
896 constexpr ElementType min() const requires std::totally_ordered<ElementType>;
897
899 constexpr ElementType minAbs() const requires is::number<ElementType>;
900
902 constexpr ElementType max() const requires std::totally_ordered<ElementType>;
903
905 constexpr ElementType maxAbs() const requires is::number<ElementType>;
906
908 constexpr ElementType mean() const requires is::number<ElementType>;
909
911 constexpr ElementType meanSquare() const requires is::number<ElementType>;
912
914 constexpr ElementType rms() const requires is::number<ElementType>;
915
917 constexpr ElementType sum() const requires has::operatorPlusEquals<std::remove_cv_t<ElementType>>;
918
919 //==============================================================================
920 // Math sanity checks.
921 //==============================================================================
923 constexpr bool allElementsAreFinite() requires std::floating_point<ElementType>;
924
926 constexpr bool allElementsAreFinite() requires is::complexFloatNumber<ElementType>;
927
929 constexpr bool anyElementIsNaN() requires std::floating_point<ElementType>;
930
932 constexpr bool anyElementIsNaN() requires is::complexFloatNumber<ElementType>;
933
934protected:
935 //==============================================================================
936 constexpr VctrBase()
937 {
938 if constexpr (has::init<StorageInfoType>)
939 StorageInfoType::init (storage.data(), storage.size());
940 }
941
942 constexpr VctrBase (StorageType&& s)
943 : storage (std::move (s))
944 {
945 if constexpr (has::init<StorageInfoType>)
946 StorageInfoType::init (storage.data(), storage.size());
947 }
948
949 template <is::storageInfo OtherStorageInfoType>
950 constexpr VctrBase (StorageType&& s, const OtherStorageInfoType& otherInfo)
951 : StorageInfoType (otherInfo),
952 storage (std::move (s))
953 {}
954
955 //==============================================================================
957 constexpr void resizeOrAssertSizeMatches (size_t desiredSize)
958 requires has::resize<StorageType>
959 {
960 storage.resize (desiredSize);
961 }
962
964 constexpr void resizeOrAssertSizeMatches ([[maybe_unused]] size_t desiredSize) const
965 {
966 VCTR_ASSERT (size() == desiredSize);
967 }
968
970 template <size_t i>
971 constexpr void assertIsInRange() const
972 requires (extent == std::dynamic_extent)
973 {
974 VCTR_ASSERT (i < size());
975 }
976
978 template <size_t i>
979 constexpr void assertIsInRange() const
980 requires (extent != std::dynamic_extent)
981 {
982 static_assert (i < extent);
983 }
984
986 void throwIfOutOfRange (size_t i) const
987 {
988 if (i >= size())
989 {
990 VCTR_ASSERT (false);
991 throw std::out_of_range ("Vctr of size " + std::to_string (size()) + ": Element " + std::to_string (i) + " is out of range.");
992 }
993 }
994
995 //==============================================================================
996 template <is::expression Expression>
997 VCTR_FORCEDINLINE constexpr void assignExpressionTemplate (const Expression& e)
998 {
999 if (! std::is_constant_evaluated())
1000 {
1001 if constexpr (has::evalNextVectorOpInExpressionChain<Expression, ElementType>)
1002 {
1003 if (e.isNotAliased (data()))
1004 {
1005 e.evalNextVectorOpInExpressionChain (data());
1006 return;
1007 }
1008 }
1009
1010 if constexpr (has::getNeon<Expression>)
1011 {
1012 assignExpressionTemplateNeon (e);
1013 return;
1014 }
1015
1016 if constexpr (has::getAVX<Expression>)
1017 {
1018 if constexpr (is::realFloatNumber<ElementType>)
1019 {
1020 if (supportedCPUInstructionSets.fma)
1021 {
1022 assignExpressionTemplateFMA (e);
1023 return;
1024 }
1025 }
1026 else
1027 {
1028 if (supportedCPUInstructionSets.avx2)
1029 {
1030 assignExpressionTemplateAVX2 (e);
1031 return;
1032 }
1033 }
1034 }
1035
1036 if constexpr (has::getSSE<Expression>)
1037 {
1038 if (supportedCPUInstructionSets.sse4_1)
1039 {
1040 assignExpressionTemplateSSE4_1 (e);
1041 return;
1042 }
1043 }
1044 }
1045
1046 const auto n = size();
1047
1048 for (size_t i = 0; i < n; ++i)
1049 storage[i] = e[i];
1050 }
1051
1053 template <class OtherContainer>
1054 static constexpr bool shouldMoveFromOtherContainer = has::begin<OtherContainer> &&
1055 has::end<OtherContainer> &&
1056 (! is::view<OtherContainer>) &&
1057 (! std::is_reference_v<OtherContainer>) &&
1058 (! std::is_trivially_copyable_v<ElementType>);
1059
1060 //==============================================================================
1061 alignas (StorageInfoType::memberAlignment) StorageType storage = StorageType {};
1062
1063private:
1064 //==============================================================================
1065 template <class Expression>
1066 void assignExpressionTemplateNeon (const Expression& e)
1067 requires archARM
1068 {
1069 constexpr auto inc = NeonRegister<ElementType>::numElements;
1070 const bool hasExtendedSIMDStorage = e.getStorageInfo().hasSIMDExtendedStorage && StorageInfoType::hasSIMDExtendedStorage;
1071 const auto n = storage.size();
1072 const auto nSIMD = hasExtendedSIMDStorage ? detail::nextMultipleOf<inc> (n) : detail::previousMultipleOf<inc> (n);
1073
1074 e.prepareNeonEvaluation();
1075 auto* d = data();
1076
1077 size_t i = 0;
1078 for (; i < nSIMD; i += inc, d += inc)
1079 e.getNeon (i).store (d);
1080
1081 for (; i < n; ++i, ++d)
1082 storage[i] = e[i];
1083 }
1084
1085 template <class Expression>
1086 VCTR_TARGET ("avx2")
1087 void assignExpressionTemplateAVX2 (const Expression& e)
1088 requires archX64
1089 {
1090 constexpr auto inc = AVXRegister<ElementType>::numElements;
1091 const bool hasExtendedSIMDStorage = e.getStorageInfo().hasSIMDExtendedStorage && StorageInfoType::hasSIMDExtendedStorage;
1092 const auto n = storage.size();
1093 const auto nSIMD = hasExtendedSIMDStorage ? detail::nextMultipleOf<inc> (n) : detail::previousMultipleOf<inc> (n);
1094
1095 e.prepareAVXEvaluation();
1096 auto* d = data();
1097
1098 if (StorageInfoType::dataIsSIMDAligned)
1099 {
1100 size_t i = 0;
1101 for (; i < nSIMD; i += inc, d += inc)
1102 e.getAVX (i).storeAligned (d);
1103
1104 for (; i < n; ++i, ++d)
1105 storage[i] = e[i];
1106 }
1107 else
1108 {
1109 size_t i = 0;
1110 for (; i < nSIMD; i += inc, d += inc)
1111 e.getAVX (i).storeUnaligned (d);
1112
1113 for (; i < n; ++i, ++d)
1114 storage[i] = e[i];
1115 }
1116 }
1117
1118 template <class Expression>
1119 VCTR_TARGET ("fma")
1120 void assignExpressionTemplateFMA (const Expression& e)
1121 requires archX64
1122 {
1123 constexpr auto inc = AVXRegister<ElementType>::numElements;
1124 const bool hasExtendedSIMDStorage = e.getStorageInfo().hasSIMDExtendedStorage && StorageInfoType::hasSIMDExtendedStorage;
1125 const auto n = storage.size();
1126 const auto nSIMD = hasExtendedSIMDStorage ? detail::nextMultipleOf<inc> (n) : detail::previousMultipleOf<inc> (n);
1127
1128 e.prepareAVXEvaluation();
1129 auto* d = data();
1130
1131 if (StorageInfoType::dataIsSIMDAligned)
1132 {
1133 size_t i = 0;
1134 for (; i < nSIMD; i += inc, d += inc)
1135 e.getAVX (i).storeAligned (d);
1136
1137 for (; i < n; ++i, ++d)
1138 storage[i] = e[i];
1139 }
1140 else
1141 {
1142 size_t i = 0;
1143 for (; i < nSIMD; i += inc, d += inc)
1144 e.getAVX (i).storeUnaligned (d);
1145
1146 for (; i < n; ++i, ++d)
1147 storage[i] = e[i];
1148 }
1149 }
1150
1151 template <class Expression>
1152 VCTR_TARGET ("sse4.1")
1153 void assignExpressionTemplateSSE4_1 (const Expression& e)
1154 requires archX64
1155 {
1156 constexpr auto inc = SSERegister<ElementType>::numElements;
1157 const bool hasExtendedSIMDStorage = e.getStorageInfo().hasSIMDExtendedStorage && StorageInfoType::hasSIMDExtendedStorage;
1158 const auto n = storage.size();
1159 const auto nSIMD = hasExtendedSIMDStorage ? detail::nextMultipleOf<inc> (n) : detail::previousMultipleOf<inc> (n);
1160
1161 e.prepareSSEEvaluation();
1162 auto* d = data();
1163
1164 if (StorageInfoType::dataIsSIMDAligned)
1165 {
1166 size_t i = 0;
1167 for (; i < nSIMD; i += inc, d += inc)
1168 e.getSSE (i).storeAligned (d);
1169
1170 for (; i < n; ++i, ++d)
1171 storage[i] = e[i];
1172 }
1173 else
1174 {
1175 size_t i = 0;
1176 for (; i < nSIMD; i += inc, d += inc)
1177 e.getSSE (i).storeUnaligned (d);
1178
1179 for (; i < n; ++i, ++d)
1180 storage[i] = e[i];
1181 }
1182 }
1183
1184 //==============================================================================
1185 template <size_t spanExtent>
1186 constexpr auto constCorrectSpan (ElementType* data, size_t spanSize);
1187
1188 template <size_t spanExtent>
1189 constexpr auto constCorrectSpan (const ElementType* data, size_t spanSize) const
1190 requires (! is::stdSpan<StorageType>);
1191
1192 template <size_t spanExtent>
1193 constexpr auto constCorrectSpan (ElementType* data, size_t spanSize) const
1194 requires is::stdSpan<StorageType>;
1195
1196 //==============================================================================
1198 static void clear (ElementType* ptr, size_t numElements)
1199 {
1200 std::memset (ptr, 0, numElements * sizeof (ElementType));
1201 }
1202
1204 static void memMove (const ElementType* src, ElementType* dst, size_t numElements)
1205 requires std::is_trivially_copyable_v<ElementType>
1206 {
1207 std::memmove (dst, src, numElements * sizeof (ElementType));
1208 }
1209
1211 template <class T>
1212 VCTR_FORCEDINLINE constexpr static T* assumeAlignedToMaxSIMDRegisterSize (T* ptr)
1213 {
1214 if (std::is_constant_evaluated())
1215 return ptr;
1216
1217 #if __cpp_lib_assume_aligned
1218 return std::assume_aligned<maxSIMDRegisterSize> (ptr);
1219 #elif VCTR_CLANG
1220 return static_cast<T*> (__builtin_assume_aligned (ptr, maxSIMDRegisterSize));
1221 #else
1222 return ptr;
1223 #endif
1224 }
1225};
1226
1232template <is::anyVctr Lhs, is::anyVctr Rhs>
1233requires std::same_as<ValueType<Lhs>, ValueType<Rhs>>
1234constexpr bool operator== (const Lhs& lhs, const Rhs& rhs)
1235{
1236 return std::equal (lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
1237}
1238
1239} // namespace vctr
1240
1241#if VCTR_MSVC
1242__pragma (warning (pop))
1243#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:743
auto findMaxElement() const
Returns an iterator to the first greatest element.
Definition: VctrBase.h:623
constexpr size_t count(const ElementType &valueToLookFor) const
Returns the number of elements that are equal to valueToLookFor.
Definition: VctrBase.h:511
auto findMaxElement()
Returns an iterator to the first greatest element.
Definition: VctrBase.h:612
constexpr bool contains(It it) const
Returns true if the iterator refers to an element inside this container or span.
Definition: VctrBase.h:566
constexpr void sort(ComparatorFn &&compare)
Sorts all elements in this vector according to the compare function.
Definition: VctrBase.h:775
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:470
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:601
constexpr void fillLinspace(ElementType start, ElementType stop, bool includeEnd=true)
Fills the vector with evenly spaced numbers between start and stop.
Definition: VctrBase.h:320
constexpr void rotate(size_t newFirstElementIdx)
Rotates the elements so that the element with the index newFirstElementIdx becomes the first element ...
Definition: VctrBase.h:703
constexpr void forEach(Fn &&fn) const
Calls a function on each element.
Definition: VctrBase.h:365
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:228
auto findMinElement()
Returns an iterator to the first smallest element.
Definition: VctrBase.h:634
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:456
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:463
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:525
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:585
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:250
constexpr void assign(std::initializer_list< ElementType > elements)
Assigns elements from the initializer list to this instance.
Definition: VctrBase.h:266
size_t indexOfMinElement() const
Returns the index of the first smallest element (aka argMin).
Definition: VctrBase.h:659
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:518
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:239
constexpr void sort()
Sorts all elements in an ascending order using operator <=>.
Definition: VctrBase.h:764
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:423
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:477
constexpr void copyFrom(const ElementType *otherData, size_t otherSize)
Copies the content from otherData to this instance.
Definition: VctrBase.h:285
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:792
constexpr void forEach(Fn &&fn)
Calls a function on each element.
Definition: VctrBase.h:354
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:577
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:484
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:505
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:498
constexpr void reverse()
Reverses the order of all elements.
Definition: VctrBase.h:695
constexpr bool allElementsEqual() const
Returns true if all elements are equal to themselves.
Definition: VctrBase.h:545
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:683
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:539
constexpr bool elementsAreSorted() const
Returns true if all elements are sorted.
Definition: VctrBase.h:781
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:670
size_t indexOfMaxElement() const
Returns the index of the first greatest element (aka argMax).
Definition: VctrBase.h:652
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:491
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:434
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:303
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:532
constexpr ElementType sum() const
Returns the sum of all elements.
auto findMinElement() const
Returns an iterator to the first smallest element.
Definition: VctrBase.h:645
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:556
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:593
void shiftLeft(size_t n, bool clearFreeSpaceAfterShiftedRegion)
Shifts all elements to the left by n.
Definition: VctrBase.h:716
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:164
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:79
Constrains a type to be any instance of std::array.
Definition: ContainerAndExpressionConcepts.h:234
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:1234
Definition: Config.h:298
Definition: NeonRegister.h:28
A helper struct intended to check if a value is a constexpr.
Definition: Traits.h:300