/* * 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 #include #include #include #include #include #include #include META_BEGIN_NAMESPACE() template struct IsIntroduceInterface { constexpr static bool VALUE = false; }; template struct IsIntroduceInterface { constexpr static bool VALUE = true; }; namespace Internal { using GIFuncType = CORE_NS::IInterface*(void*); struct UidInfo { BASE_NS::Uid uid; GIFuncType* getInterface {}; }; template 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 constexpr static void SortUidArrayImpl(UIDArray& 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 constexpr static void SortUidArray(UIDArray& 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(size); 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) { // Found match 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) { // Found match return p->getInterface(me); } if (d < 0) { // Rest of uids are bigger than reference, i.e. no match break; } ++p; } return {}; } template constexpr static CORE_NS::IInterface* SearchInterface( const BASE_NS::Uid& uid, void* me, const UIDArray& 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); } } // namespace Internal template class IntroduceInterfaces; template constexpr auto CastImpl(T* p) { return p; } template constexpr auto CastImpl(T* p) { return CastImpl(static_cast(p)); } template struct Deducer {}; template struct GetInterfacesImpl final { constexpr GetInterfacesImpl() { size_t index = 0; (FillArrayDepth(index), ...); Internal::SortUidArray(arr_); } template static constexpr size_t CountInterfacesDepth() { if constexpr (IsIntroduceInterface::VALUE) { return I::SIZE; } else { if constexpr (!BASE_NS::is_same_v) { return 1 + CountInterfacesDepth(); } } return 0; } template static constexpr size_t CountInterfaces() { return (0 + ... + CountInterfacesDepth()); } static constexpr size_t SIZE = CountInterfaces(); constexpr Internal::UIDArray 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 constexpr void FillArrayDepthIntroduce(size_t& index, Deducer) { (FillArrayDepth(index), ...); } template constexpr void FillArrayDepth(size_t& index) { if constexpr (IsIntroduceInterface::VALUE) { FillArrayDepthIntroduce(index, typename I::deducer {}); } else if (!HasUid(I::UID, index)) { if constexpr (!BASE_NS::is_same_v) { arr_.data[index].uid = I::UID; arr_.data[index].getInterface = [](void* p) constexpr { return static_cast(CastImpl(static_cast(p))); }; ++index; FillArrayDepth(index); } } } private: Internal::UIDArray arr_ {}; }; template constexpr auto GetInterfaces() { GetInterfacesImpl gi; return gi.Get(); } template BASE_NS::vector GetInterfacesVector() { auto arr = GetInterfaces(); return BASE_NS::vector(arr.data, arr.data + arr.SIZE); } template<> inline BASE_NS::vector GetInterfacesVector<>() { return BASE_NS::vector {}; } /** * @brief Check if list of interfaces (or their base classes) contains ILifecycle */ template constexpr bool HAS_ILIFECYCLE = (false || ... || BASE_NS::is_convertible_v); template struct FirstType { using Type = T; }; template using FirstTypeT = typename FirstType::Type; /** * @brief Helper class to derive from which implements reference counting and * GetInterface for you. */ template class IntroduceInterfaces : public Interfaces... { public: using deducer = Deducer; static constexpr bool INTRODUCE_INTERFACES_TAG {}; using IntroduceInterfacesType = IntroduceInterfaces; template explicit IntroduceInterfaces(Args&&... args) noexcept : FirstTypeT(BASE_NS::forward(args)...) {} void Ref() override { CORE_NS::AtomicIncrement(&refcnt_); } void Unref() override { if (CORE_NS::AtomicDecrement(&refcnt_) == 0) { if constexpr (HAS_ILIFECYCLE) { if (auto i = this->GetInterface(ILifecycle::UID)) { static_cast(i)->Destroy(); } } delete this; } } constexpr CORE_NS::IInterface* StaticGetInterface(const BASE_NS::Uid& uid) { if (uid == CORE_NS::IInterface::UID) { // CORE_NS::IInterface is implicitly implemented by everyone return static_cast(static_cast(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(this); return me->IntroduceInterfaces::GetInterface(uid); } template static BASE_NS::vector GetInterfacesVectorImpl(IndexSequence) { return { IntsImpl().data[Index].uid... }; } static BASE_NS::vector GetInterfacesVector() { return GetInterfacesVectorImpl(MakeIndexSequence()); } static auto& IntsImpl() { // this needs to be in the function to compile with newer vc++ which considers the IntroduceInterfaces // to not be defined yet when we instantiate the GetInterfaces causing static_casts to base to fail. static constexpr auto interfaces = META_NS::GetInterfaces(); return interfaces; } constexpr static size_t SIZE = GetInterfacesImpl::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 GetInterfacesVector() { return BASE_NS::vector(); } }; #define STATIC_INTERFACES_WITH_CONCRETE_BASE(introduced, baseclass) \ public: \ static BASE_NS::vector GetInterfacesVector() \ { \ return GetStaticInterfaces(); \ } \ static BASE_NS::vector GetStaticInterfaces() \ { \ auto v1 = introduced::GetInterfacesVector(); \ auto v2 = baseclass::GetInterfacesVector(); \ v1.insert(v1.end(), v2.begin(), v2.end()); \ return v1; \ } META_END_NAMESPACE() #endif