• 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         return IsSameType(functionTable_->type(), otherInfo);
251     }
252 
SameTypeWith(const Any & other)253     bool SameTypeWith(const Any& other) const noexcept
254     {
255         return IsSameType(functionTable_->type(), other.Type());
256     }
257 
258 private:
259     template <typename T>
260     friend const T* AnyCast(const Any* operand) noexcept;
261     template <typename T>
262     friend T* AnyCast(Any* operand) noexcept;
263 
264     union Storage {
265         using Stack = std::aligned_storage<STACK_STORAGE_SIZE, std::alignment_of<void*>::value>::type;
266         using Heap = void*;
267 
268         std::array<uint8_t, STACK_STORAGE_SIZE> trivialStack_;
269         Stack nonTrivialStack_;
270         Heap heap_;
271     };
272 
273     struct FunctionTable {
274         const std::type_info& (*type)() noexcept;
275         void (*destroy)(Storage&) noexcept;
276         void (*copy)(Storage&, const Storage&) noexcept;
277         void (*move)(Storage&, Storage&) noexcept;
278         void* (*getPtr)(Storage&) noexcept;
279         const void* (*getConstPtr)(const Storage&) noexcept;
280     };
281 
282     template <typename T>
283     struct TrivialStackFunctionTable {
TypeTrivialStackFunctionTable284         static const std::type_info& Type() noexcept
285         {
286             return typeid(T);
287         }
288 
DestroyTrivialStackFunctionTable289         static void Destroy(Storage& storage) noexcept
290         {
291             reinterpret_cast<T*>(storage.trivialStack_.data())->~T();
292         }
293 
CopyTrivialStackFunctionTable294         static void Copy(Storage& dest, const Storage& source) noexcept
295         {
296             // memcpy_s will always success in this function
297             memcpy_s(GetPtr(dest), sizeof(Storage), GetConstPtr(source), sizeof(Storage));
298         }
299 
MoveTrivialStackFunctionTable300         static void Move(Storage& dest, Storage& source) noexcept
301         {
302             Copy(dest, source);
303             source.trivialStack_.fill(0);
304         }
305 
GetConstPtrTrivialStackFunctionTable306         static const void* GetConstPtr(const Storage& storage) noexcept
307         {
308             return reinterpret_cast<const void*>(storage.trivialStack_.data());
309         }
310 
GetPtrTrivialStackFunctionTable311         static void* GetPtr(Storage& storage) noexcept
312         {
313             return reinterpret_cast<void*>(storage.trivialStack_.data());
314         }
315     };
316 
317     template <typename T>
318     struct StackFunctionTable {
TypeStackFunctionTable319         static const std::type_info& Type() noexcept
320         {
321             return typeid(T);
322         }
323 
DestroyStackFunctionTable324         static void Destroy(Storage& storage) noexcept
325         {
326             reinterpret_cast<T*>(GetPtr(storage))->~T(); // NOLINT: cast
327         }
328 
CopyStackFunctionTable329         static void Copy(Storage& dest, const Storage& source) noexcept
330         {
331             // NOLINTNEXTLINE: reinterpret_cast
332             new (reinterpret_cast<T*>(GetPtr(dest))) T(*reinterpret_cast<const T*>(GetConstPtr(source)));
333         }
334 
MoveStackFunctionTable335         static void Move(Storage& dest, Storage& source) noexcept
336         {
337             // NOLINTNEXTLINE: reinterpret_cast
338             new (reinterpret_cast<T*>(GetPtr(dest))) T(std::move(*reinterpret_cast<T*>(GetPtr(source))));
339             Destroy(source);
340         }
341 
GetConstPtrStackFunctionTable342         static const void* GetConstPtr(const Storage& storage) noexcept
343         {
344             return reinterpret_cast<const void*>(&storage.nonTrivialStack_);
345         }
346 
GetPtrStackFunctionTable347         static void* GetPtr(Storage& storage) noexcept
348         {
349             return reinterpret_cast<void*>(&storage.nonTrivialStack_);
350         }
351     };
352 
353     template <typename T>
354     struct HeapFunctionTable {
TypeHeapFunctionTable355         static const std::type_info& Type() noexcept
356         {
357             return typeid(T);
358         }
359 
DestroyHeapFunctionTable360         static void Destroy(Storage& storage) noexcept
361         {
362             delete reinterpret_cast<T*>(storage.heap_); // NOLINT: cast
363             storage.heap_ = nullptr;
364         }
CopyHeapFunctionTable365         static void Copy(Storage& dest, const Storage& source) noexcept
366         {
367             dest.heap_ = new T(*reinterpret_cast<T*>(source.heap_)); // NOLINT: cast
368         }
MoveHeapFunctionTable369         static void Move(Storage& dest, Storage& source) noexcept
370         {
371             dest.heap_ = source.heap_;
372             source.heap_ = nullptr;
373         }
GetConstPtrHeapFunctionTable374         static const void* GetConstPtr(const Storage& storage) noexcept
375         {
376             return storage.heap_;
377         }
GetPtrHeapFunctionTable378         static void* GetPtr(Storage& storage) noexcept
379         {
380             return storage.heap_;
381         }
382     };
383 
384     template <typename ValueType>
GetFunctionTable()385     static FunctionTable* GetFunctionTable()
386     {
387         using DecayedValueType = decay_t<ValueType>;
388         using DetailFunctionTable =
389             conditional_t<IsTrivialStackStorable<DecayedValueType>::value,
390                           TrivialStackFunctionTable<DecayedValueType>,
391                           conditional_t<IsStackStorable<DecayedValueType>::value,
392                                         StackFunctionTable<DecayedValueType>, HeapFunctionTable<DecayedValueType>>>;
393         static FunctionTable table = {
394             .type = DetailFunctionTable::Type,
395             .destroy = DetailFunctionTable::Destroy,
396             .copy = DetailFunctionTable::Copy,
397             .move = DetailFunctionTable::Move,
398             .getPtr = DetailFunctionTable::GetPtr,
399             .getConstPtr = DetailFunctionTable::GetConstPtr,
400         };
401         return &table;
402     }
403 
IsFunctionTableValid()404     bool IsFunctionTableValid() const noexcept
405     {
406         return functionTable_ != nullptr;
407     }
408 
409     template <typename DecayedValueType, typename... Args>
DoEmplace(Args &&...args)410     DecayedValueType& DoEmplace(Args&&... args)
411     {
412         functionTable_ = GetFunctionTable<DecayedValueType>();
413         DecayedValueType* ptr = nullptr;
414         if (IsTrivialStackStorable<DecayedValueType>::value || IsStackStorable<DecayedValueType>::value) {
415             ptr = reinterpret_cast<DecayedValueType*>(functionTable_->getPtr(storage_));
416             new (ptr) DecayedValueType(std::forward<Args>(args)...);
417         } else {
418             storage_.heap_ = new DecayedValueType(std::forward<Args>(args)...);
419             ptr = reinterpret_cast<DecayedValueType*>(storage_.heap_);
420         }
421         return *ptr;
422     }
423 
MoveFrom(Any && other)424     void MoveFrom(Any&& other) noexcept
425     {
426         if (other.HasValue()) {
427             functionTable_ = other.functionTable_;
428             functionTable_->move(storage_, other.storage_);
429             other.Reset();
430         }
431     }
432 
433     template <typename ValueType>
Cast()434     ValueType* Cast() noexcept
435     {
436         using DecayedValueType = decay_t<ValueType>;
437         if (!IsFunctionTableValid() || !SameTypeWith(typeid(DecayedValueType))) {
438             return nullptr;
439         }
440         return IsTrivialStackStorable<DecayedValueType>::value
441                    ? reinterpret_cast<DecayedValueType*>(storage_.trivialStack_.data())
442                    : (IsStackStorable<DecayedValueType>::value
443                           ? reinterpret_cast<DecayedValueType*>(&storage_.nonTrivialStack_)
444                           : reinterpret_cast<DecayedValueType*>(storage_.heap_));
445     }
446     template <typename ValueType>
Cast()447     const ValueType* Cast() const noexcept
448     {
449         using DecayedValueType = decay_t<ValueType>;
450         if (!IsFunctionTableValid() || !SameTypeWith(typeid(DecayedValueType))) {
451             return nullptr;
452         }
453         return IsTrivialStackStorable<DecayedValueType>::value
454                    ? reinterpret_cast<const DecayedValueType*>(storage_.trivialStack_.data())
455                    : (IsStackStorable<DecayedValueType>::value
456                           ? reinterpret_cast<const DecayedValueType*>(&storage_.nonTrivialStack_)
457                           : reinterpret_cast<const DecayedValueType*>(storage_.heap_));
458     }
459 
460 private:
461     Storage storage_ {};
462     FunctionTable* functionTable_ {nullptr};
463 };
464 
465 /**
466  * cast one Any pointer into ValueType pointer
467  *
468  * @tparam ValueType target value type
469  * @param operand any object
470  * @return nullptr if type mismatch, operand is nullptr, or valueType is function/array. Otherwise, a pointer to the
471  * const value contained by operand.
472  */
473 template <typename ValueType>
AnyCast(const Any * operand)474 const ValueType* AnyCast(const Any* operand) noexcept
475 {
476     static_assert(!std::is_void<ValueType>::value, "ValueType of any_cast must not be void");
477     if (std::is_function<ValueType>::value || std::is_array<ValueType>::value || operand == nullptr) {
478         return nullptr;
479     }
480     return operand->Cast<ValueType>();
481 }
482 
483 /**
484  * cast one Any pointer into ValueType pointer
485  *
486  * @tparam ValueType target value type
487  * @param operand any object
488  * @return nullptr if type mismatch, operand is nullptr, or valueType is function/array. Otherwise, a pointer to the
489  * value contained by operand.
490  */
491 template <typename ValueType>
AnyCast(Any * operand)492 ValueType* AnyCast(Any* operand) noexcept
493 {
494     static_assert(!std::is_void<ValueType>::value, "ValueType of any_cast must not be void");
495     if (std::is_function<ValueType>::value || std::is_array<ValueType>::value || operand == nullptr) {
496         return nullptr;
497     }
498     return operand->Cast<ValueType>();
499 }
500 
501 /**
502  * cast one Any object into ValueType object
503  *
504  * @tparam ValueType target value type. It must match both conditions:
505  * 1. ValueType must be reference or constructible
506  * 2. Let U be remove_cv_t<remove_reference_t<ValueType>>, then std::is_constructible<ValueType, const U&> must be true
507  * @param operand any object
508  * @return throws BadAnyCast exception if type mismatch, operand is nullptr, or valueType is function/array. Otherwise,
509  * one object of ValueType contained in Any.
510  */
511 template <typename ValueType>
AnyCast(const Any & other)512 ValueType AnyCast(const Any& other)
513 {
514     using U = remove_cv_t<remove_reference_t<ValueType>>;
515     static_assert(IsValidCast<ValueType>::value, "template argument must be a reference or has copy constructors");
516     static_assert(std::is_constructible<ValueType, const U&>::value,
517                   "any_cast<ValueType>(const any&) requires ValueType constructable from const "
518                   "remove_cv_t<remove_reference_t<ValueType>>&");
519     auto ptr = AnyCast<U>(&other);
520     if (ptr == nullptr) {
521         throw BadAnyCast();
522     }
523     return static_cast<ValueType>(*ptr);
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, 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(Any & other)537 ValueType AnyCast(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, U&>::value,
542                   "any_cast<ValueType>(const any&) requires ValueType constructable from "
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>(std::move(*ptr));
574 }
575 
576 /**
577  * Constructs Any object, whose content is constructed by args. The content type is T.
578  *
579  * @tparam T type of Any's content
580  * @tparam Args type of args
581  * @param args args used to construct the content
582  * @return Any object
583  */
584 template <typename T, typename... Args>
MakeAny(Args &&...args)585 Any MakeAny(Args&&... args)
586 {
587     Any tmp;
588     tmp.Emplace<T, Args...>(std::forward<Args>(args)...);
589     return tmp;
590 }
591 
592 /**
593  * Constructs Any object, whose content is constructed by il and args. The content type is T.
594  *
595  * @tparam T type of Any's content
596  * @tparam U type of initializer list
597  * @tparam Args type of args
598  * @param il initializer list
599  * @param args args
600  * @return Any object
601  */
602 template <typename T, typename U, typename... Args>
MakeAny(std::initializer_list<U> il,Args &&...args)603 Any MakeAny(std::initializer_list<U> il, Args&&... args)
604 {
605     Any tmp;
606     tmp.Emplace<T, U, Args...>(il, std::forward<Args>(args)...);
607     return tmp;
608 }
609 } // namespace Plugin
610 } // namespace Media
611 } // namespace OHOS
612 #endif
613 namespace std {
swap(OHOS::Media::Plugin::Any & lhs,OHOS::Media::Plugin::Any & rhs)614 inline void swap(OHOS::Media::Plugin::Any& lhs, OHOS::Media::Plugin::Any& rhs) noexcept
615 {
616     lhs.Swap(rhs);
617 }
618 } // namespace std
619 #endif // HISTREAMER_PLUGIN_COMMON_ANY_H
620