1 //===- Any.h - Generic type erased holder of any type -----------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file provides Any, a non-template class modeled in the spirit of 11 // std::any. The idea is to provide a type-safe replacement for C's void*. 12 // It can hold a value of any copy-constructible copy-assignable type 13 // 14 //===----------------------------------------------------------------------===// 15 16 #ifndef LLVM_ADT_ANY_H 17 #define LLVM_ADT_ANY_H 18 19 #include "llvm/ADT/STLExtras.h" 20 21 #include <cassert> 22 #include <memory> 23 #include <type_traits> 24 25 namespace llvm { 26 27 class Any { 28 template <typename T> struct TypeId { static const char Id; }; 29 30 struct StorageBase { 31 virtual ~StorageBase() = default; 32 virtual std::unique_ptr<StorageBase> clone() const = 0; 33 virtual const void *id() const = 0; 34 }; 35 36 template <typename T> struct StorageImpl : public StorageBase { 37 explicit StorageImpl(const T &Value) : Value(Value) {} 38 39 explicit StorageImpl(T &&Value) : Value(std::move(Value)) {} 40 41 std::unique_ptr<StorageBase> clone() const override { 42 return llvm::make_unique<StorageImpl<T>>(Value); 43 } 44 45 const void *id() const override { return &TypeId<T>::Id; } 46 47 T Value; 48 49 private: 50 StorageImpl &operator=(const StorageImpl &Other) = delete; 51 StorageImpl(const StorageImpl &Other) = delete; 52 }; 53 54 public: 55 Any() = default; 56 57 Any(const Any &Other) 58 : Storage(Other.Storage ? Other.Storage->clone() : nullptr) {} 59 60 // When T is Any or T is not copy-constructible we need to explicitly disable 61 // the forwarding constructor so that the copy constructor gets selected 62 // instead. 63 template < 64 typename T, 65 typename std::enable_if< 66 llvm::conjunction< 67 llvm::negation<std::is_same<typename std::decay<T>::type, Any>>, 68 std::is_copy_constructible<typename std::decay<T>::type>>::value, 69 int>::type = 0> 70 Any(T &&Value) { 71 using U = typename std::decay<T>::type; 72 Storage = llvm::make_unique<StorageImpl<U>>(std::forward<T>(Value)); 73 } 74 75 Any(Any &&Other) : Storage(std::move(Other.Storage)) {} 76 77 Any &swap(Any &Other) { 78 std::swap(Storage, Other.Storage); 79 return *this; 80 } 81 82 Any &operator=(Any Other) { 83 Storage = std::move(Other.Storage); 84 return *this; 85 } 86 87 bool hasValue() const { return !!Storage; } 88 89 void reset() { Storage.reset(); } 90 91 private: 92 template <class T> friend T any_cast(const Any &Value); 93 template <class T> friend T any_cast(Any &Value); 94 template <class T> friend T any_cast(Any &&Value); 95 template <class T> friend const T *any_cast(const Any *Value); 96 template <class T> friend T *any_cast(Any *Value); 97 template <typename T> friend bool any_isa(const Any &Value); 98 99 std::unique_ptr<StorageBase> Storage; 100 }; 101 102 template <typename T> const char Any::TypeId<T>::Id = 0; 103 104 105 template <typename T> bool any_isa(const Any &Value) { 106 if (!Value.Storage) 107 return false; 108 using U = 109 typename std::remove_cv<typename std::remove_reference<T>::type>::type; 110 return Value.Storage->id() == &Any::TypeId<U>::Id; 111 } 112 113 template <class T> T any_cast(const Any &Value) { 114 using U = 115 typename std::remove_cv<typename std::remove_reference<T>::type>::type; 116 return static_cast<T>(*any_cast<U>(&Value)); 117 } 118 119 template <class T> T any_cast(Any &Value) { 120 using U = 121 typename std::remove_cv<typename std::remove_reference<T>::type>::type; 122 return static_cast<T>(*any_cast<U>(&Value)); 123 } 124 125 template <class T> T any_cast(Any &&Value) { 126 using U = 127 typename std::remove_cv<typename std::remove_reference<T>::type>::type; 128 return static_cast<T>(std::move(*any_cast<U>(&Value))); 129 } 130 131 template <class T> const T *any_cast(const Any *Value) { 132 using U = 133 typename std::remove_cv<typename std::remove_reference<T>::type>::type; 134 assert(Value && any_isa<T>(*Value) && "Bad any cast!"); 135 if (!Value || !any_isa<U>(*Value)) 136 return nullptr; 137 return &static_cast<Any::StorageImpl<U> &>(*Value->Storage).Value; 138 } 139 140 template <class T> T *any_cast(Any *Value) { 141 using U = typename std::decay<T>::type; 142 assert(Value && any_isa<U>(*Value) && "Bad any cast!"); 143 if (!Value || !any_isa<U>(*Value)) 144 return nullptr; 145 return &static_cast<Any::StorageImpl<U> &>(*Value->Storage).Value; 146 } 147 148 } // end namespace llvm 149 150 #endif // LLVM_ADT_ANY_H 151