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 <string_view> 30#include <type_traits> 31#include "plugin/common/type_cast_ext.h" 32#include "securec.h" 33 34namespace { 35template <typename T> 36using decay_t = typename std::decay<T>::type; 37 38template <bool B, typename T = void> 39using enable_if_t = typename std::enable_if<B, T>::type; 40 41template <bool B, typename T, typename F> 42using conditional_t = typename std::conditional<B, T, F>::type; 43 44template <typename T> 45using remove_cv_t = typename std::remove_cv<T>::type; 46 47template <typename T> 48using remove_reference_t = typename std::remove_reference<T>::type; 49constexpr size_t STACK_STORAGE_SIZE = 2 * sizeof(void*); // NOLINT: global var 50 51template <typename T> 52struct IsTrivialStackStorable { 53 static constexpr bool value = 54 alignof(T) <= alignof(max_align_t) && std::is_trivially_copyable<T>::value && sizeof(T) <= STACK_STORAGE_SIZE; 55}; 56 57template <typename T> 58struct IsStackStorable { 59 static constexpr bool value = alignof(T) <= alignof(max_align_t) && std::is_nothrow_move_constructible<T>::value && 60 sizeof(T) <= STACK_STORAGE_SIZE; 61}; 62 63template <typename T> 64struct IsValidCast { 65 static constexpr bool value = std::is_reference<T>::value || std::is_copy_constructible<T>::value; 66}; 67} // namespace 68namespace OHOS { 69namespace Media { 70namespace Plugin { 71/** 72 * @brief BadAnyCast exception, which is thrown when error occurs in AnyCast 73 * 74 * @since 1.0 75 * @version 1.0 76 */ 77class BadAnyCast : public std::bad_cast { 78public: 79 const char* what() const noexcept override 80 { 81 return "bad any cast"; 82 } 83}; 84 85/** 86 * @brief This class describes a type-safe container for arbitrary type values which are copy constructible. 87 * 88 * @since 1.0 89 * @version 1.0 90 */ 91class Any final { 92public: 93 constexpr Any() noexcept 94 { 95 } 96 97 Any(const Any& other) : functionTable_(other.functionTable_) 98 { 99 if (other.HasValue()) { 100 functionTable_->copy(storage_, other.storage_); 101 } 102 } 103 104 Any(Any&& other) noexcept : functionTable_(other.functionTable_) 105 { 106 if (other.HasValue()) { 107 functionTable_->move(storage_, other.storage_); 108 other.functionTable_ = nullptr; 109 } 110 } 111 112 /** 113 * constructor from right reference value with type of ValueType. 114 * 115 * @tparam Type ValueType is not the same as Any itself. The decay type of ValueType must be copy constructible. 116 * @param value content 117 */ 118 template <typename ValueType, enable_if_t<!std::is_same<decay_t<ValueType>, Any>::value && 119 std::is_copy_constructible<decay_t<ValueType>>::value, 120 bool> = true> 121 Any(ValueType&& value) // NOLINT: explicit 122 { 123 DoEmplace<decay_t<ValueType>>(std::forward<ValueType>(value)); 124 } 125 126 Any& operator=(const Any& other) 127 { 128 *this = Any(other); 129 return *this; 130 } 131 132 Any& operator=(Any&& other) noexcept 133 { 134 Reset(); 135 MoveFrom(std::forward<Any>(other)); 136 return *this; 137 } 138 139 /** 140 * Assigns contents to Any. 141 * 142 * @tparam ValueType Type ValueType is not the same as Any itself. The decay type of ValueType must be copy 143 * constructible. 144 * @param value content 145 * @return 146 */ 147 template <typename ValueType, enable_if_t<!std::is_same<decay_t<ValueType>, Any>::value && 148 std::is_copy_constructible<decay_t<ValueType>>::value, 149 bool> = true> 150 Any& operator=(ValueType&& value) 151 { 152 *this = Any(std::forward<ValueType>(value)); 153 return *this; 154 } 155 156 template<typename T> 157 static constexpr std::string_view GetTypeName() noexcept 158 { 159 const char* charInfo = __PRETTY_FUNCTION__ ; 160 std::string_view stringInfo = charInfo; 161 uint32_t beginIndex = stringInfo.find_first_of('=') + 2; // 2 表示右移两位 162 uint32_t endIndex = stringInfo.find_first_of(']'); 163 std::string_view typeName(charInfo + beginIndex, endIndex - beginIndex + 1); 164 return typeName; 165 } 166 167 template<typename T> 168 static bool IsSameTypeWith(const Any& other) noexcept 169 { 170#ifndef HST_ANY_WITH_NO_RTTI 171 return other.SameTypeWith(typeid(T)); 172#else 173 return other.SameTypeWith(Any::GetTypeName<T>()); 174#endif 175 } 176 177 ~Any() 178 { 179 Reset(); 180 } 181 182 /** 183 * Emplace one content with type of ValueType into object. The content is constructed by args. 184 * 185 * @tparam ValueType The decay type of ValueType must be constructible from args and copy constructible. 186 * @tparam Args args type 187 * @param args args 188 * @return content with type of decay ValueType 189 */ 190 template <typename ValueType, typename... Args, 191 enable_if_t<std::is_constructible<decay_t<ValueType>, Args...>::value && 192 std::is_copy_constructible<decay_t<ValueType>>::value, 193 bool> = true> 194 decay_t<ValueType>& Emplace(Args&&... args) 195 { 196 Reset(); 197 return DoEmplace<decay_t<ValueType>>(std::forward<Args>(args)...); 198 } 199 200 /** 201 * Emplace one content with type of ValueType into object. The content is constructed by il and args. 202 * 203 * @tparam ValueType type of conetent. The decay type of ValueType must be constructible from il and args and copy 204 * constructible 205 * @tparam U type of initializer list. 206 * @tparam Args type of other args 207 * @param il initializer list 208 * @param args args 209 * @return content with type of decay ValueType 210 */ 211 template <typename ValueType, typename U, typename... Args, 212 enable_if_t<std::is_constructible<decay_t<ValueType>, std::initializer_list<U>&, Args...>::value && 213 std::is_copy_constructible<decay_t<ValueType>>::value, 214 bool> = true> 215 decay_t<ValueType>& Emplace(std::initializer_list<U> il, Args&&... args) 216 { 217 Reset(); 218 return DoEmplace<decay_t<ValueType>>(il, std::forward<Args>(args)...); 219 } 220 221 /** 222 * Destroy the inner content if exists. 223 */ 224 void Reset() noexcept 225 { 226 if (HasValue()) { 227 functionTable_->destroy(storage_); 228 storage_.trivialStack_.fill(0); 229 } 230 functionTable_ = nullptr; 231 } 232 233 /** 234 * swap contents of two any objects 235 * 236 * @param other object to swap with 237 */ 238 void Swap(Any& other) noexcept 239 { 240 Any tmp(std::move(*this)); 241 *this = std::move(other); 242 other = std::move(tmp); 243 } 244 245 /** 246 * Checks whether the object has one content. 247 * 248 * @return true if object has one content, otherwise false. 249 */ 250 bool HasValue() const noexcept 251 { 252 return IsFunctionTableValid(); 253 } 254 255#ifndef HST_ANY_WITH_NO_RTTI 256 /** 257 * Get tye type_info of object 258 * 259 * @return type info of object 260 */ 261 const std::type_info& Type() const noexcept 262 { 263 if (!HasValue()) { 264 return typeid(void); 265 } 266 return functionTable_->type(); 267 } 268#else 269 std::string_view TypeName() const noexcept 270 { 271 if (!HasValue()) { 272 return "empty"; // no value 273 } 274 return functionTable_->type_name(); 275 } 276#endif 277 278#ifndef HST_ANY_WITH_NO_RTTI 279 bool SameTypeWith(const std::type_info& otherInfo) const noexcept 280 { 281 if (functionTable_ == nullptr) { 282 return false; 283 } 284 return IsSameType(functionTable_->type(), otherInfo); 285 } 286#else 287 bool SameTypeWith(std::string_view otherTypeName) const noexcept 288 { 289 if (functionTable_ == nullptr) { 290 return false; 291 } 292 return IsSameType(functionTable_->type_name(), otherTypeName); 293 } 294#endif 295 296 bool SameTypeWith(const Any& other) const noexcept 297 { 298#ifndef HST_ANY_WITH_NO_RTTI 299 return IsSameType(functionTable_->type(), other.Type()); 300#else 301 return IsSameType(functionTable_->type_name(), other.TypeName()); 302#endif 303 } 304 305private: 306 template <typename T> 307 friend const T* AnyCast(const Any* operand) noexcept; 308 template <typename T> 309 friend T* AnyCast(Any* operand) noexcept; 310 template <typename T> 311 friend bool AnyCast(const Any* operand, T& value) noexcept; 312 313 union Storage { 314 using Stack = std::aligned_storage<STACK_STORAGE_SIZE, std::alignment_of<void*>::value>::type; 315 using Heap = void*; 316 317 std::array<uint8_t, STACK_STORAGE_SIZE> trivialStack_; 318 Stack nonTrivialStack_; 319 Heap heap_; 320 }; 321 322 struct FunctionTable { 323#ifndef HST_ANY_WITH_NO_RTTI 324 const std::type_info& (*type)() noexcept; 325#else 326 std::string_view (*type_name)() noexcept; 327#endif 328 void (*destroy)(Storage&) noexcept; 329 void (*copy)(Storage&, const Storage&) noexcept; 330 void (*move)(Storage&, Storage&) noexcept; 331 void* (*getPtr)(Storage&) noexcept; 332 const void* (*getConstPtr)(const Storage&) noexcept; 333 }; 334 335 template <typename T> 336 struct TrivialStackFunctionTable { 337#ifndef HST_ANY_WITH_NO_RTTI 338 static const std::type_info& Type() noexcept 339 { 340 return typeid(T); 341 } 342#else 343 static std::string_view TypeName() noexcept 344 { 345 return GetTypeName<T>(); 346 } 347#endif 348 349 static void Destroy(Storage& storage) noexcept 350 { 351 reinterpret_cast<T*>(storage.trivialStack_.data())->~T(); 352 } 353 354 static void Copy(Storage& dest, const Storage& source) noexcept 355 { 356 // memcpy_s will always success in this function 357 (void)memcpy_s(GetPtr(dest), sizeof(Storage), GetConstPtr(source), sizeof(Storage)); 358 } 359 360 static void Move(Storage& dest, Storage& source) noexcept 361 { 362 Copy(dest, source); 363 source.trivialStack_.fill(0); 364 } 365 366 static const void* GetConstPtr(const Storage& storage) noexcept 367 { 368 return reinterpret_cast<const void*>(storage.trivialStack_.data()); 369 } 370 371 static void* GetPtr(Storage& storage) noexcept 372 { 373 return reinterpret_cast<void*>(storage.trivialStack_.data()); 374 } 375 }; 376 377 template <typename T> 378 struct StackFunctionTable { 379#ifndef HST_ANY_WITH_NO_RTTI 380 static const std::type_info& Type() noexcept 381 { 382 return typeid(T); 383 } 384#else 385 static std::string_view TypeName() noexcept 386 { 387 return GetTypeName<T>(); 388 } 389#endif 390 391 static void Destroy(Storage& storage) noexcept 392 { 393 reinterpret_cast<T*>(GetPtr(storage))->~T(); // NOLINT: cast 394 } 395 396 static void Copy(Storage& dest, const Storage& source) noexcept 397 { 398 // NOLINTNEXTLINE: reinterpret_cast 399 new (reinterpret_cast<T*>(GetPtr(dest))) T(*reinterpret_cast<const T*>(GetConstPtr(source))); 400 } 401 402 static void Move(Storage& dest, Storage& source) noexcept 403 { 404 // NOLINTNEXTLINE: reinterpret_cast 405 new (reinterpret_cast<T*>(GetPtr(dest))) T(std::move(*reinterpret_cast<T*>(GetPtr(source)))); 406 Destroy(source); 407 } 408 409 static const void* GetConstPtr(const Storage& storage) noexcept 410 { 411 return reinterpret_cast<const void*>(&storage.nonTrivialStack_); 412 } 413 414 static void* GetPtr(Storage& storage) noexcept 415 { 416 return reinterpret_cast<void*>(&storage.nonTrivialStack_); 417 } 418 }; 419 420 template <typename T> 421 struct HeapFunctionTable { 422#ifndef HST_ANY_WITH_NO_RTTI 423 static const std::type_info& Type() noexcept 424 { 425 return typeid(T); 426 } 427#else 428 static std::string_view TypeName() noexcept 429 { 430 return GetTypeName<T>(); 431 } 432#endif 433 434 static void Destroy(Storage& storage) noexcept 435 { 436 delete reinterpret_cast<T*>(storage.heap_); // NOLINT: cast 437 storage.heap_ = nullptr; 438 } 439 static void Copy(Storage& dest, const Storage& source) noexcept 440 { 441 dest.heap_ = new T(*reinterpret_cast<T*>(source.heap_)); // NOLINT: cast 442 } 443 static void Move(Storage& dest, Storage& source) noexcept 444 { 445 dest.heap_ = source.heap_; 446 source.heap_ = nullptr; 447 } 448 static const void* GetConstPtr(const Storage& storage) noexcept 449 { 450 return storage.heap_; 451 } 452 static void* GetPtr(Storage& storage) noexcept 453 { 454 return storage.heap_; 455 } 456 }; 457 458 template <typename ValueType> 459 static FunctionTable* GetFunctionTable() 460 { 461 using DecayedValueType = decay_t<ValueType>; 462 using DetailFunctionTable = 463 conditional_t<IsTrivialStackStorable<DecayedValueType>::value, 464 TrivialStackFunctionTable<DecayedValueType>, 465 conditional_t<IsStackStorable<DecayedValueType>::value, 466 StackFunctionTable<DecayedValueType>, HeapFunctionTable<DecayedValueType>>>; 467 static FunctionTable table = { 468#ifndef HST_ANY_WITH_NO_RTTI 469 .type = DetailFunctionTable::Type, 470#else 471 .type_name = DetailFunctionTable::TypeName, 472#endif 473 .destroy = DetailFunctionTable::Destroy, 474 .copy = DetailFunctionTable::Copy, 475 .move = DetailFunctionTable::Move, 476 .getPtr = DetailFunctionTable::GetPtr, 477 .getConstPtr = DetailFunctionTable::GetConstPtr, 478 }; 479 return &table; 480 } 481 482 bool IsFunctionTableValid() const noexcept 483 { 484 return functionTable_ != nullptr; 485 } 486 487 template <typename DecayedValueType, typename... Args> 488 DecayedValueType& DoEmplace(Args&&... args) 489 { 490 functionTable_ = GetFunctionTable<DecayedValueType>(); 491 DecayedValueType* ptr = nullptr; 492 if (IsTrivialStackStorable<DecayedValueType>::value || IsStackStorable<DecayedValueType>::value) { 493 ptr = reinterpret_cast<DecayedValueType*>(functionTable_->getPtr(storage_)); 494 new (ptr) DecayedValueType(std::forward<Args>(args)...); 495 } else { 496 storage_.heap_ = new DecayedValueType(std::forward<Args>(args)...); 497 ptr = reinterpret_cast<DecayedValueType*>(storage_.heap_); 498 } 499 return *ptr; 500 } 501 502 void MoveFrom(Any&& other) noexcept 503 { 504 if (other.HasValue()) { 505 functionTable_ = other.functionTable_; 506 functionTable_->move(storage_, other.storage_); 507 other.Reset(); 508 } 509 } 510 511 template <typename ValueType> 512 ValueType* Cast() noexcept 513 { 514 using DecayedValueType = decay_t<ValueType>; 515 if (!IsFunctionTableValid()) { 516 return nullptr; 517 } 518#ifndef HST_ANY_WITH_NO_RTTI 519 if (!SameTypeWith(typeid(DecayedValueType))) { 520#else 521 if (!SameTypeWith(Any::GetTypeName<DecayedValueType>())) { 522#endif 523 return nullptr; 524 } 525 return IsTrivialStackStorable<DecayedValueType>::value 526 ? reinterpret_cast<DecayedValueType*>(storage_.trivialStack_.data()) 527 : (IsStackStorable<DecayedValueType>::value 528 ? reinterpret_cast<DecayedValueType*>(&storage_.nonTrivialStack_) 529 : reinterpret_cast<DecayedValueType*>(storage_.heap_)); 530 } 531 template <typename ValueType> 532 const ValueType* Cast() const noexcept 533 { 534 using DecayedValueType = decay_t<ValueType>; 535 if (!IsFunctionTableValid()) { 536 return nullptr; 537 } 538#ifndef HST_ANY_WITH_NO_RTTI 539 if (!SameTypeWith(typeid(DecayedValueType))) { 540#else 541 if (!SameTypeWith(Any::GetTypeName<DecayedValueType>())) { 542#endif 543 return nullptr; 544 } 545 return IsTrivialStackStorable<DecayedValueType>::value 546 ? reinterpret_cast<const DecayedValueType*>(storage_.trivialStack_.data()) 547 : (IsStackStorable<DecayedValueType>::value 548 ? reinterpret_cast<const DecayedValueType*>(&storage_.nonTrivialStack_) 549 : reinterpret_cast<const DecayedValueType*>(storage_.heap_)); 550 } 551 552private: 553 Storage storage_ {}; 554 FunctionTable* functionTable_ {nullptr}; 555}; 556 557/** 558 * cast one Any pointer into ValueType pointer 559 * 560 * @tparam ValueType target value type 561 * @param operand any object 562 * @return nullptr if type mismatch, operand is nullptr, or valueType is function/array. Otherwise, a pointer to the 563 * const value contained by operand. 564 */ 565template <typename ValueType> 566const ValueType* AnyCast(const Any* operand) noexcept 567{ 568 static_assert(!std::is_void<ValueType>::value, "ValueType of any_cast must not be void"); 569 if (std::is_function<ValueType>::value || std::is_array<ValueType>::value || operand == nullptr) { 570 return nullptr; 571 } 572 return operand->Cast<ValueType>(); 573} 574 575 /** 576 * cast one Any pointer into ValueType object 577 * 578 * @tparam ValueType target value type 579 * @param operand any object 580 * @param value ValueType 581 * @return false if type mismatch, operand is nullptr, or valueType is function/array. Otherwise, true to the 582 * value contained by operand. 583 */ 584template <typename ValueType> 585bool AnyCast(const Any* operand, ValueType& value) noexcept 586{ 587 static_assert(!std::is_void<ValueType>::value, "ValueType of any_cast must not be void"); 588 if (std::is_function<ValueType>::value || std::is_array<ValueType>::value || operand == nullptr) { 589 return false; 590 } 591#ifndef HST_ANY_WITH_NO_RTTI 592 if (!operand->SameTypeWith(typeid(ValueType))) { 593#else 594 if (!operand->SameTypeWith(Any::GetTypeName<ValueType>())) { 595#endif 596 return false; 597 } else { 598 auto casted_value = operand->Cast<ValueType>(); 599 if (casted_value != nullptr) { 600 value = *casted_value; 601 return true; 602 } 603 return false; 604 } 605} 606 607/** 608 * cast one Any pointer into ValueType pointer 609 * 610 * @tparam ValueType target value type 611 * @param operand any object 612 * @return nullptr if type mismatch, operand is nullptr, or valueType is function/array. Otherwise, a pointer to the 613 * value contained by operand. 614 */ 615template <typename ValueType> 616ValueType* AnyCast(Any* operand) noexcept 617{ 618 static_assert(!std::is_void<ValueType>::value, "ValueType of any_cast must not be void"); 619 if (std::is_function<ValueType>::value || std::is_array<ValueType>::value || operand == nullptr) { 620 return nullptr; 621 } 622 return operand->Cast<ValueType>(); 623} 624 625/** 626 * cast one Any object into ValueType object 627 * 628 * @tparam ValueType target value type. It must match both conditions: 629 * 1. ValueType must be reference or constructible 630 * 2. Let U be remove_cv_t<remove_reference_t<ValueType>>, then std::is_constructible<ValueType, const U&> must be true 631 * @param operand any object 632 * @return throws BadAnyCast exception if type mismatch, operand is nullptr, or valueType is function/array. Otherwise, 633 * one object of ValueType contained in Any. 634 */ 635template <typename ValueType> 636ValueType AnyCast(const Any& other) 637{ 638 using U = remove_cv_t<remove_reference_t<ValueType>>; 639 static_assert(IsValidCast<ValueType>::value, "template argument must be a reference or has copy constructors"); 640 static_assert(std::is_constructible<ValueType, const U&>::value, 641 "any_cast<ValueType>(const any&) requires ValueType constructable from const " 642 "remove_cv_t<remove_reference_t<ValueType>>&"); 643 auto ptr = AnyCast<U>(&other); 644 if (ptr == nullptr) { 645 throw BadAnyCast(); 646 } 647 return static_cast<ValueType>(*ptr); 648} 649 650/** 651 * cast one Any object into ValueType object 652 * 653 * @tparam ValueType target value type. It must match both conditions: 654 * 1. ValueType must be reference or constructible 655 * 2. Let U be remove_cv_t<remove_reference_t<ValueType>>, then std::is_constructible<ValueType, U&> must be true 656 * @param operand any object 657 * @return throws BadAnyCast exception if type mismatch, operand is nullptr, or valueType is function/array. Otherwise, 658 * one object of ValueType contained in Any. 659 */ 660template <typename ValueType> 661ValueType AnyCast(Any& other) 662{ 663 using U = remove_cv_t<remove_reference_t<ValueType>>; 664 static_assert(IsValidCast<ValueType>::value, "template argument must be a reference or has copy constructors"); 665 static_assert(std::is_constructible<ValueType, U&>::value, 666 "any_cast<ValueType>(const any&) requires ValueType constructable from " 667 "remove_cv_t<remove_reference_t<ValueType>>&"); 668 auto ptr = AnyCast<U>(&other); 669 if (ptr == nullptr) { 670 throw BadAnyCast(); 671 } 672 return static_cast<ValueType>(*ptr); 673} 674 675/** 676 * cast one Any object into ValueType object 677 * 678 * @tparam ValueType target value type. It must match both conditions: 679 * 1. ValueType must be reference or constructible 680 * 2. Let U be remove_cv_t<remove_reference_t<ValueType>>, then std::is_constructible<ValueType, U> must be true 681 * @param operand any object 682 * @return throws BadAnyCast exception if type mismatch, operand is nullptr, or valueType is function/array. Otherwise, 683 * one object of ValueType contained in Any. 684 */ 685template <typename ValueType> 686ValueType AnyCast(Any&& other) 687{ 688 using U = remove_cv_t<remove_reference_t<ValueType>>; 689 static_assert(IsValidCast<ValueType>::value, "template argument must be a reference or has copy constructors"); 690 static_assert(std::is_constructible<ValueType, U>::value, 691 "any_cast<ValueType>(const any&) requires ValueType constructable from " 692 "remove_cv_t<remove_reference_t<ValueType>>"); 693 auto ptr = AnyCast<U>(&other); 694 if (ptr == nullptr) { 695 throw BadAnyCast(); 696 } 697 return static_cast<ValueType>(std::move(*ptr)); 698} 699 700/** 701 * Constructs Any object, whose content is constructed by args. The content type is T. 702 * 703 * @tparam T type of Any's content 704 * @tparam Args type of args 705 * @param args args used to construct the content 706 * @return Any object 707 */ 708template <typename T, typename... Args> 709Any MakeAny(Args&&... args) 710{ 711 Any tmp; 712 tmp.Emplace<T, Args...>(std::forward<Args>(args)...); 713 return tmp; 714} 715 716/** 717 * Constructs Any object, whose content is constructed by il and args. The content type is T. 718 * 719 * @tparam T type of Any's content 720 * @tparam U type of initializer list 721 * @tparam Args type of args 722 * @param il initializer list 723 * @param args args 724 * @return Any object 725 */ 726template <typename T, typename U, typename... Args> 727Any MakeAny(std::initializer_list<U> il, Args&&... args) 728{ 729 Any tmp; 730 tmp.Emplace<T, U, Args...>(il, std::forward<Args>(args)...); 731 return tmp; 732} 733} // namespace Plugin 734} // namespace Media 735} // namespace OHOS 736#endif 737namespace std { 738inline void swap(OHOS::Media::Plugin::Any& lhs, OHOS::Media::Plugin::Any& rhs) noexcept 739{ 740 lhs.Swap(rhs); 741} 742} // namespace std 743#endif // HISTREAMER_PLUGIN_COMMON_ANY_H 744