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 assertIsInRangeIncludingEnd<startIdx>();
176 return constCorrectSpan<getExtent (startIdx)> (data() + startIdx, size() - startIdx);
177 }
178
184 template <size_t startIdx>
185 constexpr auto subSpan() const
186 {
187 assertIsInRangeIncludingEnd<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 + numElements <= size());
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 (startIdx + numElements <= size());
230 return constCorrectSpan<numElements> (data() + startIdx, numElements);
231 }
232
237 constexpr auto subSpan (size_t startIdx, size_t numElements)
238 {
239 VCTR_ASSERT (startIdx + numElements <= size());
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 (startIdx < size());
250 VCTR_ASSERT (startIdx + numElements <= size());
251 return constCorrectSpan<std::dynamic_extent> (data() + startIdx, numElements);
252 }
253
254 //==============================================================================
255 // Assign data.
256 //==============================================================================
257
263 constexpr void assign (std::initializer_list<ElementType> elements)
264 {
265 if constexpr (has::resize<StorageType>)
266 {
267 storage.resize (elements.size());
268 }
269 else
270 {
271 VCTR_ASSERT (elements.size() == size());
272 }
273
274 std::copy (elements.begin(), elements.end(), begin());
275 }
276
282 constexpr void copyFrom (const ElementType* otherData, size_t otherSize)
284 {
285 resizeOrAssertSizeMatches (otherSize);
286
288 {
289 if (! std::is_constant_evaluated())
290 {
291 std::memcpy (data(), otherData, sizeof (ElementType) * otherSize);
292 return;
293 }
294 }
295
296 std::copy_n (otherData, otherSize, begin());
297 }
298
300 constexpr void fill (const value_type& value) { std::fill (begin(), end(), value); }
301
302 //==============================================================================
303 // Generators
304 //==============================================================================
317 constexpr void fillLinspace (ElementType start, ElementType stop, bool includeEnd = true)
318 requires is::realNumber<ElementType>
319 {
320 const auto num = size();
321
322 VCTR_ASSERT (num > 0);
323 VCTR_ASSERT (! includeEnd || num != 1); // a num-one range cannot include the end
324
325 const auto increment = (stop - start) / double (num - size_t (includeEnd));
326
327#if VCTR_USE_GCEM
328 [[maybe_unused]] const auto isIntegerIncrement = increment - gcem::floor (increment) == ElementType (0);
329#else
330 [[maybe_unused]] const auto isIntegerIncrement = increment - std::floor (increment) == ElementType (0);
331#endif
332 VCTR_ASSERT (std::is_floating_point_v<ElementType> || isIntegerIncrement);
333
334 auto value = double (start);
335
336 for (int i = 0; i < num; ++i)
337 {
338 storage[i] = ElementType (value);
339 value += increment;
340 };
341 }
342
343 //==============================================================================
344 // For each functionality.
345 //==============================================================================
350 template <is::functionWithSignatureOrImplicitlyConvertible<void (value_type&)> Fn>
351 constexpr void forEach (Fn&& fn)
352 {
353 for (auto& e : *this)
354 fn (e);
355 }
356
361 template <is::functionWithSignatureOrImplicitlyConvertible<void (const value_type&)> Fn>
362 constexpr void forEach (Fn&& fn) const
363 {
364 for (const auto& e : *this)
365 fn (e);
366 }
367
372 template <is::functionWithSignatureOrImplicitlyConvertible<value_type (const value_type&)> Fn>
373 constexpr void forEach (Fn&& fn)
374 {
375 for (auto& e : *this)
376 e = fn (e);
377 }
378
383 template <is::functionWithSignatureOrImplicitlyConvertible<void (value_type&, size_t)> Fn>
384 constexpr void forEach (Fn&& fn)
385 {
386 const auto s = size();
387 for (size_t i = 0; i < s; ++i)
388 fn (storage[i], i);
389 }
390
395 template <is::functionWithSignatureOrImplicitlyConvertible<void (const value_type&, size_t)> Fn>
396 constexpr void forEach (Fn&& fn) const
397 {
398 const auto s = size();
399 for (size_t i = 0; i < s; ++i)
400 fn (storage[i], i);
401 }
402
407 template <is::functionWithSignatureOrImplicitlyConvertible<value_type (const value_type&, size_t)> Fn>
408 constexpr void forEach (Fn&& fn)
409 {
410 const auto s = size();
411 for (size_t i = 0; i < s; ++i)
412 storage[i] = fn (storage[i], i);
413 }
414
419 template <class... Args, is::functionWithSignatureOrImplicitlyConvertible<void (value_type&, Args&&...)> Fn>
420 constexpr void forEach (Fn&& fn, Args&&... fnArgs)
421 {
422 for (auto& e : *this)
423 fn (e, std::forward<Args> (fnArgs)...);
424 }
425
430 template <class... Args, is::functionWithSignatureOrImplicitlyConvertible<void (const value_type&, Args&&...)> Fn>
431 constexpr void forEach (Fn&& fn, Args&&... fnArgs) const
432 {
433 for (const auto& e : *this)
434 fn (e, std::forward<Args> (fnArgs)...);
435 }
436
441 template <class... Args, is::functionWithSignatureOrImplicitlyConvertible<value_type (const value_type&, Args&&...)> Fn>
442 constexpr void forEach (Fn&& fn, Args&&... fnArgs)
443 {
444 for (auto& e : *this)
445 e = fn (e, std::forward<Args> (fnArgs)...);
446 }
447
448 //==============================================================================
449 // Finding elements and manipulating them.
450 //==============================================================================
452 template <std::equality_comparable_with<ElementType> T>
453 constexpr auto find (const T& valueToLookFor)
454 {
455 return std::find (begin(), end(), valueToLookFor);
456 }
457
459 template <std::equality_comparable_with<ElementType> T>
460 constexpr auto find (const T& valueToLookFor) const
461 {
462 return std::find (begin(), end(), valueToLookFor);
463 }
464
466 template <std::equality_comparable_with<ElementType> T>
467 constexpr auto findReverse (const T& valueToLookFor)
468 {
469 return std::find (rbegin(), rend(), valueToLookFor);
470 }
471
473 template <std::equality_comparable_with<ElementType> T>
474 constexpr auto findReverse (const T& valueToLookFor) const
475 {
476 return std::find (rbegin(), rend(), valueToLookFor);
477 }
478
480 template <is::functionWithSignatureOrImplicitlyConvertible<bool (const ElementType&)> Fn>
481 constexpr auto findIf (Fn&& predicate)
482 {
483 return std::find_if (begin(), end(), std::forward<Fn> (predicate));
484 }
485
487 template <is::functionWithSignatureOrImplicitlyConvertible<bool (const ElementType&)> Fn>
488 constexpr auto findIf (Fn&& predicate) const
489 {
490 return std::find_if (begin(), end(), std::forward<Fn> (predicate));
491 }
492
494 template <is::functionWithSignatureOrImplicitlyConvertible<bool (const ElementType&)> Fn>
495 constexpr auto findIfReverse (Fn&& predicate)
496 {
497 return std::find_if (rbegin(), rend(), std::forward<Fn> (predicate));
498 }
499
501 template <is::functionWithSignatureOrImplicitlyConvertible<bool (const ElementType&)> Fn>
502 constexpr auto findIfReverse (Fn&& predicate) const
503 {
504 return std::find_if (rbegin(), rend(), std::forward<Fn> (predicate));
505 }
506
508 constexpr size_t count (const ElementType& valueToLookFor) const
509 {
510 return std::count (begin(), end(), valueToLookFor);
511 }
512
514 template <is::functionWithSignatureOrImplicitlyConvertible<bool (const ElementType&)> Fn>
515 constexpr size_t countIf (Fn&& predicate) const
516 {
517 return std::count_if (begin(), end(), std::forward<Fn> (predicate));
518 }
519
521 template <is::functionWithSignatureOrImplicitlyConvertible<bool (const ElementType&)> Fn>
522 constexpr bool all (Fn&& predicate) const
523 {
524 return std::all_of (begin(), end(), std::forward<Fn> (predicate));
525 }
526
528 template <is::functionWithSignatureOrImplicitlyConvertible<bool (const ElementType&)> Fn>
529 constexpr bool any (Fn&& predicate) const
530 {
531 return std::any_of (begin(), end(), std::forward<Fn> (predicate));
532 }
533
535 template <std::equality_comparable_with<ElementType> T>
536 constexpr bool allElementsEqual (const T& value) const
537 {
538 return all ([&] (const auto& e) { return e == value; });
539 }
540
542 [[nodiscard]] constexpr bool allElementsEqual() const
543 requires std::equality_comparable<ElementType>
544 {
545 if (size() < 2)
546 return true;
547
548 return std::all_of (begin() + 1, end(), [&v = storage[0]] (const auto& e) { return v == e; });
549 }
550
552 template <std::equality_comparable_with<ElementType> T>
553 constexpr bool contains (const T& value) const
554 {
555 return find (value) != end();
556 }
557
562 template <is::contiguousIteratorWithValueTypeSameAs<ElementType> It>
563 constexpr bool contains (It it) const
564 {
565 const auto* address = std::to_address (it);
566 const auto* first = std::to_address (begin());
567 const auto* last = std::to_address (end() - 1);
568
569 return address >= first && address <= last;
570 }
571
573 template <std::equality_comparable_with<ElementType> T>
574 constexpr std::optional<size_t> indexOf (const T& value) const
575 {
576 auto it = find (value);
577 return it == end() ? std::nullopt : std::optional<size_t> (std::distance (begin(), it));
578 }
579
581 template <std::equality_comparable_with<ElementType> T>
582 constexpr std::optional<size_t> indexOfReverse (const T& value) const
583 {
584 auto it = findReverse (value);
585 return it == rend() ? std::nullopt : std::optional<size_t> (std::distance (it, rend()) - 1);
586 }
587
589 template <is::functionWithSignatureOrImplicitlyConvertible<bool (const ElementType&)> Fn>
590 constexpr std::optional<size_t> indexIf (Fn&& predicate) const
591 {
592 auto it = findIf (predicate);
593 return it == end() ? std::nullopt : std::optional<size_t> (std::distance (begin(), it));
594 }
595
597 template <is::functionWithSignatureOrImplicitlyConvertible<bool (const ElementType&)> Fn>
598 constexpr std::optional<size_t> indexIfReverse (Fn&& predicate) const
599 {
600 auto it = findIfReverse (predicate);
601 return it == rend() ? std::nullopt : std::optional<size_t> (std::distance (it, rend()) - 1);
602 }
603
609 [[nodiscard]] auto findMaxElement()
610 requires std::totally_ordered<value_type>
611 {
612 return std::max_element (begin(), end());
613 }
614
620 [[nodiscard]] auto findMaxElement() const
621 requires std::totally_ordered<value_type>
622 {
623 return std::max_element (begin(), end());
624 }
625
631 [[nodiscard]] auto findMinElement()
632 requires std::totally_ordered<value_type>
633 {
634 return std::min_element (begin(), end());
635 }
636
642 [[nodiscard]] auto findMinElement() const
643 requires std::totally_ordered<value_type>
644 {
645 return std::min_element (begin(), end());
646 }
647
649 [[nodiscard]] size_t indexOfMaxElement() const
650 requires std::totally_ordered<value_type>
651 {
652 return std::distance (begin(), findMaxElement());
653 }
654
656 [[nodiscard]] size_t indexOfMinElement() const
657 requires std::totally_ordered<value_type>
658 {
659 return std::distance (begin(), findMinElement());
660 }
661
667 constexpr std::optional<value_type> firstValueGreaterThanOrEqualTo (const value_type& valueToLookFor) const
668 requires std::totally_ordered<value_type>
669 {
670 VCTR_ASSERT (elementsAreSorted());
671 auto it = std::lower_bound (begin(), end(), valueToLookFor);
672 return it == end() ? std::nullopt : std::optional<value_type> (*it);
673 }
674
680 constexpr std::optional<value_type> firstValueGreaterThan (const value_type& valueToLookFor) const
681 requires std::totally_ordered<value_type>
682 {
683 VCTR_ASSERT (elementsAreSorted());
684 auto it = std::upper_bound (begin(), end(), valueToLookFor);
685 return it == end() ? std::nullopt : std::optional<value_type> (*it);
686 }
687
688 //==============================================================================
689 // Shuffling and sorting elements
690 //==============================================================================
692 constexpr void reverse()
693 {
694 std::reverse (begin(), end());
695 }
696
700 constexpr void rotate (size_t newFirstElementIdx)
701 {
702 VCTR_ASSERT (newFirstElementIdx < size());
703 std::rotate (begin(), begin() + newFirstElementIdx, end());
704 }
705
713 void shiftLeft (size_t n, bool clearFreeSpaceAfterShiftedRegion)
714 requires std::is_trivially_copyable_v<ElementType>
715 {
716 if (n == size())
717 {
718 if (clearFreeSpaceAfterShiftedRegion)
719 clear (data(), size());
720
721 return;
722 }
723
724 VCTR_ASSERT (n < size());
725
726 auto numElementsToMove = size() - n;
727 memMove (data() + n, data(), numElementsToMove);
728
729 if (clearFreeSpaceAfterShiftedRegion)
730 clear (data() + numElementsToMove, n);
731 }
732
740 void shiftRight (size_t n, bool clearFreeSpaceBeforeShiftedRegion)
741 requires std::is_trivially_copyable_v<ElementType>
742 {
743 if (n == size())
744 {
745 if (clearFreeSpaceBeforeShiftedRegion)
746 clear (data(), size());
747
748 return;
749 }
750
751 VCTR_ASSERT (n < size());
752
753 const auto numElementsToMove = size() - n;
754 memMove (data(), data() + n, numElementsToMove);
755
756 if (clearFreeSpaceBeforeShiftedRegion)
757 clear (data(), n);
758 }
759
761 constexpr void sort()
762 requires std::totally_ordered<value_type>
763 {
764 std::sort (begin(), end());
765 }
766
771 template <is::functionWithSignatureOrImplicitlyConvertible<bool (const value_type&, const value_type&)> ComparatorFn>
772 constexpr void sort (ComparatorFn&& compare)
773 {
774 std::sort (begin(), end(), compare);
775 }
776
778 [[nodiscard]] constexpr bool elementsAreSorted() const
779 requires std::totally_ordered<value_type>
780 {
781 return std::is_sorted (begin(), end());
782 }
783
784 //==============================================================================
785 // SIMD Register Access
786 //==============================================================================
787 void prepareNeonEvaluation() const {}
788
790 requires archARM && is::realNumber<ElementType>
791 {
792 VCTR_ASSERT (i % NeonRegister<std::remove_const_t<ElementType>>::numElements == 0);
794 }
795
796 void prepareAVXEvaluation() const {}
797
798 VCTR_TARGET ("avx")
799 AVXRegister<std::remove_const_t<ElementType>> getAVX (size_t i) const
800 requires archX64 && is::realNumber<ElementType>
801 {
802 VCTR_ASSERT (i % AVXRegister<std::remove_const_t<ElementType>>::numElements == 0);
803 if (StorageInfoType::dataIsSIMDAligned)
804 return AVXRegister<std::remove_const_t<ElementType>>::loadAligned (data() + i);
805 else
806 return AVXRegister<std::remove_const_t<ElementType>>::loadUnaligned (data() + i);
807 }
808
809 void prepareSSEEvaluation() const {}
810
811 VCTR_TARGET ("sse4.1")
812 SSERegister<std::remove_const_t<ElementType>> getSSE (size_t i) const
813 requires archX64 && is::realNumber<ElementType>
814 {
815 VCTR_ASSERT (i % SSERegister<std::remove_const_t<ElementType>>::numElements == 0);
816 if (StorageInfoType::dataIsSIMDAligned)
817 return SSERegister<std::remove_const_t<ElementType>>::loadAligned (data() + i);
818 else
819 return SSERegister<std::remove_const_t<ElementType>>::loadUnaligned (data() + i);
820 }
821
822 //==============================================================================
823 // Expression chain related functions
824 //==============================================================================
828 template <is::expressionChainBuilder ExpressionChain>
829 void evalInPlace (const ExpressionChain& expression)
830 {
831 assignExpressionTemplate (expression << *this);
832 }
833
834 constexpr bool isNotAliased (const void*) const { return true; }
835
836 VCTR_FORCEDINLINE const ElementType* evalNextVectorOpInExpressionChain (void*) const { return data(); }
837
838 constexpr const StorageInfoType& getStorageInfo() const { return *this; }
839
840 //==============================================================================
841 // Math operators.
842 //==============================================================================
844 template <is::anyVctrOrExpression V>
845 constexpr void operator*= (const V& v);
846
848 constexpr void operator*= (value_type c);
849
851 template <is::anyVctrOrExpression V>
852 constexpr void operator/= (const V& v);
853
855 constexpr void operator/= (value_type c);
856
876 template <is::anyVctrOrExpression V>
877 constexpr void operator+= (const V& v);
878
880 constexpr void operator+= (value_type c);
881
883 template <is::anyVctrOrExpression V>
884 constexpr void operator-= (const V& v);
885
887 constexpr void operator-= (value_type c);
888
889 //==============================================================================
890 // Math reduction operations.
891 //==============================================================================
893 constexpr ElementType min() const requires std::totally_ordered<ElementType>;
894
896 constexpr ElementType minAbs() const requires is::number<ElementType>;
897
899 constexpr ElementType max() const requires std::totally_ordered<ElementType>;
900
902 constexpr ElementType maxAbs() const requires is::number<ElementType>;
903
905 constexpr ElementType mean() const requires is::number<ElementType>;
906
908 constexpr ElementType meanSquare() const requires is::number<ElementType>;
909
911 constexpr ElementType rms() const requires is::number<ElementType>;
912
914 constexpr ElementType sum() const requires has::operatorPlusEquals<std::remove_cv_t<ElementType>>;
915
916 //==============================================================================
917 // Math sanity checks.
918 //==============================================================================
920 constexpr bool allElementsAreFinite() requires std::floating_point<ElementType>;
921
923 constexpr bool allElementsAreFinite() requires is::complexFloatNumber<ElementType>;
924
926 constexpr bool anyElementIsNaN() requires std::floating_point<ElementType>;
927
929 constexpr bool anyElementIsNaN() requires is::complexFloatNumber<ElementType>;
930
931 //==============================================================================
932 // Conversion operators
933 //==============================================================================
935 constexpr auto toStdMap() &&
936 requires is::stdPair<value_type> && (! is::view<StorageType>)
937 {
938 return std::map<typename value_type::first_type, typename value_type::second_type> { std::make_move_iterator (begin()), std::make_move_iterator (end()) };
939 }
940
942 constexpr auto toStdMap() const &
943 requires is::stdPair<value_type>
944 {
945 return std::map<typename value_type::first_type, typename value_type::second_type> { begin(), end() };
946 }
947
948protected:
949 //==============================================================================
950 constexpr VctrBase()
951 {
952 if constexpr (has::init<StorageInfoType>)
953 StorageInfoType::init (storage.data(), storage.size());
954 }
955
956 constexpr VctrBase (StorageType&& s)
957 : storage (std::move (s))
958 {
959 if constexpr (has::init<StorageInfoType>)
960 StorageInfoType::init (storage.data(), storage.size());
961 }
962
963 template <is::storageInfo OtherStorageInfoType>
964 constexpr VctrBase (StorageType&& s, const OtherStorageInfoType& otherInfo)
965 : StorageInfoType (otherInfo),
966 storage (std::move (s))
967 {}
968
969 //==============================================================================
971 constexpr void resizeOrAssertSizeMatches (size_t desiredSize)
972 requires has::resize<StorageType>
973 {
974 storage.resize (desiredSize);
975 }
976
978 constexpr void resizeOrAssertSizeMatches ([[maybe_unused]] size_t desiredSize) const
979 {
980 VCTR_ASSERT (size() == desiredSize);
981 }
982
984 template <size_t i>
985 constexpr void assertIsInRange() const
986 requires (extent == std::dynamic_extent)
987 {
988 VCTR_ASSERT (i < size());
989 }
990
992 template <size_t i>
993 constexpr void assertIsInRange() const
994 requires (extent != std::dynamic_extent)
995 {
996 static_assert (i < extent);
997 }
998
1000 template <size_t i>
1001 constexpr void assertIsInRangeIncludingEnd() const
1002 requires (extent == std::dynamic_extent)
1003 {
1004 VCTR_ASSERT (i <= size());
1005 }
1006
1008 template <size_t i>
1009 constexpr void assertIsInRangeIncludingEnd() const
1010 requires (extent != std::dynamic_extent)
1011 {
1012 static_assert (i <= extent);
1013 }
1014
1016 void throwIfOutOfRange (size_t i) const
1017 {
1018 if (i >= size())
1019 {
1020 VCTR_ASSERT (false);
1021 throw std::out_of_range ("Vctr of size " + std::to_string (size()) + ": Element " + std::to_string (i) + " is out of range.");
1022 }
1023 }
1024
1025 //==============================================================================
1026 template <is::expression Expression>
1027 VCTR_FORCEDINLINE constexpr void assignExpressionTemplate (const Expression& e)
1028 {
1029 if (! std::is_constant_evaluated())
1030 {
1031 if constexpr (has::evalNextVectorOpInExpressionChain<Expression, ElementType>)
1032 {
1033 if (e.isNotAliased (data()))
1034 {
1035 e.evalNextVectorOpInExpressionChain (data());
1036 return;
1037 }
1038 }
1039
1040 if constexpr (has::getNeon<Expression>)
1041 {
1042 assignExpressionTemplateNeon (e);
1043 return;
1044 }
1045
1046 if constexpr (has::getAVX<Expression>)
1047 {
1048 if constexpr (is::realFloatNumber<ElementType>)
1049 {
1050 if (supportedCPUInstructionSets.fma)
1051 {
1052 assignExpressionTemplateFMA (e);
1053 return;
1054 }
1055 }
1056 else
1057 {
1058 if (supportedCPUInstructionSets.avx2)
1059 {
1060 assignExpressionTemplateAVX2 (e);
1061 return;
1062 }
1063 }
1064 }
1065
1066 if constexpr (has::getSSE<Expression>)
1067 {
1068 if (supportedCPUInstructionSets.sse4_1)
1069 {
1070 assignExpressionTemplateSSE4_1 (e);
1071 return;
1072 }
1073 }
1074 }
1075
1076 const auto n = size();
1077
1078 for (size_t i = 0; i < n; ++i)
1079 storage[i] = e[i];
1080 }
1081
1083 template <class OtherContainer>
1084 static constexpr bool shouldMoveFromOtherContainer = has::begin<OtherContainer> &&
1085 has::end<OtherContainer> &&
1086 (! is::view<OtherContainer>) &&
1087 (! std::is_reference_v<OtherContainer>) &&
1088 (! std::is_trivially_copyable_v<ElementType>);
1089
1090 //==============================================================================
1091 alignas (StorageInfoType::memberAlignment) StorageType storage = StorageType {};
1092
1093private:
1094 //==============================================================================
1095 template <class Expression>
1096 void assignExpressionTemplateNeon (const Expression& e)
1097 requires archARM
1098 {
1099 constexpr auto inc = NeonRegister<ElementType>::numElements;
1100 const bool hasExtendedSIMDStorage = e.getStorageInfo().hasSIMDExtendedStorage && StorageInfoType::hasSIMDExtendedStorage;
1101 const auto n = storage.size();
1102 const auto nSIMD = hasExtendedSIMDStorage ? detail::nextMultipleOf<inc> (n) : detail::previousMultipleOf<inc> (n);
1103
1104 e.prepareNeonEvaluation();
1105 auto* d = data();
1106
1107 size_t i = 0;
1108 for (; i < nSIMD; i += inc, d += inc)
1109 e.getNeon (i).store (d);
1110
1111 for (; i < n; ++i, ++d)
1112 storage[i] = e[i];
1113 }
1114
1115 template <class Expression>
1116 VCTR_TARGET ("avx2")
1117 void assignExpressionTemplateAVX2 (const Expression& e)
1118 requires archX64
1119 {
1120 constexpr auto inc = AVXRegister<ElementType>::numElements;
1121 const bool hasExtendedSIMDStorage = e.getStorageInfo().hasSIMDExtendedStorage && StorageInfoType::hasSIMDExtendedStorage;
1122 const auto n = storage.size();
1123 const auto nSIMD = hasExtendedSIMDStorage ? detail::nextMultipleOf<inc> (n) : detail::previousMultipleOf<inc> (n);
1124
1125 e.prepareAVXEvaluation();
1126 auto* d = data();
1127
1128 if (StorageInfoType::dataIsSIMDAligned)
1129 {
1130 size_t i = 0;
1131 for (; i < nSIMD; i += inc, d += inc)
1132 e.getAVX (i).storeAligned (d);
1133
1134 for (; i < n; ++i, ++d)
1135 storage[i] = e[i];
1136 }
1137 else
1138 {
1139 size_t i = 0;
1140 for (; i < nSIMD; i += inc, d += inc)
1141 e.getAVX (i).storeUnaligned (d);
1142
1143 for (; i < n; ++i, ++d)
1144 storage[i] = e[i];
1145 }
1146 }
1147
1148 template <class Expression>
1149 VCTR_TARGET ("fma")
1150 void assignExpressionTemplateFMA (const Expression& e)
1151 requires archX64
1152 {
1153 constexpr auto inc = AVXRegister<ElementType>::numElements;
1154 const bool hasExtendedSIMDStorage = e.getStorageInfo().hasSIMDExtendedStorage && StorageInfoType::hasSIMDExtendedStorage;
1155 const auto n = storage.size();
1156 const auto nSIMD = hasExtendedSIMDStorage ? detail::nextMultipleOf<inc> (n) : detail::previousMultipleOf<inc> (n);
1157
1158 e.prepareAVXEvaluation();
1159 auto* d = data();
1160
1161 if (StorageInfoType::dataIsSIMDAligned)
1162 {
1163 size_t i = 0;
1164 for (; i < nSIMD; i += inc, d += inc)
1165 e.getAVX (i).storeAligned (d);
1166
1167 for (; i < n; ++i, ++d)
1168 storage[i] = e[i];
1169 }
1170 else
1171 {
1172 size_t i = 0;
1173 for (; i < nSIMD; i += inc, d += inc)
1174 e.getAVX (i).storeUnaligned (d);
1175
1176 for (; i < n; ++i, ++d)
1177 storage[i] = e[i];
1178 }
1179 }
1180
1181 template <class Expression>
1182 VCTR_TARGET ("sse4.1")
1183 void assignExpressionTemplateSSE4_1 (const Expression& e)
1184 requires archX64
1185 {
1186 constexpr auto inc = SSERegister<ElementType>::numElements;
1187 const bool hasExtendedSIMDStorage = e.getStorageInfo().hasSIMDExtendedStorage && StorageInfoType::hasSIMDExtendedStorage;
1188 const auto n = storage.size();
1189 const auto nSIMD = hasExtendedSIMDStorage ? detail::nextMultipleOf<inc> (n) : detail::previousMultipleOf<inc> (n);
1190
1191 e.prepareSSEEvaluation();
1192 auto* d = data();
1193
1194 if (StorageInfoType::dataIsSIMDAligned)
1195 {
1196 size_t i = 0;
1197 for (; i < nSIMD; i += inc, d += inc)
1198 e.getSSE (i).storeAligned (d);
1199
1200 for (; i < n; ++i, ++d)
1201 storage[i] = e[i];
1202 }
1203 else
1204 {
1205 size_t i = 0;
1206 for (; i < nSIMD; i += inc, d += inc)
1207 e.getSSE (i).storeUnaligned (d);
1208
1209 for (; i < n; ++i, ++d)
1210 storage[i] = e[i];
1211 }
1212 }
1213
1214 //==============================================================================
1215 template <size_t spanExtent>
1216 constexpr auto constCorrectSpan (ElementType* data, size_t spanSize);
1217
1218 template <size_t spanExtent>
1219 constexpr auto constCorrectSpan (const ElementType* data, size_t spanSize) const
1220 requires (! is::stdSpan<StorageType>);
1221
1222 template <size_t spanExtent>
1223 constexpr auto constCorrectSpan (ElementType* data, size_t spanSize) const
1224 requires is::stdSpan<StorageType>;
1225
1226 //==============================================================================
1228 static void clear (ElementType* ptr, size_t numElements)
1229 {
1230 std::memset (ptr, 0, numElements * sizeof (ElementType));
1231 }
1232
1234 static void memMove (const ElementType* src, ElementType* dst, size_t numElements)
1235 requires std::is_trivially_copyable_v<ElementType>
1236 {
1237 std::memmove (dst, src, numElements * sizeof (ElementType));
1238 }
1239
1241 template <class T>
1242 VCTR_FORCEDINLINE constexpr static T* assumeAlignedToMaxSIMDRegisterSize (T* ptr)
1243 {
1244 if (std::is_constant_evaluated())
1245 return ptr;
1246
1247 #if __cpp_lib_assume_aligned
1248 return std::assume_aligned<maxSIMDRegisterSize> (ptr);
1249 #elif VCTR_CLANG
1250 return static_cast<T*> (__builtin_assume_aligned (ptr, maxSIMDRegisterSize));
1251 #else
1252 return ptr;
1253 #endif
1254 }
1255};
1256
1262template <is::anyVctr Lhs, is::anyVctr Rhs>
1263requires std::same_as<ValueType<Lhs>, ValueType<Rhs>>
1264constexpr bool operator== (const Lhs& lhs, const Rhs& rhs)
1265{
1266 return std::equal (lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
1267}
1268
1269} // namespace vctr
1270
1271#if VCTR_MSVC
1272__pragma (warning (pop))
1273#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:740
auto findMaxElement() const
Returns an iterator to the first greatest element.
Definition: VctrBase.h:620
constexpr size_t count(const ElementType &valueToLookFor) const
Returns the number of elements that are equal to valueToLookFor.
Definition: VctrBase.h:508
auto findMaxElement()
Returns an iterator to the first greatest element.
Definition: VctrBase.h:609
constexpr bool contains(It it) const
Returns true if the iterator refers to an element inside this container or span.
Definition: VctrBase.h:563
constexpr void sort(ComparatorFn &&compare)
Sorts all elements in this vector according to the compare function.
Definition: VctrBase.h:772
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:467
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:598
constexpr void fillLinspace(ElementType start, ElementType stop, bool includeEnd=true)
Fills the vector with evenly spaced numbers between start and stop.
Definition: VctrBase.h:317
constexpr void rotate(size_t newFirstElementIdx)
Rotates the elements so that the element with the index newFirstElementIdx becomes the first element ...
Definition: VctrBase.h:700
constexpr void forEach(Fn &&fn) const
Calls a function on each element.
Definition: VctrBase.h:362
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
auto findMinElement()
Returns an iterator to the first smallest element.
Definition: VctrBase.h:631
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:453
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:460
static constexpr size_t sizeInBytes() noexcept
Returns the container size in bytes.
Definition: VctrBase.h:79
constexpr auto toStdMap() const &
If value_type is std::pair, this converts the content into a std::map with pair::first_type being the...
Definition: VctrBase.h:942
constexpr bool all(Fn &&predicate) const
Returns true if all elements satisfy the predicate or if the container is empty.
Definition: VctrBase.h:522
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:582
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:263
size_t indexOfMinElement() const
Returns the index of the first smallest element (aka argMin).
Definition: VctrBase.h:656
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:515
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:761
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:420
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:474
constexpr void copyFrom(const ElementType *otherData, size_t otherSize)
Copies the content from otherData to this instance.
Definition: VctrBase.h:282
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:789
constexpr void forEach(Fn &&fn)
Calls a function on each element.
Definition: VctrBase.h:351
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:574
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:481
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:502
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:495
constexpr void reverse()
Reverses the order of all elements.
Definition: VctrBase.h:692
constexpr bool allElementsEqual() const
Returns true if all elements are equal to themselves.
Definition: VctrBase.h:542
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:680
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:536
constexpr bool elementsAreSorted() const
Returns true if all elements are sorted.
Definition: VctrBase.h:778
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:667
size_t indexOfMaxElement() const
Returns the index of the first greatest element (aka argMax).
Definition: VctrBase.h:649
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:488
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:431
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:300
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:529
constexpr ElementType sum() const
Returns the sum of all elements.
auto findMinElement() const
Returns an iterator to the first smallest element.
Definition: VctrBase.h:642
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:553
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:590
void shiftLeft(size_t n, bool clearFreeSpaceAfterShiftedRegion)
Shifts all elements to the left by n.
Definition: VctrBase.h:713
constexpr auto rbegin() const
Returns a const reverse iterator to the last element in the storage.
Definition: VctrBase.h:156
constexpr auto toStdMap() &&
If value_type is std::pair, this converts the content into a std::map with pair::first_type being the...
Definition: VctrBase.h:935
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:82
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:78
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:1264
Definition: Config.h:298
Definition: NeonRegister.h:28
A helper struct intended to check if a value is a constexpr.
Definition: Traits.h:300