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 2d7cdb3a76f5ec0921df5e327d97241a0b8e5160
parent c7f8b429fb63191d006ad6a6e2c54856bf69a610
Author: samuriddle@gmail.com <samuriddle@gmail.com>
Date:   Sun, 31 Jul 2016 17:28:19 +0300

merge base and expressions folders

Diffstat:
Mexamples/dft.cpp | 4++--
Mexamples/fir.cpp | 2+-
Minclude/kfr/all.hpp | 14+++++++-------
Rinclude/kfr/expressions/basic.hpp -> include/kfr/base/basic_expressions.hpp | 0
Ainclude/kfr/base/conversion.hpp | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
Rinclude/kfr/expressions/generators.hpp -> include/kfr/base/generators.hpp | 0
Ainclude/kfr/base/pointer.hpp | 169+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/kfr/base/reduce.hpp | 206+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Minclude/kfr/dsp/fir.hpp | 5+++--
Minclude/kfr/dsp/goertzel.hpp | 2+-
Minclude/kfr/dsp/impulse.hpp | 2+-
Minclude/kfr/dsp/oscillators.hpp | 2+-
Minclude/kfr/dsp/resample.hpp | 2+-
Minclude/kfr/dsp/units.hpp | 2+-
Minclude/kfr/dsp/window.hpp | 2+-
Dinclude/kfr/expressions/conversion.hpp | 53-----------------------------------------------------
Dinclude/kfr/expressions/pointer.hpp | 169-------------------------------------------------------------------------------
Dinclude/kfr/expressions/reduce.hpp | 206-------------------------------------------------------------------------------
Minclude/kfr/io/audiofile.hpp | 2+-
Msources.cmake | 10+++++-----
Mtests/complex_test.cpp | 4++--
Mtests/conv_test.cpp | 2+-
Mtests/dft_test.cpp | 4++--
Mtests/fracdelay_test.cpp | 2+-
Mtests/stat_test.cpp | 2+-
25 files changed, 460 insertions(+), 459 deletions(-)

