diff options
Diffstat (limited to 'include/libcamera/base/bound_method.h')
-rw-r--r-- | include/libcamera/base/bound_method.h | 239 |
1 files changed, 239 insertions, 0 deletions
diff --git a/include/libcamera/base/bound_method.h b/include/libcamera/base/bound_method.h new file mode 100644 index 00000000..282f9b58 --- /dev/null +++ b/include/libcamera/base/bound_method.h @@ -0,0 +1,239 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * bound_method.h - Method bind and invocation + */ +#ifndef __LIBCAMERA_BASE_BOUND_METHOD_H__ +#define __LIBCAMERA_BASE_BOUND_METHOD_H__ + +#include <memory> +#include <tuple> +#include <type_traits> +#include <utility> + +namespace libcamera { + +class Object; + +enum ConnectionType { + ConnectionTypeAuto, + ConnectionTypeDirect, + ConnectionTypeQueued, + ConnectionTypeBlocking, +}; + +class BoundMethodPackBase +{ +public: + virtual ~BoundMethodPackBase() = default; +}; + +template<typename R, typename... Args> +class BoundMethodPack : public BoundMethodPackBase +{ +public: + BoundMethodPack(const Args &... args) + : args_(args...) + { + } + + std::tuple<typename std::remove_reference_t<Args>...> args_; + R ret_; +}; + +template<typename... Args> +class BoundMethodPack<void, Args...> : public BoundMethodPackBase +{ +public: + BoundMethodPack(const Args &... args) + : args_(args...) + { + } + + std::tuple<typename std::remove_reference_t<Args>...> args_; +}; + +class BoundMethodBase +{ +public: + BoundMethodBase(void *obj, Object *object, ConnectionType type) + : obj_(obj), object_(object), connectionType_(type) + { + } + virtual ~BoundMethodBase() = default; + + template<typename T, typename std::enable_if_t<!std::is_same<Object, T>::value> * = nullptr> + bool match(T *obj) { return obj == obj_; } + bool match(Object *object) { return object == object_; } + + Object *object() const { return object_; } + + virtual void invokePack(BoundMethodPackBase *pack) = 0; + +protected: + bool activatePack(std::shared_ptr<BoundMethodPackBase> pack, + bool deleteMethod); + + void *obj_; + Object *object_; + +private: + ConnectionType connectionType_; +}; + +template<typename R, typename... Args> +class BoundMethodArgs : public BoundMethodBase +{ +public: + using PackType = BoundMethodPack<R, Args...>; + +private: + template<std::size_t... I> + void invokePack(BoundMethodPackBase *pack, std::index_sequence<I...>) + { + PackType *args = static_cast<PackType *>(pack); + args->ret_ = invoke(std::get<I>(args->args_)...); + } + +public: + BoundMethodArgs(void *obj, Object *object, ConnectionType type) + : BoundMethodBase(obj, object, type) {} + + void invokePack(BoundMethodPackBase *pack) override + { + invokePack(pack, std::make_index_sequence<sizeof...(Args)>{}); + } + + virtual R activate(Args... args, bool deleteMethod = false) = 0; + virtual R invoke(Args... args) = 0; +}; + +template<typename... Args> +class BoundMethodArgs<void, Args...> : public BoundMethodBase +{ +public: + using PackType = BoundMethodPack<void, Args...>; + +private: + template<std::size_t... I> + void invokePack(BoundMethodPackBase *pack, std::index_sequence<I...>) + { + /* args is effectively unused when the sequence I is empty. */ + PackType *args [[gnu::unused]] = static_cast<PackType *>(pack); + invoke(std::get<I>(args->args_)...); + } + +public: + BoundMethodArgs(void *obj, Object *object, ConnectionType type) + : BoundMethodBase(obj, object, type) {} + + void invokePack(BoundMethodPackBase *pack) override + { + invokePack(pack, std::make_index_sequence<sizeof...(Args)>{}); + } + + virtual void activate(Args... args, bool deleteMethod = false) = 0; + virtual void invoke(Args... args) = 0; +}; + +template<typename T, typename R, typename... Args> +class BoundMethodMember : public BoundMethodArgs<R, Args...> +{ +public: + using PackType = typename BoundMethodArgs<R, Args...>::PackType; + + BoundMethodMember(T *obj, Object *object, R (T::*func)(Args...), + ConnectionType type = ConnectionTypeAuto) + : BoundMethodArgs<R, Args...>(obj, object, type), func_(func) + { + } + + bool match(R (T::*func)(Args...)) const { return func == func_; } + + R activate(Args... args, bool deleteMethod = false) override + { + if (!this->object_) { + T *obj = static_cast<T *>(this->obj_); + return (obj->*func_)(args...); + } + + auto pack = std::make_shared<PackType>(args...); + bool sync = BoundMethodBase::activatePack(pack, deleteMethod); + return sync ? pack->ret_ : R(); + } + + R invoke(Args... args) override + { + T *obj = static_cast<T *>(this->obj_); + return (obj->*func_)(args...); + } + +private: + R (T::*func_)(Args...); +}; + +template<typename T, typename... Args> +class BoundMethodMember<T, void, Args...> : public BoundMethodArgs<void, Args...> +{ +public: + using PackType = typename BoundMethodArgs<void, Args...>::PackType; + + BoundMethodMember(T *obj, Object *object, void (T::*func)(Args...), + ConnectionType type = ConnectionTypeAuto) + : BoundMethodArgs<void, Args...>(obj, object, type), func_(func) + { + } + + bool match(void (T::*func)(Args...)) const { return func == func_; } + + void activate(Args... args, bool deleteMethod = false) override + { + if (!this->object_) { + T *obj = static_cast<T *>(this->obj_); + return (obj->*func_)(args...); + } + + auto pack = std::make_shared<PackType>(args...); + BoundMethodBase::activatePack(pack, deleteMethod); + } + + void invoke(Args... args) override + { + T *obj = static_cast<T *>(this->obj_); + return (obj->*func_)(args...); + } + +private: + void (T::*func_)(Args...); +}; + +template<typename R, typename... Args> +class BoundMethodStatic : public BoundMethodArgs<R, Args...> +{ +public: + BoundMethodStatic(R (*func)(Args...)) + : BoundMethodArgs<R, Args...>(nullptr, nullptr, ConnectionTypeAuto), + func_(func) + { + } + + bool match(R (*func)(Args...)) const { return func == func_; } + + R activate(Args... args, [[maybe_unused]] bool deleteMethod = false) override + { + return (*func_)(args...); + } + + R invoke(Args...) override + { + return R(); + } + +private: + R (*func_)(Args...); +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_BASE_BOUND_METHOD_H__ */ |