/* 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 namespace libcamera { class Object; enum ConnectionType { ConnectionTypeAuto, ConnectionTypeDirect, ConnectionTypeQueued, ConnectionTypeBlocking, }; class BoundMethodPackBase { public: virtual ~BoundMethodPackBase() {} }; template class BoundMethodPack : public BoundMethodPackBase { public: BoundMethodPack(const Args &... args) : args_(args...) { } std::tuple::type...> args_; R ret_; }; template class BoundMethodPack : public BoundMethodPackBase { public: BoundMethodPack(const Args &... args) : args_(args...) { } std::tuple::type...> args_; }; class BoundMethodBase { public: BoundMethodBase(void *obj, Object *object, ConnectionType type) : obj_(obj), object_(object), connectionType_(type) { } virtual ~BoundMethodBase() {} template::value>::type * = 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: #ifndef __DOXYGEN__ /* * This is a cheap partial implementation of std::integer_sequence<> * from C++14. */ template struct sequence { }; template struct generator : generator { }; template struct generator<0, S...> { typedef sequence type; }; #endif 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, BoundMethodBase::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, typename BoundMethodBase::generator::type()); } 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, BoundMethodBase::sequence) { /* args is effectively unused when the sequence S 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, typename BoundMethodBase::generator::type()); } virtual void activate(Args... args, bool deleteMethod = false) = 0; virtual void invoke(Args... args) = 0; }; template class BoundMemberMethod : public BoundMethodArgs { public: using PackType = typename BoundMethodArgs::PackType; BoundMemberMethod(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_) return (static_cast(this->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 { return (static_cast(this->obj_)->*func_)(args...); } private: R (T::*func_)(Args...); }; template class BoundMemberMethod : public BoundMethodArgs { public: using PackType = typename BoundMethodArgs::PackType; BoundMemberMethod(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_) return (static_cast(this->obj_)->*func_)(args...); auto pack = std::make_shared(args...); BoundMethodBase::activatePack(pack, deleteMethod); } void invoke(Args... args) override { (static_cast(this->obj_)->*func_)(args...); } private: void (T::*func_)(Args...); }; template class BoundStaticMethod : public BoundMethodArgs { public: BoundStaticMethod(R (*func)(Args...)) : BoundMethodArgs(nullptr, nullptr, ConnectionTypeAuto), func_(func) { } bool match(R (*func)(Args...)) const { return func == func_; } R activate(Args... args, bool deleteMethod = false) override { return (*func_)(args...); } R invoke(Args...) override { return R(); } private: R (*func_)(Args...); }; } /* namespace libcamera */ #endif /* __LIBCAMERA_BOUND_METHOD_H__ */