1 //===- Any.h - Generic type erased holder of any type -----------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file provides Any, a non-template class modeled in the spirit of 10 // std::any. The idea is to provide a type-safe replacement for C's void*. 11 // It can hold a value of any copy-constructible copy-assignable type 12 // 13 //===----------------------------------------------------------------------===// 14 15 #ifndef LLVM_ADT_ANY_H 16 #define LLVM_ADT_ANY_H 17 18 #include "llvm/ADT/STLExtras.h" 19 20 #include <cassert> 21 #include <memory> 22 #include <type_traits> 23 24 namespace llvm { 25 26 class LLVM_EXTERNAL_VISIBILITY Any { 27 28 // The `Typeid<T>::Id` static data member below is a globally unique 29 // identifier for the type `T`. It is explicitly marked with default 30 // visibility so that when `-fvisibility=hidden` is used, the loader still 31 // merges duplicate definitions across DSO boundaries. 32 template <typename T> struct TypeId { static const char Id; }; 33 34 struct StorageBase { 35 virtual ~StorageBase() = default; 36 virtual std::unique_ptr<StorageBase> clone() const = 0; 37 virtual const void *id() const = 0; 38 }; 39 40 template <typename T> struct StorageImpl : public StorageBase { 41 explicit StorageImpl(const T &Value) : Value(Value) {} 42 43 explicit StorageImpl(T &&Value) : Value(std::move(Value)) {} 44 45 std::unique_ptr<StorageBase> clone() const override { 46 return std::make_unique<StorageImpl<T>>(Value); 47 } 48 49 const void *id() const override { return &TypeId<T>::Id; } 50 51 T Value; 52 53 private: 54 StorageImpl &operator=(const StorageImpl &Other) = delete; 55 StorageImpl(const StorageImpl &Other) = delete; 56 }; 57 58 public: 59 Any() = default; 60 61 Any(const Any &Other) 62 : Storage(Other.Storage ? Other.Storage->clone() : nullptr) {} 63 64 // When T is Any or T is not copy-constructible we need to explicitly disable 65 // the forwarding constructor so that the copy constructor gets selected 66 // instead. 67 template <typename T, 68 std::enable_if_t< 69 llvm::conjunction< 70 llvm::negation<std::is_same<std::decay_t<T>, Any>>, 71 // We also disable this overload when an `Any` object can be 72 // converted to the parameter type because in that case, 73 // this constructor may combine with that conversion during 74 // overload resolution for determining copy 75 // constructibility, and then when we try to determine copy 76 // constructibility below we may infinitely recurse. This is 77 // being evaluated by the standards committee as a potential 78 // DR in `std::any` as well, but we're going ahead and 79 // adopting it to work-around usage of `Any` with types that 80 // need to be implicitly convertible from an `Any`. 81 llvm::negation<std::is_convertible<Any, std::decay_t<T>>>, 82 std::is_copy_constructible<std::decay_t<T>>>::value, 83 int> = 0> 84 Any(T &&Value) { 85 Storage = 86 std::make_unique<StorageImpl<std::decay_t<T>>>(std::forward<T>(Value)); 87 } 88 89 Any(Any &&Other) : Storage(std::move(Other.Storage)) {} 90 91 Any &swap(Any &Other) { 92 std::swap(Storage, Other.Storage); 93 return *this; 94 } 95 96 Any &operator=(Any Other) { 97 Storage = std::move(Other.Storage); 98 return *this; 99 } 100 101 bool hasValue() const { return !!Storage; } 102 103 void reset() { Storage.reset(); } 104 105 private: 106 template <class T> friend T any_cast(const Any &Value); 107 template <class T> friend T any_cast(Any &Value); 108 template <class T> friend T any_cast(Any &&Value); 109 template <class T> friend const T *any_cast(const Any *Value); 110 template <class T> friend T *any_cast(Any *Value); 111 template <typename T> friend bool any_isa(const Any &Value); 112 113 std::unique_ptr<StorageBase> Storage; 114 }; 115 116 template <typename T> const char Any::TypeId<T>::Id = 0; 117 118 119 template <typename T> bool any_isa(const Any &Value) { 120 if (!Value.Storage) 121 return false; 122 return Value.Storage->id() == &Any::TypeId<remove_cvref_t<T>>::Id; 123 } 124 125 template <class T> T any_cast(const Any &Value) { 126 return static_cast<T>(*any_cast<remove_cvref_t<T>>(&Value)); 127 } 128 129 template <class T> T any_cast(Any &Value) { 130 return static_cast<T>(*any_cast<remove_cvref_t<T>>(&Value)); 131 } 132 133 template <class T> T any_cast(Any &&Value) { 134 return static_cast<T>(std::move(*any_cast<remove_cvref_t<T>>(&Value))); 135 } 136 137 template <class T> const T *any_cast(const Any *Value) { 138 using U = remove_cvref_t<T>; 139 assert(Value && any_isa<T>(*Value) && "Bad any cast!"); 140 if (!Value || !any_isa<U>(*Value)) 141 return nullptr; 142 return &static_cast<Any::StorageImpl<U> &>(*Value->Storage).Value; 143 } 144 145 template <class T> T *any_cast(Any *Value) { 146 using U = std::decay_t<T>; 147 assert(Value && any_isa<U>(*Value) && "Bad any cast!"); 148 if (!Value || !any_isa<U>(*Value)) 149 return nullptr; 150 return &static_cast<Any::StorageImpl<U> &>(*Value->Storage).Value; 151 } 152 153 } // end namespace llvm 154 155 #endif // LLVM_ADT_ANY_H 156