1 /* 2 * Copyright (c) 2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef META_INTERFACE_EXT_INTERFACE_HELPERS_H 17 #define META_INTERFACE_EXT_INTERFACE_HELPERS_H 18 19 #include <base/containers/type_traits.h> 20 #include <base/containers/vector.h> 21 #include <base/util/uid.h> 22 #include <core/plugin/intf_interface.h> 23 24 #include <meta/base/atomics.h> 25 #include <meta/base/namespace.h> 26 #include <meta/base/type_traits.h> 27 #include <meta/interface/intf_lifecycle.h> 28 29 META_BEGIN_NAMESPACE() 30 31 template<typename Type, typename = int> 32 struct IsIntroduceInterface { 33 constexpr static bool VALUE = false; 34 }; 35 36 template<typename Type> 37 struct IsIntroduceInterface<Type, decltype((void)Type::INTRODUCE_INTERFACES_TAG, 0)> { 38 constexpr static bool VALUE = true; 39 }; 40 41 namespace Internal { 42 43 using GIFuncType = CORE_NS::IInterface*(void*); 44 45 struct UidInfo { 46 BASE_NS::Uid uid; 47 GIFuncType* getInterface {}; 48 }; 49 50 template<size_t Size> 51 struct UIDArray { 52 constexpr UidInfo& operator[](size_t i) noexcept 53 { 54 return data[i]; 55 } 56 constexpr const UidInfo& operator[](size_t i) const noexcept 57 { 58 return data[i]; 59 } 60 constexpr static size_t SIZE = Size; 61 UidInfo data[Size]; 62 }; 63 64 constexpr static void SwapUidInfo(UidInfo& l, UidInfo& r) noexcept 65 { 66 UidInfo tmp = BASE_NS::move(l); 67 l = BASE_NS::move(r); 68 r = BASE_NS::move(tmp); 69 } 70 71 static constexpr bool operator<(const UidInfo& lhs, const UidInfo& rhs) noexcept 72 { 73 return lhs.uid < rhs.uid; 74 } 75 76 template<size_t Size> 77 constexpr static void SortUidArrayImpl(UIDArray<Size>& array, size_t left, size_t right) noexcept 78 { 79 if (left < right) { 80 auto m = left; 81 for (auto i = left + 1; i < right; i++) { 82 if (array[i] < array[left]) { 83 SwapUidInfo(array[++m], array[i]); 84 } 85 } 86 SwapUidInfo(array[left], array[m]); 87 SortUidArrayImpl(array, left, m); 88 SortUidArrayImpl(array, m + 1, right); 89 } 90 } 91 92 template<size_t Size> 93 constexpr static void SortUidArray(UIDArray<Size>& array) noexcept 94 { 95 SortUidArrayImpl(array, 0, Size); 96 } 97 98 constexpr static CORE_NS::IInterface* BinarySearch( 99 const BASE_NS::Uid& uid, void* me, const UidInfo* info, size_t size) noexcept 100 { 101 int32_t lo = 0; 102 int32_t hi = static_cast<int32_t>(size); 103 auto* p = info; 104 while (lo <= hi) { 105 const auto mid = lo + (hi - lo) / 2; 106 p = info + mid; 107 const auto d = uid.compare(p->uid); 108 if (!d) { 109 // Found match 110 return p->getInterface(me); 111 } 112 if (d > 0) { 113 lo = mid + 1; 114 } else { 115 hi = mid - 1; 116 } 117 } 118 return {}; 119 } 120 121 constexpr static CORE_NS::IInterface* LinearSearch( 122 const BASE_NS::Uid& uid, void* me, const UidInfo* info, size_t size) noexcept 123 { 124 auto* p = info; 125 while (p < info + size) { 126 const auto d = uid.compare(p->uid); 127 if (!d) { 128 // Found match 129 return p->getInterface(me); 130 } 131 if (d < 0) { 132 // Rest of uids are bigger than reference, i.e. no match 133 break; 134 } 135 ++p; 136 } 137 return {}; 138 } 139 140 template<size_t Size> 141 constexpr static CORE_NS::IInterface* SearchInterface( 142 const BASE_NS::Uid& uid, void* me, const UIDArray<Size>& info) noexcept 143 { 144 constexpr auto linearSearchThreshold = 10; 145 if constexpr (Size == 0) { 146 return {}; 147 } 148 if constexpr (Size < linearSearchThreshold) { 149 return LinearSearch(uid, me, info.data, Size); 150 } 151 return BinarySearch(uid, me, info.data, Size); 152 } 153 154 } // namespace Internal 155 156 template<typename... Interfaces> 157 class IntroduceInterfaces; 158 159 template<typename T> 160 constexpr auto CastImpl(T* p) 161 { 162 return p; 163 } 164 template<typename T, typename Current, typename... Path> 165 constexpr auto CastImpl(T* p) 166 { 167 return CastImpl<Current, Path...>(static_cast<Current*>(p)); 168 } 169 170 template<typename...> 171 struct Deducer {}; 172 173 template<typename Me, typename... Interfaces> 174 struct GetInterfacesImpl final { 175 constexpr GetInterfacesImpl() 176 { 177 size_t index = 0; 178 (FillArrayDepth<Interfaces, Interfaces>(index), ...); 179 Internal::SortUidArray(arr_); 180 } 181 182 template<typename I> 183 static constexpr size_t CountInterfacesDepth() 184 { 185 if constexpr (IsIntroduceInterface<I>::VALUE) { 186 return I::SIZE; 187 } else { 188 if constexpr (!BASE_NS::is_same_v<I, CORE_NS::IInterface>) { 189 return 1 + CountInterfacesDepth<typename I::base>(); 190 } 191 } 192 return 0; 193 } 194 195 template<typename I, typename... Intfs> 196 static constexpr size_t CountInterfaces() 197 { 198 return (0 + ... + CountInterfacesDepth<Interfaces>()); 199 } 200 201 static constexpr size_t SIZE = CountInterfaces<Interfaces...>(); 202 203 constexpr Internal::UIDArray<SIZE> Get() const 204 { 205 return arr_; 206 } 207 208 constexpr bool HasUid(const BASE_NS::Uid& uid, size_t size) const 209 { 210 if (uid != CORE_NS::IInterface::UID) { 211 for (size_t i = 0; i != size; ++i) { 212 if (arr_.data[i].uid == uid) { 213 return true; 214 } 215 } 216 } 217 return false; 218 } 219 220 template<typename... Path, typename... Intfs> 221 constexpr void FillArrayDepthIntroduce(size_t& index, Deducer<Intfs...>) 222 { 223 (FillArrayDepth<Intfs, Path..., Intfs>(index), ...); 224 } 225 226 template<typename I, typename... Path> 227 constexpr void FillArrayDepth(size_t& index) 228 { 229 if constexpr (IsIntroduceInterface<I>::VALUE) { 230 FillArrayDepthIntroduce<Path...>(index, typename I::deducer {}); 231 } else if (!HasUid(I::UID, index)) { 232 if constexpr (!BASE_NS::is_same_v<I, CORE_NS::IInterface>) { 233 arr_.data[index].uid = I::UID; 234 arr_.data[index].getInterface = [](void* p) constexpr { 235 return static_cast<CORE_NS::IInterface*>(CastImpl<Me, Path...>(static_cast<Me*>(p))); 236 }; 237 ++index; 238 FillArrayDepth<typename I::base, Path..., typename I::base>(index); 239 } 240 } 241 } 242 243 private: 244 Internal::UIDArray<SIZE> arr_ {}; 245 }; 246 247 template<typename Me, typename... Interfaces> 248 constexpr auto GetInterfaces() 249 { 250 GetInterfacesImpl<Me, Interfaces...> gi; 251 return gi.Get(); 252 } 253 254 template<typename... Interfaces> 255 BASE_NS::vector<BASE_NS::Uid> GetInterfacesVector() 256 { 257 auto arr = GetInterfaces<Interfaces...>(); 258 return BASE_NS::vector<BASE_NS::Uid>(arr.data, arr.data + arr.SIZE); 259 } 260 261 template<> 262 inline BASE_NS::vector<BASE_NS::Uid> GetInterfacesVector<>() 263 { 264 return BASE_NS::vector<BASE_NS::Uid> {}; 265 } 266 267 /** 268 * @brief Check if list of interfaces (or their base classes) contains ILifecycle 269 */ 270 template<typename... Interfaces> 271 constexpr bool HAS_ILIFECYCLE = (false || ... || BASE_NS::is_convertible_v<Interfaces*, ILifecycle*>); 272 273 template<typename T, typename...> 274 struct FirstType { 275 using Type = T; 276 }; 277 278 template<typename... T> 279 using FirstTypeT = typename FirstType<T...>::Type; 280 281 /** 282 * @brief Helper class to derive from which implements reference counting and 283 * GetInterface for you. 284 */ 285 template<typename... Interfaces> 286 class IntroduceInterfaces : public Interfaces... { 287 public: 288 using deducer = Deducer<Interfaces...>; 289 static constexpr bool INTRODUCE_INTERFACES_TAG {}; 290 using IntroduceInterfacesType = IntroduceInterfaces; 291 292 template<typename... Args> 293 explicit IntroduceInterfaces(Args&&... args) noexcept : FirstTypeT<Interfaces...>(BASE_NS::forward<Args>(args)...) 294 {} 295 296 void Ref() override 297 { 298 CORE_NS::AtomicIncrement(&refcnt_); 299 } 300 void Unref() override 301 { 302 if (CORE_NS::AtomicDecrement(&refcnt_) == 0) { 303 if constexpr (HAS_ILIFECYCLE<Interfaces...>) { 304 if (auto i = this->GetInterface(ILifecycle::UID)) { 305 static_cast<ILifecycle*>(i)->Destroy(); 306 } 307 } 308 delete this; 309 } 310 } 311 312 constexpr CORE_NS::IInterface* StaticGetInterface(const BASE_NS::Uid& uid) 313 { 314 if (uid == CORE_NS::IInterface::UID) { 315 // CORE_NS::IInterface is implicitly implemented by everyone 316 return static_cast<CORE_NS::IInterface*>(static_cast<void*>(this)); 317 } 318 return Internal::SearchInterface(uid, this, IntsImpl()); 319 } 320 321 CORE_NS::IInterface* GetInterface(const BASE_NS::Uid& uid) override 322 { 323 return StaticGetInterface(uid); 324 } 325 const CORE_NS::IInterface* GetInterface(const BASE_NS::Uid& uid) const override 326 { 327 auto* me = const_cast<IntroduceInterfaces*>(this); 328 return me->IntroduceInterfaces::GetInterface(uid); 329 } 330 331 template<size_t... Index> 332 static BASE_NS::vector<BASE_NS::Uid> GetInterfacesVectorImpl(IndexSequence<Index...>) 333 { 334 return { IntsImpl().data[Index].uid... }; 335 } 336 337 static BASE_NS::vector<BASE_NS::Uid> GetInterfacesVector() 338 { 339 return GetInterfacesVectorImpl(MakeIndexSequence<SIZE>()); 340 } 341 342 static auto& IntsImpl() 343 { 344 // this needs to be in the function to compile with newer vc++ which considers the IntroduceInterfaces 345 // to not be defined yet when we instantiate the GetInterfaces causing static_casts to base to fail. 346 static constexpr auto interfaces = META_NS::GetInterfaces<IntroduceInterfaces, Interfaces...>(); 347 return interfaces; 348 } 349 constexpr static size_t SIZE = GetInterfacesImpl<IntroduceInterfaces, Interfaces...>::SIZE; 350 351 int32_t refcnt_ { 0 }; 352 }; 353 354 template<> 355 class IntroduceInterfaces<> { 356 public: 357 using deducer = Deducer<>; 358 static constexpr bool INTRODUCE_INTERFACES_TAG {}; 359 using IntroduceInterfacesType = IntroduceInterfaces; 360 361 CORE_NS::IInterface* GetInterface(const BASE_NS::Uid& uid) 362 { 363 return nullptr; 364 } 365 const CORE_NS::IInterface* GetInterface(const BASE_NS::Uid& uid) const 366 { 367 return nullptr; 368 } 369 370 static BASE_NS::vector<BASE_NS::Uid> GetInterfacesVector() 371 { 372 return BASE_NS::vector<BASE_NS::Uid>(); 373 } 374 }; 375 376 #define STATIC_INTERFACES_WITH_CONCRETE_BASE(introduced, baseclass) \ 377 public: \ 378 static BASE_NS::vector<BASE_NS::Uid> GetInterfacesVector() \ 379 { \ 380 return GetStaticInterfaces(); \ 381 } \ 382 static BASE_NS::vector<BASE_NS::Uid> GetStaticInterfaces() \ 383 { \ 384 auto v1 = introduced::GetInterfacesVector(); \ 385 auto v2 = baseclass::GetInterfacesVector(); \ 386 v1.insert(v1.end(), v2.begin(), v2.end()); \ 387 return v1; \ 388 } 389 390 META_END_NAMESPACE() 391 392 #endif 393