1 //===- Any.h - Generic type erased holder of any type -----------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
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
13 //===----------------------------------------------------------------------===//
15 #ifndef LLVM_ADT_ANY_H
16 #define LLVM_ADT_ANY_H
18 #include "llvm/ADT/STLExtras.h"
22 #include <type_traits>
27 template <typename T
> struct TypeId
{ static const char Id
; };
30 virtual ~StorageBase() = default;
31 virtual std::unique_ptr
<StorageBase
> clone() const = 0;
32 virtual const void *id() const = 0;
35 template <typename T
> struct StorageImpl
: public StorageBase
{
36 explicit StorageImpl(const T
&Value
) : Value(Value
) {}
38 explicit StorageImpl(T
&&Value
) : Value(std::move(Value
)) {}
40 std::unique_ptr
<StorageBase
> clone() const override
{
41 return std::make_unique
<StorageImpl
<T
>>(Value
);
44 const void *id() const override
{ return &TypeId
<T
>::Id
; }
49 StorageImpl
&operator=(const StorageImpl
&Other
) = delete;
50 StorageImpl(const StorageImpl
&Other
) = delete;
57 : Storage(Other
.Storage
? Other
.Storage
->clone() : nullptr) {}
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
64 typename
std::enable_if
<
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
,
80 using U
= typename
std::decay
<T
>::type
;
81 Storage
= std::make_unique
<StorageImpl
<U
>>(std::forward
<T
>(Value
));
84 Any(Any
&&Other
) : Storage(std::move(Other
.Storage
)) {}
86 Any
&swap(Any
&Other
) {
87 std::swap(Storage
, Other
.Storage
);
91 Any
&operator=(Any Other
) {
92 Storage
= std::move(Other
.Storage
);
96 bool hasValue() const { return !!Storage
; }
98 void reset() { Storage
.reset(); }
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
);
108 std::unique_ptr
<StorageBase
> Storage
;
111 template <typename T
> const char Any::TypeId
<T
>::Id
= 0;
114 template <typename T
> bool any_isa(const Any
&Value
) {
118 typename
std::remove_cv
<typename
std::remove_reference
<T
>::type
>::type
;
119 return Value
.Storage
->id() == &Any::TypeId
<U
>::Id
;
122 template <class T
> T
any_cast(const Any
&Value
) {
124 typename
std::remove_cv
<typename
std::remove_reference
<T
>::type
>::type
;
125 return static_cast<T
>(*any_cast
<U
>(&Value
));
128 template <class T
> T
any_cast(Any
&Value
) {
130 typename
std::remove_cv
<typename
std::remove_reference
<T
>::type
>::type
;
131 return static_cast<T
>(*any_cast
<U
>(&Value
));
134 template <class T
> T
any_cast(Any
&&Value
) {
136 typename
std::remove_cv
<typename
std::remove_reference
<T
>::type
>::type
;
137 return static_cast<T
>(std::move(*any_cast
<U
>(&Value
)));
140 template <class T
> const T
*any_cast(const Any
*Value
) {
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
))
146 return &static_cast<Any::StorageImpl
<U
> &>(*Value
->Storage
).Value
;
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
))
154 return &static_cast<Any::StorageImpl
<U
> &>(*Value
->Storage
).Value
;
157 } // end namespace llvm
159 #endif // LLVM_ADT_ANY_H