• 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 #include "plugin/common/type_cast_ext.h"
31 #include "securec.h"
32 
33 namespace {
34 template <typename T>
35 using decay_t = typename std::decay<T>::type;
36 
37 template <bool B, typename T = void>
38 using enable_if_t = typename std::enable_if<B, T>::type;
39 
40 template <bool B, typename T, typename F>
41 using conditional_t = typename std::conditional<B, T, F>::type;
42 
43 template <typename T>
44 using remove_cv_t = typename std::remove_cv<T>::type;
45 
46 template <typename T>
47 using remove_reference_t = typename std::remove_reference<T>::type;
48 constexpr size_t STACK_STORAGE_SIZE = 2 * sizeof(void*); // NOLINT: global var
49 
50 template <typename T>
51 struct IsTrivialStackStorable {
52     static constexpr bool value =
53         alignof(T) <= alignof(max_align_t) && std::is_trivially_copyable<T>::value && sizeof(T) <= STACK_STORAGE_SIZE;
54 };
55 
56 template <typename T>
57 struct IsStackStorable {
58     static constexpr bool value = alignof(T) <= alignof(max_align_t) && std::is_nothrow_move_constructible<T>::value &&
59                                   sizeof(T) <= STACK_STORAGE_SIZE;
60 };
61 
62 template <typename T>
63 struct IsValidCast {
64     static constexpr bool value = std::is_reference<T>::value || std::is_copy_constructible<T>::value;
65 };
66 } // namespace
67 namespace OHOS {
68 namespace Media {
69 namespace Plugin {
70 /**
71  * @brief BadAnyCast exception, which is thrown when error occurs in AnyCast
72  *
73  * @since 1.0
74  * @version 1.0
75  */
76 class BadAnyCast : public std::bad_cast {
77 public:
what()78     const char* what() const noexcept override
79     {
80         return "bad any cast";
81     }
82 };
83 
84 /**
85  * @brief This class describes a type-safe container for arbitrary type values which are copy constructible.
86  *
87  * @since 1.0
88  * @version 1.0
89  */
90 class Any final {
91 public:
Any()92     constexpr Any() noexcept
93     {
94     }
95 
Any(const Any & other)96     Any(const Any& other) : functionTable_(other.functionTable_)
97     {
98         if (other.HasValue()) {
99             functionTable_->copy(storage_, other.storage_);
100         }
101     }
102 
Any(Any && other)103     Any(Any&& other) noexcept : functionTable_(other.functionTable_)
104     {
105         if (other.HasValue()) {
106             functionTable_->move(storage_, other.storage_);
107             other.functionTable_ = nullptr;
108         }
109     }
110 
111     /**
112      * constructor from right reference value with type of ValueType.
113      *
114      * @tparam Type ValueType is not the same as Any itself. The decay type of ValueType must be copy constructible.
115      * @param value content
116      */
117     template <typename ValueType, enable_if_t<!std::is_same<decay_t<ValueType>, Any>::value &&
118                                                   std::is_copy_constructible<decay_t<ValueType>>::value,
119                                               bool> = true>
Any(ValueType && value)120     Any(ValueType&& value) // NOLINT: explicit
121     {
122         DoEmplace<decay_t<ValueType>>(std::forward<ValueType>(value));
123     }
124 
125     Any& operator=(const Any& other)
126     {
127         *this = Any(other);
128         return *this;
129     }
130 
131     Any& operator=(Any&& other) noexcept
132     {
133         Reset();
134         MoveFrom(std::forward<Any>(other));
135         return *this;
136     }
137 
138     /**
139      * Assigns contents to Any.
140      *
141      * @tparam ValueType Type ValueType is not the same as Any itself. The decay type of ValueType must be copy
142      * constructible.
143      * @param value content
144      * @return
145      */
146     template <typename ValueType, enable_if_t<!std::is_same<decay_t<ValueType>, Any>::value &&
147                                                   std::is_copy_constructible<decay_t<ValueType>>::value,
148                                               bool> = true>
149     Any& operator=(ValueType&& value)
150     {
151         *this = Any(std::forward<ValueType>(value));
152         return *this;
153     }
154 
~Any()155     ~Any()
156     {
157         Reset();
158     }
159 
160     /**
161      * Emplace one content with type of ValueType into object. The content is constructed by args.
162      *
163      * @tparam ValueType The decay type of ValueType must be constructible from args and copy constructible.
164      * @tparam Args args type
165      * @param args args
166      * @return content with type of decay ValueType
167      */
168     template <typename ValueType, typename... Args,
169               enable_if_t<std::is_constructible<decay_t<ValueType>, Args...>::value &&
170                               std::is_copy_constructible<decay_t<ValueType>>::value,
171                           bool> = true>
Emplace(Args &&...args)172     decay_t<ValueType>& Emplace(Args&&... args)
173     {
174         Reset();
175         return DoEmplace<decay_t<ValueType>>(std::forward<Args>(args)...);
176     }
177 
178     /**
179      * Emplace one content with type of ValueType into object. The content is constructed by il and args.
180      *
181      * @tparam ValueType type of conetent. The decay type of ValueType must be constructible from il and args and copy
182      * constructible
183      * @tparam U type of initializer list.
184      * @tparam Args type of other args
185      * @param il initializer list
186      * @param args args
187      * @return content with type of decay ValueType
188      */
189     template <typename ValueType, typename U, typename... Args,
190               enable_if_t<std::is_constructible<decay_t<ValueType>, std::initializer_list<U>&, Args...>::value &&
191                               std::is_copy_constructible<decay_t<ValueType>>::value,
192                           bool> = true>
Emplace(std::initializer_list<U> il,Args &&...args)193     decay_t<ValueType>& Emplace(std::initializer_list<U> il, Args&&... args)
194     {
195         Reset();
196         return DoEmplace<decay_t<ValueType>>(il, std::forward<Args>(args)...);
197     }
198 
199     /**
200      * Destroy the inner content if exists.
201      */
Reset()202     void Reset() noexcept
203     {
204         if (HasValue()) {
205             functionTable_->destroy(storage_);
206             storage_.trivialStack_.fill(0);
207         }
208         functionTable_ = nullptr;
209     }
210 
211     /**
212      * swap contents of two any objects
213      *
214      * @param other object to swap with
215      */
Swap(Any & other)216     void Swap(Any& other) noexcept
217     {
218         Any tmp(std::move(*this));
219         *this = std::move(other);
220         other = std::move(tmp);
221     }
222 
223     /**
224      * Checks whether the object has one content.
225      *
226      * @return true if object has one content, otherwise false.
227      */
HasValue()228     bool HasValue() const noexcept
229     {
230         return IsFunctionTableValid();
231     }
232 
233     /**
234      * Get tye type_info of object
235      *
236      * @return type info of object
237      */
Type()238     const std::type_info& Type() const noexcept
239     {
240         if (!HasValue()) {
241             return typeid(void);
242         }
243         return functionTable_->type();
244     }
245 
SameTypeWith(const std::type_info & otherInfo)246     bool SameTypeWith(const std::type_info& otherInfo) const noexcept
247     {
248         if (functionTable_ == nullptr) {
249             return false;
250         }
251         return IsSameType(functionTable_->type(), otherInfo);
252     }
253 
SameTypeWith(const Any & other)254     bool SameTypeWith(const Any& other) const noexcept
255     {
256         return IsSameType(functionTable_->type(), other.Type());
257     }
258 
259 private:
260     template <typename T>
261     friend const T* AnyCast(const Any* operand) noexcept;
262     template <typename T>
263     friend T* AnyCast(Any* operand) noexcept;
264     template <typename T>
265     friend bool AnyCast(const Any* operand, T& value) 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 object
488   *
489   * @tparam ValueType target value type
490   * @param operand any object
491   * @param value ValueType
492   * @return false if type mismatch, operand is nullptr, or valueType is function/array. Otherwise, true to the
493   *  value contained by operand.
494   */
495 template <typename ValueType>
AnyCast(const Any * operand,ValueType & value)496 bool AnyCast(const Any* operand, ValueType& value) noexcept
497 {
498     static_assert(!std::is_void<ValueType>::value, "ValueType of any_cast must not be void");
499     if (std::is_function<ValueType>::value || std::is_array<ValueType>::value || operand == nullptr
500         || !operand->SameTypeWith(typeid(ValueType))) {
501         return false;
502     } else {
503         value = *(operand->Cast<ValueType>());
504         return true;
505     }
506 }
507 
508 /**
509  * cast one Any pointer into ValueType pointer
510  *
511  * @tparam ValueType target value type
512  * @param operand any object
513  * @return nullptr if type mismatch, operand is nullptr, or valueType is function/array. Otherwise, a pointer to the
514  * value contained by operand.
515  */
516 template <typename ValueType>
AnyCast(Any * operand)517 ValueType* AnyCast(Any* operand) noexcept
518 {
519     static_assert(!std::is_void<ValueType>::value, "ValueType of any_cast must not be void");
520     if (std::is_function<ValueType>::value || std::is_array<ValueType>::value || operand == nullptr) {
521         return nullptr;
522     }
523     return operand->Cast<ValueType>();
524 }
525 
526 /**
527  * cast one Any object into ValueType object
528  *
529  * @tparam ValueType target value type. It must match both conditions:
530  * 1. ValueType must be reference or constructible
531  * 2. Let U be remove_cv_t<remove_reference_t<ValueType>>, then std::is_constructible<ValueType, const U&> must be true
532  * @param operand any object
533  * @return throws BadAnyCast exception if type mismatch, operand is nullptr, or valueType is function/array. Otherwise,
534  * one object of ValueType contained in Any.
535  */
536 template <typename ValueType>
AnyCast(const Any & other)537 ValueType AnyCast(const Any& other)
538 {
539     using U = remove_cv_t<remove_reference_t<ValueType>>;
540     static_assert(IsValidCast<ValueType>::value, "template argument must be a reference or has copy constructors");
541     static_assert(std::is_constructible<ValueType, const U&>::value,
542                   "any_cast<ValueType>(const any&) requires ValueType constructable from const "
543                   "remove_cv_t<remove_reference_t<ValueType>>&");
544     auto ptr = AnyCast<U>(&other);
545     if (ptr == nullptr) {
546         throw BadAnyCast();
547     }
548     return static_cast<ValueType>(*ptr);
549 }
550 
551 /**
552  * cast one Any object into ValueType object
553  *
554  * @tparam ValueType target value type. It must match both conditions:
555  * 1. ValueType must be reference or constructible
556  * 2. Let U be remove_cv_t<remove_reference_t<ValueType>>, then std::is_constructible<ValueType, U&> must be true
557  * @param operand any object
558  * @return throws BadAnyCast exception if type mismatch, operand is nullptr, or valueType is function/array. Otherwise,
559  * one object of ValueType contained in Any.
560  */
561 template <typename ValueType>
AnyCast(Any & other)562 ValueType AnyCast(Any& other)
563 {
564     using U = remove_cv_t<remove_reference_t<ValueType>>;
565     static_assert(IsValidCast<ValueType>::value, "template argument must be a reference or has copy constructors");
566     static_assert(std::is_constructible<ValueType, U&>::value,
567                   "any_cast<ValueType>(const any&) requires ValueType constructable from "
568                   "remove_cv_t<remove_reference_t<ValueType>>&");
569     auto ptr = AnyCast<U>(&other);
570     if (ptr == nullptr) {
571         throw BadAnyCast();
572     }
573     return static_cast<ValueType>(*ptr);
574 }
575 
576 /**
577  * cast one Any object into ValueType object
578  *
579  * @tparam ValueType target value type. It must match both conditions:
580  * 1. ValueType must be reference or constructible
581  * 2. Let U be remove_cv_t<remove_reference_t<ValueType>>, then std::is_constructible<ValueType, U> must be true
582  * @param operand any object
583  * @return throws BadAnyCast exception if type mismatch, operand is nullptr, or valueType is function/array. Otherwise,
584  * one object of ValueType contained in Any.
585  */
586 template <typename ValueType>
AnyCast(Any && other)587 ValueType AnyCast(Any&& other)
588 {
589     using U = remove_cv_t<remove_reference_t<ValueType>>;
590     static_assert(IsValidCast<ValueType>::value, "template argument must be a reference or has copy constructors");
591     static_assert(std::is_constructible<ValueType, U>::value,
592                   "any_cast<ValueType>(const any&) requires ValueType constructable from "
593                   "remove_cv_t<remove_reference_t<ValueType>>");
594     auto ptr = AnyCast<U>(&other);
595     if (ptr == nullptr) {
596         throw BadAnyCast();
597     }
598     return static_cast<ValueType>(std::move(*ptr));
599 }
600 
601 /**
602  * Constructs Any object, whose content is constructed by args. The content type is T.
603  *
604  * @tparam T type of Any's content
605  * @tparam Args type of args
606  * @param args args used to construct the content
607  * @return Any object
608  */
609 template <typename T, typename... Args>
MakeAny(Args &&...args)610 Any MakeAny(Args&&... args)
611 {
612     Any tmp;
613     tmp.Emplace<T, Args...>(std::forward<Args>(args)...);
614     return tmp;
615 }
616 
617 /**
618  * Constructs Any object, whose content is constructed by il and args. The content type is T.
619  *
620  * @tparam T type of Any's content
621  * @tparam U type of initializer list
622  * @tparam Args type of args
623  * @param il initializer list
624  * @param args args
625  * @return Any object
626  */
627 template <typename T, typename U, typename... Args>
MakeAny(std::initializer_list<U> il,Args &&...args)628 Any MakeAny(std::initializer_list<U> il, Args&&... args)
629 {
630     Any tmp;
631     tmp.Emplace<T, U, Args...>(il, std::forward<Args>(args)...);
632     return tmp;
633 }
634 } // namespace Plugin
635 } // namespace Media
636 } // namespace OHOS
637 #endif
638 namespace std {
swap(OHOS::Media::Plugin::Any & lhs,OHOS::Media::Plugin::Any & rhs)639 inline void swap(OHOS::Media::Plugin::Any& lhs, OHOS::Media::Plugin::Any& rhs) noexcept
640 {
641     lhs.Swap(rhs);
642 }
643 } // namespace std
644 #endif // HISTREAMER_PLUGIN_COMMON_ANY_H
645