/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2019, Google Inc. * * bound_method.h - Method bind and invocation */ #ifndef __LIBCAMERA_BOUND_METHOD_H__ #define __LIBCAMERA_BOUND_METHOD_H__ #include #include #include #include namespace libcamera { class Object; enum ConnectionType { ConnectionTypeAuto, ConnectionTypeDirect, ConnectionTypeQueued, ConnectionTypeBlocking, }; class BoundMethodPackBase { public: virtual ~BoundMethodPackBase() = default; }; template class BoundMethodPack : public BoundMethodPackBase { public: BoundMethodPack(const Args &... args) : args_(args...) { } std::tuple...> args_; R ret_; }; template class BoundMethodPack : public BoundMethodPackBase { public: BoundMethodPack(const Args &... args) : args_(args...) { } std::tuple...> args_; }; class BoundMethodBase { public: BoundMethodBase(void *obj, Object *object, ConnectionType type) : obj_(obj), object_(object), connectionType_(type) { } virtual ~BoundMethodBase() = default; template::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 pack, bool deleteMethod); void *obj_; Object *object_; private: ConnectionType connectionType_; }; template class BoundMethodArgs : public BoundMethodBase { public: using PackType = BoundMethodPack; private: template void invokePack(BoundMethodPackBase *pack, std::index_sequence) { PackType *args = static_cast(pack); args->ret_ = invoke(std::get(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{}); } virtual R activate(Args... args, bool deleteMethod = false) = 0; virtual R invoke(Args... args) = 0; }; template class BoundMethodArgs : public BoundMethodBase { public: using PackType = BoundMethodPack; private: template void invokePack(BoundMethodPackBase *pack, std::index_sequence) { /* args is effectively unused when the sequence I is empty. */ PackType *args [[gnu::unused]] = static_cast(pack); invoke(std::get(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{}); } virtual void activate(Args... args, bool deleteMethod = false) = 0; virtual void invoke(Args... args) = 0; }; template class BoundMethodMember : public BoundMethodArgs { public: using PackType = typename BoundMethodArgs::PackType; BoundMethodMember(T *obj, Object *object, R (T::*func)(Args...), ConnectionType type = ConnectionTypeAuto) : BoundMethodArgs(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(this->obj_); return (obj->*func_)(args...); } auto pack = std::make_shared(args...); bool sync = BoundMethodBase::activatePack(pack, deleteMethod); return sync ? pack->ret_ : R(); } R invoke(Args... args) override { T *obj = static_cast(this->obj_); return (obj->*func_)(args...); } private: R (T::*func_)(Args...); }; template class BoundMethodMember : public BoundMethodArgs { public: using PackType = typename BoundMethodArgs::PackType; BoundMethodMember(T *obj, Object *object, void (T::*func)(Args...), ConnectionType type = ConnectionTypeAuto) : BoundMethodArgs(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(this->obj_); return (obj->*func_)(args...); } auto pack = std::make_shared(args...); BoundMethodBase::activatePack(pack, deleteMethod); } void invoke(Args... args) override { T *obj = static_cast(this->obj_); return (obj->*func_)(args...); } private: void (T::*func_)(Args...); }; template class BoundMethodStatic : public BoundMethodArgs { public: BoundMethodStatic(R (*func)(Args...)) : BoundMethodArgs(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_BOUND_METHOD_H__ */