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