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 Any { 27 template <typename T> struct TypeId { static const char Id; }; 28 29 struct StorageBase { 30 virtual ~StorageBase() = default; 31 virtual std::unique_ptr<StorageBase> clone() const = 0; 32 virtual const void *id() const = 0; 33 }; 34 35 template <typename T> struct StorageImpl : public StorageBase { 36 explicit StorageImpl(const T &Value) : Value(Value) {} 37 38 explicit StorageImpl(T &&Value) : Value(std::move(Value)) {} 39 40 std::unique_ptr<StorageBase> clone() const override { 41 return std::make_unique<StorageImpl<T>>(Value); 42 } 43 44 const void *id() const override { return &TypeId<T>::Id; } 45 46 T Value; 47 48 private: 49 StorageImpl &operator=(const StorageImpl &Other) = delete; 50 StorageImpl(const StorageImpl &Other) = delete; 51 }; 52 53 public: 54 Any() = default; 55 56 Any(const Any &Other) 57 : Storage(Other.Storage ? Other.Storage->clone() : nullptr) {} 58 59 // When T is Any or T is not copy-constructible we need to explicitly disable 60 // the forwarding constructor so that the copy constructor gets selected 61 // instead. 62 template < 63 typename T, 64 typename std::enable_if< 65 llvm::conjunction< 66 llvm::negation<std::is_same<typename std::decay<T>::type, Any>>, 67 // We also disable this overload when an `Any` object can be 68 // converted to the parameter type because in that case, this 69 // constructor may combine with that conversion during overload 70 // resolution for determining copy constructibility, and then 71 // when we try to determine copy constructibility below we may 72 // infinitely recurse. This is being evaluated by the standards 73 // committee as a potential DR in `std::any` as well, but we're 74 // going ahead and adopting it to work-around usage of `Any` with 75 // types that need to be implicitly convertible from an `Any`. 76 llvm::negation<std::is_convertible<Any, typename std::decay<T>::type>>, 77 std::is_copy_constructible<typename std::decay<T>::type>>::value, 78 int>::type = 0> 79 Any(T &&Value) { 80 using U = typename std::decay<T>::type; 81 Storage = std::make_unique<StorageImpl<U>>(std::forward<T>(Value)); 82 } 83 84 Any(Any &&Other) : Storage(std::move(Other.Storage)) {} 85 86 Any &swap(Any &Other) { 87 std::swap(Storage, Other.Storage); 88 return *this; 89 } 90 91 Any &operator=(Any Other) { 92 Storage = std::move(Other.Storage); 93 return *this; 94 } 95 96 bool hasValue() const { return !!Storage; } 97 98 void reset() { Storage.reset(); } 99 100 private: 101 template <class T> friend T any_cast(const Any &Value); 102 template <class T> friend T any_cast(Any &Value); 103 template <class T> friend T any_cast(Any &&Value); 104 template <class T> friend const T *any_cast(const Any *Value); 105 template <class T> friend T *any_cast(Any *Value); 106 template <typename T> friend bool any_isa(const Any &Value); 107 108 std::unique_ptr<StorageBase> Storage; 109 }; 110 111 template <typename T> const char Any::TypeId<T>::Id = 0; 112 113 114 template <typename T> bool any_isa(const Any &Value) { 115 if (!Value.Storage) 116 return false; 117 using U = 118 typename std::remove_cv<typename std::remove_reference<T>::type>::type; 119 return Value.Storage->id() == &Any::TypeId<U>::Id; 120 } 121 122 template <class T> T any_cast(const Any &Value) { 123 using U = 124 typename std::remove_cv<typename std::remove_reference<T>::type>::type; 125 return static_cast<T>(*any_cast<U>(&Value)); 126 } 127 128 template <class T> T any_cast(Any &Value) { 129 using U = 130 typename std::remove_cv<typename std::remove_reference<T>::type>::type; 131 return static_cast<T>(*any_cast<U>(&Value)); 132 } 133 134 template <class T> T any_cast(Any &&Value) { 135 using U = 136 typename std::remove_cv<typename std::remove_reference<T>::type>::type; 137 return static_cast<T>(std::move(*any_cast<U>(&Value))); 138 } 139 140 template <class T> const T *any_cast(const Any *Value) { 141 using U = 142 typename std::remove_cv<typename std::remove_reference<T>::type>::type; 143 assert(Value && any_isa<T>(*Value) && "Bad any cast!"); 144 if (!Value || !any_isa<U>(*Value)) 145 return nullptr; 146 return &static_cast<Any::StorageImpl<U> &>(*Value->Storage).Value; 147 } 148 149 template <class T> T *any_cast(Any *Value) { 150 using U = typename std::decay<T>::type; 151 assert(Value && any_isa<U>(*Value) && "Bad any cast!"); 152 if (!Value || !any_isa<U>(*Value)) 153 return nullptr; 154 return &static_cast<Any::StorageImpl<U> &>(*Value->Storage).Value; 155 } 156 157 } // end namespace llvm 158 159 #endif // LLVM_ADT_ANY_H 160