* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef META_INTERFACE_EXT_INTERFACE_HELPERS_H
#define META_INTERFACE_EXT_INTERFACE_HELPERS_H
#include <base/containers/atomics.h>
#include <base/containers/type_traits.h>
#include <base/containers/vector.h>
#include <base/util/uid.h>
#include <core/plugin/intf_interface.h>
#include <meta/base/namespace.h>
#include <meta/base/type_traits.h>
#include <meta/interface/intf_lifecycle.h>
META_BEGIN_NAMESPACE()
template<typename Type, typename = int>
struct IsIntroduceInterface {
constexpr static bool VALUE = false;
};
template<typename Type>
struct IsIntroduceInterface<Type, decltype((void)Type::INTRODUCE_INTERFACES_TAG, 0)> {
constexpr static bool VALUE = true;
};
namespace Internal {
using GIFuncType = CORE_NS::IInterface*(void*);
struct UidInfo {
BASE_NS::Uid uid;
GIFuncType* getInterface{};
};
template<size_t Size>
struct UIDArray {
constexpr UidInfo& operator[](size_t i) noexcept
{
return data[i];
}
constexpr const UidInfo& operator[](size_t i) const noexcept
{
return data[i];
}
constexpr static size_t SIZE = Size;
UidInfo data[Size];
};
constexpr static void SwapUidInfo(UidInfo& l, UidInfo& r) noexcept
{
UidInfo tmp = BASE_NS::move(l);
l = BASE_NS::move(r);
r = BASE_NS::move(tmp);
}
static constexpr bool operator<(const UidInfo& lhs, const UidInfo& rhs) noexcept
{
return lhs.uid < rhs.uid;
}
template<size_t Size>
constexpr static void SortUidArrayImpl(UIDArray<Size>& array, size_t left, size_t right) noexcept
{
if (left < right) {
auto m = left;
for (auto i = left + 1; i < right; i++) {
if (array[i] < array[left]) {
SwapUidInfo(array[++m], array[i]);
}
}
SwapUidInfo(array[left], array[m]);
SortUidArrayImpl(array, left, m);
SortUidArrayImpl(array, m + 1, right);
}
}
template<size_t Size>
constexpr static void SortUidArray(UIDArray<Size>& array) noexcept
{
SortUidArrayImpl(array, 0, Size);
}
constexpr static CORE_NS::IInterface* BinarySearch(
const BASE_NS::Uid& uid, void* me, const UidInfo* info, size_t size) noexcept
{
int32_t lo = 0;
int32_t hi = static_cast<int32_t>(size) - 1;
auto* p = info;
while (lo <= hi) {
const auto mid = lo + (hi - lo) / 2;
p = info + mid;
const auto d = uid.compare(p->uid);
if (!d) {
return p->getInterface(me);
}
if (d > 0) {
lo = mid + 1;
} else {
hi = mid - 1;
}
}
return {};
}
constexpr static CORE_NS::IInterface* LinearSearch(
const BASE_NS::Uid& uid, void* me, const UidInfo* info, size_t size) noexcept
{
auto* p = info;
while (p < info + size) {
const auto d = uid.compare(p->uid);
if (!d) {
return p->getInterface(me);
}
if (d < 0) {
break;
}
++p;
}
return {};
}
template<size_t Size>
constexpr static CORE_NS::IInterface* SearchInterface(
const BASE_NS::Uid& uid, void* me, const UIDArray<Size>& info) noexcept
{
constexpr auto linearSearchThreshold = 10;
if constexpr (Size == 0) {
return {};
}
if constexpr (Size < linearSearchThreshold) {
return LinearSearch(uid, me, info.data, Size);
}
return BinarySearch(uid, me, info.data, Size);
}
}
template<typename... Interfaces>
class IntroduceInterfaces;
template<typename T>
constexpr auto CastImpl(T* p)
{
return p;
}
template<typename T, typename Current, typename... Path>
constexpr auto CastImpl(T* p)
{
return CastImpl<Current, Path...>(static_cast<Current*>(p));
}
template<typename...>
struct Deducer {};
template<typename Me, typename... Interfaces>
struct GetInterfacesImpl final {
constexpr GetInterfacesImpl()
{
size_t index = 0;
(FillArrayDepth<Interfaces, Interfaces>(index), ...);
Internal::SortUidArray(arr_);
}
template<typename I>
static constexpr size_t CountInterfacesDepth()
{
if constexpr (IsIntroduceInterface<I>::VALUE) {
return I::SIZE;
} else {
if constexpr (!BASE_NS::is_same_v<I, CORE_NS::IInterface>) {
return 1 + CountInterfacesDepth<typename I::base>();
}
}
return 0;
}
template<typename I, typename... Intfs>
static constexpr size_t CountInterfaces()
{
return (0 + ... + CountInterfacesDepth<Interfaces>());
}
static constexpr size_t SIZE = CountInterfaces<Interfaces...>();
constexpr Internal::UIDArray<SIZE> Get() const
{
return arr_;
}
constexpr bool HasUid(const BASE_NS::Uid& uid, size_t size) const
{
if (uid != CORE_NS::IInterface::UID) {
for (size_t i = 0; i != size; ++i) {
if (arr_.data[i].uid == uid) {
return true;
}
}
}
return false;
}
template<typename... Path, typename... Intfs>
constexpr void FillArrayDepthIntroduce(size_t& index, Deducer<Intfs...>)
{
(FillArrayDepth<Intfs, Path..., Intfs>(index), ...);
}
template<typename I, typename... Path>
constexpr void FillArrayDepth(size_t& index)
{
if constexpr (IsIntroduceInterface<I>::VALUE) {
FillArrayDepthIntroduce<Path...>(index, typename I::deducer{});
} else if (!HasUid(I::UID, index)) {
if constexpr (!BASE_NS::is_same_v<I, CORE_NS::IInterface>) {
arr_.data[index].uid = I::UID;
arr_.data[index].getInterface = [](void* p) constexpr {
return static_cast<CORE_NS::IInterface*>(CastImpl<Me, Path...>(static_cast<Me*>(p)));
};
++index;
FillArrayDepth<typename I::base, Path..., typename I::base>(index);
}
}
}
private:
Internal::UIDArray<SIZE> arr_{};
};
template<typename Me, typename... Interfaces>
constexpr auto GetInterfaces()
{
GetInterfacesImpl<Me, Interfaces...> gi;
return gi.Get();
}
template<typename... Interfaces>
BASE_NS::vector<BASE_NS::Uid> GetInterfacesVector()
{
auto arr = GetInterfaces<Interfaces...>();
return BASE_NS::vector<BASE_NS::Uid>(arr.data, arr.data + arr.SIZE);
}
template<>
inline BASE_NS::vector<BASE_NS::Uid> GetInterfacesVector<>()
{
return BASE_NS::vector<BASE_NS::Uid>{};
}
* @brief Check if list of interfaces (or their base classes) contains ILifecycle
*/
template<typename... Interfaces>
constexpr bool HAS_ILIFECYCLE = (false || ... || BASE_NS::is_convertible_v<Interfaces*, ILifecycle*>);
template<typename T, typename...>
struct FirstType {
using Type = T;
};
template<typename... T>
using FirstTypeT = typename FirstType<T...>::Type;
* @brief Helper class to derive from which implements reference counting and
* GetInterface for you.
*/
template<typename... Interfaces>
class IntroduceInterfaces : public Interfaces... {
public:
using deducer = Deducer<Interfaces...>;
static constexpr bool INTRODUCE_INTERFACES_TAG{};
using IntroduceInterfacesType = IntroduceInterfaces;
template<typename... Args>
explicit IntroduceInterfaces(Args&&... args) noexcept : FirstTypeT<Interfaces...>(BASE_NS::forward<Args>(args)...)
{}
void Ref() override
{
BASE_NS::AtomicIncrement(&refcnt_);
}
void Unref() override
{
if (BASE_NS::AtomicDecrement(&refcnt_) == 0) {
if constexpr (HAS_ILIFECYCLE<Interfaces...>) {
auto i = static_cast<ILifecycle*>(this->GetInterface(ILifecycle::UID));
assert(i);
i->Destroy();
}
delete this;
}
}
constexpr CORE_NS::IInterface* StaticGetInterface(const BASE_NS::Uid& uid)
{
if (uid == CORE_NS::IInterface::UID) {
return static_cast<CORE_NS::IInterface*>(static_cast<void*>(this));
}
return Internal::SearchInterface(uid, this, IntsImpl());
}
CORE_NS::IInterface* GetInterface(const BASE_NS::Uid& uid) override
{
return StaticGetInterface(uid);
}
const CORE_NS::IInterface* GetInterface(const BASE_NS::Uid& uid) const override
{
auto* me = const_cast<IntroduceInterfaces*>(this);
return me->IntroduceInterfaces::GetInterface(uid);
}
template<size_t... Index>
static BASE_NS::vector<BASE_NS::Uid> GetInterfacesVectorImpl(IndexSequence<Index...>)
{
return {IntsImpl().data[Index].uid...};
}
static BASE_NS::vector<BASE_NS::Uid> GetInterfacesVector()
{
return GetInterfacesVectorImpl(MakeIndexSequence<SIZE>());
}
static auto& IntsImpl()
{
static constexpr auto interfaces = META_NS::GetInterfaces<IntroduceInterfaces, Interfaces...>();
return interfaces;
}
constexpr static size_t SIZE = GetInterfacesImpl<IntroduceInterfaces, Interfaces...>::SIZE;
int32_t refcnt_{0};
};
template<>
class IntroduceInterfaces<> {
public:
using deducer = Deducer<>;
static constexpr bool INTRODUCE_INTERFACES_TAG{};
using IntroduceInterfacesType = IntroduceInterfaces;
CORE_NS::IInterface* GetInterface(const BASE_NS::Uid& uid)
{
return nullptr;
}
const CORE_NS::IInterface* GetInterface(const BASE_NS::Uid& uid) const
{
return nullptr;
}
static BASE_NS::vector<BASE_NS::Uid> GetInterfacesVector()
{
return BASE_NS::vector<BASE_NS::Uid>();
}
};
META_END_NAMESPACE()
#endif