commit 2ccc349f8bf492174a944105cf26c793e46053b2
parent 41a39838e1195d1269c36bd9d88676e745f0300f
Author: d.levin256@gmail.com <d.levin256@gmail.com>
Date: Sun, 21 Oct 2018 17:38:34 +0300
Optimize expression_vtable, add substitute
Diffstat:
2 files changed, 214 insertions(+), 123 deletions(-)
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>, std::index_sequence<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>{},
+ std::index_sequence_for<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>, std::index_sequence<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