libcamera: bound_method: Propagate method return value

Propagate the return value of the bound method all the way to the caller
of activate(). The value is stored in the arguments pack for indirect
invocation.

As C++ doesn't allow instantiating a variable of type void, we need to
specialize the template class BoundMethodPack for methods returning
void. This in turn requires template specialization for the
BoundMethodArgs class in order to store the return value in the pack,
and for the BoundMemberMethod class to extract the return value from the
pack.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>
This commit is contained in:
Laurent Pinchart
2020-01-03 22:53:09 +02:00
parent b0135a1522
commit 3d1d208171
4 changed files with 113 additions and 21 deletions
+86 -13
View File
@@ -28,7 +28,7 @@ public:
virtual ~BoundMethodPackBase() {}
};
template<typename... Args>
template<typename R, typename... Args>
class BoundMethodPack : public BoundMethodPackBase
{
public:
@@ -37,6 +37,19 @@ public:
{
}
std::tuple<typename std::remove_reference<Args>::type...> 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<Args>::type...> args_;
};
@@ -77,7 +90,7 @@ protected:
};
#endif
void activatePack(std::shared_ptr<BoundMethodPackBase> pack,
bool activatePack(std::shared_ptr<BoundMethodPackBase> pack,
bool deleteMethod);
void *obj_;
@@ -91,7 +104,34 @@ template<typename R, typename... Args>
class BoundMethodArgs : public BoundMethodBase
{
public:
using PackType = BoundMethodPack<Args...>;
using PackType = BoundMethodPack<R, Args...>;
private:
template<int... S>
void invokePack(BoundMethodPackBase *pack, BoundMethodBase::sequence<S...>)
{
PackType *args = static_cast<PackType *>(pack);
args->ret_ = invoke(std::get<S>(args->args_)...);
}
public:
BoundMethodArgs(void *obj, Object *object, ConnectionType type)
: BoundMethodBase(obj, object, type) {}
void invokePack(BoundMethodPackBase *pack) override
{
invokePack(pack, typename BoundMethodBase::generator<sizeof...(Args)>::type());
}
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<int... S>
@@ -129,15 +169,45 @@ public:
bool match(R (T::*func)(Args...)) const { return func == func_; }
R activate(Args... args, bool deleteMethod = false) override
{
if (!this->object_)
return (static_cast<T *>(this->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
{
return (static_cast<T *>(this->obj_)->*func_)(args...);
}
private:
R (T::*func_)(Args...);
};
template<typename T, typename... Args>
class BoundMemberMethod<T, void, Args...> : public BoundMethodArgs<void, Args...>
{
public:
using PackType = typename BoundMethodArgs<void *, Args...>::PackType;
BoundMemberMethod(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_) {
(static_cast<T *>(this->obj_)->*func_)(args...);
return;
}
if (!this->object_)
return (static_cast<T *>(this->obj_)->*func_)(args...);
std::shared_ptr<BoundMethodPackBase> pack =
std::make_shared<typename BoundMemberMethod<T, R, Args...>::PackType>(args...);
auto pack = std::make_shared<PackType>(args...);
BoundMethodBase::activatePack(pack, deleteMethod);
}
@@ -147,7 +217,7 @@ public:
}
private:
R (T::*func_)(Args...);
void (T::*func_)(Args...);
};
template<typename R, typename... Args>
@@ -162,12 +232,15 @@ public:
bool match(R (*func)(Args...)) const { return func == func_; }
void activate(Args... args, bool deleteMethod = false) override
R activate(Args... args, bool deleteMethod = false) override
{
(*func_)(args...);
return (*func_)(args...);
}
void invoke(Args...) override {}
R invoke(Args...) override
{
return R();
}
private:
R (*func_)(Args...);
+3 -3
View File
@@ -31,12 +31,12 @@ public:
template<typename T, typename R, typename... FuncArgs, typename... Args,
typename std::enable_if<std::is_base_of<Object, T>::value>::type * = nullptr>
void invokeMethod(R (T::*func)(FuncArgs...), ConnectionType type,
Args... args)
R invokeMethod(R (T::*func)(FuncArgs...), ConnectionType type,
Args... args)
{
T *obj = static_cast<T *>(this);
auto *method = new BoundMemberMethod<T, R, FuncArgs...>(obj, this, func, type);
method->activate(args..., true);
return method->activate(args..., true);
}
Thread *thread() const { return thread_; }