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