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 65554fb390eb8649466fc23014030c6839e1c77d
parent ecd88210a52c5485c4745a04dd23ad7843c8b669
Author: d.levin256@gmail.com <d.levin256@gmail.com>
Date:   Mon, 29 Aug 2016 04:17:31 +0300

Specify value_type for all expressions

Diffstat:
Minclude/kfr/base/basic_expressions.hpp | 22++++++++++++++--------
Minclude/kfr/base/expression.hpp | 121+++++++++++++++++++++++++++++++++++++++++++------------------------------------
Minclude/kfr/base/operators.hpp | 12++++++------
Minclude/kfr/base/random.hpp | 3++-
Minclude/kfr/base/reduce.hpp | 11-----------
Minclude/kfr/base/simd.hpp | 36++++++++++++++++++------------------
Minclude/kfr/base/types.hpp | 35++++++++++++-----------------------
Minclude/kfr/base/vec.hpp | 33++++++++++++++++++++-------------
Minclude/kfr/dsp/impulse.hpp | 3++-
Mtests/complex_test.cpp | 3---
10 files changed, 140 insertions(+), 139 deletions(-)

diff --git a/include/kfr/base/basic_expressions.hpp b/include/kfr/base/basic_expressions.hpp @@ -75,30 +75,34 @@ CMT_INLINE auto sequence(T x, Ts... rest) constexpr size_t N = arraysize(seq); return typed<T>(lambda([=](size_t index) { return seq[index % N]; })); } + +template <typename T = int> CMT_INLINE auto zeros() { - return lambda([](cinput_t, size_t, auto x) { return zerovector(x); }); + return lambda<T>([](cinput_t, size_t, auto x) { return zerovector(x); }); } + +template <typename T = int> CMT_INLINE auto ones() { - return lambda([](cinput_t, size_t, auto x) { - using U = subtype<decltype(x)>; - return U(1); - }); + return lambda<T>([](cinput_t, size_t, auto x) { return 1; }); } + +template <typename T = int> CMT_INLINE auto counter() { - return lambda([](cinput_t, size_t index, auto x) { return enumerate(x) + index; }); + return lambda<T>([](cinput_t, size_t index, auto x) { return enumerate(x) + index; }); } + template <typename T1> CMT_INLINE auto counter(T1 start) { - return lambda([start](cinput_t, size_t index, auto x) { return enumerate(x) + index + start; }); + return lambda<T1>([start](cinput_t, size_t index, auto x) { return enumerate(x) + index + start; }); } template <typename T1, typename T2> CMT_INLINE auto counter(T1 start, T2 step) { - return lambda( + return lambda<common_type<T1, T2>>( [start, step](cinput_t, size_t index, auto x) { return (enumerate(x) + index) * step + start; }); } @@ -220,6 +224,8 @@ struct expression_linspace<T, false> : input_expression template <typename T> struct expression_linspace<T, true> : input_expression { + using value_type = T; + expression_linspace(T start, T stop, size_t size, bool endpoint = false) : start(start), stop(stop), invsize(1.0 / T(endpoint ? size - 1 : size)) { diff --git a/include/kfr/base/expression.hpp b/include/kfr/base/expression.hpp @@ -34,25 +34,45 @@ namespace kfr { -template <typename T> -using is_generic = is_same<generic, typename decay<T>::value_type>; +namespace internal +{ +template <typename T, typename = void> +struct is_fixed_size_impl : std::false_type +{ +}; template <typename T> -using is_infinite = not_t<is_same<size_t, typename decay<T>::size_type>>; +struct is_fixed_size_impl<T, void_t<decltype(T::size())>> : std::true_type +{ +}; -namespace internal +template <typename T, typename = void> +struct is_infinite_impl : std::false_type { +}; -template <typename T1> -constexpr inline T1 minsize(T1 x) noexcept +template <typename T> +struct is_infinite_impl<T, void_t<decltype(T::size())>> + : std::integral_constant<bool, T::size() == infinite_size> { - return x; +}; } -template <typename T1, typename T2, typename... Ts> -constexpr inline common_type<T1, T2, Ts...> minsize(T1 x, T2 y, Ts... rest) noexcept +template <typename T> +using is_fixed_size = typename internal::is_fixed_size_impl<T>::type; + +template <typename T> +using is_infinite = typename internal::is_infinite_impl<T>::type; + +namespace internal +{ + +constexpr inline size_t minsize(size_t x) noexcept { return x; } + +template <typename... Ts> +constexpr inline size_t minsize(size_t x, size_t y, Ts... rest) noexcept { - return x < y ? minsize(x, rest...) : minsize(y, rest...); + return minsize(x < y ? x : y, rest...); } template <typename... Args> @@ -60,9 +80,7 @@ struct expression : input_expression { using value_type = common_type<typename decay<Args>::value_type...>; - using size_type = common_type<typename decay<Args>::size_type...>; - - constexpr size_type size() const noexcept { return size_impl(indicesfor_t<Args...>()); } + constexpr size_t size() const noexcept { return size_impl(indicesfor_t<Args...>()); } constexpr static size_t count = sizeof...(Args); expression() = delete; @@ -78,7 +96,7 @@ struct expression : input_expression protected: template <size_t... indices> - constexpr size_type size_impl(csizes_t<indices...>) const noexcept + constexpr size_t size_impl(csizes_t<indices...>) const noexcept { return minsize(std::get<indices>(this->args).size()...); } @@ -88,21 +106,22 @@ protected: { return call_impl(std::forward<Fn>(fn), indicesfor_t<Args...>(), index, x); } - template <size_t ArgIndex, typename T, size_t N> - CMT_INLINE vec<T, N> argument(csize_t<ArgIndex>, size_t index, vec_t<T, N> x) const + template <size_t ArgIndex, typename U, size_t N, + typename T = value_type_of<typename details::get_nth_type<ArgIndex, Args...>::type>> + CMT_INLINE vec<U, N> argument(csize_t<ArgIndex>, size_t index, vec_t<U, N>) const { static_assert(ArgIndex < count, "Incorrect ArgIndex"); - return std::get<ArgIndex>(this->args)(cinput, index, x); + return static_cast<vec<U, N>>(std::get<ArgIndex>(this->args)(cinput, index, vec_t<T, N>())); } - template <typename T, size_t N> - CMT_INLINE vec<T, N> argument_first(size_t index, vec_t<T, N> x) const + template <typename U, size_t N, + typename T = value_type_of<typename details::get_nth_type<0, Args...>::type>> + CMT_INLINE vec<U, N> argument_first(size_t index, vec_t<U, N>) const { - return std::get<0>(this->args)(cinput, index, x); + return static_cast<vec<U, N>>(std::get<0>(this->args)(cinput, index, vec_t<T, N>())); } private: - template <typename Arg, size_t N, typename Tin, - typename Tout = conditional<is_generic<Arg>::value, Tin, value_type_of<Arg>>> + template <typename Arg, size_t N, typename Tout = value_type_of<Arg>> CMT_INLINE vec_t<Tout, N> vec_t_for() const { return {}; @@ -112,10 +131,9 @@ private: { using ratio = func_ratio<Fn>; constexpr size_t Nin = N * ratio::input / ratio::output; - using Tout = conditional<is_same<generic, value_type>::value, T, common_type<T, value_type>>; return fn(std::get<indices>(this->args)(cinput, index * ratio::input / ratio::output, - vec_t_for<Args, Nin, Tout>())...); + vec_t_for<Args, Nin>())...); } template <size_t... indices> CMT_INLINE void begin_block_impl(size_t size, csizes_t<indices...>) @@ -148,10 +166,10 @@ struct expression_scalar : input_expression constexpr expression_scalar(const vec<T, width>& val) noexcept : val(val) {} vec<T, width> val; - template <typename U, size_t N> - CMT_INLINE vec<U, N> operator()(cinput_t, size_t, vec_t<U, N>) const + template <size_t N> + CMT_INLINE vec<T, N> operator()(cinput_t, size_t, vec_t<T, N>) const { - return resize<N>(static_cast<vec<U, width>>(val)); + return resize<N>(val); } }; @@ -162,24 +180,13 @@ using arg_impl = conditional<is_number<T>::value || is_vec<T>::value, template <typename T> using arg = internal::arg_impl<T>; -template <typename Fn, typename Args, typename Enable = void> -struct generic_result -{ - using type = generic; -}; - -template <typename Fn, typename... Args> -struct generic_result<Fn, ctypes_t<Args...>, void_t<enable_if<!or_t<is_same<generic, Args>...>::value>>> -{ - using type = subtype<decltype(std::declval<Fn>()(std::declval<vec<decay<Args>, 1>>()...))>; -}; - template <typename Fn, typename... Args> struct expression_function : expression<arg<Args>...> { using ratio = func_ratio<Fn>; - using value_type = typename generic_result<Fn, ctypes_t<value_type_of<arg<Args>>...>>::type; + using value_type = + subtype<decltype(std::declval<Fn>()(std::declval<vec<value_type_of<arg<Args>>, 1>>()...))>; expression_function(Fn&& fn, arg<Args>&&... args) noexcept : expression<arg<Args>...>(std::forward<arg<Args>>(args)...), @@ -194,8 +201,7 @@ struct expression_function : expression<arg<Args>...> template <typename T, size_t N> CMT_INLINE vec<T, N> operator()(cinput_t, size_t index, vec_t<T, N> x) const { - static_assert(is_same<T, value_type_of<expression_function>>::value || - is_generic<expression_function>::value, + static_assert(is_same<T, value_type_of<expression_function>>::value, "Can't cast from value_type to T"); return this->call(fn, index, x); } @@ -255,25 +261,30 @@ CMT_INLINE internal::expression_function<Fn, NewArgs...> rebind( return internal::expression_function<Fn, NewArgs...>(e.get_fn(), std::forward<NewArgs>(args)...); } -template <typename Tout, cpu_t c = cpu_t::native, size_t width = 0, typename OutFn, typename Fn> -CMT_INLINE void process(OutFn&& outfn, const Fn& fn, size_t size) +template <typename Tout, cpu_t c = cpu_t::native, size_t width = 0, typename OutputExpr, typename InputExpr> +CMT_INLINE void process(OutputExpr&& out, const InputExpr& in, size_t size) { - static_assert(is_output_expression<OutFn>::value, "OutFn must be an expression"); - static_assert(is_input_expression<Fn>::value, "Fn must be an expression"); - constexpr size_t comp = lcm(func_ratio<OutFn>::input, func_ratio<Fn>::output); + static_assert(is_output_expression<OutputExpr>::value, "OutFn must be an expression"); + static_assert(is_input_expression<InputExpr>::value, "Fn must be an expression"); + constexpr size_t comp = lcm(func_ratio<OutputExpr>::input, func_ratio<InputExpr>::output); size *= comp; - outfn.output_begin_block(size); - fn.begin_block(size); + out.output_begin_block(size); + in.begin_block(size); + + using Tin = value_type_of<InputExpr>; - using Tin = conditional<is_generic<Fn>::value, Tout, value_type_of<Fn>>; +#ifdef NDEBUG + constexpr size_t w = width == 0 ? internal::get_vector_width<Tout, c>(2, 4) : width; +#else + constexpr size_t w = width == 0 ? internal::get_vector_width<Tout, c>(1, 1) : width; +#endif size_t i = 0; - internal::process_cycle<Tout, Tin, width == 0 ? internal::get_vector_width<Tout, c>(2, 4) : width>( - std::forward<OutFn>(outfn), fn, i, size); - internal::process_cycle<Tout, Tin, comp>(std::forward<OutFn>(outfn), fn, i, size); + internal::process_cycle<Tout, Tin, w>(std::forward<OutputExpr>(out), in, i, size); + internal::process_cycle<Tout, Tin, comp>(std::forward<OutputExpr>(out), in, i, size); - fn.end_block(size); - outfn.output_end_block(size); + in.end_block(size); + out.output_end_block(size); } namespace internal diff --git a/include/kfr/base/operators.hpp b/include/kfr/base/operators.hpp @@ -434,13 +434,13 @@ KFR_FN(greaterorequal) /// @brief Fused Multiply-Add template <typename T1, typename T2, typename T3> -constexpr inline common_type<T1, T2, T3> fmadd(T1 x, T2 y, T3 z) +KFR_INTRIN constexpr common_type<T1, T2, T3> fmadd(T1 x, T2 y, T3 z) { return x * y + z; } /// @brief Fused Multiply-Sub template <typename T1, typename T2, typename T3> -constexpr inline common_type<T1, T2, T3> fmsub(T1 x, T2 y, T3 z) +KFR_INTRIN constexpr common_type<T1, T2, T3> fmsub(T1 x, T2 y, T3 z) { return x * y - z; } @@ -450,14 +450,14 @@ KFR_FN(fmsub) /// @brief Linear blend of `x` and `y` (`c` must be in the range 0...+1) /// Returns `x + ( y - x ) * c` template <typename T1, typename T2, typename T3> -constexpr inline common_type<T1, T2, T3> mix(T1 c, T2 x, T3 y) +KFR_INTRIN constexpr common_type<T1, T2, T3> mix(T1 c, T2 x, T3 y) { return fmadd(c, y - x, x); } /// @brief Linear blend of `x` and `y` (`c` must be in the range -1...+1) template <typename T1, typename T2, typename T3> -constexpr inline common_type<T1, T2, T3> mixs(T1 c, T2 x, T3 y) +KFR_INTRIN constexpr common_type<T1, T2, T3> mixs(T1 c, T2 x, T3 y) { return mix(fmadd(c, 0.5, 0.5), x, y); } @@ -711,8 +711,8 @@ struct expression_pack : expression<E...>, output_expression expression_pack(E&&... e) : expression<E...>(std::forward<E>(e)...) {} using value_type = vec<common_type<value_type_of<E>...>, count>; - using size_type = typename expression<E...>::size_type; - constexpr size_type size() const noexcept { return expression<E...>::size(); } + + using expression<E...>::size; template <typename U, size_t N> CMT_INLINE vec<U, N> operator()(cinput_t, size_t index, vec_t<U, N> x) const diff --git a/include/kfr/base/random.hpp b/include/kfr/base/random.hpp @@ -43,7 +43,8 @@ constexpr seed_from_rdtsc_t seed_from_rdtsc{}; struct random_bit_generator { random_bit_generator(seed_from_rdtsc_t) noexcept - : state(bitcast<u32>(make_vector(__builtin_readcyclecounter(), (__builtin_readcyclecounter() << 11) ^ 0x710686d615e2257bull))) + : state(bitcast<u32>(make_vector(__builtin_readcyclecounter(), + (__builtin_readcyclecounter() << 11) ^ 0x710686d615e2257bull))) { (void)operator()(); } diff --git a/include/kfr/base/reduce.hpp b/include/kfr/base/reduce.hpp @@ -110,7 +110,6 @@ template <typename ReduceFn, typename TransformFn = fn_pass_through, typename Fi KFR_SINTRIN T reduce(E1&& e1, ReduceFn&& reducefn, TransformFn&& transformfn = fn_pass_through(), FinalFn&& finalfn = fn_pass_through()) { - static_assert(!is_generic<E1>::value, "e1 must be a typed expression (use typed<T>())"); static_assert(!is_infinite<E1>::value, "e1 must be a sized expression (use typed<T>())"); const size_t size = e1.size(); using reducer_t = expression_reduce<T, decay<ReduceFn>, decay<TransformFn>, decay<FinalFn>>; @@ -135,7 +134,6 @@ KFR_FN(reduce) template <typename E1, typename T = value_type_of<E1>, KFR_ENABLE_IF(is_input_expression<E1>::value)> KFR_SINTRIN T sum(E1&& x) { - static_assert(!is_generic<E1>::value, "e1 must be a typed expression (use typed<T>())"); static_assert(!is_infinite<E1>::value, "e1 must be a sized expression (use typed<T>())"); return internal::reduce(std::forward<E1>(x), fn_add()); } @@ -151,7 +149,6 @@ KFR_SINTRIN T sum(E1&& x) template <typename E1, typename T = value_type_of<E1>, KFR_ENABLE_IF(is_input_expression<E1>::value)> KFR_SINTRIN T mean(E1&& x) { - static_assert(!is_generic<E1>::value, "e1 must be a typed expression (use typed<T>())"); static_assert(!is_infinite<E1>::value, "e1 must be a sized expression (use typed<T>())"); return internal::reduce(std::forward<E1>(x), fn_add(), fn_pass_through(), fn_final_mean()); } @@ -164,7 +161,6 @@ KFR_SINTRIN T mean(E1&& x) template <typename E1, typename T = value_type_of<E1>, KFR_ENABLE_IF(is_input_expression<E1>::value)> KFR_SINTRIN T minof(E1&& x) { - static_assert(!is_generic<E1>::value, "e1 must be a typed expression (use typed<T>())"); static_assert(!is_infinite<E1>::value, "e1 must be a sized expression (use typed<T>())"); return internal::reduce(std::forward<E1>(x), fn::min()); } @@ -177,7 +173,6 @@ KFR_SINTRIN T minof(E1&& x) template <typename E1, typename T = value_type_of<E1>, KFR_ENABLE_IF(is_input_expression<E1>::value)> KFR_SINTRIN T maxof(E1&& x) { - static_assert(!is_generic<E1>::value, "e1 must be a typed expression (use typed<T>())"); static_assert(!is_infinite<E1>::value, "e1 must be a sized expression (use typed<T>())"); return internal::reduce(std::forward<E1>(x), fn::max()); } @@ -190,7 +185,6 @@ KFR_SINTRIN T maxof(E1&& x) template <typename E1, typename T = value_type_of<E1>, KFR_ENABLE_IF(is_input_expression<E1>::value)> KFR_SINTRIN T absminof(E1&& x) { - static_assert(!is_generic<E1>::value, "e1 must be a typed expression (use typed<T>())"); static_assert(!is_infinite<E1>::value, "e1 must be a sized expression (use typed<T>())"); return internal::reduce(std::forward<E1>(x), fn::absmin()); } @@ -203,7 +197,6 @@ KFR_SINTRIN T absminof(E1&& x) template <typename E1, typename T = value_type_of<E1>, KFR_ENABLE_IF(is_input_expression<E1>::value)> KFR_SINTRIN T absmaxof(E1&& x) { - static_assert(!is_generic<E1>::value, "e1 must be a typed expression (use typed<T>())"); static_assert(!is_infinite<E1>::value, "e1 must be a sized expression (use typed<T>())"); return internal::reduce(std::forward<E1>(x), fn::absmax()); } @@ -222,7 +215,6 @@ KFR_SINTRIN T dotproduct(E1&& x, E2&& y) { auto m = std::forward<E1>(x) * std::forward<E2>(y); using E12 = decltype(m); - static_assert(!is_generic<E12>::value, "e1 must be a typed expression (use typed<T>())"); static_assert(!is_infinite<E12>::value, "e1 must be a sized expression (use typed<T>())"); return internal::reduce(std::move(m), fn_add()); } @@ -238,7 +230,6 @@ KFR_SINTRIN T dotproduct(E1&& x, E2&& y) template <typename E1, typename T = value_type_of<E1>, KFR_ENABLE_IF(is_input_expression<E1>::value)> KFR_SINTRIN T rms(E1&& x) { - static_assert(!is_generic<E1>::value, "e1 must be a typed expression (use typed<T>())"); static_assert(!is_infinite<E1>::value, "e1 must be a sized expression (use typed<T>())"); return internal::reduce(std::forward<E1>(x), fn_add(), fn_sqr(), fn_final_rootmean()); } @@ -254,7 +245,6 @@ KFR_SINTRIN T rms(E1&& x) template <typename E1, typename T = value_type_of<E1>, KFR_ENABLE_IF(is_input_expression<E1>::value)> KFR_SINTRIN T sumsqr(E1&& x) { - static_assert(!is_generic<E1>::value, "e1 must be a typed expression (use typed<T>())"); static_assert(!is_infinite<E1>::value, "e1 must be a sized expression (use typed<T>())"); return internal::reduce(std::forward<E1>(x), fn_add(), fn_sqr()); } @@ -270,7 +260,6 @@ KFR_SINTRIN T sumsqr(E1&& x) template <typename E1, typename T = value_type_of<E1>, KFR_ENABLE_IF(is_input_expression<E1>::value)> KFR_SINTRIN T product(E1&& x) { - static_assert(!is_generic<E1>::value, "e1 must be a typed expression (use typed<T>())"); static_assert(!is_infinite<E1>::value, "e1 must be a sized expression (use typed<T>())"); return internal::reduce(std::forward<E1>(x), fn_mul()); } diff --git a/include/kfr/base/simd.hpp b/include/kfr/base/simd.hpp @@ -87,75 +87,75 @@ struct vec_op using utype = kfr::utype<type>; constexpr static size_t w = compound_type_traits<T>::width * N; - constexpr static simd<type, w> add(const simd<type, w>& x, const simd<type, w>& y) noexcept + CMT_INLINE constexpr static simd<type, w> add(const simd<type, w>& x, const simd<type, w>& y) noexcept { return x + y; } - constexpr static simd<type, w> sub(const simd<type, w>& x, const simd<type, w>& y) noexcept + CMT_INLINE constexpr static simd<type, w> sub(const simd<type, w>& x, const simd<type, w>& y) noexcept { return x - y; } - constexpr static simd<type, w> mul(const simd<type, w>& x, const simd<type, w>& y) noexcept + CMT_INLINE constexpr static simd<type, w> mul(const simd<type, w>& x, const simd<type, w>& y) noexcept { return x * y; } - constexpr static simd<type, w> div(const simd<type, w>& x, const simd<type, w>& y) noexcept + CMT_INLINE constexpr static simd<type, w> div(const simd<type, w>& x, const simd<type, w>& y) noexcept { return x / y; } - constexpr static simd<type, w> rem(const simd<type, w>& x, const simd<type, w>& y) noexcept + CMT_INLINE constexpr static simd<type, w> rem(const simd<type, w>& x, const simd<type, w>& y) noexcept { return x % y; } - constexpr static simd<type, w> shl(const simd<type, w>& x, const simd<type, w>& y) noexcept + CMT_INLINE constexpr static simd<type, w> shl(const simd<type, w>& x, const simd<type, w>& y) noexcept { return x << y; } - constexpr static simd<type, w> shr(const simd<type, w>& x, const simd<type, w>& y) noexcept + CMT_INLINE constexpr static simd<type, w> shr(const simd<type, w>& x, const simd<type, w>& y) noexcept { return x >> y; } - constexpr static simd<type, w> neg(const simd<type, w>& x) noexcept { return -x; } - constexpr static simd<type, w> band(const simd<type, w>& x, const simd<type, w>& y) noexcept + CMT_INLINE constexpr static simd<type, w> neg(const simd<type, w>& x) noexcept { return -x; } + CMT_INLINE constexpr static simd<type, w> band(const simd<type, w>& x, const simd<type, w>& y) noexcept { return reinterpret_cast<simd<type, w>>(reinterpret_cast<simd<utype, w>>(x) & reinterpret_cast<simd<utype, w>>(y)); } - constexpr static simd<type, w> bor(const simd<type, w>& x, const simd<type, w>& y) noexcept + CMT_INLINE constexpr static simd<type, w> bor(const simd<type, w>& x, const simd<type, w>& y) noexcept { return reinterpret_cast<simd<type, w>>(reinterpret_cast<simd<utype, w>>(x) | reinterpret_cast<simd<utype, w>>(y)); } - constexpr static simd<type, w> bxor(const simd<type, w>& x, const simd<type, w>& y) noexcept + CMT_INLINE constexpr static simd<type, w> bxor(const simd<type, w>& x, const simd<type, w>& y) noexcept { return reinterpret_cast<simd<type, w>>(reinterpret_cast<simd<utype, w>>(x) ^ reinterpret_cast<simd<utype, w>>(y)); } - constexpr static simd<type, w> bnot(const simd<type, w>& x) noexcept + CMT_INLINE constexpr static simd<type, w> bnot(const simd<type, w>& x) noexcept { return reinterpret_cast<simd<type, w>>(~reinterpret_cast<simd<utype, w>>(x)); } - constexpr static simd<type, w> eq(const simd<type, w>& x, const simd<type, w>& y) noexcept + CMT_INLINE constexpr static simd<type, w> eq(const simd<type, w>& x, const simd<type, w>& y) noexcept { return reinterpret_cast<simd<type, w>>(x == y); } - constexpr static simd<type, w> ne(const simd<type, w>& x, const simd<type, w>& y) noexcept + CMT_INLINE constexpr static simd<type, w> ne(const simd<type, w>& x, const simd<type, w>& y) noexcept { return reinterpret_cast<simd<type, w>>(x != y); } - constexpr static simd<type, w> lt(const simd<type, w>& x, const simd<type, w>& y) noexcept + CMT_INLINE constexpr static simd<type, w> lt(const simd<type, w>& x, const simd<type, w>& y) noexcept { return reinterpret_cast<simd<type, w>>(x < y); } - constexpr static simd<type, w> gt(const simd<type, w>& x, const simd<type, w>& y) noexcept + CMT_INLINE constexpr static simd<type, w> gt(const simd<type, w>& x, const simd<type, w>& y) noexcept { return reinterpret_cast<simd<type, w>>(x > y); } - constexpr static simd<type, w> le(const simd<type, w>& x, const simd<type, w>& y) noexcept + CMT_INLINE constexpr static simd<type, w> le(const simd<type, w>& x, const simd<type, w>& y) noexcept { return reinterpret_cast<simd<type, w>>(x <= y); } - constexpr static simd<type, w> ge(const simd<type, w>& x, const simd<type, w>& y) noexcept + CMT_INLINE constexpr static simd<type, w> ge(const simd<type, w>& x, const simd<type, w>& y) noexcept { return reinterpret_cast<simd<type, w>>(x >= y); } diff --git a/include/kfr/base/types.hpp b/include/kfr/base/types.hpp @@ -201,15 +201,6 @@ inline datatype operator&(datatype x, datatype y) return static_cast<datatype>(static_cast<type>(x) | static_cast<type>(y)); } -struct generic -{ - template <typename T> - CMT_INLINE constexpr operator T() const noexcept - { - return T(); - } -}; - struct infinite { template <typename T> @@ -546,49 +537,49 @@ CMT_INLINE void zeroize(T1& value) #endif template <typename T, typename U> -constexpr inline static T& ref_cast(U& ptr) +CMT_INLINE constexpr static T& ref_cast(U& ptr) { return reinterpret_cast<T&>(ptr); } template <typename T, typename U> -constexpr inline static const T& ref_cast(const U& ptr) +CMT_INLINE constexpr static const T& ref_cast(const U& ptr) { return reinterpret_cast<const T&>(ptr); } template <typename T, typename U> -constexpr inline static T* ptr_cast(U* ptr) +CMT_INLINE constexpr static T* ptr_cast(U* ptr) { return reinterpret_cast<T*>(ptr); } template <typename T, typename U> -constexpr inline static const T* ptr_cast(const U* ptr) +CMT_INLINE constexpr static const T* ptr_cast(const U* ptr) { return reinterpret_cast<const T*>(ptr); } template <typename T, typename U> -constexpr inline static T* ptr_cast(U* ptr, ptrdiff_t offset) +CMT_INLINE constexpr static T* ptr_cast(U* ptr, ptrdiff_t offset) { return ptr_cast<T>(ptr_cast<u8>(ptr) + offset); } template <typename T, typename U> -constexpr inline static T* derived_cast(U* ptr) +CMT_INLINE constexpr static T* derived_cast(U* ptr) { return static_cast<T*>(ptr); } template <typename T, typename U> -constexpr inline static const T* derived_cast(const U* ptr) +CMT_INLINE constexpr static const T* derived_cast(const U* ptr) { return static_cast<const T*>(ptr); } template <typename T, typename U> -constexpr inline static T implicit_cast(U&& value) +CMT_INLINE constexpr static T implicit_cast(U&& value) { return std::forward<T>(value); } @@ -711,12 +702,12 @@ constexpr size_t native_int_vector_size = c == cpu_t::neon ? 16 : common_int_vector_size; #endif +constexpr size_t infinite_size = static_cast<size_t>(-1); + /// @brief Base class of all input expressoins struct input_expression { - using value_type = generic; - using size_type = infinite; - constexpr size_type size() const noexcept { return {}; } + constexpr static size_t size() noexcept { return infinite_size; } CMT_INLINE void begin_block(size_t) const {} CMT_INLINE void end_block(size_t) const {} @@ -725,9 +716,7 @@ struct input_expression /// @brief Base class of all output expressoins struct output_expression { - using value_type = generic; - using size_type = infinite; - constexpr size_type size() const noexcept { return {}; } + constexpr static size_t size() noexcept { return infinite_size; } CMT_INLINE void output_begin_block(size_t) const {} CMT_INLINE void output_end_block(size_t) const {} diff --git a/include/kfr/base/vec.hpp b/include/kfr/base/vec.hpp @@ -699,7 +699,7 @@ struct vec : vec_t<T, N>, operators::empty CMT_INLINE array_t arr() { return ref_cast<array_t>(v); } template <typename U, KFR_ENABLE_IF(std::is_convertible<T, U>::value && !std::is_same<U, vec>::value)> - constexpr operator vec<U, N>() const noexcept + CMT_INLINE constexpr operator vec<U, N>() const noexcept { return internal::conversion<vec<U, N>, vec<T, N>>::cast(*this); } @@ -708,8 +708,8 @@ private: struct getter_setter; public: - getter_setter operator()(size_t index) { return { v, index }; } - scalar_type operator()(size_t index) const { return v[index]; } + CMT_INLINE getter_setter operator()(size_t index) { return { v, index }; } + CMT_INLINE scalar_type operator()(size_t index) const { return v[index]; } protected: template <typename U, size_t M> @@ -1332,18 +1332,19 @@ KFR_FN(high) namespace internal { -template <typename Fn> +template <typename T, typename Fn> struct expression_lambda : input_expression { + using value_type = T; CMT_INLINE expression_lambda(Fn&& fn) : fn(std::move(fn)) {} - template <typename T, size_t N, KFR_ENABLE_IF(N&& is_callable<Fn, cinput_t, size_t, vec_t<T, N>>::value)> + template <size_t N, KFR_ENABLE_IF(N&& is_callable<Fn, cinput_t, size_t, vec_t<T, N>>::value)> CMT_INLINE vec<T, N> operator()(cinput_t, size_t index, vec_t<T, N> y) const { return fn(cinput, index, y); } - template <typename T, size_t N, KFR_ENABLE_IF(N&& is_callable<Fn, size_t>::value)> + template <size_t N, KFR_ENABLE_IF(N&& is_callable<Fn, size_t>::value)> CMT_INLINE vec<T, N> operator()(cinput_t, size_t index, vec_t<T, N>) const { vec<T, N> result; @@ -1353,7 +1354,7 @@ struct expression_lambda : input_expression } return result; } - template <typename T, size_t N, KFR_ENABLE_IF(N&& is_callable<Fn>::value)> + template <size_t N, KFR_ENABLE_IF(N&& is_callable<Fn>::value)> CMT_INLINE vec<T, N> operator()(cinput_t, size_t, vec_t<T, N>) const { vec<T, N> result; @@ -1368,10 +1369,10 @@ struct expression_lambda : input_expression }; } -template <typename Fn> -internal::expression_lambda<decay<Fn>> lambda(Fn&& fn) +template <typename T, typename Fn> +internal::expression_lambda<T, decay<Fn>> lambda(Fn&& fn) { - return internal::expression_lambda<Fn>(std::move(fn)); + return internal::expression_lambda<T, decay<Fn>>(std::move(fn)); } } @@ -1394,7 +1395,10 @@ struct compound_type_traits<kfr::simd<T, N>> template <typename U> using deep_rebind = kfr::simd<cometa::deep_rebind<subtype, U>, N>; - static constexpr const subtype& at(const kfr::simd<T, N>& value, size_t index) { return value[index]; } + CMT_INLINE static constexpr const subtype& at(const kfr::simd<T, N>& value, size_t index) + { + return value[index]; + } }; #endif @@ -1412,7 +1416,7 @@ struct compound_type_traits<kfr::vec<T, N>> template <typename U> using deep_rebind = kfr::vec<cometa::deep_rebind<subtype, U>, N>; - static constexpr subtype at(const kfr::vec<T, N>& value, size_t index) { return value[index]; } + CMT_INLINE static constexpr subtype at(const kfr::vec<T, N>& value, size_t index) { return value[index]; } }; template <typename T, size_t N> @@ -1429,7 +1433,10 @@ struct compound_type_traits<kfr::mask<T, N>> template <typename U> using deep_rebind = kfr::mask<cometa::deep_rebind<subtype, U>, N>; - static constexpr subtype at(const kfr::mask<T, N>& value, size_t index) { return value[index]; } + CMT_INLINE static constexpr subtype at(const kfr::mask<T, N>& value, size_t index) + { + return value[index]; + } }; } namespace std diff --git a/include/kfr/dsp/impulse.hpp b/include/kfr/dsp/impulse.hpp @@ -33,9 +33,10 @@ namespace kfr /** * @brief Returns expression template that generates unit impulse */ +template <typename T = int> inline auto simpleimpulse() { - return lambda([](cinput_t, size_t index, auto x) { + return lambda<T>([](cinput_t, size_t index, auto x) { if (index == 0) return onoff(x); else diff --git a/tests/complex_test.cpp b/tests/complex_test.cpp @@ -147,9 +147,6 @@ TEST(complex_basic_expressions) TEST(complex_function_expressions) { - static_assert(is_generic<decltype(counter())>::value, ""); - static_assert(is_generic<decltype(sqr(counter()))>::value, ""); - const univector<c32, 4> uv1 = sqr(counter()); CHECK(uv1[0] == c32{ 0, 0 }); CHECK(uv1[1] == c32{ 1, 0 });