• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {
StorageImplStorageImpl37     explicit StorageImpl(const T &Value) : Value(Value) {}
38 
StorageImplStorageImpl39     explicit StorageImpl(T &&Value) : Value(std::move(Value)) {}
40 
cloneStorageImpl41     std::unique_ptr<StorageBase> clone() const override {
42       return llvm::make_unique<StorageImpl<T>>(Value);
43     }
44 
idStorageImpl45     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 
Any(const Any & Other)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>
Any(T && Value)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 
Any(Any && Other)75   Any(Any &&Other) : Storage(std::move(Other.Storage)) {}
76 
swap(Any & Other)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 
hasValue()87   bool hasValue() const { return !!Storage; }
88 
reset()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 
any_isa(const Any & Value)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 
any_cast(const Any & Value)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 
any_cast(Any & Value)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 
any_cast(Any && Value)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 
any_cast(const Any * Value)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 
any_cast(Any * Value)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