• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2021 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 HISTREAMER_PLUGIN_COMMON_ANY_H
17 #define HISTREAMER_PLUGIN_COMMON_ANY_H
18 
19 #if defined(__clang__) || defined(__GNUC__)
20 #define CPP_STANDARD __cplusplus
21 #elif defined(_MSC_VER)
22 #define CPP_STANDARD _MSVC_LANG
23 #endif
24 
25 #if CPP_STANDARD >= 201103L
26 
27 #include <array>
28 #include <cstring>
29 #include <type_traits>
30 
31 #include "securec.h"
32 
33 #include "type_cast_ext.h"
34 
35 namespace {
36 template <typename T>
37 using decay_t = typename std::decay<T>::type;
38 
39 template <bool B, typename T = void>
40 using enable_if_t = typename std::enable_if<B, T>::type;
41 
42 template <bool B, typename T, typename F>
43 using conditional_t = typename std::conditional<B, T, F>::type;
44 
45 template <typename T>
46 using remove_cv_t = typename std::remove_cv<T>::type;
47 
48 template <typename T>
49 using remove_reference_t = typename std::remove_reference<T>::type;
50 constexpr size_t STACK_STORAGE_SIZE = 2 * sizeof(void*); // NOLINT: global var
51 
52 template <typename T>
53 struct IsTrivialStackStorable {
54     static constexpr bool value =
55         alignof(T) <= alignof(max_align_t) && std::is_trivially_copyable<T>::value && sizeof(T) <= STACK_STORAGE_SIZE;
56 };
57 
58 template <typename T>
59 struct IsStackStorable {
60     static constexpr bool value = alignof(T) <= alignof(max_align_t) && std::is_nothrow_move_constructible<T>::value &&
61                                   sizeof(T) <= STACK_STORAGE_SIZE;
62 };
63 
64 template <typename T>
65 struct IsValidCast {
66     static constexpr bool value = std::is_reference<T>::value || std::is_copy_constructible<T>::value;
67 };
68 } // namespace
69 namespace OHOS {
70 namespace Media {
71 namespace Plugin {
72 /**
73  * @brief BadAnyCast exception, which is thrown when error occurs in AnyCast
74  *
75  * @since 1.0
76  * @version 1.0
77  */
78 class BadAnyCast : public std::bad_cast {
79 public:
what()80     const char* what() const noexcept override
81     {
82         return "bad any cast";
83     }
84 };
85 
86 /**
87  * @brief This class describes a type-safe container for arbitrary type values which are copy constructible.
88  *
89  * @since 1.0
90  * @version 1.0
91  */
92 class Any final {
93 public:
Any()94     constexpr Any() noexcept
95     {
96     }
97 
Any(const Any & other)98     Any(const Any& other) : functionTable_(other.functionTable_)
99     {
100         if (other.HasValue()) {
101             functionTable_->copy(storage_, other.storage_);
102         }
103     }
104 
Any(Any && other)105     Any(Any&& other) noexcept : functionTable_(other.functionTable_)
106     {
107         if (other.HasValue()) {
108             functionTable_->move(storage_, other.storage_);
109             other.functionTable_ = nullptr;
110         }
111     }
112 
113     /**
114      * constructor from right reference value with type of ValueType.
115      *
116      * @tparam Type ValueType is not the same as Any itself. The decay type of ValueType must be copy constructible.
117      * @param value content
118      */
119     template <typename ValueType, enable_if_t<!std::is_same<decay_t<ValueType>, Any>::value &&
120                                                   std::is_copy_constructible<decay_t<ValueType>>::value,
121                                               bool> = true>
Any(ValueType && value)122     Any(ValueType&& value) // NOLINT: explicit
123     {
124         DoEmplace<decay_t<ValueType>>(std::forward<ValueType>(value));
125     }
126 
127     Any& operator=(const Any& other)
128     {
129         *this = Any(other);
130         return *this;
131     }
132 
133     Any& operator=(Any&& other) noexcept
134     {
135         Reset();
136         MoveFrom(std::forward<Any>(other));
137         return *this;
138     }
139 
140     /**
141      * Assigns contents to Any.
142      *
143      * @tparam ValueType Type ValueType is not the same as Any itself. The decay type of ValueType must be copy
144      * constructible.
145      * @param value content
146      * @return
147      */
148     template <typename ValueType, enable_if_t<!std::is_same<decay_t<ValueType>, Any>::value &&
149                                                   std::is_copy_constructible<decay_t<ValueType>>::value,
150                                               bool> = true>
151     Any& operator=(ValueType&& value)
152     {
153         *this = Any(std::forward<ValueType>(value));
154         return *this;
155     }
156 
~Any()157     ~Any()
158     {
159         Reset();
160     }
161 
162     /**
163      * Emplace one content with type of ValueType into object. The content is constructed by args.
164      *
165      * @tparam ValueType The decay type of ValueType must be constructible from args and copy constructible.
166      * @tparam Args args type
167      * @param args args
168      * @return content with type of decay ValueType
169      */
170     template <typename ValueType, typename... Args,
171               enable_if_t<std::is_constructible<decay_t<ValueType>, Args...>::value &&
172                               std::is_copy_constructible<decay_t<ValueType>>::value,
173                           bool> = true>
Emplace(Args &&...args)174     decay_t<ValueType>& Emplace(Args&&... args)
175     {
176         Reset();
177         return DoEmplace<decay_t<ValueType>>(std::forward<Args>(args)...);
178     }
179 
180     /**
181      * Emplace one content with type of ValueType into object. The content is constructed by il and args.
182      *
183      * @tparam ValueType type of conetent. The decay type of ValueType must be constructible from il and args and copy
184      * constructible
185      * @tparam U type of initializer list.
186      * @tparam Args type of other args
187      * @param il initializer list
188      * @param args args
189      * @return content with type of decay ValueType
190      */
191     template <typename ValueType, typename U, typename... Args,
192               enable_if_t<std::is_constructible<decay_t<ValueType>, std::initializer_list<U>&, Args...>::value &&
193                               std::is_copy_constructible<decay_t<ValueType>>::value,
194                           bool> = true>
Emplace(std::initializer_list<U> il,Args &&...args)195     decay_t<ValueType>& Emplace(std::initializer_list<U> il, Args&&... args)
196     {
197         Reset();
198         return DoEmplace<decay_t<ValueType>>(il, std::forward<Args>(args)...);
199     }
200 
201     /**
202      * Destroy the inner content if exists.
203      */
Reset()204     void Reset() noexcept
205     {
206         if (HasValue()) {
207             functionTable_->destroy(storage_);
208             storage_.trivialStack_.fill(0);
209         }
210         functionTable_ = nullptr;
211     }
212 
213     /**
214      * swap contents of two any objects
215      *
216      * @param other object to swap with
217      */
Swap(Any & other)218     void Swap(Any& other) noexcept
219     {
220         Any tmp(std::move(*this));
221         *this = std::move(other);
222         other = std::move(tmp);
223     }
224 
225     /**
226      * Checks whether the object has one content.
227      *
228      * @return true if object has one content, otherwise false.
229      */
HasValue()230     bool HasValue() const noexcept
231     {
232         return IsFunctionTableValid();
233     }
234 
235     /**
236      * Get tye type_info of object
237      *
238      * @return type info of object
239      */
Type()240     const std::type_info& Type() const noexcept
241     {
242         if (!HasValue()) {
243             return typeid(void);
244         }
245         return functionTable_->type();
246     }
247 
SameTypeWith(const std::type_info & otherInfo)248     bool SameTypeWith(const std::type_info& otherInfo) const noexcept
249     {
250         if (functionTable_ == nullptr) {
251             return false;
252         }
253         return IsSameType(functionTable_->type(), otherInfo);
254     }
255 
SameTypeWith(const Any & other)256     bool SameTypeWith(const Any& other) const noexcept
257     {
258         return IsSameType(functionTable_->type(), other.Type());
259     }
260 
261 private:
262     template <typename T>
263     friend const T* AnyCast(const Any* operand) noexcept;
264     template <typename T>
265     friend T* AnyCast(Any* operand) noexcept;
266 
267     union Storage {
268         using Stack = std::aligned_storage<STACK_STORAGE_SIZE, std::alignment_of<void*>::value>::type;
269         using Heap = void*;
270 
271         std::array<uint8_t, STACK_STORAGE_SIZE> trivialStack_;
272         Stack nonTrivialStack_;
273         Heap heap_;
274     };
275 
276     struct FunctionTable {
277         const std::type_info& (*type)() noexcept;
278         void (*destroy)(Storage&) noexcept;
279         void (*copy)(Storage&, const Storage&) noexcept;
280         void (*move)(Storage&, Storage&) noexcept;
281         void* (*getPtr)(Storage&) noexcept;
282         const void* (*getConstPtr)(const Storage&) noexcept;
283     };
284 
285     template <typename T>
286     struct TrivialStackFunctionTable {
TypeTrivialStackFunctionTable287         static const std::type_info& Type() noexcept
288         {
289             return typeid(T);
290         }
291 
DestroyTrivialStackFunctionTable292         static void Destroy(Storage& storage) noexcept
293         {
294             reinterpret_cast<T*>(storage.trivialStack_.data())->~T();
295         }
296 
CopyTrivialStackFunctionTable297         static void Copy(Storage& dest, const Storage& source) noexcept
298         {
299             // memcpy_s will always success in this function
300             (void)memcpy_s(GetPtr(dest), sizeof(Storage), GetConstPtr(source), sizeof(Storage));
301         }
302 
MoveTrivialStackFunctionTable303         static void Move(Storage& dest, Storage& source) noexcept
304         {
305             Copy(dest, source);
306             source.trivialStack_.fill(0);
307         }
308 
GetConstPtrTrivialStackFunctionTable309         static const void* GetConstPtr(const Storage& storage) noexcept
310         {
311             return reinterpret_cast<const void*>(storage.trivialStack_.data());
312         }
313 
GetPtrTrivialStackFunctionTable314         static void* GetPtr(Storage& storage) noexcept
315         {
316             return reinterpret_cast<void*>(storage.trivialStack_.data());
317         }
318     };
319 
320     template <typename T>
321     struct StackFunctionTable {
TypeStackFunctionTable322         static const std::type_info& Type() noexcept
323         {
324             return typeid(T);
325         }
326 
DestroyStackFunctionTable327         static void Destroy(Storage& storage) noexcept
328         {
329             reinterpret_cast<T*>(GetPtr(storage))->~T(); // NOLINT: cast
330         }
331 
CopyStackFunctionTable332         static void Copy(Storage& dest, const Storage& source) noexcept
333         {
334             // NOLINTNEXTLINE: reinterpret_cast
335             new (reinterpret_cast<T*>(GetPtr(dest))) T(*reinterpret_cast<const T*>(GetConstPtr(source)));
336         }
337 
MoveStackFunctionTable338         static void Move(Storage& dest, Storage& source) noexcept
339         {
340             // NOLINTNEXTLINE: reinterpret_cast
341             new (reinterpret_cast<T*>(GetPtr(dest))) T(std::move(*reinterpret_cast<T*>(GetPtr(source))));
342             Destroy(source);
343         }
344 
GetConstPtrStackFunctionTable345         static const void* GetConstPtr(const Storage& storage) noexcept
346         {
347             return reinterpret_cast<const void*>(&storage.nonTrivialStack_);
348         }
349 
GetPtrStackFunctionTable350         static void* GetPtr(Storage& storage) noexcept
351         {
352             return reinterpret_cast<void*>(&storage.nonTrivialStack_);
353         }
354     };
355 
356     template <typename T>
357     struct HeapFunctionTable {
TypeHeapFunctionTable358         static const std::type_info& Type() noexcept
359         {
360             return typeid(T);
361         }
362 
DestroyHeapFunctionTable363         static void Destroy(Storage& storage) noexcept
364         {
365             delete reinterpret_cast<T*>(storage.heap_); // NOLINT: cast
366             storage.heap_ = nullptr;
367         }
CopyHeapFunctionTable368         static void Copy(Storage& dest, const Storage& source) noexcept
369         {
370             dest.heap_ = new T(*reinterpret_cast<T*>(source.heap_)); // NOLINT: cast
371         }
MoveHeapFunctionTable372         static void Move(Storage& dest, Storage& source) noexcept
373         {
374             dest.heap_ = source.heap_;
375             source.heap_ = nullptr;
376         }
GetConstPtrHeapFunctionTable377         static const void* GetConstPtr(const Storage& storage) noexcept
378         {
379             return storage.heap_;
380         }
GetPtrHeapFunctionTable381         static void* GetPtr(Storage& storage) noexcept
382         {
383             return storage.heap_;
384         }
385     };
386 
387     template <typename ValueType>
GetFunctionTable()388     static FunctionTable* GetFunctionTable()
389     {
390         using DecayedValueType = decay_t<ValueType>;
391         using DetailFunctionTable =
392             conditional_t<IsTrivialStackStorable<DecayedValueType>::value,
393                           TrivialStackFunctionTable<DecayedValueType>,
394                           conditional_t<IsStackStorable<DecayedValueType>::value,
395                                         StackFunctionTable<DecayedValueType>, HeapFunctionTable<DecayedValueType>>>;
396         static FunctionTable table = {
397             .type = DetailFunctionTable::Type,
398             .destroy = DetailFunctionTable::Destroy,
399             .copy = DetailFunctionTable::Copy,
400             .move = DetailFunctionTable::Move,
401             .getPtr = DetailFunctionTable::GetPtr,
402             .getConstPtr = DetailFunctionTable::GetConstPtr,
403         };
404         return &table;
405     }
406 
IsFunctionTableValid()407     bool IsFunctionTableValid() const noexcept
408     {
409         return functionTable_ != nullptr;
410     }
411 
412     template <typename DecayedValueType, typename... Args>
DoEmplace(Args &&...args)413     DecayedValueType& DoEmplace(Args&&... args)
414     {
415         functionTable_ = GetFunctionTable<DecayedValueType>();
416         DecayedValueType* ptr = nullptr;
417         if (IsTrivialStackStorable<DecayedValueType>::value || IsStackStorable<DecayedValueType>::value) {
418             ptr = reinterpret_cast<DecayedValueType*>(functionTable_->getPtr(storage_));
419             new (ptr) DecayedValueType(std::forward<Args>(args)...);
420         } else {
421             storage_.heap_ = new DecayedValueType(std::forward<Args>(args)...);
422             ptr = reinterpret_cast<DecayedValueType*>(storage_.heap_);
423         }
424         return *ptr;
425     }
426 
MoveFrom(Any && other)427     void MoveFrom(Any&& other) noexcept
428     {
429         if (other.HasValue()) {
430             functionTable_ = other.functionTable_;
431             functionTable_->move(storage_, other.storage_);
432             other.Reset();
433         }
434     }
435 
436     template <typename ValueType>
Cast()437     ValueType* Cast() noexcept
438     {
439         using DecayedValueType = decay_t<ValueType>;
440         if (!IsFunctionTableValid() || !SameTypeWith(typeid(DecayedValueType))) {
441             return nullptr;
442         }
443         return IsTrivialStackStorable<DecayedValueType>::value
444                    ? reinterpret_cast<DecayedValueType*>(storage_.trivialStack_.data())
445                    : (IsStackStorable<DecayedValueType>::value
446                           ? reinterpret_cast<DecayedValueType*>(&storage_.nonTrivialStack_)
447                           : reinterpret_cast<DecayedValueType*>(storage_.heap_));
448     }
449     template <typename ValueType>
Cast()450     const ValueType* Cast() const noexcept
451     {
452         using DecayedValueType = decay_t<ValueType>;
453         if (!IsFunctionTableValid() || !SameTypeWith(typeid(DecayedValueType))) {
454             return nullptr;
455         }
456         return IsTrivialStackStorable<DecayedValueType>::value
457                    ? reinterpret_cast<const DecayedValueType*>(storage_.trivialStack_.data())
458                    : (IsStackStorable<DecayedValueType>::value
459                           ? reinterpret_cast<const DecayedValueType*>(&storage_.nonTrivialStack_)
460                           : reinterpret_cast<const DecayedValueType*>(storage_.heap_));
461     }
462 
463 private:
464     Storage storage_ {};
465     FunctionTable* functionTable_ {nullptr};
466 };
467 
468 /**
469  * cast one Any pointer into ValueType pointer
470  *
471  * @tparam ValueType target value type
472  * @param operand any object
473  * @return nullptr if type mismatch, operand is nullptr, or valueType is function/array. Otherwise, a pointer to the
474  * const value contained by operand.
475  */
476 template <typename ValueType>
AnyCast(const Any * operand)477 const ValueType* AnyCast(const Any* operand) noexcept
478 {
479     static_assert(!std::is_void<ValueType>::value, "ValueType of any_cast must not be void");
480     if (std::is_function<ValueType>::value || std::is_array<ValueType>::value || operand == nullptr) {
481         return nullptr;
482     }
483     return operand->Cast<ValueType>();
484 }
485 
486 /**
487  * cast one Any pointer into ValueType pointer
488  *
489  * @tparam ValueType target value type
490  * @param operand any object
491  * @return nullptr if type mismatch, operand is nullptr, or valueType is function/array. Otherwise, a pointer to the
492  * value contained by operand.
493  */
494 template <typename ValueType>
AnyCast(Any * operand)495 ValueType* AnyCast(Any* operand) noexcept
496 {
497     static_assert(!std::is_void<ValueType>::value, "ValueType of any_cast must not be void");
498     if (std::is_function<ValueType>::value || std::is_array<ValueType>::value || operand == nullptr) {
499         return nullptr;
500     }
501     return operand->Cast<ValueType>();
502 }
503 
504 /**
505  * cast one Any object into ValueType object
506  *
507  * @tparam ValueType target value type. It must match both conditions:
508  * 1. ValueType must be reference or constructible
509  * 2. Let U be remove_cv_t<remove_reference_t<ValueType>>, then std::is_constructible<ValueType, const U&> must be true
510  * @param operand any object
511  * @return throws BadAnyCast exception if type mismatch, operand is nullptr, or valueType is function/array. Otherwise,
512  * one object of ValueType contained in Any.
513  */
514 template <typename ValueType>
AnyCast(const Any & other)515 ValueType AnyCast(const Any& other)
516 {
517     using U = remove_cv_t<remove_reference_t<ValueType>>;
518     static_assert(IsValidCast<ValueType>::value, "template argument must be a reference or has copy constructors");
519     static_assert(std::is_constructible<ValueType, const U&>::value,
520                   "any_cast<ValueType>(const any&) requires ValueType constructable from const "
521                   "remove_cv_t<remove_reference_t<ValueType>>&");
522     auto ptr = AnyCast<U>(&other);
523     if (ptr == nullptr) {
524         throw BadAnyCast();
525     }
526     return static_cast<ValueType>(*ptr);
527 }
528 
529 /**
530  * cast one Any object into ValueType object
531  *
532  * @tparam ValueType target value type. It must match both conditions:
533  * 1. ValueType must be reference or constructible
534  * 2. Let U be remove_cv_t<remove_reference_t<ValueType>>, then std::is_constructible<ValueType, U&> must be true
535  * @param operand any object
536  * @return throws BadAnyCast exception if type mismatch, operand is nullptr, or valueType is function/array. Otherwise,
537  * one object of ValueType contained in Any.
538  */
539 template <typename ValueType>
AnyCast(Any & other)540 ValueType AnyCast(Any& other)
541 {
542     using U = remove_cv_t<remove_reference_t<ValueType>>;
543     static_assert(IsValidCast<ValueType>::value, "template argument must be a reference or has copy constructors");
544     static_assert(std::is_constructible<ValueType, U&>::value,
545                   "any_cast<ValueType>(const any&) requires ValueType constructable from "
546                   "remove_cv_t<remove_reference_t<ValueType>>&");
547     auto ptr = AnyCast<U>(&other);
548     if (ptr == nullptr) {
549         throw BadAnyCast();
550     }
551     return static_cast<ValueType>(*ptr);
552 }
553 
554 /**
555  * cast one Any object into ValueType object
556  *
557  * @tparam ValueType target value type. It must match both conditions:
558  * 1. ValueType must be reference or constructible
559  * 2. Let U be remove_cv_t<remove_reference_t<ValueType>>, then std::is_constructible<ValueType, U> must be true
560  * @param operand any object
561  * @return throws BadAnyCast exception if type mismatch, operand is nullptr, or valueType is function/array. Otherwise,
562  * one object of ValueType contained in Any.
563  */
564 template <typename ValueType>
AnyCast(Any && other)565 ValueType AnyCast(Any&& other)
566 {
567     using U = remove_cv_t<remove_reference_t<ValueType>>;
568     static_assert(IsValidCast<ValueType>::value, "template argument must be a reference or has copy constructors");
569     static_assert(std::is_constructible<ValueType, U>::value,
570                   "any_cast<ValueType>(const any&) requires ValueType constructable from "
571                   "remove_cv_t<remove_reference_t<ValueType>>");
572     auto ptr = AnyCast<U>(&other);
573     if (ptr == nullptr) {
574         throw BadAnyCast();
575     }
576     return static_cast<ValueType>(std::move(*ptr));
577 }
578 
579 /**
580  * Constructs Any object, whose content is constructed by args. The content type is T.
581  *
582  * @tparam T type of Any's content
583  * @tparam Args type of args
584  * @param args args used to construct the content
585  * @return Any object
586  */
587 template <typename T, typename... Args>
MakeAny(Args &&...args)588 Any MakeAny(Args&&... args)
589 {
590     Any tmp;
591     tmp.Emplace<T, Args...>(std::forward<Args>(args)...);
592     return tmp;
593 }
594 
595 /**
596  * Constructs Any object, whose content is constructed by il and args. The content type is T.
597  *
598  * @tparam T type of Any's content
599  * @tparam U type of initializer list
600  * @tparam Args type of args
601  * @param il initializer list
602  * @param args args
603  * @return Any object
604  */
605 template <typename T, typename U, typename... Args>
MakeAny(std::initializer_list<U> il,Args &&...args)606 Any MakeAny(std::initializer_list<U> il, Args&&... args)
607 {
608     Any tmp;
609     tmp.Emplace<T, U, Args...>(il, std::forward<Args>(args)...);
610     return tmp;
611 }
612 } // namespace Plugin
613 } // namespace Media
614 } // namespace OHOS
615 #endif
616 namespace std {
swap(OHOS::Media::Plugin::Any & lhs,OHOS::Media::Plugin::Any & rhs)617 inline void swap(OHOS::Media::Plugin::Any& lhs, OHOS::Media::Plugin::Any& rhs) noexcept
618 {
619     lhs.Swap(rhs);
620 }
621 } // namespace std
622 #endif // HISTREAMER_PLUGIN_COMMON_ANY_H
623