LLVM 18.0.0git
Any.h
Go to the documentation of this file.
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/// \file
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
21
22#include <cassert>
23#include <memory>
24#include <type_traits>
25
26namespace llvm {
27
29
30 // The `Typeid<T>::Id` static data member below is a globally unique
31 // identifier for the type `T`. It is explicitly marked with default
32 // visibility so that when `-fvisibility=hidden` is used, the loader still
33 // merges duplicate definitions across DSO boundaries.
34 // We also cannot mark it as `const`, otherwise msvc merges all definitions
35 // when lto is enabled, making any comparison return true.
36 template <typename T> struct TypeId { static char Id; };
37
38 struct StorageBase {
39 virtual ~StorageBase() = default;
40 virtual std::unique_ptr<StorageBase> clone() const = 0;
41 virtual const void *id() const = 0;
42 };
43
44 template <typename T> struct StorageImpl : public StorageBase {
45 explicit StorageImpl(const T &Value) : Value(Value) {}
46
47 explicit StorageImpl(T &&Value) : Value(std::move(Value)) {}
48
49 std::unique_ptr<StorageBase> clone() const override {
50 return std::make_unique<StorageImpl<T>>(Value);
51 }
52
53 const void *id() const override { return &TypeId<T>::Id; }
54
55 T Value;
56
57 private:
58 StorageImpl &operator=(const StorageImpl &Other) = delete;
59 StorageImpl(const StorageImpl &Other) = delete;
60 };
61
62public:
63 Any() = default;
64
65 Any(const Any &Other)
66 : Storage(Other.Storage ? Other.Storage->clone() : nullptr) {}
67
68 // When T is Any or T is not copy-constructible we need to explicitly disable
69 // the forwarding constructor so that the copy constructor gets selected
70 // instead.
71 template <typename T,
72 std::enable_if_t<
73 std::conjunction<
74 std::negation<std::is_same<std::decay_t<T>, Any>>,
75 // We also disable this overload when an `Any` object can be
76 // converted to the parameter type because in that case,
77 // this constructor may combine with that conversion during
78 // overload resolution for determining copy
79 // constructibility, and then when we try to determine copy
80 // constructibility below we may infinitely recurse. This is
81 // being evaluated by the standards committee as a potential
82 // DR in `std::any` as well, but we're going ahead and
83 // adopting it to work-around usage of `Any` with types that
84 // need to be implicitly convertible from an `Any`.
85 std::negation<std::is_convertible<Any, std::decay_t<T>>>,
86 std::is_copy_constructible<std::decay_t<T>>>::value,
87 int> = 0>
88 Any(T &&Value) {
89 Storage =
90 std::make_unique<StorageImpl<std::decay_t<T>>>(std::forward<T>(Value));
91 }
92
93 Any(Any &&Other) : Storage(std::move(Other.Storage)) {}
94
96 std::swap(Storage, Other.Storage);
97 return *this;
98 }
99
101 Storage = std::move(Other.Storage);
102 return *this;
103 }
104
105 bool has_value() const { return !!Storage; }
106
107 void reset() { Storage.reset(); }
108
109private:
110 // Only used for the internal llvm::Any implementation
111 template <typename T> bool isa() const {
112 if (!Storage)
113 return false;
114 return Storage->id() == &Any::TypeId<remove_cvref_t<T>>::Id;
115 }
116
117 template <class T> friend T any_cast(const Any &Value);
118 template <class T> friend T any_cast(Any &Value);
119 template <class T> friend T any_cast(Any &&Value);
120 template <class T> friend const T *any_cast(const Any *Value);
121 template <class T> friend T *any_cast(Any *Value);
122 template <typename T> friend bool any_isa(const Any &Value);
123
124 std::unique_ptr<StorageBase> Storage;
125};
126
127// Define the type id and initialize with a non-zero value.
128// Initializing with a zero value means the variable can end up in either the
129// .data or the .bss section. This can lead to multiple definition linker errors
130// when some object files are compiled with a compiler that puts the variable
131// into .data but they are linked to object files from a different compiler that
132// put the variable into .bss. To prevent this issue from happening, initialize
133// the variable with a non-zero value, which forces it to land in .data (because
134// .bss is zero-initialized).
135// See also https://github.com/llvm/llvm-project/issues/62270
136template <typename T> char Any::TypeId<T>::Id = 1;
137
138template <class T> T any_cast(const Any &Value) {
139 assert(Value.isa<T>() && "Bad any cast!");
140 return static_cast<T>(*any_cast<remove_cvref_t<T>>(&Value));
141}
142
143template <class T> T any_cast(Any &Value) {
144 assert(Value.isa<T>() && "Bad any cast!");
145 return static_cast<T>(*any_cast<remove_cvref_t<T>>(&Value));
146}
147
148template <class T> T any_cast(Any &&Value) {
149 assert(Value.isa<T>() && "Bad any cast!");
150 return static_cast<T>(std::move(*any_cast<remove_cvref_t<T>>(&Value)));
151}
152
153template <class T> const T *any_cast(const Any *Value) {
154 using U = remove_cvref_t<T>;
155 if (!Value || !Value->isa<U>())
156 return nullptr;
157 return &static_cast<Any::StorageImpl<U> &>(*Value->Storage).Value;
158}
159
160template <class T> T *any_cast(Any *Value) {
161 using U = std::decay_t<T>;
162 if (!Value || !Value->isa<U>())
163 return nullptr;
164 return &static_cast<Any::StorageImpl<U> &>(*Value->Storage).Value;
165}
166
167} // end namespace llvm
168
169#endif // LLVM_ADT_ANY_H
#define LLVM_EXTERNAL_VISIBILITY
Definition: Compiler.h:135
Given that RA is a live value
std::optional< std::vector< StOtherPiece > > Other
Definition: ELFYAML.cpp:1275
#define T
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file contains library features backported from future STL versions.
Definition: Any.h:28
Any(Any &&Other)
Definition: Any.h:93
Any(T &&Value)
Definition: Any.h:88
void reset()
Definition: Any.h:107
Any & operator=(Any Other)
Definition: Any.h:100
Any & swap(Any &Other)
Definition: Any.h:95
bool has_value() const
Definition: Any.h:105
Any(const Any &Other)
Definition: Any.h:65
Any()=default
friend bool any_isa(const Any &Value)
LLVM Value Representation.
Definition: Value.h:74
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
T any_cast(const Any &Value)
Definition: Any.h:138
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition: Casting.h:548
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1853
Implement std::hash so that hash_code can be used in STL containers.
Definition: BitVector.h:858
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition: BitVector.h:860