Files
external_libcamera/include/libcamera/base/bound_method.h
Laurent Pinchart c4e2b00d51 libcamera: base: bound_method: Remove BoundMethodArgs specialization
The BoundMethodArgs specialization for the void return type is only
needed to avoid accessing the ret_ member variable that is lacking from
the corresponding BoundMethodPack specialization. As the member variable
is only accessed in the invokePack() function, instead of specializing
the whole class we can use SFINAE to select between two different
implementations of the function.

SFINAE can only depend on the function template parameters, not the
parameters of the class template in which the function is defined:

"Only the failures in the types and expressions in the immediate context
of the function type or its template parameter types are SFINAE errors."

We thus can't use the type R in an std::enable_if expression for the
invokePack() function. To work around this, we have to add a type T to
the function template definition, which defaults to R, and use T with
std::enable_if.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Umang Jain <umang.jain@ideasonboard.com>
2021-09-02 01:16:45 +03:00

196 lines
4.3 KiB
C++

/* 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...)
{
}
R returnValue()
{
return ret_;
}
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...)
{
}
void returnValue()
{
}
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, typename T = R>
std::enable_if_t<!std::is_void<T>::value, void>
invokePack(BoundMethodPackBase *pack, std::index_sequence<I...>)
{
PackType *args = static_cast<PackType *>(pack);
args->ret_ = invoke(std::get<I>(args->args_)...);
}
template<std::size_t... I, typename T = R>
std::enable_if_t<std::is_void<T>::value, 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 R activate(Args... args, bool deleteMethod = false) = 0;
virtual R 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->returnValue() : R();
}
R invoke(Args... args) override
{
T *obj = static_cast<T *>(this->obj_);
return (obj->*func_)(args...);
}
private:
R (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__ */