commit 35d5c0c5c1718f076f541c96be5f40e7dd00c04c
parent 0e2acdf098b243683853f777f3ee864389f630b4
Author: d.levin256@gmail.com <d.levin256@gmail.com>
Date: Sun, 21 Oct 2018 18:55:26 +0300
Merge branch 'dev'
Diffstat:
9 files changed, 318 insertions(+), 151 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -69,6 +69,8 @@ var/
*.egg-info/
.installed.cfg
*.egg
+venv/
+
# Sphinx documentation
docs/
@@ -76,5 +78,10 @@ docs/
# CLion
.idea/
+# VSCode
+.vs-code/
+
+# CLion
+cmake-*
-*.TMP
-\ No newline at end of file
+*.TMP
diff --git a/.travis.yml b/.travis.yml
@@ -43,11 +43,15 @@ matrix:
osx_image: xcode9.4
env:
- TEST=XCODE9.4 CMAKEARGS="-DCMAKE_BUILD_TYPE=Release .."
+ - os: osx
+ osx_image: xcode10
+ env:
+ - TEST=XCODE10.0 CMAKEARGS="-DCMAKE_BUILD_TYPE=Release .."
before_install:
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then cmake --version || brew install cmake; fi
- cmake --version
-
+
script:
- mkdir build
- cd build
diff --git a/examples/biquads.cpp b/examples/biquads.cpp
@@ -20,7 +20,7 @@ int main()
{
biquad_params<fbase> bq[] = { biquad_notch(0.1, 0.5), biquad_notch(0.2, 0.5), biquad_notch(0.3, 0.5),
biquad_notch(0.4, 0.5) };
- output = biquad(bq, unitimpulse());
+ output = biquad(bq, unitimpulse());
}
plot_save("biquad_notch", output, options + ", title='Four Biquad Notch filters'");
@@ -66,5 +66,33 @@ int main()
}
plot_save("biquad_bandpass", output, options + ", title='Biquad band pass (0.25, 0.2)'");
+ {
+ // filter initialization
+ biquad_params<fbase> bq[] = { biquad_lowpass(0.2, 0.9) };
+ expression_filter<fbase> filter = to_filter(biquad(bq, placeholder<fbase>()));
+
+ // prepare data
+ output = unitimpulse();
+
+ // apply filter
+ filter.apply(output);
+ }
+ plot_save("biquad_custom_filter_lowpass", output,
+ options + ", title='Biquad Low pass filter (0.2, 0.9) (using expression_filter)'");
+
+ {
+ // filter initialization
+ biquad_params<fbase> bq[] = { biquad_lowpass(0.2, 0.9) };
+ biquad_filter<fbase> filter(bq);
+
+ // prepare data
+ output = unitimpulse();
+
+ // apply filter
+ filter.apply(output);
+ }
+ plot_save("biquad_filter_lowpass", output,
+ options + ", title='Biquad Low pass filter (0.2, 0.9) (using biquad_filter)'");
+
return 0;
}
diff --git a/include/kfr/base/filter.hpp b/include/kfr/base/filter.hpp
@@ -26,6 +26,7 @@
#pragma once
#include "basic_expressions.hpp"
+#include "expression.hpp"
#include "pointer.hpp"
#include "univector.hpp"
@@ -101,4 +102,43 @@ protected:
virtual void process_buffer(T* dest, const T* src, size_t size) = 0;
virtual void process_expression(T* dest, const expression_pointer<T>& src, size_t size) = 0;
};
+
+template <typename T>
+class expression_filter : public filter<T>
+{
+public:
+ template <typename... Args>
+ explicit expression_filter(expression_pointer<T>&& filter_expr) : filter_expr(std::move(filter_expr))
+ {
+ }
+
+protected:
+ void process_buffer(T* dest, const T* src, size_t size) override
+ {
+ substitute(filter_expr, to_pointer(make_univector(src, size)));
+ process(make_univector(dest, size), filter_expr, 0, size);
+ }
+ void process_expression(T* dest, const expression_pointer<T>& src, size_t size) override
+ {
+ substitute(filter_expr, src);
+ process(make_univector(dest, size), filter_expr, 0, size);
+ }
+
+ expression_pointer<T> filter_expr;
+};
+
+/// @brief Converts expression with placeholder to filter. Placeholder and filter must have the same type
+template <typename E, typename T = value_type_of<E>>
+KFR_SINTRIN expression_filter<T> to_filter(E&& e)
+{
+ return expression_filter<T>(to_pointer(std::move(e)));
}
+
+/// @brief Converts expression with placeholder to filter. Placeholder and filter must have the same type
+template <typename T, typename E>
+KFR_SINTRIN expression_filter<T> to_filter(expression_pointer<T>&& e)
+{
+ return expression_filter<T>(std::move(e));
+}
+
+} // namespace kfr
diff --git a/include/kfr/base/pointer.hpp b/include/kfr/base/pointer.hpp
@@ -34,13 +34,79 @@ namespace kfr
constexpr size_t maximum_expression_width = platform<float>::vector_capacity / 4;
-constexpr size_t expression_vtable_size = 3 + ilog2(maximum_expression_width) + 1;
+template <typename T, bool enable_resource = true>
+struct expression_pointer;
-template <typename T>
-using expression_vtable = std::array<void*, expression_vtable_size>;
+namespace internal
+{
+
+template <typename Expression, typename T, size_t key = 0>
+KFR_SINTRIN bool invoke_substitute(Expression& expr, expression_pointer<T>&& new_pointer,
+ csize_t<key> = csize_t<key>{});
+
+}
+
+template <typename T, size_t N = maximum_expression_width>
+struct expression_vtable : expression_vtable<T, N / 2>
+{
+ using func_get = void (*)(void*, size_t, vec<T, N>&);
+ func_get get;
+
+ template <typename Expression>
+ expression_vtable(ctype_t<Expression> t)
+ : expression_vtable<T, N / 2>(t), get(&expression_vtable<T, N>::template static_get<Expression>)
+ {
+ }
+
+ template <typename Expression>
+ static void static_get(void* instance, size_t index, vec<T, N>& result)
+ {
+ result = static_cast<Expression*>(instance)->operator()(cinput, index, vec_t<T, N>());
+ }
+};
-struct dummy_content
+template <typename T>
+struct expression_vtable<T, 0>
{
+ using func_size = size_t (*)(void* p);
+ using func_begin_block = void (*)(void*, size_t);
+ using func_end_block = void (*)(void*, size_t);
+ using func_substitute = bool (*)(void*, expression_pointer<T>&&);
+
+ func_size size;
+ func_begin_block begin_block;
+ func_end_block end_block;
+ func_substitute substitute;
+
+ template <typename Expression>
+ expression_vtable(ctype_t<Expression> t)
+ : size(&expression_vtable<T, 0>::template static_size<Expression>),
+ begin_block(&expression_vtable<T, 0>::template static_begin_block<Expression>),
+ end_block(&expression_vtable<T, 0>::template static_end_block<Expression>),
+ substitute(&expression_vtable<T, 0>::template static_substitute<Expression>)
+ {
+ }
+
+ template <typename Expression>
+ static size_t static_size(void* instance)
+ {
+ return static_cast<Expression*>(instance)->size();
+ }
+ template <typename Expression>
+ static void static_begin_block(void* instance, size_t size)
+ {
+ return static_cast<Expression*>(instance)->begin_block(cinput, size);
+ }
+ template <typename Expression>
+ static void static_end_block(void* instance, size_t size)
+ {
+ return static_cast<Expression*>(instance)->end_block(cinput, size);
+ }
+ template <typename Expression>
+ static bool static_substitute(void* instance, expression_pointer<T>&& ptr)
+ {
+ return internal::invoke_substitute(*static_cast<Expression*>(instance), std::move(ptr));
+ }
};
struct expression_resource
@@ -48,25 +114,27 @@ struct expression_resource
virtual ~expression_resource() {}
virtual void* instance() { return nullptr; }
};
+
template <typename E>
struct alignas(const_max(size_t(8), alignof(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)
+KFR_SINTRIN 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, bool enable_resource = true>
+template <typename T, bool enable_resource>
struct expression_pointer : input_expression
{
using value_type = T;
@@ -80,150 +148,45 @@ struct expression_pointer : input_expression
template <size_t N, KFR_ENABLE_IF(N <= maximum_expression_width)>
CMT_INLINE vec<T, N> operator()(cinput_t, size_t index, vec_t<T, N>) const
{
- using func_t = void (*)(void*, size_t, vec<T, N>&);
-
static_assert(is_poweroftwo(N), "N must be a power of two");
- constexpr size_t findex = ilog2(N);
- func_t func = reinterpret_cast<func_t>((*vtable)[3 + findex]);
vec<T, N> result;
- func(instance, index, result);
+ static_cast<const expression_vtable<T, N>*>(vtable)->get(instance, index, result);
return result;
}
template <size_t N, KFR_ENABLE_IF(N > maximum_expression_width)>
CMT_INLINE vec<T, N> operator()(cinput_t cinput, size_t index, vec_t<T, N>) const
{
- return concat(operator()(cinput, index, vec_t<T, N / 2>()),
- operator()(cinput, index + N / 2, vec_t<T, N / 2>()));
- }
- CMT_INLINE void begin_block(cinput_t, size_t size) const
- {
- using func_t = void (*)(void*, size_t);
- func_t func = reinterpret_cast<func_t>((*vtable)[0]);
- func(instance, size);
- }
- CMT_INLINE void end_block(cinput_t, size_t size) const
- {
- using func_t = void (*)(void*, size_t);
- func_t func = reinterpret_cast<func_t>((*vtable)[1]);
- func(instance, size);
- }
- CMT_INLINE size_t size() const
- {
- using func_t = size_t (*)(void*);
- func_t func = reinterpret_cast<func_t>((*vtable)[2]);
- return func(instance);
+ return concat(operator()(cinput, index, vec_t<T, N / 2>()), operator()(cinput, index + N / 2,
+ vec_t<T, N / 2>()));
}
+ CMT_INLINE void begin_block(cinput_t, size_t size) const { vtable->begin_block(instance, size); }
+ CMT_INLINE void end_block(cinput_t, size_t size) const { vtable->end_block(instance, size); }
+ CMT_INLINE size_t size() const { return vtable->size(instance); }
-private:
- void* instance;
- const expression_vtable<T>* vtable;
- std::shared_ptr<expression_resource> resource;
-};
-
-template <typename T>
-struct expression_pointer<T, false> : input_expression
-{
- using value_type = T;
-
- expression_pointer() noexcept : instance(nullptr), vtable(nullptr) {}
- expression_pointer(void* instance, const expression_vtable<T>* vtable)
- : instance(instance), vtable(vtable)
+ CMT_INLINE bool substitute(expression_pointer<T>&& new_pointer, csize_t<0> = csize_t<0>{}) const
{
+ return vtable->substitute(instance, std::move(new_pointer));
}
- template <size_t N, KFR_ENABLE_IF(N <= maximum_expression_width)>
- CMT_INLINE vec<T, N> operator()(cinput_t, size_t index, vec_t<T, N>) const
- {
- using func_t = void (*)(void*, size_t, vec<T, N>&);
- static_assert(is_poweroftwo(N), "N must be a power of two");
- constexpr size_t findex = ilog2(N);
- func_t func = reinterpret_cast<func_t>((*vtable)[3 + findex]);
- vec<T, N> result;
- func(instance, index, result);
- return result;
- }
- template <size_t N, KFR_ENABLE_IF(N > maximum_expression_width)>
- CMT_INLINE vec<T, N> operator()(cinput_t input, size_t index, vec_t<T, N>) const
- {
- return concat(operator()(cinput, index, vec_t<T, N / 2>()),
- operator()(cinput, index + N / 2, vec_t<T, N / 2>()));
- }
- CMT_INLINE void begin_block(cinput_t, size_t size) const
- {
- using func_t = void (*)(void*, size_t);
- func_t func = reinterpret_cast<func_t>((*vtable)[0]);
- func(instance, size);
- }
- CMT_INLINE void end_block(cinput_t, size_t size) const
- {
- using func_t = void (*)(void*, size_t);
- func_t func = reinterpret_cast<func_t>((*vtable)[1]);
- func(instance, size);
- }
- CMT_INLINE size_t size() const
- {
- using func_t = size_t (*)(void*);
- func_t func = reinterpret_cast<func_t>((*vtable)[2]);
- return func(instance);
- }
+ explicit operator bool() const { return instance != nullptr; }
private:
void* instance;
const expression_vtable<T>* vtable;
+ std::shared_ptr<expression_resource> resource;
};
namespace internal
{
-template <typename T, size_t N, typename Fn, typename Ret = vec<T, N>,
- typename NonMemFn = void (*)(void*, size_t, Ret&)>
-CMT_INLINE NonMemFn make_expression_func()
-{
- return [](void* fn, size_t index, Ret& result) {
- result = (reinterpret_cast<Fn*>(fn)->operator()(cinput, index, vec_t<T, N>()));
- };
-}
-
-template <typename Fn, typename NonMemFn = void (*)(void*, size_t)>
-CMT_INLINE NonMemFn make_expression_begin_block()
-{
- return [](void* fn, size_t size) { reinterpret_cast<Fn*>(fn)->begin_block(cinput, size); };
-}
-template <typename Fn, typename NonMemFn = void (*)(void*, size_t)>
-CMT_INLINE NonMemFn make_expression_end_block()
-{
- return [](void* fn, size_t size) { reinterpret_cast<Fn*>(fn)->end_block(cinput, size); };
-}
-template <typename Fn, typename NonMemFn = size_t (*)(void*)>
-CMT_INLINE NonMemFn make_expression_size()
-{
- return [](void* fn) -> size_t { return reinterpret_cast<Fn*>(fn)->size(); };
-}
-
-template <typename T, typename E>
-expression_vtable<T> make_expression_vtable_impl()
-{
- expression_vtable<T> result;
-
- result[0] = reinterpret_cast<void*>(internal::make_expression_begin_block<decay<E>>());
- result[1] = reinterpret_cast<void*>(internal::make_expression_end_block<decay<E>>());
- result[2] = reinterpret_cast<void*>(internal::make_expression_size<decay<E>>());
-
- cforeach(csizeseq_t<expression_vtable_size - 3>(), [&](auto u) {
- constexpr size_t N = 1 << val_of(decltype(u)());
- result[3 + val_of(decltype(u)())] =
- reinterpret_cast<void*>(internal::make_expression_func<T, N, decay<E>>());
- });
- return result;
-}
template <typename T, typename E>
CMT_INLINE expression_vtable<T>* make_expression_vtable()
{
static_assert(is_input_expression<E>::value, "E must be an expression");
- static expression_vtable<T> vtable = internal::make_expression_vtable_impl<T, E>();
+ static expression_vtable<T> vtable{ ctype_t<decay<E>>{} };
return &vtable;
}
-}
+} // namespace internal
/** @brief Converts the given expression into an opaque object.
* This overload takes reference to the expression.
@@ -247,4 +210,92 @@ CMT_INLINE expression_pointer<T> to_pointer(E&& expr)
std::shared_ptr<expression_resource> ptr = make_resource(std::move(expr));
return expression_pointer<T>(ptr->instance(), internal::make_expression_vtable<T, E>(), std::move(ptr));
}
+
+template <typename T, size_t key>
+class expression_placeholder : public input_expression
+{
+public:
+ using value_type = T;
+ expression_placeholder() noexcept = default;
+ template <typename U, size_t N>
+ CMT_INLINE vec<U, N> operator()(cinput_t, size_t index, vec_t<U, N>) const
+ {
+ return pointer ? cast<U>(pointer(cinput, index, vec_t<T, N>())) : 0;
+ }
+ expression_pointer<T> pointer;
+};
+
+template <typename T, size_t key = 0>
+KFR_SINTRIN expression_placeholder<T, key> placeholder(csize_t<key> = csize_t<key>{})
+{
+ return expression_placeholder<T, key>();
+}
+
+template <typename... Args>
+KFR_SINTRIN bool substitute(input_expression&, Args&&...)
+{
+ return false;
}
+
+namespace internal
+{
+template <typename... Args, typename T, size_t key, size_t... indices>
+KFR_SINTRIN bool substitute(internal::expression_base<Args...>& expr, expression_pointer<T>&& new_pointer,
+ csize_t<key>, csizes_t<indices...>);
+
+}
+
+template <typename T, size_t key = 0>
+KFR_SINTRIN bool substitute(expression_placeholder<T, key>& expr, expression_pointer<T>&& new_pointer,
+ csize_t<key> = csize_t<key>{})
+{
+ expr.pointer = std::move(new_pointer);
+ return true;
+}
+
+template <typename... Args, typename T, size_t key = 0>
+KFR_SINTRIN bool substitute(internal::expression_base<Args...>& expr, expression_pointer<T>&& new_pointer,
+ csize_t<key> = csize_t<key>{})
+{
+ return internal::substitute(expr, std::move(new_pointer), csize_t<key>{},
+ indicesfor_t<Args...>{});
+}
+
+template <typename T, size_t key = 0>
+KFR_SINTRIN bool substitute(expression_pointer<T>& expr, expression_pointer<T>&& new_pointer,
+ csize_t<key> = csize_t<key>{})
+{
+ return expr.substitute(std::move(new_pointer), csize_t<key>{});
+}
+
+namespace internal
+{
+
+KFR_SINTRIN bool var_or() { return false; }
+
+template <typename... Args>
+KFR_SINTRIN bool var_or(bool b, Args... args)
+{
+ return b || var_or(args...);
+}
+
+template <typename... Args, typename T, size_t key, size_t... indices>
+KFR_SINTRIN bool substitute(internal::expression_base<Args...>& expr, expression_pointer<T>&& new_pointer,
+ csize_t<key>, csizes_t<indices...>)
+{
+ return var_or(substitute(std::get<indices>(expr.args), std::move(new_pointer), csize_t<key>())...);
+}
+
+} // namespace internal
+
+namespace internal
+{
+
+template <typename Expression, typename T, size_t key>
+KFR_SINTRIN bool invoke_substitute(Expression& expr, expression_pointer<T>&& new_pointer, csize_t<key>)
+{
+ return kfr::substitute(expr, std::move(new_pointer), csize_t<key>{});
+}
+
+} // namespace internal
+} // namespace kfr
diff --git a/include/kfr/dsp/biquad.hpp b/include/kfr/dsp/biquad.hpp
@@ -157,8 +157,8 @@ struct expression_biquads_l : public expression_base<E1>
const vec<T, filters>& in)
{
const vec<T, filters> out = bq.b0 * in + state.s1;
- state.s1 = state.s2 + bq.b1 * in - bq.a1 * out;
- state.s2 = bq.b2 * in - bq.a2 * out;
+ state.s1 = state.s2 + bq.b1 * in - bq.a1 * out;
+ state.s2 = bq.b2 * in - bq.a2 * out;
return out;
}
biquad_block<T, filters> bq;
@@ -181,7 +181,7 @@ struct expression_biquads : expression_base<E1>
for (size_t i = 0; i < filters - 1; i++)
{
const vec<T, 1> in = i < size ? this->argument_first(cinput, i, vec_t<T, 1>()) : 0;
- state.out = process(bq, state, insertleft(in[0], state.out));
+ state.out = process(bq, state, insertleft(in[0], state.out));
}
}
CMT_INLINE void end_block(cinput_t cinput, size_t) const { state = saved_state; }
@@ -219,8 +219,8 @@ struct expression_biquads : expression_base<E1>
for (; i < std::min(width, block_end - index); i++)
{
const vec<T, 1> in = this->argument_first(cinput, index + i, vec_t<T, 1>());
- state.out = process(bq, state, insertleft(in[0], state.out));
- out[i] = state.out[filters - 1];
+ state.out = process(bq, state, insertleft(in[0], state.out));
+ out[i] = state.out[filters - 1];
}
saved_state = state;
for (; i < width; i++)
@@ -235,8 +235,8 @@ struct expression_biquads : expression_base<E1>
vec<T, filters> in)
{
const vec<T, filters> out = bq.b0 * in + state.s1;
- state.s1 = state.s2 + bq.b1 * in - bq.a1 * out;
- state.s2 = bq.b2 * in - bq.a2 * out;
+ state.s1 = state.s2 + bq.b1 * in - bq.a1 * out;
+ state.s2 = bq.b2 * in - bq.a2 * out;
return out;
}
biquad_block<T, filters> bq;
@@ -245,7 +245,7 @@ struct expression_biquads : expression_base<E1>
mutable biquad_state<T, filters> saved_state;
mutable size_t block_end;
};
-}
+} // namespace internal
/**
* @brief Returns template expressions that applies biquad filter to the input.
@@ -301,4 +301,19 @@ CMT_INLINE expression_pointer<T> biquad(const biquad_params<T>* bq, size_t count
},
[&] { return to_pointer(zeros<T>()); });
}
-}
+
+template <typename T>
+class biquad_filter : public expression_filter<T>
+{
+public:
+ biquad_filter(const biquad_params<T>* bq, size_t count)
+ : expression_filter<T>(to_pointer(biquad(bq, count, placeholder<T>())))
+ {
+ }
+
+ template <size_t N>
+ biquad_filter(const biquad_params<T> (&bq)[N]) : biquad_filter(bq, N)
+ {
+ }
+};
+} // namespace kfr
diff --git a/include/kfr/io/python_plot.hpp b/include/kfr/io/python_plot.hpp
@@ -78,7 +78,7 @@ inline T flush_to_zero(T value)
{
return static_cast<double>(value);
}
-}
+} // namespace internal
inline std::string concat_args() { return {}; }
@@ -89,15 +89,22 @@ std::string concat_args(const std::string& left, const Ts&... rest)
return left.empty() ? right : right.empty() ? left : left + ", " + right;
}
+inline std::string python_prologue()
+{
+ return "#!/usr/bin/env python\n"
+ "import sys\n"
+ "import os\n"
+ "sys.path.append(os.path.abspath(__file__ + '/../../../../dspplot/dspplot'))\n"
+ "sys.path.append(os.path.abspath(__file__ + '/../../../dspplot/dspplot'))\n"
+ "import dspplotting as dspplot\n\n";
+}
+
template <int = 0>
void plot_show(const std::string& name, const std::string& wavfile, const std::string& options = "")
{
print(name, "...");
std::string ss;
- ss += "#!/usr/bin/env python\n"
- "import dspplot\n\n"
- "dspplot.plot(" +
- concat_args("r'" + wavfile + "'", options) + ")\n";
+ ss += python_prologue() + "dspplot.plot(" + concat_args("r'" + wavfile + "'", options) + ")\n";
internal::python(name, ss);
print("done\n");
@@ -115,9 +122,7 @@ void plot_show(const std::string& name, T&& x, const std::string& options = "")
print(name, "...");
auto array = make_array_ref(std::forward<T>(x));
std::string ss;
- ss += "#!/usr/bin/env python\n"
- "import dspplot\n\n"
- "data = [\n";
+ ss += python_prologue() + "data = [\n";
for (size_t i = 0; i < array.size(); i++)
ss += as_string(fmt<'g', 20, 17>(internal::flush_to_zero(array[i])), ",\n");
ss += "]\n";
@@ -141,8 +146,7 @@ void perfplot_show(const std::string& name, T1&& data, T2&& labels, const std::s
auto array = make_array_ref(std::forward<T1>(data));
auto labels_array = make_array_ref(std::forward<T2>(labels));
std::string ss;
- ss += "#!/usr/bin/env python\n";
- ss += "import dspplot\n\n";
+ ss += python_prologue();
ss += "data = [\n";
for (size_t i = 0; i < array.size(); i++)
{
@@ -174,4 +178,4 @@ void perfplot_save(const std::string& name, T1&& data, T2&& labels, const std::s
perfplot_show(name, std::forward<T1>(data), std::forward<T2>(labels),
concat_args(options, "file='../perf/" + name + ".svg'"));
}
-}
+} // namespace kfr
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
@@ -44,6 +44,9 @@ if (MPFR_FOUND)
include_directories(${MPFR_INCLUDE_DIR})
add_executable(transcendental_test transcendental_test.cpp ${KFR_SRC} ${TEST_SRC})
target_link_libraries(transcendental_test ${MPFR_LIBRARIES})
+ if (WIN32)
+ target_link_libraries(transcendental_test gmp) # for MSYS
+ endif()
endif ()
add_executable(dsp_test dsp_test.cpp ${KFR_SRC} ${TEST_SRC})
add_executable(empty_test empty_test.cpp ${KFR_SRC} ${TEST_SRC})
diff --git a/tests/expression_test.cpp b/tests/expression_test.cpp
@@ -63,12 +63,28 @@ TEST(test_arg_replace)
{
univector<float, 10> v1 = counter();
univector<float, 10> v2 = -counter();
- auto e1 = to_pointer(v1) * 10;
- std::get<0>(e1.args) = to_pointer(v2);
+ auto e1 = to_pointer(v1) * 10;
+ std::get<0>(e1.args) = to_pointer(v2);
CHECK_EXPRESSION(e1, 10, [](size_t i) { return i * -10.0; });
}
+TEST(placeholders)
+{
+ auto expr = 100 * placeholder<float>();
+ CHECK_EXPRESSION(expr, infinite_size, [](size_t) { return 0.f; });
+ substitute(expr, to_pointer(counter<float>()));
+ CHECK_EXPRESSION(expr, infinite_size, [](size_t i) { return 100.f * i; });
+}
+
+TEST(placeholders_pointer)
+{
+ expression_pointer<float> expr = to_pointer(10 * placeholder<float>());
+ CHECK_EXPRESSION(expr, infinite_size, [](size_t) { return 0.f; });
+ substitute(expr, to_pointer(counter<float>()));
+ CHECK_EXPRESSION(expr, infinite_size, [](size_t i) { return 10.f * i; });
+}
+
TEST(size_calc)
{
auto a = counter();
@@ -99,7 +115,7 @@ TEST(partition)
{
{
univector<double, 400> output = zeros();
- auto result = partition(output, counter(), 5, 1);
+ auto result = partition(output, counter(), 5, 1);
CHECK(result.count == 5);
CHECK(result.chunk_size == 80);
@@ -117,7 +133,7 @@ TEST(partition)
{
univector<double, 400> output = zeros();
- auto result = partition(output, counter(), 5, 160);
+ auto result = partition(output, counter(), 5, 160);
CHECK(result.count == 3);
CHECK(result.chunk_size == 160);