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