diff options
author | Kieran Bingham <kieran.bingham@ideasonboard.com> | 2021-06-15 16:15:12 +0100 |
---|---|---|
committer | Kieran Bingham <kieran.bingham@ideasonboard.com> | 2021-06-25 16:11:08 +0100 |
commit | 27aff949fbc1b9aabfc594bbfd6f94be55a086ec (patch) | |
tree | 9ddbc2462a685a6db3ed33f09ed7a493376439d6 /include/libcamera/base/bound_method.h | |
parent | 6410d1d37c1ea9d1d168840a7ba063facb0bc9d6 (diff) |
libcamera/base: Move extended base functionality
Move the functionality for the following components to the new
base support library:
- BoundMethod
- EventDispatcher
- EventDispatcherPoll
- Log
- Message
- Object
- Signal
- Semaphore
- Thread
- Timer
While it would be preferable to see these split to move one component
per commit, these components are all interdependent upon each other,
which leaves us with one big change performing the move for all of them.
Reviewed-by: Hirokazu Honda <hiroh@chromium.org>
Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
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__ */ |