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