llvm.org GIT mirror llvm / cb48b14
[ADT] Split optional to only include copy mechanics and dtor for non-trivial types. This makes uses of Optional more transparent to the compiler (and clang-tidy) and generates slightly smaller code. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@317019 91177308-0d34-0410-b5e6-96231b3b80d8 Benjamin Kramer 1 year, 9 months ago
2 changed file(s) with 122 addition(s) and 63 deletion(s). Raw diff Collapse all Expand all
2626
2727 namespace llvm {
2828
29 template
30 class Optional {
29 namespace optional_detail {
30 /// Storage for any type.
31 template struct OptionalStorage {
3132 AlignedCharArrayUnion storage;
3233 bool hasVal = false;
3334
34 public:
35 using value_type = T;
36
37 Optional(NoneType) {}
38 explicit Optional() {}
39
40 Optional(const T &y) : hasVal(true) {
41 new (storage.buffer) T(y);
42 }
43
44 Optional(const Optional &O) : hasVal(O.hasVal) {
35 OptionalStorage() = default;
36
37 OptionalStorage(const T &y) : hasVal(true) { new (storage.buffer) T(y); }
38 OptionalStorage(const OptionalStorage &O) : hasVal(O.hasVal) {
4539 if (hasVal)
46 new (storage.buffer) T(*O);
47 }
48
49 Optional(T &&y) : hasVal(true) {
40 new (storage.buffer) T(*O.getPointer());
41 }
42 OptionalStorage(T &&y) : hasVal(true) {
5043 new (storage.buffer) T(std::forward(y));
5144 }
52
53 Optional(Optional &&O) : hasVal(O) {
54 if (O) {
55 new (storage.buffer) T(std::move(*O));
45 OptionalStorage(OptionalStorage &&O) : hasVal(O.hasVal) {
46 if (O.hasVal) {
47 new (storage.buffer) T(std::move(*O.getPointer()));
5648 O.reset();
5749 }
5850 }
5951
60 ~Optional() {
61 reset();
62 }
63
64 Optional &operator=(T &&y) {
52 OptionalStorage &operator=(T &&y) {
6553 if (hasVal)
66 **this = std::move(y);
54 *getPointer() = std::move(y);
6755 else {
6856 new (storage.buffer) T(std::move(y));
6957 hasVal = true;
7058 }
7159 return *this;
7260 }
73
74 Optional &operator=(Optional &&O) {
75 if (!O)
61 OptionalStorage &operator=(OptionalStorage &&O) {
62 if (!O.hasVal)
7663 reset();
7764 else {
78 *this = std::move(*O);
65 *this = std::move(*O.getPointer());
7966 O.reset();
8067 }
8168 return *this;
82 }
83
84 /// Create a new object by constructing it in place with the given arguments.
85 template
86 void emplace(ArgTypes &&...Args) {
87 reset();
88 hasVal = true;
89 new (storage.buffer) T(std::forward(Args)...);
90 }
91
92 static inline Optional create(const T* y) {
93 return y ? Optional(*y) : Optional();
9469 }
9570
9671 // FIXME: these assignments (& the equivalent const T&/const Optional& ctors)
9873 // with the rvalue versions above - but this could place a different set of
9974 // requirements (notably: the existence of a default ctor) when implemented
10075 // in that way. Careful SFINAE to avoid such pitfalls would be required.
101 Optional &operator=(const T &y) {
76 OptionalStorage &operator=(const T &y) {
10277 if (hasVal)
103 **this = y;
78 *getPointer() = y;
10479 else {
10580 new (storage.buffer) T(y);
10681 hasVal = true;
10782 }
10883 return *this;
10984 }
110
111 Optional &operator=(const Optional &O) {
112 if (!O)
85 OptionalStorage &operator=(const OptionalStorage &O) {
86 if (!O.hasVal)
11387 reset();
11488 else
115 *this = *O;
116 return *this;
117 }
89 *this = *O.getPointer();
90 return *this;
91 }
92
93 ~OptionalStorage() { reset(); }
11894
11995 void reset() {
12096 if (hasVal) {
121 (**this).~T();
97 (*getPointer()).~T();
12298 hasVal = false;
12399 }
124100 }
125101
126 const T* getPointer() const { assert(hasVal); return reinterpret_cast(storage.buffer); }
127 T* getPointer() { assert(hasVal); return reinterpret_cast(storage.buffer); }
128 const T& getValue() const LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); }
129 T& getValue() LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); }
130
131 explicit operator bool() const { return hasVal; }
132 bool hasValue() const { return hasVal; }
102 T *getPointer() {
103 assert(hasVal);
104 return reinterpret_cast(storage.buffer);
105 }
106 const T *getPointer() const {
107 assert(hasVal);
108 return reinterpret_cast(storage.buffer);
109 }
110 };
111
112 /// Storage for trivially copyable types only.
113 template struct OptionalStorage {
114 AlignedCharArrayUnion storage;
115 bool hasVal = false;
116
117 OptionalStorage() = default;
118
119 OptionalStorage(const T &y) : hasVal(true) { new (storage.buffer) T(y); }
120 OptionalStorage &operator=(const T &y) {
121 new (storage.buffer) T(y);
122 hasVal = true;
123 return *this;
124 }
125
126 void reset() { hasVal = false; }
127 };
128 } // namespace optional_detail
129
130 template class Optional {
131 optional_detail::OptionalStorage::value> Storage;
132
133 public:
134 using value_type = T;
135
136 constexpr Optional() {}
137 constexpr Optional(NoneType) {}
138
139 Optional(const T &y) : Storage(y) {}
140 Optional(const Optional &O) = default;
141
142 Optional(T &&y) : Storage(std::forward(y)) {}
143 Optional(Optional &&O) = default;
144
145 Optional &operator=(T &&y) {
146 Storage = std::move(y);
147 return *this;
148 }
149 Optional &operator=(Optional &&O) = default;
150
151 /// Create a new object by constructing it in place with the given arguments.
152 template void emplace(ArgTypes &&... Args) {
153 reset();
154 Storage.hasVal = true;
155 new (getPointer()) T(std::forward(Args)...);
156 }
157
158 static inline Optional create(const T *y) {
159 return y ? Optional(*y) : Optional();
160 }
161
162 Optional &operator=(const T &y) {
163 Storage = y;
164 return *this;
165 }
166 Optional &operator=(const Optional &O) = default;
167
168 void reset() { Storage.reset(); }
169
170 const T *getPointer() const {
171 assert(Storage.hasVal);
172 return reinterpret_cast(Storage.storage.buffer);
173 }
174 T *getPointer() {
175 assert(Storage.hasVal);
176 return reinterpret_cast(Storage.storage.buffer);
177 }
178 const T &getValue() const LLVM_LVALUE_FUNCTION { return *getPointer(); }
179 T &getValue() LLVM_LVALUE_FUNCTION { return *getPointer(); }
180
181 explicit operator bool() const { return Storage.hasVal; }
182 bool hasValue() const { return Storage.hasVal; }
133183 const T* operator->() const { return getPointer(); }
134184 T* operator->() { return getPointer(); }
135 const T& operator*() const LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); }
136 T& operator*() LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); }
185 const T &operator*() const LLVM_LVALUE_FUNCTION { return *getPointer(); }
186 T &operator*() LLVM_LVALUE_FUNCTION { return *getPointer(); }
137187
138188 template
139189 constexpr T getValueOr(U &&value) const LLVM_LVALUE_FUNCTION {
141191 }
142192
143193 #if LLVM_HAS_RVALUE_REFERENCE_THIS
144 T&& getValue() && { assert(hasVal); return std::move(*getPointer()); }
145 T&& operator*() && { assert(hasVal); return std::move(*getPointer()); }
194 T &&getValue() && { return std::move(*getPointer()); }
195 T &&operator*() && { return std::move(*getPointer()); }
146196
147197 template
148198 T getValueOr(U &&value) && {
517517 CheckRelation(InequalityLhs, InequalityRhs, !IsLess);
518518 }
519519
520 #if (__has_feature(is_trivially_copyable) && defined(_LIBCPP_VERSION)) || \
521 (defined(__GNUC__) && __GNUC__ >= 5)
522 static_assert(std::is_trivially_copyable>::value,
523 "Should be trivially copyable");
524 static_assert(
525 !std::is_trivially_copyable>::value,
526 "Shouldn't be trivially copyable");
527 #endif
528
520529 } // end anonymous namespace
521530