diff --git a/examples/dft.cpp b/examples/dft.cpp @@ -12,13 +12,13 @@ // print(), format() #include <kfr/cometa/string.hpp> +#include <kfr/base/basic_expressions.hpp> #include <kfr/base/random.hpp> +#include <kfr/base/reduce.hpp> #include <kfr/dft/fft.hpp> #include <kfr/dft/reference_dft.hpp> #include <kfr/dsp/oscillators.hpp> #include <kfr/dsp/units.hpp> -#include <kfr/expressions/basic.hpp> -#include <kfr/expressions/reduce.hpp> #include <kfr/math.hpp> using namespace kfr; diff --git a/examples/fir.cpp b/examples/fir.cpp @@ -13,7 +13,7 @@ #include <kfr/math.hpp> // expression_pointer<>, topointer() -#include <kfr/expressions/pointer.hpp> +#include <kfr/base/pointer.hpp> // simpleimpulse() #include <kfr/dsp/oscillators.hpp> diff --git a/include/kfr/all.hpp b/include/kfr/all.hpp @@ -26,13 +26,18 @@ #include "base/abs.hpp" #include "base/asin_acos.hpp" #include "base/atan.hpp" +#include "base/basic_expressions.hpp" #include "base/clamp.hpp" #include "base/compiletime.hpp" #include "base/complex.hpp" #include "base/constants.hpp" +#include "base/conversion.hpp" +#include "base/cpuid.hpp" +#include "base/cpuid_auto.hpp" #include "base/digitreverse.hpp" #include "base/function.hpp" #include "base/gamma.hpp" +#include "base/generators.hpp" #include "base/hyperbolic.hpp" #include "base/log_exp.hpp" #include "base/logical.hpp" @@ -40,8 +45,10 @@ #include "base/min_max.hpp" #include "base/modzerobessel.hpp" #include "base/operators.hpp" +#include "base/pointer.hpp" #include "base/random.hpp" #include "base/read_write.hpp" +#include "base/reduce.hpp" #include "base/round.hpp" #include "base/saturation.hpp" #include "base/select.hpp" @@ -54,13 +61,6 @@ #include "base/types.hpp" #include "base/univector.hpp" #include "base/vec.hpp" -#include "base/cpuid.hpp" -#include "base/cpuid_auto.hpp" -#include "expressions/basic.hpp" -#include "expressions/conversion.hpp" -#include "expressions/generators.hpp" -#include "expressions/pointer.hpp" -#include "expressions/reduce.hpp" #include "version.hpp" #include "data/bitrev.hpp" diff --git a/include/kfr/expressions/basic.hpp b/include/kfr/base/basic_expressions.hpp diff --git a/include/kfr/base/conversion.hpp b/include/kfr/base/conversion.hpp @@ -0,0 +1,53 @@ +/** + * Copyright (C) 2016 D Levin (http://www.kfrlib.com) + * This file is part of KFR + * + * KFR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * KFR is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with KFR. + * + * If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + * Buying a commercial license is mandatory as soon as you develop commercial activities without + * disclosing the source code of your own applications. + * See http://www.kfrlib.com for details. + */ + +#pragma once + +#include "../base/basic_expressions.hpp" +#include "../base/function.hpp" +#include "../base/operators.hpp" +#include "../base/vec.hpp" + +namespace kfr +{ +namespace internal +{ +template <typename From, typename E> +struct expression_convert : expression<E> +{ + KFR_INLINE expression_convert(E&& expr) noexcept : expression<E>(std::forward<E>(expr)) {} + + template <typename T, size_t N> + KFR_INLINE vec<T, N> operator()(cinput_t, size_t index, vec_t<T, N>) const + { + return this->argument_first(index, vec_t<From, N>()); + } +}; +} + +template <typename From, typename E> +KFR_INLINE internal::expression_convert<From, decay<E>> convert(E&& expr) +{ + return internal::expression_convert<From, decay<E>>(std::forward<E>(expr)); +} +} diff --git a/include/kfr/expressions/generators.hpp b/include/kfr/base/generators.hpp diff --git a/include/kfr/base/pointer.hpp b/include/kfr/base/pointer.hpp @@ -0,0 +1,169 @@ +/** + * Copyright (C) 2016 D Levin (http://www.kfrlib.com) + * This file is part of KFR + * + * KFR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * KFR is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with KFR. + * + * If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + * Buying a commercial license is mandatory as soon as you develop commercial activities without + * disclosing the source code of your own applications. + * See http://www.kfrlib.com for details. + */ +#pragma once + +#include "../base/vec.hpp" +#include "basic_expressions.hpp" +#include <memory> + +namespace kfr +{ + +constexpr size_t maximum_expression_width() { return bitness_const(16, 32); } + +template <typename T, size_t maxwidth = maximum_expression_width()> +using expression_vtable = carray<void*, 2 + ilog2(maxwidth) + 1>; + +struct dummy_content +{ +}; + +struct expression_resource +{ + virtual ~expression_resource() {} + virtual void* instance() { return nullptr; } +}; +template <typename E> +struct alignas(E) expression_resource_impl : expression_resource +{ + expression_resource_impl(E&& e) noexcept : e(std::move(e)) {} + virtual ~expression_resource_impl() {} + virtual void* instance() override final { return &e; } +private: + E e; +}; + +template <typename E> +std::shared_ptr<expression_resource> make_resource(E&& e) +{ + using T = expression_resource_impl<decay<E>>; + return std::static_pointer_cast<expression_resource>( + std::allocate_shared<T>(allocator<T>(), std::move(e))); +} + +template <typename T, size_t maxwidth = maximum_expression_width()> +struct expression_pointer : input_expression +{ + using value_type = T; + + static_assert(is_poweroftwo(maxwidth), "N must be a power of two"); + expression_pointer() noexcept : instance(nullptr), vtable(nullptr) {} + expression_pointer(void* instance, const expression_vtable<T, maxwidth>* vtable, + std::shared_ptr<expression_resource> resource = nullptr) + : instance(instance), vtable(vtable), resource(std::move(resource)) + { + } + template <typename U, size_t N> + KFR_INLINE vec<U, N> operator()(cinput_t, size_t index, vec_t<U, N>) const + { + using func_t = simd<T, N> (*)(void*, size_t); + + static_assert(is_poweroftwo(N), "N must be a power of two"); + constexpr size_t findex = ilog2(N); + static_assert(N <= maxwidth, "N is greater than maxwidth"); + func_t func = reinterpret_cast<func_t>(vtable->get(csize<2 + findex>)); + vec<U, N> result = cast<U>(func(instance, index)); + return result; + } + KFR_INLINE void begin_block(size_t size) const + { + using func_t = void (*)(void*, size_t); + func_t func = reinterpret_cast<func_t>(vtable->get(csize<0>)); + func(instance, size); + } + KFR_INLINE void end_block(size_t size) const + { + using func_t = void (*)(void*, size_t); + func_t func = reinterpret_cast<func_t>(vtable->get(csize<1>)); + func(instance, size); + } + +private: + void* instance; + const expression_vtable<T, maxwidth>* vtable; + std::shared_ptr<expression_resource> resource; +}; + +namespace internal +{ +template <typename T, size_t N, typename Fn, typename Ret = simd<T, N>, + typename NonMemFn = Ret (*)(Fn*, size_t, vec_t<T, N>)> +KFR_INLINE NonMemFn make_expression_func() +{ + return [](Fn* fn, size_t index, vec_t<T, N> x) { return *(fn->operator()(cinput, index, x)); }; +} + +template <typename Fn, typename NonMemFn = void (*)(Fn*, size_t)> +KFR_INLINE NonMemFn make_expression_begin_block() +{ + return [](Fn* fn, size_t size) { return fn->begin_block(size); }; +} +template <typename Fn, typename NonMemFn = void (*)(Fn*, size_t)> +KFR_INLINE NonMemFn make_expression_end_block() +{ + return [](Fn* fn, size_t size) { return fn->end_block(size); }; +} + +template <typename T, size_t maxwidth, typename E> +expression_vtable<T, maxwidth> make_expression_vtable_impl() +{ + expression_vtable<T, maxwidth> result; + constexpr size_t size = result.size() - 2; + + result.get(csize<0>) = reinterpret_cast<void*>(&internal::make_expression_begin_block<decay<E>>); + result.get(csize<1>) = reinterpret_cast<void*>(&internal::make_expression_end_block<decay<E>>); + + cforeach(csizeseq<size>, [&](auto u) { + constexpr size_t N = 1 << val_of(u); + result.get(csize<2 + val_of(u)>) = + reinterpret_cast<void*>(internal::make_expression_func<T, N, decay<E>>()); + }); + return result; +} + +template <typename T, size_t maxwidth, typename E> +KFR_INLINE expression_vtable<T, maxwidth>* make_expression_vtable() +{ + static_assert(is_input_expression<E>::value, "E must be an expression"); + static expression_vtable<T, maxwidth> vtable = internal::make_expression_vtable_impl<T, maxwidth, E>(); + return &vtable; +} +} + +template <typename E, typename T = value_type_of<E>, size_t maxwidth = maximum_expression_width()> +KFR_INLINE expression_pointer<T, maxwidth> to_pointer(E& expr) +{ + static_assert(is_input_expression<E>::value, "E must be an expression"); + return expression_pointer<T, maxwidth>(std::addressof(expr), + internal::make_expression_vtable<T, maxwidth, E>()); +} + +template <typename E, typename T = value_type_of<E>, size_t maxwidth = maximum_expression_width()> +KFR_INLINE expression_pointer<T, maxwidth> to_pointer(E&& expr) +{ + static_assert(is_input_expression<E>::value, "E must be an expression"); + std::shared_ptr<expression_resource> ptr = make_resource(std::move(expr)); + return expression_pointer<T, maxwidth>( + ptr->instance(), internal::make_expression_vtable<T, maxwidth, E>(), std::move(ptr)); +} +} diff --git a/include/kfr/base/reduce.hpp b/include/kfr/base/reduce.hpp @@ -0,0 +1,206 @@ +/** + * Copyright (C) 2016 D Levin (http://www.kfrlib.com) + * This file is part of KFR + * + * KFR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * KFR is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with KFR. + * + * If GPL is not suitable for your project, you must purchase a commercial license to use KFR. + * Buying a commercial license is mandatory as soon as you develop commercial activities without + * disclosing the source code of your own applications. + * See http://www.kfrlib.com for details. + */ +#pragma once + +#include "../base/function.hpp" +#include "../base/min_max.hpp" +#include "../base/operators.hpp" +#include "../base/vec.hpp" +#include "basic_expressions.hpp" + +namespace kfr +{ + +template <typename T> +KFR_INLINE T final_mean(T value, size_t size) +{ + return value / T(size); +} +KFR_FN(final_mean) + +template <typename T> +KFR_INLINE T final_rootmean(T value, size_t size) +{ + return internal::builtin_sqrt(value / T(size)); +} +KFR_FN(final_rootmean) + +namespace internal +{ +template <typename FinalFn, typename T, KFR_ENABLE_IF(is_callable<FinalFn, T, size_t>::value)> +KFR_INLINE auto reduce_call_final(FinalFn&& finalfn, size_t size, T value) +{ + return finalfn(value, size); +} +template <typename FinalFn, typename T, KFR_ENABLE_IF(!is_callable<FinalFn, T, size_t>::value)> +KFR_INLINE auto reduce_call_final(FinalFn&& finalfn, size_t, T value) +{ + return finalfn(value); +} + +template <typename T, typename ReduceFn, typename TransformFn, typename FinalFn, cpu_t cpu = cpu_t::native> +struct expression_reduce : output_expression +{ + constexpr static size_t width = vector_width<T, cpu> * bitness_const(1, 2); + + expression_reduce(ReduceFn&& reducefn, TransformFn&& transformfn, FinalFn&& finalfn) + : counter(0), reducefn(std::move(reducefn)), transformfn(std::move(transformfn)), + finalfn(std::move(finalfn)), value(resize<width>(make_vector(reducefn(initialvalue<T>{})))) + { + } + + template <typename U, size_t N> + KFR_INLINE void operator()(coutput_t, size_t, const vec<U, N>& x) const + { + counter += N; + process(x); + } + + KFR_INLINE T get() { return internal::reduce_call_final(finalfn, counter, horizontal(value, reducefn)); } + +protected: + void reset() { counter = 0; } + KFR_INLINE void process(vec<T, width> x) const { value = reducefn(transformfn(x), value); } + + template <size_t N, KFR_ENABLE_IF(N < width)> + KFR_INLINE void process(vec<T, N> x) const + { + value = combine(value, reducefn(transformfn(x), narrow<N>(value))); + } + + template <size_t N, KFR_ENABLE_IF(N > width)> + KFR_INLINE void process(vec<T, N> x) const + { + process(low(x)); + process(high(x)); + } + + mutable size_t counter; + ReduceFn reducefn; + TransformFn transformfn; + FinalFn finalfn; + mutable vec<T, width> value; +}; + +template <typename ReduceFn, typename TransformFn = fn_pass_through, typename FinalFn = fn_pass_through, + typename E1, typename T = value_type_of<E1>> +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>>; + reducer_t red(std::forward<ReduceFn>(reducefn), std::forward<TransformFn>(transformfn), + std::forward<FinalFn>(finalfn)); + process<T>(red, std::forward<E1>(e1), size); + + return red.get(); +} + +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()); +} + +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()); +} + +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()); +} + +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()); +} + +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()); +} + +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()); +} + +template <typename E1, typename E2, typename T = value_type_of<E1>, + KFR_ENABLE_IF(is_input_expressions<E1, E2>::value)> +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()); +} + +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()); +} + +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()); +} + +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/dsp/fir.hpp b/include/kfr/dsp/fir.hpp @@ -22,11 +22,12 @@ */ #pragma once +#include "../base/basic_expressions.hpp" #include "../base/memory.hpp" +#include "../base/reduce.hpp" #include "../base/sin_cos.hpp" +#include "../base/univector.hpp" #include "../base/vec.hpp" -#include "../expressions/basic.hpp" -#include "../expressions/reduce.hpp" #include "window.hpp" namespace kfr diff --git a/include/kfr/dsp/goertzel.hpp b/include/kfr/dsp/goertzel.hpp @@ -22,10 +22,10 @@ */ #pragma once +#include "../base/basic_expressions.hpp" #include "../base/complex.hpp" #include "../base/sin_cos.hpp" #include "../base/vec.hpp" -#include "../expressions/basic.hpp" namespace kfr { diff --git a/include/kfr/dsp/impulse.hpp b/include/kfr/dsp/impulse.hpp @@ -22,8 +22,8 @@ */ #pragma once +#include "../base/basic_expressions.hpp" #include "../base/vec.hpp" -#include "../expressions/basic.hpp" namespace kfr { diff --git a/include/kfr/dsp/oscillators.hpp b/include/kfr/dsp/oscillators.hpp @@ -22,8 +22,8 @@ */ #pragma once +#include "../base/basic_expressions.hpp" #include "../base/sin_cos.hpp" -#include "../expressions/basic.hpp" namespace kfr { diff --git a/include/kfr/dsp/resample.hpp b/include/kfr/dsp/resample.hpp @@ -24,8 +24,8 @@ #include "../base/function.hpp" #include "../base/memory.hpp" +#include "../base/reduce.hpp" #include "../base/vec.hpp" -#include "../expressions/reduce.hpp" #include "window.hpp" namespace kfr diff --git a/include/kfr/dsp/units.hpp b/include/kfr/dsp/units.hpp @@ -27,9 +27,9 @@ */ #pragma once +#include "../base/basic_expressions.hpp" #include "../base/log_exp.hpp" #include "../base/vec.hpp" -#include "../expressions/basic.hpp" namespace kfr { diff --git a/include/kfr/dsp/window.hpp b/include/kfr/dsp/window.hpp @@ -24,10 +24,10 @@ #include "../base/log_exp.hpp" #include "../base/modzerobessel.hpp" +#include "../base/pointer.hpp" #include "../base/sin_cos.hpp" #include "../base/sqrt.hpp" #include "../base/vec.hpp" -#include "../expressions/pointer.hpp" namespace kfr { diff --git a/include/kfr/expressions/conversion.hpp b/include/kfr/expressions/conversion.hpp @@ -1,53 +0,0 @@ -/** - * Copyright (C) 2016 D Levin (http://www.kfrlib.com) - * This file is part of KFR - * - * KFR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * KFR is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with KFR. - * - * If GPL is not suitable for your project, you must purchase a commercial license to use KFR. - * Buying a commercial license is mandatory as soon as you develop commercial activities without - * disclosing the source code of your own applications. - * See http://www.kfrlib.com for details. - */ - -#pragma once - -#include "../base/function.hpp" -#include "../base/operators.hpp" -#include "../base/vec.hpp" -#include "../expressions/basic.hpp" - -namespace kfr -{ -namespace internal -{ -template <typename From, typename E> -struct expression_convert : expression<E> -{ - KFR_INLINE expression_convert(E&& expr) noexcept : expression<E>(std::forward<E>(expr)) {} - - template <typename T, size_t N> - KFR_INLINE vec<T, N> operator()(cinput_t, size_t index, vec_t<T, N>) const - { - return this->argument_first(index, vec_t<From, N>()); - } -}; -} - -template <typename From, typename E> -KFR_INLINE internal::expression_convert<From, decay<E>> convert(E&& expr) -{ - return internal::expression_convert<From, decay<E>>(std::forward<E>(expr)); -} -} diff --git a/include/kfr/expressions/pointer.hpp b/include/kfr/expressions/pointer.hpp @@ -1,169 +0,0 @@ -/** - * Copyright (C) 2016 D Levin (http://www.kfrlib.com) - * This file is part of KFR - * - * KFR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * KFR is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with KFR. - * - * If GPL is not suitable for your project, you must purchase a commercial license to use KFR. - * Buying a commercial license is mandatory as soon as you develop commercial activities without - * disclosing the source code of your own applications. - * See http://www.kfrlib.com for details. - */ -#pragma once - -#include "../base/vec.hpp" -#include "basic.hpp" -#include <memory> - -namespace kfr -{ - -constexpr size_t maximum_expression_width() { return bitness_const(16, 32); } - -template <typename T, size_t maxwidth = maximum_expression_width()> -using expression_vtable = carray<void*, 2 + ilog2(maxwidth) + 1>; - -struct dummy_content -{ -}; - -struct expression_resource -{ - virtual ~expression_resource() {} - virtual void* instance() { return nullptr; } -}; -template <typename E> -struct alignas(E) expression_resource_impl : expression_resource -{ - expression_resource_impl(E&& e) noexcept : e(std::move(e)) {} - virtual ~expression_resource_impl() {} - virtual void* instance() override final { return &e; } -private: - E e; -}; - -template <typename E> -std::shared_ptr<expression_resource> make_resource(E&& e) -{ - using T = expression_resource_impl<decay<E>>; - return std::static_pointer_cast<expression_resource>( - std::allocate_shared<T>(allocator<T>(), std::move(e))); -} - -template <typename T, size_t maxwidth = maximum_expression_width()> -struct expression_pointer : input_expression -{ - using value_type = T; - - static_assert(is_poweroftwo(maxwidth), "N must be a power of two"); - expression_pointer() noexcept : instance(nullptr), vtable(nullptr) {} - expression_pointer(void* instance, const expression_vtable<T, maxwidth>* vtable, - std::shared_ptr<expression_resource> resource = nullptr) - : instance(instance), vtable(vtable), resource(std::move(resource)) - { - } - template <typename U, size_t N> - KFR_INLINE vec<U, N> operator()(cinput_t, size_t index, vec_t<U, N>) const - { - using func_t = simd<T, N> (*)(void*, size_t); - - static_assert(is_poweroftwo(N), "N must be a power of two"); - constexpr size_t findex = ilog2(N); - static_assert(N <= maxwidth, "N is greater than maxwidth"); - func_t func = reinterpret_cast<func_t>(vtable->get(csize<2 + findex>)); - vec<U, N> result = cast<U>(func(instance, index)); - return result; - } - KFR_INLINE void begin_block(size_t size) const - { - using func_t = void (*)(void*, size_t); - func_t func = reinterpret_cast<func_t>(vtable->get(csize<0>)); - func(instance, size); - } - KFR_INLINE void end_block(size_t size) const - { - using func_t = void (*)(void*, size_t); - func_t func = reinterpret_cast<func_t>(vtable->get(csize<1>)); - func(instance, size); - } - -private: - void* instance; - const expression_vtable<T, maxwidth>* vtable; - std::shared_ptr<expression_resource> resource; -}; - -namespace internal -{ -template <typename T, size_t N, typename Fn, typename Ret = simd<T, N>, - typename NonMemFn = Ret (*)(Fn*, size_t, vec_t<T, N>)> -KFR_INLINE NonMemFn make_expression_func() -{ - return [](Fn* fn, size_t index, vec_t<T, N> x) { return *(fn->operator()(cinput, index, x)); }; -} - -template <typename Fn, typename NonMemFn = void (*)(Fn*, size_t)> -KFR_INLINE NonMemFn make_expression_begin_block() -{ - return [](Fn* fn, size_t size) { return fn->begin_block(size); }; -} -template <typename Fn, typename NonMemFn = void (*)(Fn*, size_t)> -KFR_INLINE NonMemFn make_expression_end_block() -{ - return [](Fn* fn, size_t size) { return fn->end_block(size); }; -} - -template <typename T, size_t maxwidth, typename E> -expression_vtable<T, maxwidth> make_expression_vtable_impl() -{ - expression_vtable<T, maxwidth> result; - constexpr size_t size = result.size() - 2; - - result.get(csize<0>) = reinterpret_cast<void*>(&internal::make_expression_begin_block<decay<E>>); - result.get(csize<1>) = reinterpret_cast<void*>(&internal::make_expression_end_block<decay<E>>); - - cforeach(csizeseq<size>, [&](auto u) { - constexpr size_t N = 1 << val_of(u); - result.get(csize<2 + val_of(u)>) = - reinterpret_cast<void*>(internal::make_expression_func<T, N, decay<E>>()); - }); - return result; -} - -template <typename T, size_t maxwidth, typename E> -KFR_INLINE expression_vtable<T, maxwidth>* make_expression_vtable() -{ - static_assert(is_input_expression<E>::value, "E must be an expression"); - static expression_vtable<T, maxwidth> vtable = internal::make_expression_vtable_impl<T, maxwidth, E>(); - return &vtable; -} -} - -template <typename E, typename T = value_type_of<E>, size_t maxwidth = maximum_expression_width()> -KFR_INLINE expression_pointer<T, maxwidth> to_pointer(E& expr) -{ - static_assert(is_input_expression<E>::value, "E must be an expression"); - return expression_pointer<T, maxwidth>(std::addressof(expr), - internal::make_expression_vtable<T, maxwidth, E>()); -} - -template <typename E, typename T = value_type_of<E>, size_t maxwidth = maximum_expression_width()> -KFR_INLINE expression_pointer<T, maxwidth> to_pointer(E&& expr) -{ - static_assert(is_input_expression<E>::value, "E must be an expression"); - std::shared_ptr<expression_resource> ptr = make_resource(std::move(expr)); - return expression_pointer<T, maxwidth>( - ptr->instance(), internal::make_expression_vtable<T, maxwidth, E>(), std::move(ptr)); -} -} diff --git a/include/kfr/expressions/reduce.hpp b/include/kfr/expressions/reduce.hpp @@ -1,206 +0,0 @@ -/** - * Copyright (C) 2016 D Levin (http://www.kfrlib.com) - * This file is part of KFR - * - * KFR is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * KFR is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with KFR. - * - * If GPL is not suitable for your project, you must purchase a commercial license to use KFR. - * Buying a commercial license is mandatory as soon as you develop commercial activities without - * disclosing the source code of your own applications. - * See http://www.kfrlib.com for details. - */ -#pragma once - -#include "../base/function.hpp" -#include "../base/min_max.hpp" -#include "../base/operators.hpp" -#include "../base/vec.hpp" -#include "basic.hpp" - -namespace kfr -{ - -template <typename T> -KFR_INLINE T final_mean(T value, size_t size) -{ - return value / T(size); -} -KFR_FN(final_mean) - -template <typename T> -KFR_INLINE T final_rootmean(T value, size_t size) -{ - return internal::builtin_sqrt(value / T(size)); -} -KFR_FN(final_rootmean) - -namespace internal -{ -template <typename FinalFn, typename T, KFR_ENABLE_IF(is_callable<FinalFn, T, size_t>::value)> -KFR_INLINE auto reduce_call_final(FinalFn&& finalfn, size_t size, T value) -{ - return finalfn(value, size); -} -template <typename FinalFn, typename T, KFR_ENABLE_IF(!is_callable<FinalFn, T, size_t>::value)> -KFR_INLINE auto reduce_call_final(FinalFn&& finalfn, size_t, T value) -{ - return finalfn(value); -} - -template <typename T, typename ReduceFn, typename TransformFn, typename FinalFn, cpu_t cpu = cpu_t::native> -struct expression_reduce : output_expression -{ - constexpr static size_t width = vector_width<T, cpu> * bitness_const(1, 2); - - expression_reduce(ReduceFn&& reducefn, TransformFn&& transformfn, FinalFn&& finalfn) - : counter(0), reducefn(std::move(reducefn)), transformfn(std::move(transformfn)), - finalfn(std::move(finalfn)), value(resize<width>(make_vector(reducefn(initialvalue<T>{})))) - { - } - - template <typename U, size_t N> - KFR_INLINE void operator()(coutput_t, size_t, const vec<U, N>& x) const - { - counter += N; - process(x); - } - - KFR_INLINE T get() { return internal::reduce_call_final(finalfn, counter, horizontal(value, reducefn)); } - -protected: - void reset() { counter = 0; } - KFR_INLINE void process(vec<T, width> x) const { value = reducefn(transformfn(x), value); } - - template <size_t N, KFR_ENABLE_IF(N < width)> - KFR_INLINE void process(vec<T, N> x) const - { - value = combine(value, reducefn(transformfn(x), narrow<N>(value))); - } - - template <size_t N, KFR_ENABLE_IF(N > width)> - KFR_INLINE void process(vec<T, N> x) const - { - process(low(x)); - process(high(x)); - } - - mutable size_t counter; - ReduceFn reducefn; - TransformFn transformfn; - FinalFn finalfn; - mutable vec<T, width> value; -}; - -template <typename ReduceFn, typename TransformFn = fn_pass_through, typename FinalFn = fn_pass_through, - typename E1, typename T = value_type_of<E1>> -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>>; - reducer_t red(std::forward<ReduceFn>(reducefn), std::forward<TransformFn>(transformfn), - std::forward<FinalFn>(finalfn)); - process<T>(red, std::forward<E1>(e1), size); - - return red.get(); -} - -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()); -} - -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()); -} - -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()); -} - -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()); -} - -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()); -} - -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()); -} - -template <typename E1, typename E2, typename T = value_type_of<E1>, - KFR_ENABLE_IF(is_input_expressions<E1, E2>::value)> -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()); -} - -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()); -} - -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()); -} - -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/io/audiofile.hpp b/include/kfr/io/audiofile.hpp @@ -22,9 +22,9 @@ */ #pragma once +#include "../base/basic_expressions.hpp" #include "../base/univector.hpp" #include "../base/vec.hpp" -#include "../expressions/basic.hpp" #include "file.hpp" namespace kfr diff --git a/sources.cmake b/sources.cmake @@ -72,11 +72,11 @@ set( ${PROJECT_SOURCE_DIR}/include/kfr/dsp/waveshaper.hpp ${PROJECT_SOURCE_DIR}/include/kfr/dsp/weighting.hpp ${PROJECT_SOURCE_DIR}/include/kfr/dsp/window.hpp - ${PROJECT_SOURCE_DIR}/include/kfr/expressions/basic.hpp - ${PROJECT_SOURCE_DIR}/include/kfr/expressions/conversion.hpp - ${PROJECT_SOURCE_DIR}/include/kfr/expressions/generators.hpp - ${PROJECT_SOURCE_DIR}/include/kfr/expressions/pointer.hpp - ${PROJECT_SOURCE_DIR}/include/kfr/expressions/reduce.hpp + ${PROJECT_SOURCE_DIR}/include/kfr/base/basic_expressions.hpp + ${PROJECT_SOURCE_DIR}/include/kfr/base/conversion.hpp + ${PROJECT_SOURCE_DIR}/include/kfr/base/generators.hpp + ${PROJECT_SOURCE_DIR}/include/kfr/base/pointer.hpp + ${PROJECT_SOURCE_DIR}/include/kfr/base/reduce.hpp ${PROJECT_SOURCE_DIR}/include/kfr/io/audiofile.hpp ${PROJECT_SOURCE_DIR}/include/kfr/io/file.hpp ${PROJECT_SOURCE_DIR}/include/kfr/io/python_plot.hpp diff --git a/tests/complex_test.cpp b/tests/complex_test.cpp @@ -7,10 +7,10 @@ #include <kfr/io/tostring.hpp> #include "testo/testo.hpp" +#include <kfr/base/basic_expressions.hpp> #include <kfr/base/complex.hpp> +#include <kfr/base/reduce.hpp> #include <kfr/cometa/string.hpp> -#include <kfr/expressions/basic.hpp> -#include <kfr/expressions/reduce.hpp> #include <kfr/math.hpp> #include <kfr/version.hpp> diff --git a/tests/conv_test.cpp b/tests/conv_test.cpp @@ -8,7 +8,7 @@ #include <kfr/io/tostring.hpp> #include <kfr/version.hpp> -#include <kfr/expressions/reduce.hpp> +#include <kfr/base/reduce.hpp> #include <tuple> diff --git a/tests/dft_test.cpp b/tests/dft_test.cpp @@ -10,12 +10,12 @@ #include <tuple> #include "testo/testo.hpp" +#include <kfr/base/basic_expressions.hpp> #include <kfr/base/random.hpp> +#include <kfr/base/reduce.hpp> #include <kfr/cometa/string.hpp> #include <kfr/dft/fft.hpp> #include <kfr/dft/reference_dft.hpp> -#include <kfr/expressions/basic.hpp> -#include <kfr/expressions/reduce.hpp> #include <kfr/io/tostring.hpp> #include <kfr/math.hpp> #include <kfr/version.hpp> diff --git a/tests/fracdelay_test.cpp b/tests/fracdelay_test.cpp @@ -8,7 +8,7 @@ #include <kfr/io/tostring.hpp> #include <kfr/version.hpp> -#include <kfr/expressions/reduce.hpp> +#include <kfr/base/reduce.hpp> #include <tuple> diff --git a/tests/stat_test.cpp b/tests/stat_test.cpp @@ -10,7 +10,7 @@ #include <kfr/math.hpp> -#include <kfr/expressions/reduce.hpp> +#include <kfr/base/reduce.hpp> #include <tuple>