kfr

Fast, modern C++ DSP framework, FFT, Sample Rate Conversion, FIR/IIR/Biquad Filters (SSE, AVX, AVX-512, ARM NEON)
Log | Files | Refs | README

commit 428f0eab709d03dbce133aedc4e259b8b1dc77dd
parent f89c24671f8fce4051fa411eb12b6c48530eb013
Author: d.levin256@gmail.com <d.levin256@gmail.com>
Date:   Thu, 14 Jul 2022 19:42:41 +0100

CTAD for vec{}, writable front/back

Diffstat:
Minclude/kfr/simd/vec.hpp | 147+++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------
1 file changed, 107 insertions(+), 40 deletions(-)

diff --git a/include/kfr/simd/vec.hpp b/include/kfr/simd/vec.hpp @@ -88,9 +88,6 @@ CMT_PRAGMA_MSVC(warning(disable : 4814)) namespace kfr { -inline namespace CMT_ARCH_NAME -{ - template <typename T, size_t N> struct alignas(next_poweroftwo(sizeof(T)) * next_poweroftwo(N)) portable_vec { @@ -106,8 +103,14 @@ struct alignas(next_poweroftwo(sizeof(T)) * next_poweroftwo(N)) portable_vec constexpr static size_t size() CMT_NOEXCEPT { return N; } T elem[N]; + + T operator[](size_t index) const { return elem[index]; } + T& operator[](size_t index) { return elem[index]; } }; +inline namespace CMT_ARCH_NAME +{ + template <typename T, size_t N> struct vec; @@ -324,9 +327,17 @@ struct alignas(internal::vec_alignment<T, N_>) vec KFR_MEM_INTRINSIC constexpr element operator[](size_t index) & CMT_NOEXCEPT { return { *this, index }; } - KFR_MEM_INTRINSIC value_type front() const CMT_NOEXCEPT { return get(csize<0>); } + KFR_MEM_INTRINSIC value_type front() const& CMT_NOEXCEPT { return get(csize<0>); } + + KFR_MEM_INTRINSIC value_type back() const& CMT_NOEXCEPT { return get(csize<N - 1>); } + + KFR_MEM_INTRINSIC value_type front() && CMT_NOEXCEPT { return get(csize<0>); } - KFR_MEM_INTRINSIC value_type back() const CMT_NOEXCEPT { return get(csize<N - 1>); } + KFR_MEM_INTRINSIC value_type back() && CMT_NOEXCEPT { return get(csize<N - 1>); } + + KFR_MEM_INTRINSIC element front() & CMT_NOEXCEPT { return { *this, 0 }; } + + KFR_MEM_INTRINSIC element back() & CMT_NOEXCEPT { return { *this, N - 1 }; } template <int dummy = 0, KFR_ENABLE_IF(dummy == 0 && compound_type_traits<T>::is_scalar)> KFR_MEM_INTRINSIC constexpr value_type get(size_t index) const CMT_NOEXCEPT @@ -338,7 +349,8 @@ struct alignas(internal::vec_alignment<T, N_>) vec KFR_ENABLE_IF(dummy == 0 && !compound_type_traits<T>::is_scalar)> KFR_MEM_INTRINSIC constexpr value_type get(size_t index) const CMT_NOEXCEPT { - union { + union + { simd_type v; T s[N]; } u{ this->v }; @@ -374,7 +386,8 @@ struct alignas(internal::vec_alignment<T, N_>) vec template <int dummy = 0, KFR_ENABLE_IF(dummy == 0 && !compound_type_traits<T>::is_scalar)> KFR_MEM_INTRINSIC constexpr void set(size_t index, const value_type& s) CMT_NOEXCEPT { - union { + union + { simd_type v; T s[N]; } u{ this->v }; @@ -405,6 +418,49 @@ struct alignas(internal::vec_alignment<T, N_>) vec return *this; } + KFR_MEM_INTRINSIC element& operator+=(const value_type& s) CMT_NOEXCEPT + { + v.set(index, v.get(index) + s); + return *this; + } + KFR_MEM_INTRINSIC element& operator-=(const value_type& s) CMT_NOEXCEPT + { + v.set(index, v.get(index) - s); + return *this; + } + KFR_MEM_INTRINSIC element& operator*=(const value_type& s) CMT_NOEXCEPT + { + v.set(index, v.get(index) * s); + return *this; + } + KFR_MEM_INTRINSIC element& operator/=(const value_type& s) CMT_NOEXCEPT + { + v.set(index, v.get(index) / s); + return *this; + } + KFR_MEM_INTRINSIC element& operator++() CMT_NOEXCEPT + { + v.set(index, v.get(index) + 1); + return *this; + } + KFR_MEM_INTRINSIC element& operator--() CMT_NOEXCEPT + { + v.set(index, v.get(index) - 1); + return *this; + } + KFR_MEM_INTRINSIC value_type operator++(int) CMT_NOEXCEPT + { + value_type val = v.get(index) + 1; + v.set(index, val); + return val; + } + KFR_MEM_INTRINSIC value_type operator--(int) CMT_NOEXCEPT + { + value_type val = v.get(index) - 1; + v.set(index, val); + return val; + } + KFR_MEM_INTRINSIC element& operator=(const element& s) CMT_NOEXCEPT { v.set(index, static_cast<value_type>(s)); @@ -447,7 +503,8 @@ struct alignas(internal::vec_alignment<T, N_>) vec using simd_element_type = simd<ST, simd_element_size>; public: - union { + union + { simd_type v; vec_halves<T, N> h; // simd_element_type w[simd_element_count]; @@ -455,6 +512,9 @@ public: }; }; +template <typename... T> +vec(T&&...) -> vec<std::common_type_t<T...>, sizeof...(T)>; + template <typename T> constexpr inline bool is_vec_element = is_simd_type<deep_subtype<remove_const<T>>>; @@ -666,7 +726,8 @@ template <typename To, typename From> CMT_GNU_CONSTEXPR KFR_INTRINSIC To bitcast(const From& value) CMT_NOEXCEPT { static_assert(sizeof(From) == sizeof(To), "bitcast: Incompatible types"); - union { + union + { From from; To to; } u{ value }; @@ -1130,28 +1191,31 @@ vec<T, N> test_enumerate(vec_shape<T, N>, csizes_t<indices...>, double start = 0 template <int Cat, typename Fn, typename RefFn, typename IsApplicable = fn_return_constant<bool, true>> void test_function1(cint_t<Cat> cat, Fn&& fn, RefFn&& reffn, IsApplicable&& isapplicable = IsApplicable{}) { - testo::matrix( - named("value") = special_values(), named("type") = test_catogories::types(cat), - [&](special_value value, auto type) { - using T = typename decltype(type)::type; - if (isapplicable(ctype<T>, value)) - { - const T x(value); - CHECK(is_same<decltype(fn(x)), typename compound_type_traits<T>::template rebind<decltype( - reffn(std::declval<subtype<T>>()))>>); - const auto fn_x = fn(x); - const auto ref_x = apply(reffn, x); - ::testo::active_test()->check(testo::deep_is_equal(ref_x, fn_x), - as_string(fn_x, " == ", ref_x), "fn(x) == apply(reffn, x)"); - // CHECK(fn(x) == apply(reffn, x)); - } - }); - - testo::matrix(named("type") = test_catogories::types(cint<Cat & ~1>), [&](auto type) { - using T = typename decltype(type)::type; - const T x = test_enumerate(T::shape(), csizeseq<T::size()>, 0); - CHECK(fn(x) == apply(reffn, x)); - }); + testo::matrix(named("value") = special_values(), named("type") = test_catogories::types(cat), + [&](special_value value, auto type) + { + using T = typename decltype(type)::type; + if (isapplicable(ctype<T>, value)) + { + const T x(value); + CHECK(is_same<decltype(fn(x)), typename compound_type_traits<T>::template rebind< + decltype(reffn(std::declval<subtype<T>>()))>>); + const auto fn_x = fn(x); + const auto ref_x = apply(reffn, x); + ::testo::active_test()->check(testo::deep_is_equal(ref_x, fn_x), + as_string(fn_x, " == ", ref_x), + "fn(x) == apply(reffn, x)"); + // CHECK(fn(x) == apply(reffn, x)); + } + }); + + testo::matrix(named("type") = test_catogories::types(cint<Cat & ~1>), + [&](auto type) + { + using T = typename decltype(type)::type; + const T x = test_enumerate(T::shape(), csizeseq<T::size()>, 0); + CHECK(fn(x) == apply(reffn, x)); + }); } template <int Cat, typename Fn, typename RefFn, typename IsApplicable = fn_return_constant<bool, true>> @@ -1159,25 +1223,28 @@ void test_function2(cint_t<Cat> cat, Fn&& fn, RefFn&& reffn, IsApplicable&& isap { testo::matrix(named("value1") = special_values(), // named("value2") = special_values(), named("type") = test_catogories::types(cat), - [&](special_value value1, special_value value2, auto type) { + [&](special_value value1, special_value value2, auto type) + { using T = typename decltype(type)::type; const T x1(value1); const T x2(value2); if (isapplicable(ctype<T>, value1, value2)) { CHECK(is_same<decltype(fn(x1, x2)), - typename compound_type_traits<T>::template rebind<decltype( - reffn(std::declval<subtype<T>>(), std::declval<subtype<T>>()))>>); + typename compound_type_traits<T>::template rebind<decltype(reffn( + std::declval<subtype<T>>(), std::declval<subtype<T>>()))>>); CHECK(fn(x1, x2) == apply(reffn, x1, x2)); } }); - testo::matrix(named("type") = test_catogories::types(cint<Cat & ~1>), [&](auto type) { - using T = typename decltype(type)::type; - const T x1 = test_enumerate(T::shape(), csizeseq<T::size()>, 0, 1); - const T x2 = test_enumerate(T::shape(), csizeseq<T::size()>, 100, -1); - CHECK(fn(x1, x2) == apply(reffn, x1, x2)); - }); + testo::matrix(named("type") = test_catogories::types(cint<Cat & ~1>), + [&](auto type) + { + using T = typename decltype(type)::type; + const T x1 = test_enumerate(T::shape(), csizeseq<T::size()>, 0, 1); + const T x2 = test_enumerate(T::shape(), csizeseq<T::size()>, 100, -1); + CHECK(fn(x1, x2) == apply(reffn, x1, x2)); + }); } #endif