File: | build/source/flang/include/flang/Common/indirection.h |
Warning: | line 87, column 39 Assigned value is garbage or undefined |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===-- lib/Evaluate/designate.cpp ------------------------------*- 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 | #include "flang/Evaluate/fold-designator.h" | ||||||||
10 | #include "flang/Semantics/tools.h" | ||||||||
11 | |||||||||
12 | namespace Fortran::evaluate { | ||||||||
13 | |||||||||
14 | DEFINE_DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(OffsetSymbol)OffsetSymbol::OffsetSymbol(const OffsetSymbol &) = default ; OffsetSymbol::OffsetSymbol(OffsetSymbol &&) = default ; OffsetSymbol &OffsetSymbol::operator=(const OffsetSymbol &) = default; OffsetSymbol &OffsetSymbol::operator=( OffsetSymbol &&) = default; | ||||||||
15 | |||||||||
16 | std::optional<OffsetSymbol> DesignatorFolder::FoldDesignator( | ||||||||
17 | const Symbol &symbol, ConstantSubscript which) { | ||||||||
18 | if (IsAllocatableOrPointer(symbol)) { | ||||||||
19 | // A pointer may appear as a DATA statement object if it is the | ||||||||
20 | // rightmost symbol in a designator and has no subscripts. | ||||||||
21 | // An allocatable may appear if its initializer is NULL(). | ||||||||
22 | if (which > 0) { | ||||||||
23 | isEmpty_ = true; | ||||||||
24 | } else { | ||||||||
25 | return OffsetSymbol{symbol, symbol.size()}; | ||||||||
26 | } | ||||||||
27 | } else if (symbol.has<semantics::ObjectEntityDetails>() && | ||||||||
28 | !IsNamedConstant(symbol)) { | ||||||||
29 | if (auto type{DynamicType::From(symbol)}) { | ||||||||
30 | if (auto extents{GetConstantExtents(context_, symbol)}) { | ||||||||
31 | if (auto bytes{ToInt64( | ||||||||
32 | type->MeasureSizeInBytes(context_, GetRank(*extents) > 0))}) { | ||||||||
33 | OffsetSymbol result{symbol, static_cast<std::size_t>(*bytes)}; | ||||||||
34 | if (which < GetSize(*extents)) { | ||||||||
35 | result.Augment(*bytes * which); | ||||||||
36 | return result; | ||||||||
37 | } else { | ||||||||
38 | isEmpty_ = true; | ||||||||
39 | } | ||||||||
40 | } | ||||||||
41 | } | ||||||||
42 | } | ||||||||
43 | } | ||||||||
44 | return std::nullopt; | ||||||||
45 | } | ||||||||
46 | |||||||||
47 | std::optional<OffsetSymbol> DesignatorFolder::FoldDesignator( | ||||||||
48 | const ArrayRef &x, ConstantSubscript which) { | ||||||||
49 | const Symbol &array{x.base().GetLastSymbol()}; | ||||||||
50 | if (auto type{DynamicType::From(array)}) { | ||||||||
51 | if (auto extents{GetConstantExtents(context_, array)}) { | ||||||||
52 | if (auto bytes{ToInt64(type->MeasureSizeInBytes(context_, true))}) { | ||||||||
53 | Shape lbs{GetLBOUNDs(context_, x.base())}; | ||||||||
54 | if (auto lowerBounds{AsConstantExtents(context_, lbs)}) { | ||||||||
55 | std::optional<OffsetSymbol> result; | ||||||||
56 | if (!x.base().IsSymbol() && | ||||||||
57 | x.base().GetComponent().base().Rank() > 0) { | ||||||||
58 | // A(:)%B(1) - apply elementNumber_ to base | ||||||||
59 | result = FoldDesignator(x.base(), which); | ||||||||
60 | which = 0; | ||||||||
61 | } else { // A(1)%B(:) - apply elementNumber_ to subscripts | ||||||||
62 | result = FoldDesignator(x.base(), 0); | ||||||||
63 | } | ||||||||
64 | if (!result) { | ||||||||
65 | return std::nullopt; | ||||||||
66 | } | ||||||||
67 | auto stride{*bytes}; | ||||||||
68 | int dim{0}; | ||||||||
69 | for (const Subscript &subscript : x.subscript()) { | ||||||||
70 | ConstantSubscript lower{lowerBounds->at(dim)}; | ||||||||
71 | ConstantSubscript extent{extents->at(dim)}; | ||||||||
72 | ConstantSubscript upper{lower + extent - 1}; | ||||||||
73 | if (!common::visit( | ||||||||
74 | common::visitors{ | ||||||||
75 | [&](const IndirectSubscriptIntegerExpr &expr) { | ||||||||
76 | auto folded{ | ||||||||
77 | Fold(context_, common::Clone(expr.value()))}; | ||||||||
78 | if (auto value{UnwrapConstantValue<SubscriptInteger>( | ||||||||
79 | folded)}) { | ||||||||
80 | CHECK(value->Rank() <= 1)((value->Rank() <= 1) || (Fortran::common::die("CHECK(" "value->Rank() <= 1" ") failed" " at " "flang/lib/Evaluate/fold-designator.cpp" "(%d)", 80), false)); | ||||||||
81 | if (value->size() != 0) { | ||||||||
82 | // Apply subscript, possibly vector-valued | ||||||||
83 | auto quotient{which / value->size()}; | ||||||||
84 | auto remainder{which - value->size() * quotient}; | ||||||||
85 | ConstantSubscript at{ | ||||||||
86 | value->values().at(remainder).ToInt64()}; | ||||||||
87 | if (at < lower || at > upper) { | ||||||||
88 | isOutOfRange_ = true; | ||||||||
89 | } | ||||||||
90 | result->Augment((at - lower) * stride); | ||||||||
91 | which = quotient; | ||||||||
92 | return true; | ||||||||
93 | } | ||||||||
94 | } | ||||||||
95 | return false; | ||||||||
96 | }, | ||||||||
97 | [&](const Triplet &triplet) { | ||||||||
98 | auto start{ToInt64(Fold(context_, | ||||||||
99 | triplet.lower().value_or(ExtentExpr{lower})))}; | ||||||||
100 | auto end{ToInt64(Fold(context_, | ||||||||
101 | triplet.upper().value_or(ExtentExpr{upper})))}; | ||||||||
102 | auto step{ToInt64(Fold(context_, triplet.stride()))}; | ||||||||
103 | if (start && end && step && *step != 0) { | ||||||||
104 | ConstantSubscript range{ | ||||||||
105 | (*end - *start + *step) / *step}; | ||||||||
106 | if (range > 0) { | ||||||||
107 | auto quotient{which / range}; | ||||||||
108 | auto remainder{which - range * quotient}; | ||||||||
109 | auto j{*start + remainder * *step}; | ||||||||
110 | result->Augment((j - lower) * stride); | ||||||||
111 | which = quotient; | ||||||||
112 | return true; | ||||||||
113 | } | ||||||||
114 | } | ||||||||
115 | return false; | ||||||||
116 | }, | ||||||||
117 | }, | ||||||||
118 | subscript.u)) { | ||||||||
119 | return std::nullopt; | ||||||||
120 | } | ||||||||
121 | ++dim; | ||||||||
122 | stride *= extent; | ||||||||
123 | } | ||||||||
124 | if (which > 0) { | ||||||||
125 | isEmpty_ = true; | ||||||||
126 | } else { | ||||||||
127 | return result; | ||||||||
128 | } | ||||||||
129 | } | ||||||||
130 | } | ||||||||
131 | } | ||||||||
132 | } | ||||||||
133 | return std::nullopt; | ||||||||
134 | } | ||||||||
135 | |||||||||
136 | std::optional<OffsetSymbol> DesignatorFolder::FoldDesignator( | ||||||||
137 | const Component &component, ConstantSubscript which) { | ||||||||
138 | const Symbol &comp{component.GetLastSymbol()}; | ||||||||
139 | const DataRef &base{component.base()}; | ||||||||
140 | std::optional<OffsetSymbol> baseResult, compResult; | ||||||||
141 | if (base.Rank() == 0) { // A%X(:) - apply "which" to component | ||||||||
142 | baseResult = FoldDesignator(base, 0); | ||||||||
143 | compResult = FoldDesignator(comp, which); | ||||||||
144 | } else { // A(:)%X - apply "which" to base | ||||||||
145 | baseResult = FoldDesignator(base, which); | ||||||||
146 | compResult = FoldDesignator(comp, 0); | ||||||||
147 | } | ||||||||
148 | if (baseResult && compResult) { | ||||||||
149 | OffsetSymbol result{baseResult->symbol(), compResult->size()}; | ||||||||
150 | result.Augment(baseResult->offset() + compResult->offset() + comp.offset()); | ||||||||
151 | return {std::move(result)}; | ||||||||
152 | } else { | ||||||||
153 | return std::nullopt; | ||||||||
154 | } | ||||||||
155 | } | ||||||||
156 | |||||||||
157 | std::optional<OffsetSymbol> DesignatorFolder::FoldDesignator( | ||||||||
158 | const ComplexPart &z, ConstantSubscript which) { | ||||||||
159 | if (auto result{FoldDesignator(z.complex(), which)}) { | ||||||||
160 | result->set_size(result->size() >> 1); | ||||||||
161 | if (z.part() == ComplexPart::Part::IM) { | ||||||||
162 | result->Augment(result->size()); | ||||||||
163 | } | ||||||||
164 | return result; | ||||||||
165 | } else { | ||||||||
166 | return std::nullopt; | ||||||||
167 | } | ||||||||
168 | } | ||||||||
169 | |||||||||
170 | std::optional<OffsetSymbol> DesignatorFolder::FoldDesignator( | ||||||||
171 | const DataRef &dataRef, ConstantSubscript which) { | ||||||||
172 | return common::visit( | ||||||||
173 | [&](const auto &x) { return FoldDesignator(x, which); }, dataRef.u); | ||||||||
174 | } | ||||||||
175 | |||||||||
176 | std::optional<OffsetSymbol> DesignatorFolder::FoldDesignator( | ||||||||
177 | const NamedEntity &entity, ConstantSubscript which) { | ||||||||
178 | return entity.IsSymbol() ? FoldDesignator(entity.GetLastSymbol(), which) | ||||||||
179 | : FoldDesignator(entity.GetComponent(), which); | ||||||||
180 | } | ||||||||
181 | |||||||||
182 | std::optional<OffsetSymbol> DesignatorFolder::FoldDesignator( | ||||||||
183 | const CoarrayRef &, ConstantSubscript) { | ||||||||
184 | return std::nullopt; | ||||||||
185 | } | ||||||||
186 | |||||||||
187 | std::optional<OffsetSymbol> DesignatorFolder::FoldDesignator( | ||||||||
188 | const ProcedureDesignator &proc, ConstantSubscript which) { | ||||||||
189 | if (const Symbol * symbol{proc.GetSymbol()}) { | ||||||||
190 | if (const Component * component{proc.GetComponent()}) { | ||||||||
191 | return FoldDesignator(*component, which); | ||||||||
192 | } else if (which > 0) { | ||||||||
193 | isEmpty_ = true; | ||||||||
194 | } else { | ||||||||
195 | return FoldDesignator(*symbol, 0); | ||||||||
196 | } | ||||||||
197 | } | ||||||||
198 | return std::nullopt; | ||||||||
199 | } | ||||||||
200 | |||||||||
201 | // Conversions of offset symbols (back) to Designators | ||||||||
202 | |||||||||
203 | // Reconstructs subscripts. | ||||||||
204 | // "offset" is decremented in place to hold remaining component offset. | ||||||||
205 | static std::optional<ArrayRef> OffsetToArrayRef(FoldingContext &context, | ||||||||
206 | NamedEntity &&entity, const Shape &shape, const DynamicType &elementType, | ||||||||
207 | ConstantSubscript &offset) { | ||||||||
208 | auto extents{AsConstantExtents(context, shape)}; | ||||||||
209 | Shape lbs{GetRawLowerBounds(context, entity)}; | ||||||||
210 | auto lower{AsConstantExtents(context, lbs)}; | ||||||||
211 | auto elementBytes{ToInt64(elementType.MeasureSizeInBytes(context, true))}; | ||||||||
212 | if (!extents || !lower || !elementBytes || *elementBytes <= 0) { | ||||||||
213 | return std::nullopt; | ||||||||
214 | } | ||||||||
215 | int rank{GetRank(shape)}; | ||||||||
216 | CHECK(extents->size() == static_cast<std::size_t>(rank) &&((extents->size() == static_cast<std::size_t>(rank) && lower->size() == extents->size()) || (Fortran::common:: die("CHECK(" "extents->size() == static_cast<std::size_t>(rank) && lower->size() == extents->size()" ") failed" " at " "flang/lib/Evaluate/fold-designator.cpp" "(%d)" , 217), false)) | ||||||||
217 | lower->size() == extents->size())((extents->size() == static_cast<std::size_t>(rank) && lower->size() == extents->size()) || (Fortran::common:: die("CHECK(" "extents->size() == static_cast<std::size_t>(rank) && lower->size() == extents->size()" ") failed" " at " "flang/lib/Evaluate/fold-designator.cpp" "(%d)" , 217), false)); | ||||||||
218 | auto element{offset / static_cast<std::size_t>(*elementBytes)}; | ||||||||
219 | std::vector<Subscript> subscripts; | ||||||||
220 | auto at{element}; | ||||||||
221 | for (int dim{0}; dim + 1 < rank; ++dim) { | ||||||||
222 | auto extent{(*extents)[dim]}; | ||||||||
223 | if (extent <= 0) { | ||||||||
224 | return std::nullopt; | ||||||||
225 | } | ||||||||
226 | auto quotient{at / extent}; | ||||||||
227 | auto remainder{at - quotient * extent}; | ||||||||
228 | subscripts.emplace_back(ExtentExpr{(*lower)[dim] + remainder}); | ||||||||
229 | at = quotient; | ||||||||
230 | } | ||||||||
231 | // This final subscript might be out of range for use in error reporting. | ||||||||
232 | subscripts.emplace_back(ExtentExpr{(*lower)[rank - 1] + at}); | ||||||||
233 | offset -= element * static_cast<std::size_t>(*elementBytes); | ||||||||
234 | return ArrayRef{std::move(entity), std::move(subscripts)}; | ||||||||
235 | } | ||||||||
236 | |||||||||
237 | // Maps an offset back to a component, when unambiguous. | ||||||||
238 | static const Symbol *OffsetToUniqueComponent( | ||||||||
239 | const semantics::DerivedTypeSpec &spec, ConstantSubscript offset) { | ||||||||
240 | const Symbol *result{nullptr}; | ||||||||
241 | if (const semantics::Scope * scope{spec.scope()}) { | ||||||||
242 | for (const auto &pair : *scope) { | ||||||||
243 | const Symbol &component{*pair.second}; | ||||||||
244 | if (offset >= static_cast<ConstantSubscript>(component.offset()) && | ||||||||
245 | offset < static_cast<ConstantSubscript>( | ||||||||
246 | component.offset() + component.size())) { | ||||||||
247 | if (result) { | ||||||||
248 | return nullptr; // MAP overlap or error recovery | ||||||||
249 | } | ||||||||
250 | result = &component; | ||||||||
251 | } | ||||||||
252 | } | ||||||||
253 | } | ||||||||
254 | return result; | ||||||||
255 | } | ||||||||
256 | |||||||||
257 | // Converts an offset into subscripts &/or component references. Recursive. | ||||||||
258 | // Any remaining offset is left in place in the "offset" reference argument. | ||||||||
259 | static std::optional<DataRef> OffsetToDataRef(FoldingContext &context, | ||||||||
260 | NamedEntity &&entity, ConstantSubscript &offset, std::size_t size) { | ||||||||
261 | const Symbol &symbol{entity.GetLastSymbol()}; | ||||||||
262 | if (IsAllocatableOrPointer(symbol)) { | ||||||||
263 | return entity.IsSymbol() ? DataRef{symbol} | ||||||||
264 | : DataRef{std::move(entity.GetComponent())}; | ||||||||
265 | } | ||||||||
266 | std::optional<DataRef> result; | ||||||||
267 | if (std::optional<DynamicType> type{DynamicType::From(symbol)}) { | ||||||||
268 | if (!type->IsUnlimitedPolymorphic()) { | ||||||||
269 | if (std::optional<Shape> shape{GetShape(context, symbol)}) { | ||||||||
270 | if (GetRank(*shape) > 0) { | ||||||||
271 | if (auto aref{OffsetToArrayRef( | ||||||||
272 | context, std::move(entity), *shape, *type, offset)}) { | ||||||||
273 | result = DataRef{std::move(*aref)}; | ||||||||
274 | } | ||||||||
275 | } else { | ||||||||
276 | result = entity.IsSymbol() | ||||||||
277 | ? DataRef{symbol} | ||||||||
278 | : DataRef{std::move(entity.GetComponent())}; | ||||||||
279 | } | ||||||||
280 | if (result && type->category() == TypeCategory::Derived && | ||||||||
281 | size < result->GetLastSymbol().size()) { | ||||||||
282 | if (const Symbol * | ||||||||
283 | component
| ||||||||
284 | type->GetDerivedTypeSpec(), offset)}) { | ||||||||
285 | offset -= component->offset(); | ||||||||
286 | return OffsetToDataRef(context, | ||||||||
287 | NamedEntity{Component{std::move(*result), *component}}, offset, | ||||||||
288 | size); | ||||||||
289 | } | ||||||||
290 | result.reset(); | ||||||||
291 | } | ||||||||
292 | } | ||||||||
293 | } | ||||||||
294 | } | ||||||||
295 | return result; | ||||||||
296 | } | ||||||||
297 | |||||||||
298 | // Reconstructs a Designator from a symbol, an offset, and a size. | ||||||||
299 | std::optional<Expr<SomeType>> OffsetToDesignator(FoldingContext &context, | ||||||||
300 | const Symbol &baseSymbol, ConstantSubscript offset, std::size_t size) { | ||||||||
301 | if (offset < 0) { | ||||||||
302 | return std::nullopt; | ||||||||
303 | } | ||||||||
304 | if (std::optional<DataRef> dataRef{ | ||||||||
305 | OffsetToDataRef(context, NamedEntity{baseSymbol}, offset, size)}) { | ||||||||
306 | const Symbol &symbol{dataRef->GetLastSymbol()}; | ||||||||
307 | if (std::optional<Expr<SomeType>> result{ | ||||||||
308 | AsGenericExpr(std::move(*dataRef))}) { | ||||||||
309 | if (IsAllocatableOrPointer(symbol)) { | ||||||||
310 | } else if (auto type{DynamicType::From(symbol)}) { | ||||||||
311 | if (auto elementBytes{ | ||||||||
312 | ToInt64(type->MeasureSizeInBytes(context, true))}) { | ||||||||
313 | if (auto *zExpr{std::get_if<Expr<SomeComplex>>(&result->u)}) { | ||||||||
314 | if (size * 2 > static_cast<std::size_t>(*elementBytes)) { | ||||||||
315 | return result; | ||||||||
316 | } else if (offset == 0 || offset * 2 == *elementBytes) { | ||||||||
317 | // Pick a COMPLEX component | ||||||||
318 | auto part{ | ||||||||
319 | offset == 0 ? ComplexPart::Part::RE : ComplexPart::Part::IM}; | ||||||||
320 | return common::visit( | ||||||||
321 | [&](const auto &z) -> std::optional<Expr<SomeType>> { | ||||||||
322 | using PartType = typename ResultType<decltype(z)>::Part; | ||||||||
323 | return AsGenericExpr(Designator<PartType>{ComplexPart{ | ||||||||
324 | ExtractDataRef(std::move(*zExpr)).value(), part}}); | ||||||||
325 | }, | ||||||||
326 | zExpr->u); | ||||||||
327 | } | ||||||||
328 | } else if (auto *cExpr{ | ||||||||
329 | std::get_if<Expr<SomeCharacter>>(&result->u)}) { | ||||||||
330 | if (offset > 0 || size != static_cast<std::size_t>(*elementBytes)) { | ||||||||
331 | // Select a substring | ||||||||
332 | return common::visit( | ||||||||
333 | [&](const auto &x) -> std::optional<Expr<SomeType>> { | ||||||||
334 | using T = typename std::decay_t<decltype(x)>::Result; | ||||||||
335 | return AsGenericExpr(Designator<T>{ | ||||||||
336 | Substring{ExtractDataRef(std::move(*cExpr)).value(), | ||||||||
337 | std::optional<Expr<SubscriptInteger>>{ | ||||||||
338 | 1 + (offset / T::kind)}, | ||||||||
339 | std::optional<Expr<SubscriptInteger>>{ | ||||||||
340 | 1 + ((offset + size - 1) / T::kind)}}}); | ||||||||
341 | }, | ||||||||
342 | cExpr->u); | ||||||||
343 | } | ||||||||
344 | } | ||||||||
345 | } | ||||||||
346 | } | ||||||||
347 | if (offset == 0) { | ||||||||
348 | return result; | ||||||||
349 | } | ||||||||
350 | } | ||||||||
351 | } | ||||||||
352 | return std::nullopt; | ||||||||
353 | } | ||||||||
354 | |||||||||
355 | std::optional<Expr<SomeType>> OffsetToDesignator( | ||||||||
356 | FoldingContext &context, const OffsetSymbol &offsetSymbol) { | ||||||||
357 | return OffsetToDesignator(context, offsetSymbol.symbol(), | ||||||||
| |||||||||
358 | offsetSymbol.offset(), offsetSymbol.size()); | ||||||||
359 | } | ||||||||
360 | |||||||||
361 | ConstantObjectPointer ConstantObjectPointer::From( | ||||||||
362 | FoldingContext &context, const Expr<SomeType> &expr) { | ||||||||
363 | auto extents{GetConstantExtents(context, expr)}; | ||||||||
364 | CHECK(extents)((extents) || (Fortran::common::die("CHECK(" "extents" ") failed" " at " "flang/lib/Evaluate/fold-designator.cpp" "(%d)", 364) , false)); | ||||||||
365 | std::size_t elements{TotalElementCount(*extents)}; | ||||||||
366 | CHECK(elements > 0)((elements > 0) || (Fortran::common::die("CHECK(" "elements > 0" ") failed" " at " "flang/lib/Evaluate/fold-designator.cpp" "(%d)" , 366), false)); | ||||||||
367 | int rank{GetRank(*extents)}; | ||||||||
368 | ConstantSubscripts at(rank, 1); | ||||||||
369 | ConstantObjectPointer::Dimensions dimensions(rank); | ||||||||
370 | for (int j{0}; j < rank; ++j) { | ||||||||
371 | dimensions[j].extent = (*extents)[j]; | ||||||||
372 | } | ||||||||
373 | DesignatorFolder designatorFolder{context}; | ||||||||
374 | const Symbol *symbol{nullptr}; | ||||||||
375 | ConstantSubscript baseOffset{0}; | ||||||||
376 | std::size_t elementSize{0}; | ||||||||
377 | for (std::size_t j{0}; j < elements; ++j) { | ||||||||
378 | auto folded{designatorFolder.FoldDesignator(expr)}; | ||||||||
379 | CHECK(folded)((folded) || (Fortran::common::die("CHECK(" "folded" ") failed" " at " "flang/lib/Evaluate/fold-designator.cpp" "(%d)", 379) , false)); | ||||||||
380 | if (j == 0) { | ||||||||
381 | symbol = &folded->symbol(); | ||||||||
382 | baseOffset = folded->offset(); | ||||||||
383 | elementSize = folded->size(); | ||||||||
384 | } else { | ||||||||
385 | CHECK(symbol == &folded->symbol())((symbol == &folded->symbol()) || (Fortran::common::die ("CHECK(" "symbol == &folded->symbol()" ") failed" " at " "flang/lib/Evaluate/fold-designator.cpp" "(%d)", 385), false )); | ||||||||
386 | CHECK(elementSize == folded->size())((elementSize == folded->size()) || (Fortran::common::die( "CHECK(" "elementSize == folded->size()" ") failed" " at " "flang/lib/Evaluate/fold-designator.cpp" "(%d)", 386), false )); | ||||||||
387 | } | ||||||||
388 | int twoDim{-1}; | ||||||||
389 | for (int k{0}; k < rank; ++k) { | ||||||||
390 | if (at[k] == 2 && twoDim == -1) { | ||||||||
391 | twoDim = k; | ||||||||
392 | } else if (at[k] != 1) { | ||||||||
393 | twoDim = -2; | ||||||||
394 | } | ||||||||
395 | } | ||||||||
396 | if (twoDim >= 0) { | ||||||||
397 | // Exactly one subscript is a 2 and the rest are 1. | ||||||||
398 | dimensions[twoDim].byteStride = folded->offset() - baseOffset; | ||||||||
399 | } | ||||||||
400 | ConstantSubscript checkOffset{baseOffset}; | ||||||||
401 | for (int k{0}; k < rank; ++k) { | ||||||||
402 | checkOffset += (at[k] - 1) * dimensions[twoDim].byteStride; | ||||||||
403 | } | ||||||||
404 | CHECK(checkOffset == folded->offset())((checkOffset == folded->offset()) || (Fortran::common::die ("CHECK(" "checkOffset == folded->offset()" ") failed" " at " "flang/lib/Evaluate/fold-designator.cpp" "(%d)", 404), false )); | ||||||||
405 | CHECK(IncrementSubscripts(at, *extents) == (j + 1 < elements))((IncrementSubscripts(at, *extents) == (j + 1 < elements)) || (Fortran::common::die("CHECK(" "IncrementSubscripts(at, *extents) == (j + 1 < elements)" ") failed" " at " "flang/lib/Evaluate/fold-designator.cpp" "(%d)" , 405), false)); | ||||||||
406 | } | ||||||||
407 | CHECK(!designatorFolder.FoldDesignator(expr))((!designatorFolder.FoldDesignator(expr)) || (Fortran::common ::die("CHECK(" "!designatorFolder.FoldDesignator(expr)" ") failed" " at " "flang/lib/Evaluate/fold-designator.cpp" "(%d)", 407) , false)); | ||||||||
408 | return ConstantObjectPointer{ | ||||||||
409 | DEREF(symbol)Fortran::common::Deref(symbol, "flang/lib/Evaluate/fold-designator.cpp" , 409), elementSize, std::move(dimensions)}; | ||||||||
410 | } | ||||||||
411 | } // namespace Fortran::evaluate |
1 | //===-- include/flang/Evaluate/variable.h -----------------------*- 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 | #ifndef FORTRAN_EVALUATE_VARIABLE_H_ |
10 | #define FORTRAN_EVALUATE_VARIABLE_H_ |
11 | |
12 | // Defines data structures to represent data access and function calls |
13 | // for use in expressions and assignment statements. Both copy and move |
14 | // semantics are supported. The representation adheres closely to the |
15 | // Fortran 2018 language standard (q.v.) and uses strong typing to ensure |
16 | // that only admissable combinations can be constructed. |
17 | |
18 | #include "call.h" |
19 | #include "common.h" |
20 | #include "formatting.h" |
21 | #include "static-data.h" |
22 | #include "type.h" |
23 | #include "flang/Common/idioms.h" |
24 | #include "flang/Common/reference.h" |
25 | #include "flang/Common/template.h" |
26 | #include "flang/Parser/char-block.h" |
27 | #include <optional> |
28 | #include <variant> |
29 | #include <vector> |
30 | |
31 | namespace llvm { |
32 | class raw_ostream; |
33 | } |
34 | |
35 | namespace Fortran::semantics { |
36 | class Symbol; |
37 | } |
38 | |
39 | namespace Fortran::evaluate { |
40 | |
41 | using semantics::Symbol; |
42 | using SymbolRef = common::Reference<const Symbol>; |
43 | using SymbolVector = std::vector<SymbolRef>; |
44 | |
45 | // Forward declarations |
46 | struct DataRef; |
47 | template <typename T> struct Variable; |
48 | |
49 | // Reference a base object in memory. This can be a Fortran symbol, |
50 | // static data (e.g., CHARACTER literal), or compiler-created temporary. |
51 | struct BaseObject { |
52 | EVALUATE_UNION_CLASS_BOILERPLATE(BaseObject)BaseObject() = delete; BaseObject(const BaseObject &) = default ; BaseObject(BaseObject &&) = default; BaseObject & operator=(const BaseObject &) = default; BaseObject & operator=(BaseObject &&) = default; template <typename _A> explicit BaseObject(const _A &x) : u{x} {} template <typename _A, typename = common::NoLvalue<_A>> explicit BaseObject(_A &&x) : u(std::move(x)) {} bool operator ==(const BaseObject &) const; |
53 | int Rank() const; |
54 | std::optional<Expr<SubscriptInteger>> LEN() const; |
55 | llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const; |
56 | const Symbol *symbol() const { |
57 | if (const auto *result{std::get_if<SymbolRef>(&u)}) { |
58 | return &result->get(); |
59 | } else { |
60 | return nullptr; |
61 | } |
62 | } |
63 | std::variant<SymbolRef, StaticDataObject::Pointer> u; |
64 | }; |
65 | |
66 | // R913 structure-component & C920: Defined to be a multi-part |
67 | // data-ref whose last part has no subscripts (or image-selector, although |
68 | // that isn't explicit in the document). Pointer and allocatable components |
69 | // are not explicitly indirected in this representation. |
70 | // Complex components (%RE, %IM) are isolated below in ComplexPart. |
71 | // (Type parameter inquiries look like component references but are distinct |
72 | // constructs and not represented by this class.) |
73 | class Component { |
74 | public: |
75 | CLASS_BOILERPLATE(Component)Component() = delete; Component(const Component &) = default ; Component(Component &&) = default; Component &operator =(const Component &) = default; Component &operator=( Component &&) = default; |
76 | Component(const DataRef &b, const Symbol &c) : base_{b}, symbol_{c} {} |
77 | Component(DataRef &&b, const Symbol &c) : base_{std::move(b)}, symbol_{c} {} |
78 | Component(common::CopyableIndirection<DataRef> &&b, const Symbol &c) |
79 | : base_{std::move(b)}, symbol_{c} {} |
80 | |
81 | const DataRef &base() const { return base_.value(); } |
82 | DataRef &base() { return base_.value(); } |
83 | const SymbolRef &symbol() const { return symbol_; } |
84 | SymbolRef &symbol() { return symbol_; } |
85 | |
86 | int Rank() const; |
87 | const Symbol &GetFirstSymbol() const; |
88 | const Symbol &GetLastSymbol() const { return symbol_; } |
89 | std::optional<Expr<SubscriptInteger>> LEN() const; |
90 | bool operator==(const Component &) const; |
91 | llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const; |
92 | |
93 | private: |
94 | common::CopyableIndirection<DataRef> base_; |
95 | SymbolRef symbol_; |
96 | }; |
97 | |
98 | // A NamedEntity is either a whole Symbol or a component in an instance |
99 | // of a derived type. It may be a descriptor. |
100 | // TODO: this is basically a symbol with an optional DataRef base; |
101 | // could be used to replace Component. |
102 | class NamedEntity { |
103 | public: |
104 | CLASS_BOILERPLATE(NamedEntity)NamedEntity() = delete; NamedEntity(const NamedEntity &) = default; NamedEntity(NamedEntity &&) = default; NamedEntity &operator=(const NamedEntity &) = default; NamedEntity &operator=(NamedEntity &&) = default; |
105 | explicit NamedEntity(const Symbol &symbol) : u_{symbol} {} |
106 | explicit NamedEntity(Component &&c) : u_{std::move(c)} {} |
107 | |
108 | bool IsSymbol() const { return std::holds_alternative<SymbolRef>(u_); } |
109 | const Symbol &GetFirstSymbol() const; |
110 | const Symbol &GetLastSymbol() const; |
111 | const Component &GetComponent() const { return std::get<Component>(u_); } |
112 | Component &GetComponent() { return std::get<Component>(u_); } |
113 | const SymbolRef *UnwrapSymbolRef() const; // null if a Component |
114 | SymbolRef *UnwrapSymbolRef(); |
115 | const Component *UnwrapComponent() const; // null if not a Component |
116 | Component *UnwrapComponent(); |
117 | |
118 | int Rank() const; |
119 | std::optional<Expr<SubscriptInteger>> LEN() const; |
120 | bool operator==(const NamedEntity &) const; |
121 | llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const; |
122 | |
123 | private: |
124 | std::variant<SymbolRef, Component> u_; |
125 | }; |
126 | |
127 | // R916 type-param-inquiry |
128 | // N.B. x%LEN for CHARACTER is rewritten in semantics to LEN(x), which is |
129 | // then handled via LEN() member functions in the various classes; |
130 | // it becomes a DescriptorInquiry with Field::Len for assumed-length |
131 | // CHARACTER objects. |
132 | // x%KIND for intrinsic types is similarly rewritten in semantics to |
133 | // KIND(x), which is then folded to a constant value. |
134 | // "Bare" type parameter references within a derived type definition do |
135 | // not have base objects. |
136 | class TypeParamInquiry { |
137 | public: |
138 | using Result = SubscriptInteger; |
139 | CLASS_BOILERPLATE(TypeParamInquiry)TypeParamInquiry() = delete; TypeParamInquiry(const TypeParamInquiry &) = default; TypeParamInquiry(TypeParamInquiry && ) = default; TypeParamInquiry &operator=(const TypeParamInquiry &) = default; TypeParamInquiry &operator=(TypeParamInquiry &&) = default; |
140 | TypeParamInquiry(NamedEntity &&x, const Symbol ¶m) |
141 | : base_{std::move(x)}, parameter_{param} {} |
142 | TypeParamInquiry(std::optional<NamedEntity> &&x, const Symbol ¶m) |
143 | : base_{std::move(x)}, parameter_{param} {} |
144 | |
145 | const std::optional<NamedEntity> &base() const { return base_; } |
146 | std::optional<NamedEntity> &base() { return base_; } |
147 | const Symbol ¶meter() const { return parameter_; } |
148 | |
149 | static constexpr int Rank() { return 0; } // always scalar |
150 | bool operator==(const TypeParamInquiry &) const; |
151 | llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const; |
152 | |
153 | private: |
154 | std::optional<NamedEntity> base_; |
155 | SymbolRef parameter_; |
156 | }; |
157 | |
158 | // R921 subscript-triplet |
159 | class Triplet { |
160 | public: |
161 | Triplet(); |
162 | DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(Triplet)Triplet(const Triplet &) = default; Triplet(Triplet && ) = default; Triplet &operator=(const Triplet &) = default ; Triplet &operator=(Triplet &&) = default; |
163 | Triplet(std::optional<Expr<SubscriptInteger>> &&, |
164 | std::optional<Expr<SubscriptInteger>> &&, |
165 | std::optional<Expr<SubscriptInteger>> &&); |
166 | |
167 | std::optional<Expr<SubscriptInteger>> lower() const; |
168 | const Expr<SubscriptInteger> *GetLower() const { |
169 | return lower_.has_value() ? &lower_->value() : nullptr; |
170 | } |
171 | Triplet &set_lower(Expr<SubscriptInteger> &&); |
172 | std::optional<Expr<SubscriptInteger>> upper() const; |
173 | const Expr<SubscriptInteger> *GetUpper() const { |
174 | return upper_.has_value() ? &upper_->value() : nullptr; |
175 | } |
176 | Triplet &set_upper(Expr<SubscriptInteger> &&); |
177 | Expr<SubscriptInteger> stride() const; // N.B. result is not optional<> |
178 | const Expr<SubscriptInteger> &GetStride() const { return stride_.value(); } |
179 | Triplet &set_stride(Expr<SubscriptInteger> &&); |
180 | |
181 | bool operator==(const Triplet &) const; |
182 | llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const; |
183 | |
184 | private: |
185 | std::optional<IndirectSubscriptIntegerExpr> lower_, upper_; |
186 | IndirectSubscriptIntegerExpr stride_; |
187 | }; |
188 | |
189 | // R919 subscript when rank 0, R923 vector-subscript when rank 1 |
190 | struct Subscript { |
191 | EVALUATE_UNION_CLASS_BOILERPLATE(Subscript)Subscript() = delete; Subscript(const Subscript &) = default ; Subscript(Subscript &&) = default; Subscript &operator =(const Subscript &) = default; Subscript &operator=( Subscript &&) = default; template <typename _A> explicit Subscript(const _A &x) : u{x} {} template <typename _A, typename = common::NoLvalue<_A>> explicit Subscript (_A &&x) : u(std::move(x)) {} bool operator==(const Subscript &) const; |
192 | explicit Subscript(Expr<SubscriptInteger> &&s) |
193 | : u{IndirectSubscriptIntegerExpr::Make(std::move(s))} {} |
194 | int Rank() const; |
195 | llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const; |
196 | std::variant<IndirectSubscriptIntegerExpr, Triplet> u; |
197 | }; |
198 | |
199 | // R917 array-element, R918 array-section; however, the case of an |
200 | // array-section that is a complex-part-designator is represented here |
201 | // as a ComplexPart instead. C919 & C925 require that at most one set of |
202 | // subscripts have rank greater than 0, but that is not explicit in |
203 | // these types. |
204 | class ArrayRef { |
205 | public: |
206 | CLASS_BOILERPLATE(ArrayRef)ArrayRef() = delete; ArrayRef(const ArrayRef &) = default ; ArrayRef(ArrayRef &&) = default; ArrayRef &operator =(const ArrayRef &) = default; ArrayRef &operator=(ArrayRef &&) = default; |
207 | ArrayRef(const Symbol &symbol, std::vector<Subscript> &&ss) |
208 | : base_{symbol}, subscript_(std::move(ss)) {} |
209 | ArrayRef(Component &&c, std::vector<Subscript> &&ss) |
210 | : base_{std::move(c)}, subscript_(std::move(ss)) {} |
211 | ArrayRef(NamedEntity &&base, std::vector<Subscript> &&ss) |
212 | : base_{std::move(base)}, subscript_(std::move(ss)) {} |
213 | |
214 | NamedEntity &base() { return base_; } |
215 | const NamedEntity &base() const { return base_; } |
216 | std::vector<Subscript> &subscript() { return subscript_; } |
217 | const std::vector<Subscript> &subscript() const { return subscript_; } |
218 | |
219 | int size() const { return static_cast<int>(subscript_.size()); } |
220 | Subscript &at(int n) { return subscript_.at(n); } |
221 | const Subscript &at(int n) const { return subscript_.at(n); } |
222 | template <typename A> common::IfNoLvalue<Subscript &, A> emplace_back(A &&x) { |
223 | return subscript_.emplace_back(std::move(x)); |
224 | } |
225 | |
226 | int Rank() const; |
227 | const Symbol &GetFirstSymbol() const; |
228 | const Symbol &GetLastSymbol() const; |
229 | std::optional<Expr<SubscriptInteger>> LEN() const; |
230 | bool operator==(const ArrayRef &) const; |
231 | llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const; |
232 | |
233 | private: |
234 | NamedEntity base_; |
235 | std::vector<Subscript> subscript_; |
236 | }; |
237 | |
238 | // R914 coindexed-named-object |
239 | // R924 image-selector, R926 image-selector-spec. |
240 | // C825 severely limits the usage of derived types with coarray ultimate |
241 | // components: they can't be pointers, allocatables, arrays, coarrays, or |
242 | // function results. They can be components of other derived types. |
243 | // Although the F'2018 Standard never prohibits multiple image-selectors |
244 | // per se in the same data-ref or designator, nor the presence of an |
245 | // image-selector after a part-ref with rank, the constraints on the |
246 | // derived types that would have be involved make it impossible to declare |
247 | // an object that could be referenced in these ways (esp. C748 & C825). |
248 | // C930 precludes having both TEAM= and TEAM_NUMBER=. |
249 | // TODO C931 prohibits the use of a coindexed object as a stat-variable. |
250 | class CoarrayRef { |
251 | public: |
252 | CLASS_BOILERPLATE(CoarrayRef)CoarrayRef() = delete; CoarrayRef(const CoarrayRef &) = default ; CoarrayRef(CoarrayRef &&) = default; CoarrayRef & operator=(const CoarrayRef &) = default; CoarrayRef & operator=(CoarrayRef &&) = default; |
253 | CoarrayRef(SymbolVector &&, std::vector<Subscript> &&, |
254 | std::vector<Expr<SubscriptInteger>> &&); |
255 | |
256 | const SymbolVector &base() const { return base_; } |
257 | SymbolVector &base() { return base_; } |
258 | const std::vector<Subscript> &subscript() const { return subscript_; } |
259 | std::vector<Subscript> &subscript() { return subscript_; } |
260 | const std::vector<Expr<SubscriptInteger>> &cosubscript() const { |
261 | return cosubscript_; |
262 | } |
263 | std::vector<Expr<SubscriptInteger>> &cosubscript() { return cosubscript_; } |
264 | |
265 | // These integral expressions for STAT= and TEAM= must be variables |
266 | // (i.e., Designator or pointer-valued FunctionRef). |
267 | std::optional<Expr<SomeInteger>> stat() const; |
268 | CoarrayRef &set_stat(Expr<SomeInteger> &&); |
269 | std::optional<Expr<SomeInteger>> team() const; |
270 | bool teamIsTeamNumber() const { return teamIsTeamNumber_; } |
271 | CoarrayRef &set_team(Expr<SomeInteger> &&, bool isTeamNumber = false); |
272 | |
273 | int Rank() const; |
274 | const Symbol &GetFirstSymbol() const; |
275 | const Symbol &GetLastSymbol() const; |
276 | NamedEntity GetBase() const; |
277 | std::optional<Expr<SubscriptInteger>> LEN() const; |
278 | bool operator==(const CoarrayRef &) const; |
279 | llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const; |
280 | |
281 | private: |
282 | SymbolVector base_; |
283 | std::vector<Subscript> subscript_; |
284 | std::vector<Expr<SubscriptInteger>> cosubscript_; |
285 | std::optional<common::CopyableIndirection<Expr<SomeInteger>>> stat_, team_; |
286 | bool teamIsTeamNumber_{false}; // false: TEAM=, true: TEAM_NUMBER= |
287 | }; |
288 | |
289 | // R911 data-ref is defined syntactically as a series of part-refs, which |
290 | // would be far too expressive if the constraints were ignored. Here, the |
291 | // possible outcomes are spelled out. Note that a data-ref cannot include |
292 | // a terminal substring range or complex component designator; use |
293 | // R901 designator for that. |
294 | struct DataRef { |
295 | EVALUATE_UNION_CLASS_BOILERPLATE(DataRef)DataRef() = delete; DataRef(const DataRef &) = default; DataRef (DataRef &&) = default; DataRef &operator=(const DataRef &) = default; DataRef &operator=(DataRef &&) = default; template <typename _A> explicit DataRef(const _A &x) : u{x} {} template <typename _A, typename = common ::NoLvalue<_A>> explicit DataRef(_A &&x) : u (std::move(x)) {} bool operator==(const DataRef &) const; |
296 | int Rank() const; |
297 | const Symbol &GetFirstSymbol() const; |
298 | const Symbol &GetLastSymbol() const; |
299 | std::optional<Expr<SubscriptInteger>> LEN() const; |
300 | llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const; |
301 | |
302 | std::variant<SymbolRef, Component, ArrayRef, CoarrayRef> u; |
303 | }; |
304 | |
305 | // R908 substring, R909 parent-string, R910 substring-range. |
306 | // The base object of a substring can be a literal. |
307 | // In the F2018 standard, substrings of array sections are parsed as |
308 | // variants of sections instead. |
309 | class Substring { |
310 | using Parent = std::variant<DataRef, StaticDataObject::Pointer>; |
311 | |
312 | public: |
313 | CLASS_BOILERPLATE(Substring)Substring() = delete; Substring(const Substring &) = default ; Substring(Substring &&) = default; Substring &operator =(const Substring &) = default; Substring &operator=( Substring &&) = default; |
314 | Substring(DataRef &&parent, std::optional<Expr<SubscriptInteger>> &&lower, |
315 | std::optional<Expr<SubscriptInteger>> &&upper) |
316 | : parent_{std::move(parent)} { |
317 | SetBounds(lower, upper); |
318 | } |
319 | Substring(StaticDataObject::Pointer &&parent, |
320 | std::optional<Expr<SubscriptInteger>> &&lower, |
321 | std::optional<Expr<SubscriptInteger>> &&upper) |
322 | : parent_{std::move(parent)} { |
323 | SetBounds(lower, upper); |
324 | } |
325 | |
326 | Expr<SubscriptInteger> lower() const; |
327 | Substring &set_lower(Expr<SubscriptInteger> &&); |
328 | std::optional<Expr<SubscriptInteger>> upper() const; |
329 | Substring &set_upper(Expr<SubscriptInteger> &&); |
330 | const Parent &parent() const { return parent_; } |
331 | Parent &parent() { return parent_; } |
332 | |
333 | int Rank() const; |
334 | template <typename A> const A *GetParentIf() const { |
335 | return std::get_if<A>(&parent_); |
336 | } |
337 | BaseObject GetBaseObject() const; |
338 | const Symbol *GetLastSymbol() const; |
339 | std::optional<Expr<SubscriptInteger>> LEN() const; |
340 | bool operator==(const Substring &) const; |
341 | llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const; |
342 | |
343 | std::optional<Expr<SomeCharacter>> Fold(FoldingContext &); |
344 | |
345 | private: |
346 | void SetBounds(std::optional<Expr<SubscriptInteger>> &, |
347 | std::optional<Expr<SubscriptInteger>> &); |
348 | Parent parent_; |
349 | std::optional<IndirectSubscriptIntegerExpr> lower_, upper_; |
350 | }; |
351 | |
352 | // R915 complex-part-designator |
353 | // In the F2018 standard, complex parts of array sections are parsed as |
354 | // variants of sections instead. |
355 | class ComplexPart { |
356 | public: |
357 | ENUM_CLASS(Part, RE, IM)enum class Part { RE, IM }; [[maybe_unused]] static constexpr std::size_t Part_enumSize{ ::Fortran::common::CountEnumNames ("RE, IM")}; [[maybe_unused]] static inline std::string_view EnumToString (Part e) { static const constexpr char vaArgs[]{"RE, IM"}; static const constexpr auto names{ ::Fortran::common::EnumNames< Part_enumSize>(vaArgs)}; return names[static_cast<std:: size_t>(e)]; } |
358 | CLASS_BOILERPLATE(ComplexPart)ComplexPart() = delete; ComplexPart(const ComplexPart &) = default; ComplexPart(ComplexPart &&) = default; ComplexPart &operator=(const ComplexPart &) = default; ComplexPart &operator=(ComplexPart &&) = default; |
359 | ComplexPart(DataRef &&z, Part p) : complex_{std::move(z)}, part_{p} {} |
360 | DataRef &complex() { return complex_; } |
361 | const DataRef &complex() const { return complex_; } |
362 | Part part() const { return part_; } |
363 | int Rank() const; |
364 | const Symbol &GetFirstSymbol() const { return complex_.GetFirstSymbol(); } |
365 | const Symbol &GetLastSymbol() const { return complex_.GetLastSymbol(); } |
366 | bool operator==(const ComplexPart &) const; |
367 | llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const; |
368 | |
369 | private: |
370 | DataRef complex_; |
371 | Part part_; |
372 | }; |
373 | |
374 | // R901 designator is the most general data reference object, apart from |
375 | // calls to pointer-valued functions. Its variant holds everything that |
376 | // a DataRef can, and possibly also a substring reference or a |
377 | // complex component (%RE/%IM) reference. |
378 | template <typename T> class Designator { |
379 | using DataRefs = std::decay_t<decltype(DataRef::u)>; |
380 | using MaybeSubstring = |
381 | std::conditional_t<T::category == TypeCategory::Character, |
382 | std::variant<Substring>, std::variant<>>; |
383 | using MaybeComplexPart = std::conditional_t<T::category == TypeCategory::Real, |
384 | std::variant<ComplexPart>, std::variant<>>; |
385 | using Variant = |
386 | common::CombineVariants<DataRefs, MaybeSubstring, MaybeComplexPart>; |
387 | |
388 | public: |
389 | using Result = T; |
390 | static_assert( |
391 | IsSpecificIntrinsicType<Result> || std::is_same_v<Result, SomeDerived>); |
392 | EVALUATE_UNION_CLASS_BOILERPLATE(Designator)Designator() = delete; Designator(const Designator &) = default ; Designator(Designator &&) = default; Designator & operator=(const Designator &) = default; Designator & operator=(Designator &&) = default; template <typename _A> explicit Designator(const _A &x) : u{x} {} template <typename _A, typename = common::NoLvalue<_A>> explicit Designator(_A &&x) : u(std::move(x)) {} bool operator ==(const Designator &) const; |
393 | Designator(const DataRef &that) : u{common::CopyVariant<Variant>(that.u)} {} |
394 | Designator(DataRef &&that) |
395 | : u{common::MoveVariant<Variant>(std::move(that.u))} {} |
396 | |
397 | std::optional<DynamicType> GetType() const; |
398 | int Rank() const; |
399 | BaseObject GetBaseObject() const; |
400 | const Symbol *GetLastSymbol() const; |
401 | std::optional<Expr<SubscriptInteger>> LEN() const; |
402 | llvm::raw_ostream &AsFortran(llvm::raw_ostream &o) const; |
403 | |
404 | Variant u; |
405 | }; |
406 | |
407 | FOR_EACH_CHARACTER_KIND(extern template class Designator, )extern template class Designator<Type<TypeCategory::Character , 1>> ; extern template class Designator<Type<TypeCategory ::Character, 2>> ; extern template class Designator< Type<TypeCategory::Character, 4>> ; |
408 | |
409 | class DescriptorInquiry { |
410 | public: |
411 | using Result = SubscriptInteger; |
412 | ENUM_CLASS(Field, LowerBound, Extent, Stride, Rank, Len)enum class Field { LowerBound, Extent, Stride, Rank, Len }; [ [maybe_unused]] static constexpr std::size_t Field_enumSize{ :: Fortran::common::CountEnumNames("LowerBound, Extent, Stride, Rank, Len" )}; [[maybe_unused]] static inline std::string_view EnumToString (Field e) { static const constexpr char vaArgs[]{"LowerBound, Extent, Stride, Rank, Len" }; static const constexpr auto names{ ::Fortran::common::EnumNames <Field_enumSize>(vaArgs)}; return names[static_cast< std::size_t>(e)]; } |
413 | |
414 | CLASS_BOILERPLATE(DescriptorInquiry)DescriptorInquiry() = delete; DescriptorInquiry(const DescriptorInquiry &) = default; DescriptorInquiry(DescriptorInquiry && ) = default; DescriptorInquiry &operator=(const DescriptorInquiry &) = default; DescriptorInquiry &operator=(DescriptorInquiry &&) = default; |
415 | DescriptorInquiry(const NamedEntity &, Field, int = 0); |
416 | DescriptorInquiry(NamedEntity &&, Field, int = 0); |
417 | |
418 | NamedEntity &base() { return base_; } |
419 | const NamedEntity &base() const { return base_; } |
420 | Field field() const { return field_; } |
421 | int dimension() const { return dimension_; } |
422 | |
423 | static constexpr int Rank() { return 0; } // always scalar |
424 | bool operator==(const DescriptorInquiry &) const; |
425 | llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const; |
426 | |
427 | private: |
428 | NamedEntity base_; |
429 | Field field_; |
430 | int dimension_{0}; // zero-based |
431 | }; |
432 | |
433 | #define INSTANTIATE_VARIABLE_TEMPLATEStemplate class Designator<Type<TypeCategory::Integer, 1 >> ; template class Designator<Type<TypeCategory:: Integer, 2>> ; template class Designator<Type<TypeCategory ::Integer, 4>> ; template class Designator<Type<TypeCategory ::Integer, 8>> ; template class Designator<Type<TypeCategory ::Integer, 16>> ; template class Designator<Type< TypeCategory::Real, 2>> ; template class Designator< Type<TypeCategory::Real, 3>> ; template class Designator <Type<TypeCategory::Real, 4>> ; template class Designator <Type<TypeCategory::Real, 8>> ; template class Designator <Type<TypeCategory::Real, 10>> ; template class Designator <Type<TypeCategory::Real, 16>> ; template class Designator <Type<TypeCategory::Complex, 2>> ; template class Designator<Type<TypeCategory::Complex, 3>> ; template class Designator<Type<TypeCategory::Complex, 4>> ; template class Designator<Type<TypeCategory::Complex , 8>> ; template class Designator<Type<TypeCategory ::Complex, 10>> ; template class Designator<Type< TypeCategory::Complex, 16>> ; template class Designator <Type<TypeCategory::Logical, 1>> ; template class Designator<Type<TypeCategory::Logical, 2>> ; template class Designator<Type<TypeCategory::Logical, 4>> ; template class Designator<Type<TypeCategory::Logical , 8>> ; template class Designator<Type<TypeCategory ::Character, 1>> ; template class Designator<Type< TypeCategory::Character, 2>> ; template class Designator <Type<TypeCategory::Character, 4>> ; template class Designator<SomeDerived> ; \ |
434 | FOR_EACH_SPECIFIC_TYPE(template class Designator, )template class Designator<Type<TypeCategory::Integer, 1 >> ; template class Designator<Type<TypeCategory:: Integer, 2>> ; template class Designator<Type<TypeCategory ::Integer, 4>> ; template class Designator<Type<TypeCategory ::Integer, 8>> ; template class Designator<Type<TypeCategory ::Integer, 16>> ; template class Designator<Type< TypeCategory::Real, 2>> ; template class Designator< Type<TypeCategory::Real, 3>> ; template class Designator <Type<TypeCategory::Real, 4>> ; template class Designator <Type<TypeCategory::Real, 8>> ; template class Designator <Type<TypeCategory::Real, 10>> ; template class Designator <Type<TypeCategory::Real, 16>> ; template class Designator <Type<TypeCategory::Complex, 2>> ; template class Designator<Type<TypeCategory::Complex, 3>> ; template class Designator<Type<TypeCategory::Complex, 4>> ; template class Designator<Type<TypeCategory::Complex , 8>> ; template class Designator<Type<TypeCategory ::Complex, 10>> ; template class Designator<Type< TypeCategory::Complex, 16>> ; template class Designator <Type<TypeCategory::Logical, 1>> ; template class Designator<Type<TypeCategory::Logical, 2>> ; template class Designator<Type<TypeCategory::Logical, 4>> ; template class Designator<Type<TypeCategory::Logical , 8>> ; template class Designator<Type<TypeCategory ::Character, 1>> ; template class Designator<Type< TypeCategory::Character, 2>> ; template class Designator <Type<TypeCategory::Character, 4>> ; template class Designator<SomeDerived> ; |
435 | } // namespace Fortran::evaluate |
436 | #endif // FORTRAN_EVALUATE_VARIABLE_H_ |
1 | // <variant> -*- C++ -*- |
2 | |
3 | // Copyright (C) 2016-2020 Free Software Foundation, Inc. |
4 | // |
5 | // This file is part of the GNU ISO C++ Library. This library is free |
6 | // software; you can redistribute it and/or modify it under the |
7 | // terms of the GNU General Public License as published by the |
8 | // Free Software Foundation; either version 3, or (at your option) |
9 | // any later version. |
10 | |
11 | // This library is distributed in the hope that it will be useful, |
12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | // GNU General Public License for more details. |
15 | |
16 | // Under Section 7 of GPL version 3, you are granted additional |
17 | // permissions described in the GCC Runtime Library Exception, version |
18 | // 3.1, as published by the Free Software Foundation. |
19 | |
20 | // You should have received a copy of the GNU General Public License and |
21 | // a copy of the GCC Runtime Library Exception along with this program; |
22 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
23 | // <http://www.gnu.org/licenses/>. |
24 | |
25 | /** @file variant |
26 | * This is the <variant> C++ Library header. |
27 | */ |
28 | |
29 | #ifndef _GLIBCXX_VARIANT1 |
30 | #define _GLIBCXX_VARIANT1 1 |
31 | |
32 | #pragma GCC system_header |
33 | |
34 | #if __cplusplus201703L >= 201703L |
35 | |
36 | #include <type_traits> |
37 | #include <utility> |
38 | #include <bits/enable_special_members.h> |
39 | #include <bits/functexcept.h> |
40 | #include <bits/move.h> |
41 | #include <bits/functional_hash.h> |
42 | #include <bits/invoke.h> |
43 | #include <ext/aligned_buffer.h> |
44 | #include <bits/parse_numbers.h> |
45 | #include <bits/stl_iterator_base_types.h> |
46 | #include <bits/stl_iterator_base_funcs.h> |
47 | #include <bits/stl_construct.h> |
48 | #if __cplusplus201703L > 201703L |
49 | # include <compare> |
50 | #endif |
51 | |
52 | namespace std _GLIBCXX_VISIBILITY(default)__attribute__ ((__visibility__ ("default"))) |
53 | { |
54 | _GLIBCXX_BEGIN_NAMESPACE_VERSION |
55 | |
56 | namespace __detail |
57 | { |
58 | namespace __variant |
59 | { |
60 | template<size_t _Np, typename... _Types> |
61 | struct _Nth_type; |
62 | |
63 | template<size_t _Np, typename _First, typename... _Rest> |
64 | struct _Nth_type<_Np, _First, _Rest...> |
65 | : _Nth_type<_Np-1, _Rest...> { }; |
66 | |
67 | template<typename _First, typename... _Rest> |
68 | struct _Nth_type<0, _First, _Rest...> |
69 | { using type = _First; }; |
70 | |
71 | } // namespace __variant |
72 | } // namespace __detail |
73 | |
74 | #define __cpp_lib_variant201606L 201606L |
75 | |
76 | template<typename... _Types> class tuple; |
77 | template<typename... _Types> class variant; |
78 | template <typename> struct hash; |
79 | |
80 | template<typename _Variant> |
81 | struct variant_size; |
82 | |
83 | template<typename _Variant> |
84 | struct variant_size<const _Variant> : variant_size<_Variant> {}; |
85 | |
86 | template<typename _Variant> |
87 | struct variant_size<volatile _Variant> : variant_size<_Variant> {}; |
88 | |
89 | template<typename _Variant> |
90 | struct variant_size<const volatile _Variant> : variant_size<_Variant> {}; |
91 | |
92 | template<typename... _Types> |
93 | struct variant_size<variant<_Types...>> |
94 | : std::integral_constant<size_t, sizeof...(_Types)> {}; |
95 | |
96 | template<typename _Variant> |
97 | inline constexpr size_t variant_size_v = variant_size<_Variant>::value; |
98 | |
99 | template<size_t _Np, typename _Variant> |
100 | struct variant_alternative; |
101 | |
102 | template<size_t _Np, typename _First, typename... _Rest> |
103 | struct variant_alternative<_Np, variant<_First, _Rest...>> |
104 | : variant_alternative<_Np-1, variant<_Rest...>> {}; |
105 | |
106 | template<typename _First, typename... _Rest> |
107 | struct variant_alternative<0, variant<_First, _Rest...>> |
108 | { using type = _First; }; |
109 | |
110 | template<size_t _Np, typename _Variant> |
111 | using variant_alternative_t = |
112 | typename variant_alternative<_Np, _Variant>::type; |
113 | |
114 | template<size_t _Np, typename _Variant> |
115 | struct variant_alternative<_Np, const _Variant> |
116 | { using type = add_const_t<variant_alternative_t<_Np, _Variant>>; }; |
117 | |
118 | template<size_t _Np, typename _Variant> |
119 | struct variant_alternative<_Np, volatile _Variant> |
120 | { using type = add_volatile_t<variant_alternative_t<_Np, _Variant>>; }; |
121 | |
122 | template<size_t _Np, typename _Variant> |
123 | struct variant_alternative<_Np, const volatile _Variant> |
124 | { using type = add_cv_t<variant_alternative_t<_Np, _Variant>>; }; |
125 | |
126 | inline constexpr size_t variant_npos = -1; |
127 | |
128 | template<size_t _Np, typename... _Types> |
129 | constexpr variant_alternative_t<_Np, variant<_Types...>>& |
130 | get(variant<_Types...>&); |
131 | |
132 | template<size_t _Np, typename... _Types> |
133 | constexpr variant_alternative_t<_Np, variant<_Types...>>&& |
134 | get(variant<_Types...>&&); |
135 | |
136 | template<size_t _Np, typename... _Types> |
137 | constexpr variant_alternative_t<_Np, variant<_Types...>> const& |
138 | get(const variant<_Types...>&); |
139 | |
140 | template<size_t _Np, typename... _Types> |
141 | constexpr variant_alternative_t<_Np, variant<_Types...>> const&& |
142 | get(const variant<_Types...>&&); |
143 | |
144 | template<typename _Result_type, typename _Visitor, typename... _Variants> |
145 | constexpr decltype(auto) |
146 | __do_visit(_Visitor&& __visitor, _Variants&&... __variants); |
147 | |
148 | template <typename... _Types, typename _Tp> |
149 | decltype(auto) |
150 | __variant_cast(_Tp&& __rhs) |
151 | { |
152 | if constexpr (is_lvalue_reference_v<_Tp>) |
153 | { |
154 | if constexpr (is_const_v<remove_reference_t<_Tp>>) |
155 | return static_cast<const variant<_Types...>&>(__rhs); |
156 | else |
157 | return static_cast<variant<_Types...>&>(__rhs); |
158 | } |
159 | else |
160 | return static_cast<variant<_Types...>&&>(__rhs); |
161 | } |
162 | |
163 | namespace __detail |
164 | { |
165 | namespace __variant |
166 | { |
167 | // Returns the first appearence of _Tp in _Types. |
168 | // Returns sizeof...(_Types) if _Tp is not in _Types. |
169 | template<typename _Tp, typename... _Types> |
170 | struct __index_of : std::integral_constant<size_t, 0> {}; |
171 | |
172 | template<typename _Tp, typename... _Types> |
173 | inline constexpr size_t __index_of_v = __index_of<_Tp, _Types...>::value; |
174 | |
175 | template<typename _Tp, typename _First, typename... _Rest> |
176 | struct __index_of<_Tp, _First, _Rest...> : |
177 | std::integral_constant<size_t, is_same_v<_Tp, _First> |
178 | ? 0 : __index_of_v<_Tp, _Rest...> + 1> {}; |
179 | |
180 | // used for raw visitation |
181 | struct __variant_cookie {}; |
182 | // used for raw visitation with indices passed in |
183 | struct __variant_idx_cookie { using type = __variant_idx_cookie; }; |
184 | // Used to enable deduction (and same-type checking) for std::visit: |
185 | template<typename> struct __deduce_visit_result { }; |
186 | |
187 | // Visit variants that might be valueless. |
188 | template<typename _Visitor, typename... _Variants> |
189 | constexpr void |
190 | __raw_visit(_Visitor&& __visitor, _Variants&&... __variants) |
191 | { |
192 | std::__do_visit<__variant_cookie>(std::forward<_Visitor>(__visitor), |
193 | std::forward<_Variants>(__variants)...); |
194 | } |
195 | |
196 | // Visit variants that might be valueless, passing indices to the visitor. |
197 | template<typename _Visitor, typename... _Variants> |
198 | constexpr void |
199 | __raw_idx_visit(_Visitor&& __visitor, _Variants&&... __variants) |
200 | { |
201 | std::__do_visit<__variant_idx_cookie>(std::forward<_Visitor>(__visitor), |
202 | std::forward<_Variants>(__variants)...); |
203 | } |
204 | |
205 | // _Uninitialized<T> is guaranteed to be a trivially destructible type, |
206 | // even if T is not. |
207 | template<typename _Type, bool = std::is_trivially_destructible_v<_Type>> |
208 | struct _Uninitialized; |
209 | |
210 | template<typename _Type> |
211 | struct _Uninitialized<_Type, true> |
212 | { |
213 | template<typename... _Args> |
214 | constexpr |
215 | _Uninitialized(in_place_index_t<0>, _Args&&... __args) |
216 | : _M_storage(std::forward<_Args>(__args)...) |
217 | { } |
218 | |
219 | constexpr const _Type& _M_get() const & noexcept |
220 | { return _M_storage; } |
221 | |
222 | constexpr _Type& _M_get() & noexcept |
223 | { return _M_storage; } |
224 | |
225 | constexpr const _Type&& _M_get() const && noexcept |
226 | { return std::move(_M_storage); } |
227 | |
228 | constexpr _Type&& _M_get() && noexcept |
229 | { return std::move(_M_storage); } |
230 | |
231 | _Type _M_storage; |
232 | }; |
233 | |
234 | template<typename _Type> |
235 | struct _Uninitialized<_Type, false> |
236 | { |
237 | template<typename... _Args> |
238 | constexpr |
239 | _Uninitialized(in_place_index_t<0>, _Args&&... __args) |
240 | { |
241 | ::new ((void*)std::addressof(_M_storage)) |
242 | _Type(std::forward<_Args>(__args)...); |
243 | } |
244 | |
245 | const _Type& _M_get() const & noexcept |
246 | { return *_M_storage._M_ptr(); } |
247 | |
248 | _Type& _M_get() & noexcept |
249 | { return *_M_storage._M_ptr(); } |
250 | |
251 | const _Type&& _M_get() const && noexcept |
252 | { return std::move(*_M_storage._M_ptr()); } |
253 | |
254 | _Type&& _M_get() && noexcept |
255 | { return std::move(*_M_storage._M_ptr()); } |
256 | |
257 | __gnu_cxx::__aligned_membuf<_Type> _M_storage; |
258 | }; |
259 | |
260 | template<typename _Union> |
261 | constexpr decltype(auto) |
262 | __get(in_place_index_t<0>, _Union&& __u) noexcept |
263 | { return std::forward<_Union>(__u)._M_first._M_get(); } |
264 | |
265 | template<size_t _Np, typename _Union> |
266 | constexpr decltype(auto) |
267 | __get(in_place_index_t<_Np>, _Union&& __u) noexcept |
268 | { |
269 | return __variant::__get(in_place_index<_Np-1>, |
270 | std::forward<_Union>(__u)._M_rest); |
271 | } |
272 | |
273 | // Returns the typed storage for __v. |
274 | template<size_t _Np, typename _Variant> |
275 | constexpr decltype(auto) |
276 | __get(_Variant&& __v) noexcept |
277 | { |
278 | return __variant::__get(std::in_place_index<_Np>, |
279 | std::forward<_Variant>(__v)._M_u); |
280 | } |
281 | |
282 | template<typename... _Types> |
283 | struct _Traits |
284 | { |
285 | static constexpr bool _S_default_ctor = |
286 | is_default_constructible_v<typename _Nth_type<0, _Types...>::type>; |
287 | static constexpr bool _S_copy_ctor = |
288 | (is_copy_constructible_v<_Types> && ...); |
289 | static constexpr bool _S_move_ctor = |
290 | (is_move_constructible_v<_Types> && ...); |
291 | static constexpr bool _S_copy_assign = |
292 | _S_copy_ctor |
293 | && (is_copy_assignable_v<_Types> && ...); |
294 | static constexpr bool _S_move_assign = |
295 | _S_move_ctor |
296 | && (is_move_assignable_v<_Types> && ...); |
297 | |
298 | static constexpr bool _S_trivial_dtor = |
299 | (is_trivially_destructible_v<_Types> && ...); |
300 | static constexpr bool _S_trivial_copy_ctor = |
301 | (is_trivially_copy_constructible_v<_Types> && ...); |
302 | static constexpr bool _S_trivial_move_ctor = |
303 | (is_trivially_move_constructible_v<_Types> && ...); |
304 | static constexpr bool _S_trivial_copy_assign = |
305 | _S_trivial_dtor && _S_trivial_copy_ctor |
306 | && (is_trivially_copy_assignable_v<_Types> && ...); |
307 | static constexpr bool _S_trivial_move_assign = |
308 | _S_trivial_dtor && _S_trivial_move_ctor |
309 | && (is_trivially_move_assignable_v<_Types> && ...); |
310 | |
311 | // The following nothrow traits are for non-trivial SMFs. Trivial SMFs |
312 | // are always nothrow. |
313 | static constexpr bool _S_nothrow_default_ctor = |
314 | is_nothrow_default_constructible_v< |
315 | typename _Nth_type<0, _Types...>::type>; |
316 | static constexpr bool _S_nothrow_copy_ctor = false; |
317 | static constexpr bool _S_nothrow_move_ctor = |
318 | (is_nothrow_move_constructible_v<_Types> && ...); |
319 | static constexpr bool _S_nothrow_copy_assign = false; |
320 | static constexpr bool _S_nothrow_move_assign = |
321 | _S_nothrow_move_ctor |
322 | && (is_nothrow_move_assignable_v<_Types> && ...); |
323 | }; |
324 | |
325 | // Defines members and ctors. |
326 | template<typename... _Types> |
327 | union _Variadic_union { }; |
328 | |
329 | template<typename _First, typename... _Rest> |
330 | union _Variadic_union<_First, _Rest...> |
331 | { |
332 | constexpr _Variadic_union() : _M_rest() { } |
333 | |
334 | template<typename... _Args> |
335 | constexpr _Variadic_union(in_place_index_t<0>, _Args&&... __args) |
336 | : _M_first(in_place_index<0>, std::forward<_Args>(__args)...) |
337 | { } |
338 | |
339 | template<size_t _Np, typename... _Args> |
340 | constexpr _Variadic_union(in_place_index_t<_Np>, _Args&&... __args) |
341 | : _M_rest(in_place_index<_Np-1>, std::forward<_Args>(__args)...) |
342 | { } |
343 | |
344 | _Uninitialized<_First> _M_first; |
345 | _Variadic_union<_Rest...> _M_rest; |
346 | }; |
347 | |
348 | // _Never_valueless_alt is true for variant alternatives that can |
349 | // always be placed in a variant without it becoming valueless. |
350 | |
351 | // For suitably-small, trivially copyable types we can create temporaries |
352 | // on the stack and then memcpy them into place. |
353 | template<typename _Tp> |
354 | struct _Never_valueless_alt |
355 | : __and_<bool_constant<sizeof(_Tp) <= 256>, is_trivially_copyable<_Tp>> |
356 | { }; |
357 | |
358 | // Specialize _Never_valueless_alt for other types which have a |
359 | // non-throwing and cheap move construction and move assignment operator, |
360 | // so that emplacing the type will provide the strong exception-safety |
361 | // guarantee, by creating and moving a temporary. |
362 | // Whether _Never_valueless_alt<T> is true or not affects the ABI of a |
363 | // variant using that alternative, so we can't change the value later! |
364 | |
365 | // True if every alternative in _Types... can be emplaced in a variant |
366 | // without it becoming valueless. If this is true, variant<_Types...> |
367 | // can never be valueless, which enables some minor optimizations. |
368 | template <typename... _Types> |
369 | constexpr bool __never_valueless() |
370 | { |
371 | return _Traits<_Types...>::_S_move_assign |
372 | && (_Never_valueless_alt<_Types>::value && ...); |
373 | } |
374 | |
375 | // Defines index and the dtor, possibly trivial. |
376 | template<bool __trivially_destructible, typename... _Types> |
377 | struct _Variant_storage; |
378 | |
379 | template <typename... _Types> |
380 | using __select_index = |
381 | typename __select_int::_Select_int_base<sizeof...(_Types), |
382 | unsigned char, |
383 | unsigned short>::type::value_type; |
384 | |
385 | template<typename... _Types> |
386 | struct _Variant_storage<false, _Types...> |
387 | { |
388 | constexpr |
389 | _Variant_storage() |
390 | : _M_index(static_cast<__index_type>(variant_npos)) |
391 | { } |
392 | |
393 | template<size_t _Np, typename... _Args> |
394 | constexpr |
395 | _Variant_storage(in_place_index_t<_Np>, _Args&&... __args) |
396 | : _M_u(in_place_index<_Np>, std::forward<_Args>(__args)...), |
397 | _M_index{_Np} |
398 | { } |
399 | |
400 | void _M_reset() |
401 | { |
402 | if (!_M_valid()) [[unlikely]] |
403 | return; |
404 | |
405 | std::__do_visit<void>([](auto&& __this_mem) mutable |
406 | { |
407 | std::_Destroy(std::__addressof(__this_mem)); |
408 | }, __variant_cast<_Types...>(*this)); |
409 | |
410 | _M_index = static_cast<__index_type>(variant_npos); |
411 | } |
412 | |
413 | ~_Variant_storage() |
414 | { _M_reset(); } |
415 | |
416 | void* |
417 | _M_storage() const noexcept |
418 | { |
419 | return const_cast<void*>(static_cast<const void*>( |
420 | std::addressof(_M_u))); |
421 | } |
422 | |
423 | constexpr bool |
424 | _M_valid() const noexcept |
425 | { |
426 | if constexpr (__variant::__never_valueless<_Types...>()) |
427 | return true; |
428 | return this->_M_index != __index_type(variant_npos); |
429 | } |
430 | |
431 | _Variadic_union<_Types...> _M_u; |
432 | using __index_type = __select_index<_Types...>; |
433 | __index_type _M_index; |
434 | }; |
435 | |
436 | template<typename... _Types> |
437 | struct _Variant_storage<true, _Types...> |
438 | { |
439 | constexpr |
440 | _Variant_storage() |
441 | : _M_index(static_cast<__index_type>(variant_npos)) |
442 | { } |
443 | |
444 | template<size_t _Np, typename... _Args> |
445 | constexpr |
446 | _Variant_storage(in_place_index_t<_Np>, _Args&&... __args) |
447 | : _M_u(in_place_index<_Np>, std::forward<_Args>(__args)...), |
448 | _M_index{_Np} |
449 | { } |
450 | |
451 | void _M_reset() noexcept |
452 | { _M_index = static_cast<__index_type>(variant_npos); } |
453 | |
454 | void* |
455 | _M_storage() const noexcept |
456 | { |
457 | return const_cast<void*>(static_cast<const void*>( |
458 | std::addressof(_M_u))); |
459 | } |
460 | |
461 | constexpr bool |
462 | _M_valid() const noexcept |
463 | { |
464 | if constexpr (__variant::__never_valueless<_Types...>()) |
465 | return true; |
466 | return this->_M_index != static_cast<__index_type>(variant_npos); |
467 | } |
468 | |
469 | _Variadic_union<_Types...> _M_u; |
470 | using __index_type = __select_index<_Types...>; |
471 | __index_type _M_index; |
472 | }; |
473 | |
474 | template<typename... _Types> |
475 | using _Variant_storage_alias = |
476 | _Variant_storage<_Traits<_Types...>::_S_trivial_dtor, _Types...>; |
477 | |
478 | template<typename _Tp, typename _Up> |
479 | void __variant_construct_single(_Tp&& __lhs, _Up&& __rhs_mem) |
480 | { |
481 | void* __storage = std::addressof(__lhs._M_u); |
482 | using _Type = remove_reference_t<decltype(__rhs_mem)>; |
483 | if constexpr (!is_same_v<_Type, __variant_cookie>) |
484 | ::new (__storage) |
485 | _Type(std::forward<decltype(__rhs_mem)>(__rhs_mem)); |
486 | } |
487 | |
488 | template<typename... _Types, typename _Tp, typename _Up> |
489 | void __variant_construct(_Tp&& __lhs, _Up&& __rhs) |
490 | { |
491 | __lhs._M_index = __rhs._M_index; |
492 | __variant::__raw_visit([&__lhs](auto&& __rhs_mem) mutable |
493 | { |
494 | __variant_construct_single(std::forward<_Tp>(__lhs), |
495 | std::forward<decltype(__rhs_mem)>(__rhs_mem)); |
496 | }, __variant_cast<_Types...>(std::forward<_Up>(__rhs))); |
497 | } |
498 | |
499 | // The following are (Copy|Move) (ctor|assign) layers for forwarding |
500 | // triviality and handling non-trivial SMF behaviors. |
501 | |
502 | template<bool, typename... _Types> |
503 | struct _Copy_ctor_base : _Variant_storage_alias<_Types...> |
504 | { |
505 | using _Base = _Variant_storage_alias<_Types...>; |
506 | using _Base::_Base; |
507 | |
508 | _Copy_ctor_base(const _Copy_ctor_base& __rhs) |
509 | noexcept(_Traits<_Types...>::_S_nothrow_copy_ctor) |
510 | { |
511 | __variant_construct<_Types...>(*this, __rhs); |
512 | } |
513 | |
514 | _Copy_ctor_base(_Copy_ctor_base&&) = default; |
515 | _Copy_ctor_base& operator=(const _Copy_ctor_base&) = default; |
516 | _Copy_ctor_base& operator=(_Copy_ctor_base&&) = default; |
517 | }; |
518 | |
519 | template<typename... _Types> |
520 | struct _Copy_ctor_base<true, _Types...> : _Variant_storage_alias<_Types...> |
521 | { |
522 | using _Base = _Variant_storage_alias<_Types...>; |
523 | using _Base::_Base; |
524 | }; |
525 | |
526 | template<typename... _Types> |
527 | using _Copy_ctor_alias = |
528 | _Copy_ctor_base<_Traits<_Types...>::_S_trivial_copy_ctor, _Types...>; |
529 | |
530 | template<bool, typename... _Types> |
531 | struct _Move_ctor_base : _Copy_ctor_alias<_Types...> |
532 | { |
533 | using _Base = _Copy_ctor_alias<_Types...>; |
534 | using _Base::_Base; |
535 | |
536 | _Move_ctor_base(_Move_ctor_base&& __rhs) |
537 | noexcept(_Traits<_Types...>::_S_nothrow_move_ctor) |
538 | { |
539 | __variant_construct<_Types...>(*this, std::move(__rhs)); |
540 | } |
541 | |
542 | template<typename _Up> |
543 | void _M_destructive_move(unsigned short __rhs_index, _Up&& __rhs) |
544 | { |
545 | this->_M_reset(); |
546 | __variant_construct_single(*this, std::forward<_Up>(__rhs)); |
547 | this->_M_index = __rhs_index; |
548 | } |
549 | |
550 | template<typename _Up> |
551 | void _M_destructive_copy(unsigned short __rhs_index, const _Up& __rhs) |
552 | { |
553 | this->_M_reset(); |
554 | __variant_construct_single(*this, __rhs); |
555 | this->_M_index = __rhs_index; |
556 | } |
557 | |
558 | _Move_ctor_base(const _Move_ctor_base&) = default; |
559 | _Move_ctor_base& operator=(const _Move_ctor_base&) = default; |
560 | _Move_ctor_base& operator=(_Move_ctor_base&&) = default; |
561 | }; |
562 | |
563 | template<typename... _Types> |
564 | struct _Move_ctor_base<true, _Types...> : _Copy_ctor_alias<_Types...> |
565 | { |
566 | using _Base = _Copy_ctor_alias<_Types...>; |
567 | using _Base::_Base; |
568 | |
569 | template<typename _Up> |
570 | void _M_destructive_move(unsigned short __rhs_index, _Up&& __rhs) |
571 | { |
572 | this->_M_reset(); |
573 | __variant_construct_single(*this, std::forward<_Up>(__rhs)); |
574 | this->_M_index = __rhs_index; |
575 | } |
576 | |
577 | template<typename _Up> |
578 | void _M_destructive_copy(unsigned short __rhs_index, const _Up& __rhs) |
579 | { |
580 | this->_M_reset(); |
581 | __variant_construct_single(*this, __rhs); |
582 | this->_M_index = __rhs_index; |
583 | } |
584 | }; |
585 | |
586 | template<typename... _Types> |
587 | using _Move_ctor_alias = |
588 | _Move_ctor_base<_Traits<_Types...>::_S_trivial_move_ctor, _Types...>; |
589 | |
590 | template<bool, typename... _Types> |
591 | struct _Copy_assign_base : _Move_ctor_alias<_Types...> |
592 | { |
593 | using _Base = _Move_ctor_alias<_Types...>; |
594 | using _Base::_Base; |
595 | |
596 | _Copy_assign_base& |
597 | operator=(const _Copy_assign_base& __rhs) |
598 | noexcept(_Traits<_Types...>::_S_nothrow_copy_assign) |
599 | { |
600 | __variant::__raw_idx_visit( |
601 | [this](auto&& __rhs_mem, auto __rhs_index) mutable |
602 | { |
603 | if constexpr (__rhs_index != variant_npos) |
604 | { |
605 | if (this->_M_index == __rhs_index) |
606 | __variant::__get<__rhs_index>(*this) = __rhs_mem; |
607 | else |
608 | { |
609 | using __rhs_type = __remove_cvref_t<decltype(__rhs_mem)>; |
610 | if constexpr (is_nothrow_copy_constructible_v<__rhs_type> |
611 | || !is_nothrow_move_constructible_v<__rhs_type>) |
612 | // The standard says this->emplace<__rhs_type>(__rhs_mem) |
613 | // should be used here, but _M_destructive_copy is |
614 | // equivalent in this case. Either copy construction |
615 | // doesn't throw, so _M_destructive_copy gives strong |
616 | // exception safety guarantee, or both copy construction |
617 | // and move construction can throw, so emplace only gives |
618 | // basic exception safety anyway. |
619 | this->_M_destructive_copy(__rhs_index, __rhs_mem); |
620 | else |
621 | __variant_cast<_Types...>(*this) |
622 | = variant<_Types...>(std::in_place_index<__rhs_index>, |
623 | __rhs_mem); |
624 | } |
625 | } |
626 | else |
627 | this->_M_reset(); |
628 | }, __variant_cast<_Types...>(__rhs)); |
629 | return *this; |
630 | } |
631 | |
632 | _Copy_assign_base(const _Copy_assign_base&) = default; |
633 | _Copy_assign_base(_Copy_assign_base&&) = default; |
634 | _Copy_assign_base& operator=(_Copy_assign_base&&) = default; |
635 | }; |
636 | |
637 | template<typename... _Types> |
638 | struct _Copy_assign_base<true, _Types...> : _Move_ctor_alias<_Types...> |
639 | { |
640 | using _Base = _Move_ctor_alias<_Types...>; |
641 | using _Base::_Base; |
642 | }; |
643 | |
644 | template<typename... _Types> |
645 | using _Copy_assign_alias = |
646 | _Copy_assign_base<_Traits<_Types...>::_S_trivial_copy_assign, _Types...>; |
647 | |
648 | template<bool, typename... _Types> |
649 | struct _Move_assign_base : _Copy_assign_alias<_Types...> |
650 | { |
651 | using _Base = _Copy_assign_alias<_Types...>; |
652 | using _Base::_Base; |
653 | |
654 | _Move_assign_base& |
655 | operator=(_Move_assign_base&& __rhs) |
656 | noexcept(_Traits<_Types...>::_S_nothrow_move_assign) |
657 | { |
658 | __variant::__raw_idx_visit( |
659 | [this](auto&& __rhs_mem, auto __rhs_index) mutable |
660 | { |
661 | if constexpr (__rhs_index != variant_npos) |
662 | { |
663 | if (this->_M_index == __rhs_index) |
664 | __variant::__get<__rhs_index>(*this) = std::move(__rhs_mem); |
665 | else |
666 | __variant_cast<_Types...>(*this) |
667 | .template emplace<__rhs_index>(std::move(__rhs_mem)); |
668 | } |
669 | else |
670 | this->_M_reset(); |
671 | }, __variant_cast<_Types...>(__rhs)); |
672 | return *this; |
673 | } |
674 | |
675 | _Move_assign_base(const _Move_assign_base&) = default; |
676 | _Move_assign_base(_Move_assign_base&&) = default; |
677 | _Move_assign_base& operator=(const _Move_assign_base&) = default; |
678 | }; |
679 | |
680 | template<typename... _Types> |
681 | struct _Move_assign_base<true, _Types...> : _Copy_assign_alias<_Types...> |
682 | { |
683 | using _Base = _Copy_assign_alias<_Types...>; |
684 | using _Base::_Base; |
685 | }; |
686 | |
687 | template<typename... _Types> |
688 | using _Move_assign_alias = |
689 | _Move_assign_base<_Traits<_Types...>::_S_trivial_move_assign, _Types...>; |
690 | |
691 | template<typename... _Types> |
692 | struct _Variant_base : _Move_assign_alias<_Types...> |
693 | { |
694 | using _Base = _Move_assign_alias<_Types...>; |
695 | |
696 | constexpr |
697 | _Variant_base() |
698 | noexcept(_Traits<_Types...>::_S_nothrow_default_ctor) |
699 | : _Variant_base(in_place_index<0>) { } |
700 | |
701 | template<size_t _Np, typename... _Args> |
702 | constexpr explicit |
703 | _Variant_base(in_place_index_t<_Np> __i, _Args&&... __args) |
704 | : _Base(__i, std::forward<_Args>(__args)...) |
705 | { } |
706 | |
707 | _Variant_base(const _Variant_base&) = default; |
708 | _Variant_base(_Variant_base&&) = default; |
709 | _Variant_base& operator=(const _Variant_base&) = default; |
710 | _Variant_base& operator=(_Variant_base&&) = default; |
711 | }; |
712 | |
713 | // For how many times does _Tp appear in _Tuple? |
714 | template<typename _Tp, typename _Tuple> |
715 | struct __tuple_count; |
716 | |
717 | template<typename _Tp, typename _Tuple> |
718 | inline constexpr size_t __tuple_count_v = |
719 | __tuple_count<_Tp, _Tuple>::value; |
720 | |
721 | template<typename _Tp, typename... _Types> |
722 | struct __tuple_count<_Tp, tuple<_Types...>> |
723 | : integral_constant<size_t, 0> { }; |
724 | |
725 | template<typename _Tp, typename _First, typename... _Rest> |
726 | struct __tuple_count<_Tp, tuple<_First, _Rest...>> |
727 | : integral_constant< |
728 | size_t, |
729 | __tuple_count_v<_Tp, tuple<_Rest...>> + is_same_v<_Tp, _First>> { }; |
730 | |
731 | // TODO: Reuse this in <tuple> ? |
732 | template<typename _Tp, typename... _Types> |
733 | inline constexpr bool __exactly_once = |
734 | __tuple_count_v<_Tp, tuple<_Types...>> == 1; |
735 | |
736 | // Helper used to check for valid conversions that don't involve narrowing. |
737 | template<typename _Ti> struct _Arr { _Ti _M_x[1]; }; |
738 | |
739 | // Build an imaginary function FUN(Ti) for each alternative type Ti |
740 | template<size_t _Ind, typename _Tp, typename _Ti, |
741 | bool _Ti_is_cv_bool = is_same_v<remove_cv_t<_Ti>, bool>, |
742 | typename = void> |
743 | struct _Build_FUN |
744 | { |
745 | // This function means 'using _Build_FUN<I, T, Ti>::_S_fun;' is valid, |
746 | // but only static functions will be considered in the call below. |
747 | void _S_fun(); |
748 | }; |
749 | |
750 | // ... for which Ti x[] = {std::forward<T>(t)}; is well-formed, |
751 | template<size_t _Ind, typename _Tp, typename _Ti> |
752 | struct _Build_FUN<_Ind, _Tp, _Ti, false, |
753 | void_t<decltype(_Arr<_Ti>{{std::declval<_Tp>()}})>> |
754 | { |
755 | // This is the FUN function for type _Ti, with index _Ind |
756 | static integral_constant<size_t, _Ind> _S_fun(_Ti); |
757 | }; |
758 | |
759 | // ... and if Ti is cv bool, remove_cvref_t<T> is bool. |
760 | template<size_t _Ind, typename _Tp, typename _Ti> |
761 | struct _Build_FUN<_Ind, _Tp, _Ti, true, |
762 | enable_if_t<is_same_v<__remove_cvref_t<_Tp>, bool>>> |
763 | { |
764 | // This is the FUN function for when _Ti is cv bool, with index _Ind |
765 | static integral_constant<size_t, _Ind> _S_fun(_Ti); |
766 | }; |
767 | |
768 | template<typename _Tp, typename _Variant, |
769 | typename = make_index_sequence<variant_size_v<_Variant>>> |
770 | struct _Build_FUNs; |
771 | |
772 | template<typename _Tp, typename... _Ti, size_t... _Ind> |
773 | struct _Build_FUNs<_Tp, variant<_Ti...>, index_sequence<_Ind...>> |
774 | : _Build_FUN<_Ind, _Tp, _Ti>... |
775 | { |
776 | using _Build_FUN<_Ind, _Tp, _Ti>::_S_fun...; |
777 | }; |
778 | |
779 | // The index j of the overload FUN(Tj) selected by overload resolution |
780 | // for FUN(std::forward<_Tp>(t)) |
781 | template<typename _Tp, typename _Variant> |
782 | using _FUN_type |
783 | = decltype(_Build_FUNs<_Tp, _Variant>::_S_fun(std::declval<_Tp>())); |
784 | |
785 | // The index selected for FUN(std::forward<T>(t)), or variant_npos if none. |
786 | template<typename _Tp, typename _Variant, typename = void> |
787 | struct __accepted_index |
788 | : integral_constant<size_t, variant_npos> |
789 | { }; |
790 | |
791 | template<typename _Tp, typename _Variant> |
792 | struct __accepted_index<_Tp, _Variant, void_t<_FUN_type<_Tp, _Variant>>> |
793 | : _FUN_type<_Tp, _Variant> |
794 | { }; |
795 | |
796 | // Returns the raw storage for __v. |
797 | template<typename _Variant> |
798 | void* __get_storage(_Variant&& __v) noexcept |
799 | { return __v._M_storage(); } |
800 | |
801 | template <typename _Maybe_variant_cookie, typename _Variant> |
802 | struct _Extra_visit_slot_needed |
803 | { |
804 | template <typename> struct _Variant_never_valueless; |
805 | |
806 | template <typename... _Types> |
807 | struct _Variant_never_valueless<variant<_Types...>> |
808 | : bool_constant<__variant::__never_valueless<_Types...>()> {}; |
809 | |
810 | static constexpr bool value = |
811 | (is_same_v<_Maybe_variant_cookie, __variant_cookie> |
812 | || is_same_v<_Maybe_variant_cookie, __variant_idx_cookie>) |
813 | && !_Variant_never_valueless<__remove_cvref_t<_Variant>>::value; |
814 | }; |
815 | |
816 | // Used for storing a multi-dimensional vtable. |
817 | template<typename _Tp, size_t... _Dimensions> |
818 | struct _Multi_array; |
819 | |
820 | // Partial specialization with rank zero, stores a single _Tp element. |
821 | template<typename _Tp> |
822 | struct _Multi_array<_Tp> |
823 | { |
824 | template<typename> |
825 | struct __untag_result |
826 | : false_type |
827 | { using element_type = _Tp; }; |
828 | |
829 | template <typename... _Args> |
830 | struct __untag_result<const void(*)(_Args...)> |
831 | : false_type |
832 | { using element_type = void(*)(_Args...); }; |
833 | |
834 | template <typename... _Args> |
835 | struct __untag_result<__variant_cookie(*)(_Args...)> |
836 | : false_type |
837 | { using element_type = void(*)(_Args...); }; |
838 | |
839 | template <typename... _Args> |
840 | struct __untag_result<__variant_idx_cookie(*)(_Args...)> |
841 | : false_type |
842 | { using element_type = void(*)(_Args...); }; |
843 | |
844 | template <typename _Res, typename... _Args> |
845 | struct __untag_result<__deduce_visit_result<_Res>(*)(_Args...)> |
846 | : true_type |
847 | { using element_type = _Res(*)(_Args...); }; |
848 | |
849 | using __result_is_deduced = __untag_result<_Tp>; |
850 | |
851 | constexpr const typename __untag_result<_Tp>::element_type& |
852 | _M_access() const |
853 | { return _M_data; } |
854 | |
855 | typename __untag_result<_Tp>::element_type _M_data; |
856 | }; |
857 | |
858 | // Partial specialization with rank >= 1. |
859 | template<typename _Ret, |
860 | typename _Visitor, |
861 | typename... _Variants, |
862 | size_t __first, size_t... __rest> |
863 | struct _Multi_array<_Ret(*)(_Visitor, _Variants...), __first, __rest...> |
864 | { |
865 | static constexpr size_t __index = |
866 | sizeof...(_Variants) - sizeof...(__rest) - 1; |
867 | |
868 | using _Variant = typename _Nth_type<__index, _Variants...>::type; |
869 | |
870 | static constexpr int __do_cookie = |
871 | _Extra_visit_slot_needed<_Ret, _Variant>::value ? 1 : 0; |
872 | |
873 | using _Tp = _Ret(*)(_Visitor, _Variants...); |
874 | |
875 | template<typename... _Args> |
876 | constexpr decltype(auto) |
877 | _M_access(size_t __first_index, _Args... __rest_indices) const |
878 | { |
879 | return _M_arr[__first_index + __do_cookie] |
880 | ._M_access(__rest_indices...); |
881 | } |
882 | |
883 | _Multi_array<_Tp, __rest...> _M_arr[__first + __do_cookie]; |
884 | }; |
885 | |
886 | // Creates a multi-dimensional vtable recursively. |
887 | // |
888 | // For example, |
889 | // visit([](auto, auto){}, |
890 | // variant<int, char>(), // typedef'ed as V1 |
891 | // variant<float, double, long double>()) // typedef'ed as V2 |
892 | // will trigger instantiations of: |
893 | // __gen_vtable_impl<_Multi_array<void(*)(V1&&, V2&&), 2, 3>, |
894 | // tuple<V1&&, V2&&>, std::index_sequence<>> |
895 | // __gen_vtable_impl<_Multi_array<void(*)(V1&&, V2&&), 3>, |
896 | // tuple<V1&&, V2&&>, std::index_sequence<0>> |
897 | // __gen_vtable_impl<_Multi_array<void(*)(V1&&, V2&&)>, |
898 | // tuple<V1&&, V2&&>, std::index_sequence<0, 0>> |
899 | // __gen_vtable_impl<_Multi_array<void(*)(V1&&, V2&&)>, |
900 | // tuple<V1&&, V2&&>, std::index_sequence<0, 1>> |
901 | // __gen_vtable_impl<_Multi_array<void(*)(V1&&, V2&&)>, |
902 | // tuple<V1&&, V2&&>, std::index_sequence<0, 2>> |
903 | // __gen_vtable_impl<_Multi_array<void(*)(V1&&, V2&&), 3>, |
904 | // tuple<V1&&, V2&&>, std::index_sequence<1>> |
905 | // __gen_vtable_impl<_Multi_array<void(*)(V1&&, V2&&)>, |
906 | // tuple<V1&&, V2&&>, std::index_sequence<1, 0>> |
907 | // __gen_vtable_impl<_Multi_array<void(*)(V1&&, V2&&)>, |
908 | // tuple<V1&&, V2&&>, std::index_sequence<1, 1>> |
909 | // __gen_vtable_impl<_Multi_array<void(*)(V1&&, V2&&)>, |
910 | // tuple<V1&&, V2&&>, std::index_sequence<1, 2>> |
911 | // The returned multi-dimensional vtable can be fast accessed by the visitor |
912 | // using index calculation. |
913 | template<typename _Array_type, typename _Index_seq> |
914 | struct __gen_vtable_impl; |
915 | |
916 | // Defines the _S_apply() member that returns a _Multi_array populated |
917 | // with function pointers that perform the visitation expressions e(m) |
918 | // for each valid pack of indexes into the variant types _Variants. |
919 | // |
920 | // This partial specialization builds up the index sequences by recursively |
921 | // calling _S_apply() on the next specialization of __gen_vtable_impl. |
922 | // The base case of the recursion defines the actual function pointers. |
923 | template<typename _Result_type, typename _Visitor, size_t... __dimensions, |
924 | typename... _Variants, size_t... __indices> |
925 | struct __gen_vtable_impl< |
926 | _Multi_array<_Result_type (*)(_Visitor, _Variants...), __dimensions...>, |
927 | std::index_sequence<__indices...>> |
928 | { |
929 | using _Next = |
930 | remove_reference_t<typename _Nth_type<sizeof...(__indices), |
931 | _Variants...>::type>; |
932 | using _Array_type = |
933 | _Multi_array<_Result_type (*)(_Visitor, _Variants...), |
934 | __dimensions...>; |
935 | |
936 | static constexpr _Array_type |
937 | _S_apply() |
938 | { |
939 | _Array_type __vtable{}; |
940 | _S_apply_all_alts( |
941 | __vtable, make_index_sequence<variant_size_v<_Next>>()); |
942 | return __vtable; |
943 | } |
944 | |
945 | template<size_t... __var_indices> |
946 | static constexpr void |
947 | _S_apply_all_alts(_Array_type& __vtable, |
948 | std::index_sequence<__var_indices...>) |
949 | { |
950 | if constexpr (_Extra_visit_slot_needed<_Result_type, _Next>::value) |
951 | (_S_apply_single_alt<true, __var_indices>( |
952 | __vtable._M_arr[__var_indices + 1], |
953 | &(__vtable._M_arr[0])), ...); |
954 | else |
955 | (_S_apply_single_alt<false, __var_indices>( |
956 | __vtable._M_arr[__var_indices]), ...); |
957 | } |
958 | |
959 | template<bool __do_cookie, size_t __index, typename _Tp> |
960 | static constexpr void |
961 | _S_apply_single_alt(_Tp& __element, _Tp* __cookie_element = nullptr) |
962 | { |
963 | if constexpr (__do_cookie) |
964 | { |
965 | __element = __gen_vtable_impl< |
966 | _Tp, |
967 | std::index_sequence<__indices..., __index>>::_S_apply(); |
968 | *__cookie_element = __gen_vtable_impl< |
969 | _Tp, |
970 | std::index_sequence<__indices..., variant_npos>>::_S_apply(); |
971 | } |
972 | else |
973 | { |
974 | __element = __gen_vtable_impl< |
975 | remove_reference_t<decltype(__element)>, |
976 | std::index_sequence<__indices..., __index>>::_S_apply(); |
977 | } |
978 | } |
979 | }; |
980 | |
981 | // This partial specialization is the base case for the recursion. |
982 | // It populates a _Multi_array element with the address of a function |
983 | // that invokes the visitor with the alternatives specified by __indices. |
984 | template<typename _Result_type, typename _Visitor, typename... _Variants, |
985 | size_t... __indices> |
986 | struct __gen_vtable_impl< |
987 | _Multi_array<_Result_type (*)(_Visitor, _Variants...)>, |
988 | std::index_sequence<__indices...>> |
989 | { |
990 | using _Array_type = |
991 | _Multi_array<_Result_type (*)(_Visitor, _Variants...)>; |
992 | |
993 | template<size_t __index, typename _Variant> |
994 | static constexpr decltype(auto) |
995 | __element_by_index_or_cookie(_Variant&& __var) noexcept |
996 | { |
997 | if constexpr (__index != variant_npos) |
998 | return __variant::__get<__index>(std::forward<_Variant>(__var)); |
999 | else |
1000 | return __variant_cookie{}; |
1001 | } |
1002 | |
1003 | static constexpr decltype(auto) |
1004 | __visit_invoke(_Visitor&& __visitor, _Variants... __vars) |
1005 | { |
1006 | if constexpr (is_same_v<_Result_type, __variant_idx_cookie>) |
1007 | // For raw visitation using indices, pass the indices to the visitor |
1008 | // and discard the return value: |
1009 | std::__invoke(std::forward<_Visitor>(__visitor), |
1010 | __element_by_index_or_cookie<__indices>( |
1011 | std::forward<_Variants>(__vars))..., |
1012 | integral_constant<size_t, __indices>()...); |
1013 | else if constexpr (is_same_v<_Result_type, __variant_cookie>) |
1014 | // For raw visitation without indices, and discard the return value: |
1015 | std::__invoke(std::forward<_Visitor>(__visitor), |
1016 | __element_by_index_or_cookie<__indices>( |
1017 | std::forward<_Variants>(__vars))...); |
1018 | else if constexpr (_Array_type::__result_is_deduced::value) |
1019 | // For the usual std::visit case deduce the return value: |
1020 | return std::__invoke(std::forward<_Visitor>(__visitor), |
1021 | __element_by_index_or_cookie<__indices>( |
1022 | std::forward<_Variants>(__vars))...); |
1023 | else // for std::visit<R> use INVOKE<R> |
1024 | return std::__invoke_r<_Result_type>( |
1025 | std::forward<_Visitor>(__visitor), |
1026 | __variant::__get<__indices>(std::forward<_Variants>(__vars))...); |
1027 | } |
1028 | |
1029 | static constexpr auto |
1030 | _S_apply() |
1031 | { return _Array_type{&__visit_invoke}; } |
1032 | }; |
1033 | |
1034 | template<typename _Result_type, typename _Visitor, typename... _Variants> |
1035 | struct __gen_vtable |
1036 | { |
1037 | using _Array_type = |
1038 | _Multi_array<_Result_type (*)(_Visitor, _Variants...), |
1039 | variant_size_v<remove_reference_t<_Variants>>...>; |
1040 | |
1041 | static constexpr _Array_type _S_vtable |
1042 | = __gen_vtable_impl<_Array_type, std::index_sequence<>>::_S_apply(); |
1043 | }; |
1044 | |
1045 | template<size_t _Np, typename _Tp> |
1046 | struct _Base_dedup : public _Tp { }; |
1047 | |
1048 | template<typename _Variant, typename __indices> |
1049 | struct _Variant_hash_base; |
1050 | |
1051 | template<typename... _Types, size_t... __indices> |
1052 | struct _Variant_hash_base<variant<_Types...>, |
1053 | std::index_sequence<__indices...>> |
1054 | : _Base_dedup<__indices, __poison_hash<remove_const_t<_Types>>>... { }; |
1055 | |
1056 | } // namespace __variant |
1057 | } // namespace __detail |
1058 | |
1059 | template<size_t _Np, typename _Variant, typename... _Args> |
1060 | void __variant_construct_by_index(_Variant& __v, _Args&&... __args) |
1061 | { |
1062 | __v._M_index = _Np; |
1063 | auto&& __storage = __detail::__variant::__get<_Np>(__v); |
1064 | ::new ((void*)std::addressof(__storage)) |
1065 | remove_reference_t<decltype(__storage)> |
1066 | (std::forward<_Args>(__args)...); |
1067 | } |
1068 | |
1069 | template<typename _Tp, typename... _Types> |
1070 | constexpr bool |
1071 | holds_alternative(const variant<_Types...>& __v) noexcept |
1072 | { |
1073 | static_assert(__detail::__variant::__exactly_once<_Tp, _Types...>, |
1074 | "T must occur exactly once in alternatives"); |
1075 | return __v.index() == __detail::__variant::__index_of_v<_Tp, _Types...>; |
1076 | } |
1077 | |
1078 | template<typename _Tp, typename... _Types> |
1079 | constexpr _Tp& get(variant<_Types...>& __v) |
1080 | { |
1081 | static_assert(__detail::__variant::__exactly_once<_Tp, _Types...>, |
1082 | "T must occur exactly once in alternatives"); |
1083 | static_assert(!is_void_v<_Tp>, "_Tp must not be void"); |
1084 | return std::get<__detail::__variant::__index_of_v<_Tp, _Types...>>(__v); |
1085 | } |
1086 | |
1087 | template<typename _Tp, typename... _Types> |
1088 | constexpr _Tp&& get(variant<_Types...>&& __v) |
1089 | { |
1090 | static_assert(__detail::__variant::__exactly_once<_Tp, _Types...>, |
1091 | "T must occur exactly once in alternatives"); |
1092 | static_assert(!is_void_v<_Tp>, "_Tp must not be void"); |
1093 | return std::get<__detail::__variant::__index_of_v<_Tp, _Types...>>( |
1094 | std::move(__v)); |
1095 | } |
1096 | |
1097 | template<typename _Tp, typename... _Types> |
1098 | constexpr const _Tp& get(const variant<_Types...>& __v) |
1099 | { |
1100 | static_assert(__detail::__variant::__exactly_once<_Tp, _Types...>, |
1101 | "T must occur exactly once in alternatives"); |
1102 | static_assert(!is_void_v<_Tp>, "_Tp must not be void"); |
1103 | return std::get<__detail::__variant::__index_of_v<_Tp, _Types...>>(__v); |
1104 | } |
1105 | |
1106 | template<typename _Tp, typename... _Types> |
1107 | constexpr const _Tp&& get(const variant<_Types...>&& __v) |
1108 | { |
1109 | static_assert(__detail::__variant::__exactly_once<_Tp, _Types...>, |
1110 | "T must occur exactly once in alternatives"); |
1111 | static_assert(!is_void_v<_Tp>, "_Tp must not be void"); |
1112 | return std::get<__detail::__variant::__index_of_v<_Tp, _Types...>>( |
1113 | std::move(__v)); |
1114 | } |
1115 | |
1116 | template<size_t _Np, typename... _Types> |
1117 | constexpr add_pointer_t<variant_alternative_t<_Np, variant<_Types...>>> |
1118 | get_if(variant<_Types...>* __ptr) noexcept |
1119 | { |
1120 | using _Alternative_type = variant_alternative_t<_Np, variant<_Types...>>; |
1121 | static_assert(_Np < sizeof...(_Types), |
1122 | "The index must be in [0, number of alternatives)"); |
1123 | static_assert(!is_void_v<_Alternative_type>, "_Tp must not be void"); |
1124 | if (__ptr && __ptr->index() == _Np) |
1125 | return std::addressof(__detail::__variant::__get<_Np>(*__ptr)); |
1126 | return nullptr; |
1127 | } |
1128 | |
1129 | template<size_t _Np, typename... _Types> |
1130 | constexpr |
1131 | add_pointer_t<const variant_alternative_t<_Np, variant<_Types...>>> |
1132 | get_if(const variant<_Types...>* __ptr) noexcept |
1133 | { |
1134 | using _Alternative_type = variant_alternative_t<_Np, variant<_Types...>>; |
1135 | static_assert(_Np < sizeof...(_Types), |
1136 | "The index must be in [0, number of alternatives)"); |
1137 | static_assert(!is_void_v<_Alternative_type>, "_Tp must not be void"); |
1138 | if (__ptr && __ptr->index() == _Np) |
1139 | return std::addressof(__detail::__variant::__get<_Np>(*__ptr)); |
1140 | return nullptr; |
1141 | } |
1142 | |
1143 | template<typename _Tp, typename... _Types> |
1144 | constexpr add_pointer_t<_Tp> |
1145 | get_if(variant<_Types...>* __ptr) noexcept |
1146 | { |
1147 | static_assert(__detail::__variant::__exactly_once<_Tp, _Types...>, |
1148 | "T must occur exactly once in alternatives"); |
1149 | static_assert(!is_void_v<_Tp>, "_Tp must not be void"); |
1150 | return std::get_if<__detail::__variant::__index_of_v<_Tp, _Types...>>( |
1151 | __ptr); |
1152 | } |
1153 | |
1154 | template<typename _Tp, typename... _Types> |
1155 | constexpr add_pointer_t<const _Tp> |
1156 | get_if(const variant<_Types...>* __ptr) noexcept |
1157 | { |
1158 | static_assert(__detail::__variant::__exactly_once<_Tp, _Types...>, |
1159 | "T must occur exactly once in alternatives"); |
1160 | static_assert(!is_void_v<_Tp>, "_Tp must not be void"); |
1161 | return std::get_if<__detail::__variant::__index_of_v<_Tp, _Types...>>( |
1162 | __ptr); |
1163 | } |
1164 | |
1165 | struct monostate { }; |
1166 | |
1167 | #define _VARIANT_RELATION_FUNCTION_TEMPLATE(__OP, __NAME) \ |
1168 | template<typename... _Types> \ |
1169 | constexpr bool operator __OP(const variant<_Types...>& __lhs, \ |
1170 | const variant<_Types...>& __rhs) \ |
1171 | { \ |
1172 | bool __ret = true; \ |
1173 | __detail::__variant::__raw_idx_visit( \ |
1174 | [&__ret, &__lhs] (auto&& __rhs_mem, auto __rhs_index) mutable \ |
1175 | { \ |
1176 | if constexpr (__rhs_index != variant_npos) \ |
1177 | { \ |
1178 | if (__lhs.index() == __rhs_index) \ |
1179 | { \ |
1180 | auto& __this_mem = std::get<__rhs_index>(__lhs); \ |
1181 | __ret = __this_mem __OP __rhs_mem; \ |
1182 | } \ |
1183 | else \ |
1184 | __ret = (__lhs.index() + 1) __OP (__rhs_index + 1); \ |
1185 | } \ |
1186 | else \ |
1187 | __ret = (__lhs.index() + 1) __OP (__rhs_index + 1); \ |
1188 | }, __rhs); \ |
1189 | return __ret; \ |
1190 | } |
1191 | |
1192 | _VARIANT_RELATION_FUNCTION_TEMPLATE(<, less) |
1193 | _VARIANT_RELATION_FUNCTION_TEMPLATE(<=, less_equal) |
1194 | _VARIANT_RELATION_FUNCTION_TEMPLATE(==, equal) |
1195 | _VARIANT_RELATION_FUNCTION_TEMPLATE(!=, not_equal) |
1196 | _VARIANT_RELATION_FUNCTION_TEMPLATE(>=, greater_equal) |
1197 | _VARIANT_RELATION_FUNCTION_TEMPLATE(>, greater) |
1198 | |
1199 | #undef _VARIANT_RELATION_FUNCTION_TEMPLATE |
1200 | |
1201 | constexpr bool operator==(monostate, monostate) noexcept { return true; } |
1202 | |
1203 | #ifdef __cpp_lib_three_way_comparison |
1204 | template<typename... _Types> |
1205 | requires (three_way_comparable<_Types> && ...) |
1206 | constexpr |
1207 | common_comparison_category_t<compare_three_way_result_t<_Types>...> |
1208 | operator<=>(const variant<_Types...>& __v, const variant<_Types...>& __w) |
1209 | { |
1210 | common_comparison_category_t<compare_three_way_result_t<_Types>...> __ret |
1211 | = strong_ordering::equal; |
1212 | |
1213 | __detail::__variant::__raw_idx_visit( |
1214 | [&__ret, &__v] (auto&& __w_mem, auto __w_index) mutable |
1215 | { |
1216 | if constexpr (__w_index != variant_npos) |
1217 | { |
1218 | if (__v.index() == __w_index) |
1219 | { |
1220 | auto& __this_mem = std::get<__w_index>(__v); |
1221 | __ret = __this_mem <=> __w_mem; |
1222 | return; |
1223 | } |
1224 | } |
1225 | __ret = (__v.index() + 1) <=> (__w_index + 1); |
1226 | }, __w); |
1227 | return __ret; |
1228 | } |
1229 | |
1230 | constexpr strong_ordering |
1231 | operator<=>(monostate, monostate) noexcept { return strong_ordering::equal; } |
1232 | #else |
1233 | constexpr bool operator!=(monostate, monostate) noexcept { return false; } |
1234 | constexpr bool operator<(monostate, monostate) noexcept { return false; } |
1235 | constexpr bool operator>(monostate, monostate) noexcept { return false; } |
1236 | constexpr bool operator<=(monostate, monostate) noexcept { return true; } |
1237 | constexpr bool operator>=(monostate, monostate) noexcept { return true; } |
1238 | #endif |
1239 | |
1240 | template<typename _Visitor, typename... _Variants> |
1241 | constexpr decltype(auto) visit(_Visitor&&, _Variants&&...); |
1242 | |
1243 | template<typename... _Types> |
1244 | inline enable_if_t<(is_move_constructible_v<_Types> && ...) |
1245 | && (is_swappable_v<_Types> && ...)> |
1246 | swap(variant<_Types...>& __lhs, variant<_Types...>& __rhs) |
1247 | noexcept(noexcept(__lhs.swap(__rhs))) |
1248 | { __lhs.swap(__rhs); } |
1249 | |
1250 | template<typename... _Types> |
1251 | enable_if_t<!((is_move_constructible_v<_Types> && ...) |
1252 | && (is_swappable_v<_Types> && ...))> |
1253 | swap(variant<_Types...>&, variant<_Types...>&) = delete; |
1254 | |
1255 | class bad_variant_access : public exception |
1256 | { |
1257 | public: |
1258 | bad_variant_access() noexcept { } |
1259 | |
1260 | const char* what() const noexcept override |
1261 | { return _M_reason; } |
1262 | |
1263 | private: |
1264 | bad_variant_access(const char* __reason) noexcept : _M_reason(__reason) { } |
1265 | |
1266 | // Must point to a string with static storage duration: |
1267 | const char* _M_reason = "bad variant access"; |
1268 | |
1269 | friend void __throw_bad_variant_access(const char* __what); |
1270 | }; |
1271 | |
1272 | // Must only be called with a string literal |
1273 | inline void |
1274 | __throw_bad_variant_access(const char* __what) |
1275 | { _GLIBCXX_THROW_OR_ABORT(bad_variant_access(__what))(__builtin_abort()); } |
1276 | |
1277 | inline void |
1278 | __throw_bad_variant_access(bool __valueless) |
1279 | { |
1280 | if (__valueless) [[__unlikely__]] |
1281 | __throw_bad_variant_access("std::get: variant is valueless"); |
1282 | else |
1283 | __throw_bad_variant_access("std::get: wrong index for variant"); |
1284 | } |
1285 | |
1286 | template<typename... _Types> |
1287 | class variant |
1288 | : private __detail::__variant::_Variant_base<_Types...>, |
1289 | private _Enable_default_constructor< |
1290 | __detail::__variant::_Traits<_Types...>::_S_default_ctor, |
1291 | variant<_Types...>>, |
1292 | private _Enable_copy_move< |
1293 | __detail::__variant::_Traits<_Types...>::_S_copy_ctor, |
1294 | __detail::__variant::_Traits<_Types...>::_S_copy_assign, |
1295 | __detail::__variant::_Traits<_Types...>::_S_move_ctor, |
1296 | __detail::__variant::_Traits<_Types...>::_S_move_assign, |
1297 | variant<_Types...>> |
1298 | { |
1299 | private: |
1300 | template <typename... _UTypes, typename _Tp> |
1301 | friend decltype(auto) __variant_cast(_Tp&&); |
1302 | template<size_t _Np, typename _Variant, typename... _Args> |
1303 | friend void __variant_construct_by_index(_Variant& __v, |
1304 | _Args&&... __args); |
1305 | |
1306 | static_assert(sizeof...(_Types) > 0, |
1307 | "variant must have at least one alternative"); |
1308 | static_assert(!(std::is_reference_v<_Types> || ...), |
1309 | "variant must have no reference alternative"); |
1310 | static_assert(!(std::is_void_v<_Types> || ...), |
1311 | "variant must have no void alternative"); |
1312 | |
1313 | using _Base = __detail::__variant::_Variant_base<_Types...>; |
1314 | using _Default_ctor_enabler = |
1315 | _Enable_default_constructor< |
1316 | __detail::__variant::_Traits<_Types...>::_S_default_ctor, |
1317 | variant<_Types...>>; |
1318 | |
1319 | template<typename _Tp> |
1320 | static constexpr bool __not_self |
1321 | = !is_same_v<__remove_cvref_t<_Tp>, variant>; |
1322 | |
1323 | template<typename _Tp> |
1324 | static constexpr bool |
1325 | __exactly_once = __detail::__variant::__exactly_once<_Tp, _Types...>; |
1326 | |
1327 | template<typename _Tp> |
1328 | static constexpr size_t __accepted_index |
1329 | = __detail::__variant::__accepted_index<_Tp, variant>::value; |
1330 | |
1331 | template<size_t _Np, typename = enable_if_t<(_Np < sizeof...(_Types))>> |
1332 | using __to_type = variant_alternative_t<_Np, variant>; |
1333 | |
1334 | template<typename _Tp, typename = enable_if_t<__not_self<_Tp>>> |
1335 | using __accepted_type = __to_type<__accepted_index<_Tp>>; |
1336 | |
1337 | template<typename _Tp> |
1338 | static constexpr size_t __index_of = |
1339 | __detail::__variant::__index_of_v<_Tp, _Types...>; |
1340 | |
1341 | using _Traits = __detail::__variant::_Traits<_Types...>; |
1342 | |
1343 | template<typename _Tp> |
1344 | struct __is_in_place_tag : false_type { }; |
1345 | template<typename _Tp> |
1346 | struct __is_in_place_tag<in_place_type_t<_Tp>> : true_type { }; |
1347 | template<size_t _Np> |
1348 | struct __is_in_place_tag<in_place_index_t<_Np>> : true_type { }; |
1349 | |
1350 | template<typename _Tp> |
1351 | static constexpr bool __not_in_place_tag |
1352 | = !__is_in_place_tag<__remove_cvref_t<_Tp>>::value; |
1353 | |
1354 | public: |
1355 | variant() = default; |
1356 | variant(const variant& __rhs) = default; |
1357 | variant(variant&&) = default; |
1358 | variant& operator=(const variant&) = default; |
1359 | variant& operator=(variant&&) = default; |
1360 | ~variant() = default; |
1361 | |
1362 | template<typename _Tp, |
1363 | typename = enable_if_t<sizeof...(_Types) != 0>, |
1364 | typename = enable_if_t<__not_in_place_tag<_Tp>>, |
1365 | typename _Tj = __accepted_type<_Tp&&>, |
1366 | typename = enable_if_t<__exactly_once<_Tj> |
1367 | && is_constructible_v<_Tj, _Tp>>> |
1368 | constexpr |
1369 | variant(_Tp&& __t) |
1370 | noexcept(is_nothrow_constructible_v<_Tj, _Tp>) |
1371 | : variant(in_place_index<__accepted_index<_Tp>>, |
1372 | std::forward<_Tp>(__t)) |
1373 | { } |
1374 | |
1375 | template<typename _Tp, typename... _Args, |
1376 | typename = enable_if_t<__exactly_once<_Tp> |
1377 | && is_constructible_v<_Tp, _Args...>>> |
1378 | constexpr explicit |
1379 | variant(in_place_type_t<_Tp>, _Args&&... __args) |
1380 | : variant(in_place_index<__index_of<_Tp>>, |
1381 | std::forward<_Args>(__args)...) |
1382 | { } |
1383 | |
1384 | template<typename _Tp, typename _Up, typename... _Args, |
1385 | typename = enable_if_t<__exactly_once<_Tp> |
1386 | && is_constructible_v<_Tp, |
1387 | initializer_list<_Up>&, _Args...>>> |
1388 | constexpr explicit |
1389 | variant(in_place_type_t<_Tp>, initializer_list<_Up> __il, |
1390 | _Args&&... __args) |
1391 | : variant(in_place_index<__index_of<_Tp>>, __il, |
1392 | std::forward<_Args>(__args)...) |
1393 | { } |
1394 | |
1395 | template<size_t _Np, typename... _Args, |
1396 | typename _Tp = __to_type<_Np>, |
1397 | typename = enable_if_t<is_constructible_v<_Tp, _Args...>>> |
1398 | constexpr explicit |
1399 | variant(in_place_index_t<_Np>, _Args&&... __args) |
1400 | : _Base(in_place_index<_Np>, std::forward<_Args>(__args)...), |
1401 | _Default_ctor_enabler(_Enable_default_constructor_tag{}) |
1402 | { } |
1403 | |
1404 | template<size_t _Np, typename _Up, typename... _Args, |
1405 | typename _Tp = __to_type<_Np>, |
1406 | typename = enable_if_t<is_constructible_v<_Tp, |
1407 | initializer_list<_Up>&, |
1408 | _Args...>>> |
1409 | constexpr explicit |
1410 | variant(in_place_index_t<_Np>, initializer_list<_Up> __il, |
1411 | _Args&&... __args) |
1412 | : _Base(in_place_index<_Np>, __il, std::forward<_Args>(__args)...), |
1413 | _Default_ctor_enabler(_Enable_default_constructor_tag{}) |
1414 | { } |
1415 | |
1416 | template<typename _Tp> |
1417 | enable_if_t<__exactly_once<__accepted_type<_Tp&&>> |
1418 | && is_constructible_v<__accepted_type<_Tp&&>, _Tp> |
1419 | && is_assignable_v<__accepted_type<_Tp&&>&, _Tp>, |
1420 | variant&> |
1421 | operator=(_Tp&& __rhs) |
1422 | noexcept(is_nothrow_assignable_v<__accepted_type<_Tp&&>&, _Tp> |
1423 | && is_nothrow_constructible_v<__accepted_type<_Tp&&>, _Tp>) |
1424 | { |
1425 | constexpr auto __index = __accepted_index<_Tp>; |
1426 | if (index() == __index) |
1427 | std::get<__index>(*this) = std::forward<_Tp>(__rhs); |
1428 | else |
1429 | { |
1430 | using _Tj = __accepted_type<_Tp&&>; |
1431 | if constexpr (is_nothrow_constructible_v<_Tj, _Tp> |
1432 | || !is_nothrow_move_constructible_v<_Tj>) |
1433 | this->emplace<__index>(std::forward<_Tp>(__rhs)); |
1434 | else |
1435 | operator=(variant(std::forward<_Tp>(__rhs))); |
1436 | } |
1437 | return *this; |
1438 | } |
1439 | |
1440 | template<typename _Tp, typename... _Args> |
1441 | enable_if_t<is_constructible_v<_Tp, _Args...> && __exactly_once<_Tp>, |
1442 | _Tp&> |
1443 | emplace(_Args&&... __args) |
1444 | { |
1445 | constexpr size_t __index = __index_of<_Tp>; |
1446 | return this->emplace<__index>(std::forward<_Args>(__args)...); |
1447 | } |
1448 | |
1449 | template<typename _Tp, typename _Up, typename... _Args> |
1450 | enable_if_t<is_constructible_v<_Tp, initializer_list<_Up>&, _Args...> |
1451 | && __exactly_once<_Tp>, |
1452 | _Tp&> |
1453 | emplace(initializer_list<_Up> __il, _Args&&... __args) |
1454 | { |
1455 | constexpr size_t __index = __index_of<_Tp>; |
1456 | return this->emplace<__index>(__il, std::forward<_Args>(__args)...); |
1457 | } |
1458 | |
1459 | template<size_t _Np, typename... _Args> |
1460 | enable_if_t<is_constructible_v<variant_alternative_t<_Np, variant>, |
1461 | _Args...>, |
1462 | variant_alternative_t<_Np, variant>&> |
1463 | emplace(_Args&&... __args) |
1464 | { |
1465 | static_assert(_Np < sizeof...(_Types), |
1466 | "The index must be in [0, number of alternatives)"); |
1467 | using type = variant_alternative_t<_Np, variant>; |
1468 | // Provide the strong exception-safety guarantee when possible, |
1469 | // to avoid becoming valueless. |
1470 | if constexpr (is_nothrow_constructible_v<type, _Args...>) |
1471 | { |
1472 | this->_M_reset(); |
1473 | __variant_construct_by_index<_Np>(*this, |
1474 | std::forward<_Args>(__args)...); |
1475 | } |
1476 | else if constexpr (is_scalar_v<type>) |
1477 | { |
1478 | // This might invoke a potentially-throwing conversion operator: |
1479 | const type __tmp(std::forward<_Args>(__args)...); |
1480 | // But these steps won't throw: |
1481 | this->_M_reset(); |
1482 | __variant_construct_by_index<_Np>(*this, __tmp); |
1483 | } |
1484 | else if constexpr (__detail::__variant::_Never_valueless_alt<type>() |
1485 | && _Traits::_S_move_assign) |
1486 | { |
1487 | // This construction might throw: |
1488 | variant __tmp(in_place_index<_Np>, |
1489 | std::forward<_Args>(__args)...); |
1490 | // But _Never_valueless_alt<type> means this won't: |
1491 | *this = std::move(__tmp); |
1492 | } |
1493 | else |
1494 | { |
1495 | // This case only provides the basic exception-safety guarantee, |
1496 | // i.e. the variant can become valueless. |
1497 | this->_M_reset(); |
1498 | __tryif (true) |
1499 | { |
1500 | __variant_construct_by_index<_Np>(*this, |
1501 | std::forward<_Args>(__args)...); |
1502 | } |
1503 | __catch (...)if (false) |
1504 | { |
1505 | this->_M_index = variant_npos; |
1506 | __throw_exception_again; |
1507 | } |
1508 | } |
1509 | return std::get<_Np>(*this); |
1510 | } |
1511 | |
1512 | template<size_t _Np, typename _Up, typename... _Args> |
1513 | enable_if_t<is_constructible_v<variant_alternative_t<_Np, variant>, |
1514 | initializer_list<_Up>&, _Args...>, |
1515 | variant_alternative_t<_Np, variant>&> |
1516 | emplace(initializer_list<_Up> __il, _Args&&... __args) |
1517 | { |
1518 | static_assert(_Np < sizeof...(_Types), |
1519 | "The index must be in [0, number of alternatives)"); |
1520 | using type = variant_alternative_t<_Np, variant>; |
1521 | // Provide the strong exception-safety guarantee when possible, |
1522 | // to avoid becoming valueless. |
1523 | if constexpr (is_nothrow_constructible_v<type, |
1524 | initializer_list<_Up>&, |
1525 | _Args...>) |
1526 | { |
1527 | this->_M_reset(); |
1528 | __variant_construct_by_index<_Np>(*this, __il, |
1529 | std::forward<_Args>(__args)...); |
1530 | } |
1531 | else if constexpr (__detail::__variant::_Never_valueless_alt<type>() |
1532 | && _Traits::_S_move_assign) |
1533 | { |
1534 | // This construction might throw: |
1535 | variant __tmp(in_place_index<_Np>, __il, |
1536 | std::forward<_Args>(__args)...); |
1537 | // But _Never_valueless_alt<type> means this won't: |
1538 | *this = std::move(__tmp); |
1539 | } |
1540 | else |
1541 | { |
1542 | // This case only provides the basic exception-safety guarantee, |
1543 | // i.e. the variant can become valueless. |
1544 | this->_M_reset(); |
1545 | __tryif (true) |
1546 | { |
1547 | __variant_construct_by_index<_Np>(*this, __il, |
1548 | std::forward<_Args>(__args)...); |
1549 | } |
1550 | __catch (...)if (false) |
1551 | { |
1552 | this->_M_index = variant_npos; |
1553 | __throw_exception_again; |
1554 | } |
1555 | } |
1556 | return std::get<_Np>(*this); |
1557 | } |
1558 | |
1559 | constexpr bool valueless_by_exception() const noexcept |
1560 | { return !this->_M_valid(); } |
1561 | |
1562 | constexpr size_t index() const noexcept |
1563 | { |
1564 | using __index_type = typename _Base::__index_type; |
1565 | if constexpr (__detail::__variant::__never_valueless<_Types...>()) |
1566 | return this->_M_index; |
1567 | else if constexpr (sizeof...(_Types) <= __index_type(-1) / 2) |
1568 | return make_signed_t<__index_type>(this->_M_index); |
1569 | else |
1570 | return size_t(__index_type(this->_M_index + 1)) - 1; |
1571 | } |
1572 | |
1573 | void |
1574 | swap(variant& __rhs) |
1575 | noexcept((__is_nothrow_swappable<_Types>::value && ...) |
1576 | && is_nothrow_move_constructible_v<variant>) |
1577 | { |
1578 | __detail::__variant::__raw_idx_visit( |
1579 | [this, &__rhs](auto&& __rhs_mem, auto __rhs_index) mutable |
1580 | { |
1581 | if constexpr (__rhs_index != variant_npos) |
1582 | { |
1583 | if (this->index() == __rhs_index) |
1584 | { |
1585 | auto& __this_mem = |
1586 | std::get<__rhs_index>(*this); |
1587 | using std::swap; |
1588 | swap(__this_mem, __rhs_mem); |
1589 | } |
1590 | else |
1591 | { |
1592 | if (!this->valueless_by_exception()) [[__likely__]] |
1593 | { |
1594 | auto __tmp(std::move(__rhs_mem)); |
1595 | __rhs = std::move(*this); |
1596 | this->_M_destructive_move(__rhs_index, |
1597 | std::move(__tmp)); |
1598 | } |
1599 | else |
1600 | { |
1601 | this->_M_destructive_move(__rhs_index, |
1602 | std::move(__rhs_mem)); |
1603 | __rhs._M_reset(); |
1604 | } |
1605 | } |
1606 | } |
1607 | else |
1608 | { |
1609 | if (!this->valueless_by_exception()) [[__likely__]] |
1610 | { |
1611 | __rhs = std::move(*this); |
1612 | this->_M_reset(); |
1613 | } |
1614 | } |
1615 | }, __rhs); |
1616 | } |
1617 | |
1618 | private: |
1619 | |
1620 | #if defined(__clang__1) && __clang_major__17 <= 7 |
1621 | public: |
1622 | using _Base::_M_u; // See https://bugs.llvm.org/show_bug.cgi?id=31852 |
1623 | private: |
1624 | #endif |
1625 | |
1626 | template<size_t _Np, typename _Vp> |
1627 | friend constexpr decltype(auto) |
1628 | __detail::__variant::__get(_Vp&& __v) noexcept; |
1629 | |
1630 | template<typename _Vp> |
1631 | friend void* |
1632 | __detail::__variant::__get_storage(_Vp&& __v) noexcept; |
1633 | |
1634 | #define _VARIANT_RELATION_FUNCTION_TEMPLATE(__OP) \ |
1635 | template<typename... _Tp> \ |
1636 | friend constexpr bool \ |
1637 | operator __OP(const variant<_Tp...>& __lhs, \ |
1638 | const variant<_Tp...>& __rhs); |
1639 | |
1640 | _VARIANT_RELATION_FUNCTION_TEMPLATE(<) |
1641 | _VARIANT_RELATION_FUNCTION_TEMPLATE(<=) |
1642 | _VARIANT_RELATION_FUNCTION_TEMPLATE(==) |
1643 | _VARIANT_RELATION_FUNCTION_TEMPLATE(!=) |
1644 | _VARIANT_RELATION_FUNCTION_TEMPLATE(>=) |
1645 | _VARIANT_RELATION_FUNCTION_TEMPLATE(>) |
1646 | |
1647 | #undef _VARIANT_RELATION_FUNCTION_TEMPLATE |
1648 | }; |
1649 | |
1650 | template<size_t _Np, typename... _Types> |
1651 | constexpr variant_alternative_t<_Np, variant<_Types...>>& |
1652 | get(variant<_Types...>& __v) |
1653 | { |
1654 | static_assert(_Np < sizeof...(_Types), |
1655 | "The index must be in [0, number of alternatives)"); |
1656 | if (__v.index() != _Np) |
1657 | __throw_bad_variant_access(__v.valueless_by_exception()); |
1658 | return __detail::__variant::__get<_Np>(__v); |
1659 | } |
1660 | |
1661 | template<size_t _Np, typename... _Types> |
1662 | constexpr variant_alternative_t<_Np, variant<_Types...>>&& |
1663 | get(variant<_Types...>&& __v) |
1664 | { |
1665 | static_assert(_Np < sizeof...(_Types), |
1666 | "The index must be in [0, number of alternatives)"); |
1667 | if (__v.index() != _Np) |
1668 | __throw_bad_variant_access(__v.valueless_by_exception()); |
1669 | return __detail::__variant::__get<_Np>(std::move(__v)); |
1670 | } |
1671 | |
1672 | template<size_t _Np, typename... _Types> |
1673 | constexpr const variant_alternative_t<_Np, variant<_Types...>>& |
1674 | get(const variant<_Types...>& __v) |
1675 | { |
1676 | static_assert(_Np < sizeof...(_Types), |
1677 | "The index must be in [0, number of alternatives)"); |
1678 | if (__v.index() != _Np) |
1679 | __throw_bad_variant_access(__v.valueless_by_exception()); |
1680 | return __detail::__variant::__get<_Np>(__v); |
1681 | } |
1682 | |
1683 | template<size_t _Np, typename... _Types> |
1684 | constexpr const variant_alternative_t<_Np, variant<_Types...>>&& |
1685 | get(const variant<_Types...>&& __v) |
1686 | { |
1687 | static_assert(_Np < sizeof...(_Types), |
1688 | "The index must be in [0, number of alternatives)"); |
1689 | if (__v.index() != _Np) |
1690 | __throw_bad_variant_access(__v.valueless_by_exception()); |
1691 | return __detail::__variant::__get<_Np>(std::move(__v)); |
1692 | } |
1693 | |
1694 | template<typename _Result_type, typename _Visitor, typename... _Variants> |
1695 | constexpr decltype(auto) |
1696 | __do_visit(_Visitor&& __visitor, _Variants&&... __variants) |
1697 | { |
1698 | constexpr auto& __vtable = __detail::__variant::__gen_vtable< |
1699 | _Result_type, _Visitor&&, _Variants&&...>::_S_vtable; |
1700 | |
1701 | auto __func_ptr = __vtable._M_access(__variants.index()...); |
1702 | return (*__func_ptr)(std::forward<_Visitor>(__visitor), |
1703 | std::forward<_Variants>(__variants)...); |
1704 | } |
1705 | |
1706 | template<typename _Visitor, typename... _Variants> |
1707 | constexpr decltype(auto) |
1708 | visit(_Visitor&& __visitor, _Variants&&... __variants) |
1709 | { |
1710 | if ((__variants.valueless_by_exception() || ...)) |
1711 | __throw_bad_variant_access("std::visit: variant is valueless"); |
1712 | |
1713 | using _Result_type = std::invoke_result_t<_Visitor, |
1714 | decltype(std::get<0>(std::declval<_Variants>()))...>; |
1715 | |
1716 | using _Tag = __detail::__variant::__deduce_visit_result<_Result_type>; |
1717 | |
1718 | return std::__do_visit<_Tag>(std::forward<_Visitor>(__visitor), |
1719 | std::forward<_Variants>(__variants)...); |
1720 | } |
1721 | |
1722 | #if __cplusplus201703L > 201703L |
1723 | template<typename _Res, typename _Visitor, typename... _Variants> |
1724 | constexpr _Res |
1725 | visit(_Visitor&& __visitor, _Variants&&... __variants) |
1726 | { |
1727 | if ((__variants.valueless_by_exception() || ...)) |
1728 | __throw_bad_variant_access("std::visit<R>: variant is valueless"); |
1729 | |
1730 | return std::__do_visit<_Res>(std::forward<_Visitor>(__visitor), |
1731 | std::forward<_Variants>(__variants)...); |
1732 | } |
1733 | #endif |
1734 | |
1735 | template<bool, typename... _Types> |
1736 | struct __variant_hash_call_base_impl |
1737 | { |
1738 | size_t |
1739 | operator()(const variant<_Types...>& __t) const |
1740 | noexcept((is_nothrow_invocable_v<hash<decay_t<_Types>>, _Types> && ...)) |
1741 | { |
1742 | size_t __ret; |
1743 | __detail::__variant::__raw_visit( |
1744 | [&__t, &__ret](auto&& __t_mem) mutable |
1745 | { |
1746 | using _Type = __remove_cvref_t<decltype(__t_mem)>; |
1747 | if constexpr (!is_same_v<_Type, |
1748 | __detail::__variant::__variant_cookie>) |
1749 | __ret = std::hash<size_t>{}(__t.index()) |
1750 | + std::hash<_Type>{}(__t_mem); |
1751 | else |
1752 | __ret = std::hash<size_t>{}(__t.index()); |
1753 | }, __t); |
1754 | return __ret; |
1755 | } |
1756 | }; |
1757 | |
1758 | template<typename... _Types> |
1759 | struct __variant_hash_call_base_impl<false, _Types...> {}; |
1760 | |
1761 | template<typename... _Types> |
1762 | using __variant_hash_call_base = |
1763 | __variant_hash_call_base_impl<(__poison_hash<remove_const_t<_Types>>:: |
1764 | __enable_hash_call &&...), _Types...>; |
1765 | |
1766 | template<typename... _Types> |
1767 | struct hash<variant<_Types...>> |
1768 | : private __detail::__variant::_Variant_hash_base< |
1769 | variant<_Types...>, std::index_sequence_for<_Types...>>, |
1770 | public __variant_hash_call_base<_Types...> |
1771 | { |
1772 | using result_type [[__deprecated__]] = size_t; |
1773 | using argument_type [[__deprecated__]] = variant<_Types...>; |
1774 | }; |
1775 | |
1776 | template<> |
1777 | struct hash<monostate> |
1778 | { |
1779 | using result_type [[__deprecated__]] = size_t; |
1780 | using argument_type [[__deprecated__]] = monostate; |
1781 | |
1782 | size_t |
1783 | operator()(const monostate&) const noexcept |
1784 | { |
1785 | constexpr size_t __magic_monostate_hash = -7777; |
1786 | return __magic_monostate_hash; |
1787 | } |
1788 | }; |
1789 | |
1790 | template<typename... _Types> |
1791 | struct __is_fast_hash<hash<variant<_Types...>>> |
1792 | : bool_constant<(__is_fast_hash<_Types>::value && ...)> |
1793 | { }; |
1794 | |
1795 | _GLIBCXX_END_NAMESPACE_VERSION |
1796 | } // namespace std |
1797 | |
1798 | #endif // C++17 |
1799 | |
1800 | #endif // _GLIBCXX_VARIANT |
1 | //===-- include/flang/Common/indirection.h ----------------------*- 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 | #ifndef FORTRAN_COMMON_INDIRECTION_H_ | |||
10 | #define FORTRAN_COMMON_INDIRECTION_H_ | |||
11 | ||||
12 | // Define a smart pointer class template that is rather like | |||
13 | // non-nullable std::unique_ptr<>. Indirection<> is, like a C++ reference | |||
14 | // type, restricted to be non-null when constructed or assigned. | |||
15 | // Indirection<> optionally supports copy construction and copy assignment. | |||
16 | // | |||
17 | // To use Indirection<> with forward-referenced types, add | |||
18 | // extern template class Fortran::common::Indirection<FORWARD_TYPE>; | |||
19 | // outside any namespace in a header before use, and | |||
20 | // template class Fortran::common::Indirection<FORWARD_TYPE>; | |||
21 | // in one C++ source file later where a definition of the type is visible. | |||
22 | ||||
23 | #include "idioms.h" | |||
24 | #include <memory> | |||
25 | #include <type_traits> | |||
26 | #include <utility> | |||
27 | ||||
28 | namespace Fortran::common { | |||
29 | ||||
30 | // The default case does not support (deep) copy construction or assignment. | |||
31 | template <typename A, bool COPY = false> class Indirection { | |||
32 | public: | |||
33 | using element_type = A; | |||
34 | Indirection() = delete; | |||
35 | Indirection(A *&&p) : p_{p} { | |||
36 | CHECK(p_ && "assigning null pointer to Indirection")((p_ && "assigning null pointer to Indirection") || ( Fortran::common::die("CHECK(" "p_ && \"assigning null pointer to Indirection\"" ") failed" " at " "flang/include/flang/Common/indirection.h" "(%d)", 36), false)); | |||
37 | p = nullptr; | |||
38 | } | |||
39 | Indirection(A &&x) : p_{new A(std::move(x))} {} | |||
40 | Indirection(Indirection &&that) : p_{that.p_} { | |||
41 | CHECK(p_ && "move construction of Indirection from null Indirection")((p_ && "move construction of Indirection from null Indirection" ) || (Fortran::common::die("CHECK(" "p_ && \"move construction of Indirection from null Indirection\"" ") failed" " at " "flang/include/flang/Common/indirection.h" "(%d)", 41), false)); | |||
42 | that.p_ = nullptr; | |||
43 | } | |||
44 | ~Indirection() { | |||
45 | delete p_; | |||
46 | p_ = nullptr; | |||
47 | } | |||
48 | Indirection &operator=(Indirection &&that) { | |||
49 | CHECK(that.p_ && "move assignment of null Indirection to Indirection")((that.p_ && "move assignment of null Indirection to Indirection" ) || (Fortran::common::die("CHECK(" "that.p_ && \"move assignment of null Indirection to Indirection\"" ") failed" " at " "flang/include/flang/Common/indirection.h" "(%d)", 49), false)); | |||
50 | auto tmp{p_}; | |||
51 | p_ = that.p_; | |||
52 | that.p_ = tmp; | |||
53 | return *this; | |||
54 | } | |||
55 | ||||
56 | A &value() { return *p_; } | |||
57 | const A &value() const { return *p_; } | |||
58 | ||||
59 | bool operator==(const A &that) const { return *p_ == that; } | |||
60 | bool operator==(const Indirection &that) const { return *p_ == *that.p_; } | |||
61 | ||||
62 | template <typename... ARGS> | |||
63 | static common::IfNoLvalue<Indirection, ARGS...> Make(ARGS &&...args) { | |||
64 | return {new A(std::move(args)...)}; | |||
65 | } | |||
66 | ||||
67 | private: | |||
68 | A *p_{nullptr}; | |||
69 | }; | |||
70 | ||||
71 | // Variant with copy construction and assignment | |||
72 | template <typename A> class Indirection<A, true> { | |||
73 | public: | |||
74 | using element_type = A; | |||
75 | ||||
76 | Indirection() = delete; | |||
77 | Indirection(A *&&p) : p_{p} { | |||
78 | CHECK(p_ && "assigning null pointer to Indirection")((p_ && "assigning null pointer to Indirection") || ( Fortran::common::die("CHECK(" "p_ && \"assigning null pointer to Indirection\"" ") failed" " at " "flang/include/flang/Common/indirection.h" "(%d)", 78), false)); | |||
79 | p = nullptr; | |||
80 | } | |||
81 | Indirection(const A &x) : p_{new A(x)} {} | |||
82 | Indirection(A &&x) : p_{new A(std::move(x))} {} | |||
83 | Indirection(const Indirection &that) { | |||
84 | CHECK(that.p_ && "copy construction of Indirection from null Indirection")((that.p_ && "copy construction of Indirection from null Indirection" ) || (Fortran::common::die("CHECK(" "that.p_ && \"copy construction of Indirection from null Indirection\"" ") failed" " at " "flang/include/flang/Common/indirection.h" "(%d)", 84), false)); | |||
85 | p_ = new A(*that.p_); | |||
86 | } | |||
87 | Indirection(Indirection &&that) : p_{that.p_} { | |||
| ||||
88 | CHECK(p_ && "move construction of Indirection from null Indirection")((p_ && "move construction of Indirection from null Indirection" ) || (Fortran::common::die("CHECK(" "p_ && \"move construction of Indirection from null Indirection\"" ") failed" " at " "flang/include/flang/Common/indirection.h" "(%d)", 88), false)); | |||
89 | that.p_ = nullptr; | |||
90 | } | |||
91 | ~Indirection() { | |||
92 | delete p_; | |||
93 | p_ = nullptr; | |||
94 | } | |||
95 | Indirection &operator=(const Indirection &that) { | |||
96 | CHECK(that.p_ && "copy assignment of Indirection from null Indirection")((that.p_ && "copy assignment of Indirection from null Indirection" ) || (Fortran::common::die("CHECK(" "that.p_ && \"copy assignment of Indirection from null Indirection\"" ") failed" " at " "flang/include/flang/Common/indirection.h" "(%d)", 96), false)); | |||
97 | *p_ = *that.p_; | |||
98 | return *this; | |||
99 | } | |||
100 | Indirection &operator=(Indirection &&that) { | |||
101 | CHECK(that.p_ && "move assignment of null Indirection to Indirection")((that.p_ && "move assignment of null Indirection to Indirection" ) || (Fortran::common::die("CHECK(" "that.p_ && \"move assignment of null Indirection to Indirection\"" ") failed" " at " "flang/include/flang/Common/indirection.h" "(%d)", 101), false)); | |||
102 | auto tmp{p_}; | |||
103 | p_ = that.p_; | |||
104 | that.p_ = tmp; | |||
105 | return *this; | |||
106 | } | |||
107 | ||||
108 | A &value() { return *p_; } | |||
109 | const A &value() const { return *p_; } | |||
110 | ||||
111 | bool operator==(const A &that) const { return *p_ == that; } | |||
112 | bool operator==(const Indirection &that) const { return *p_ == *that.p_; } | |||
113 | ||||
114 | template <typename... ARGS> | |||
115 | static common::IfNoLvalue<Indirection, ARGS...> Make(ARGS &&...args) { | |||
116 | return {new A(std::move(args)...)}; | |||
117 | } | |||
118 | ||||
119 | private: | |||
120 | A *p_{nullptr}; | |||
121 | }; | |||
122 | ||||
123 | template <typename A> using CopyableIndirection = Indirection<A, true>; | |||
124 | ||||
125 | // A variation of std::unique_ptr<> with a reified deletion routine. | |||
126 | // Used to avoid dependence cycles between shared libraries. | |||
127 | template <typename A> class ForwardOwningPointer { | |||
128 | public: | |||
129 | ForwardOwningPointer() {} | |||
130 | ForwardOwningPointer(A *p, void (*del)(A *)) : p_{p}, deleter_{del} {} | |||
131 | ForwardOwningPointer(ForwardOwningPointer &&that) | |||
132 | : p_{that.p_}, deleter_{that.deleter_} { | |||
133 | that.p_ = nullptr; | |||
134 | } | |||
135 | ForwardOwningPointer &operator=(ForwardOwningPointer &&that) { | |||
136 | p_ = that.p_; | |||
137 | that.p_ = nullptr; | |||
138 | deleter_ = that.deleter_; | |||
139 | return *this; | |||
140 | } | |||
141 | ~ForwardOwningPointer() { | |||
142 | if (p_) { | |||
143 | deleter_(p_); | |||
144 | } | |||
145 | } | |||
146 | ||||
147 | A &operator*() const { return *p_; } | |||
148 | A *operator->() const { return p_; } | |||
149 | operator bool() const { return p_ != nullptr; } | |||
150 | A *get() { return p_; } | |||
151 | A *release() { | |||
152 | A *result{p_}; | |||
153 | p_ = nullptr; | |||
154 | return result; | |||
155 | } | |||
156 | ||||
157 | void Reset(A *p = nullptr) { | |||
158 | if (p_) { | |||
159 | deleter_(p_); | |||
160 | } | |||
161 | p_ = p; | |||
162 | } | |||
163 | void Reset(A *p, void (*del)(A *)) { | |||
164 | Reset(p); | |||
165 | deleter_ = del; | |||
166 | } | |||
167 | ||||
168 | private: | |||
169 | A *p_{nullptr}; | |||
170 | void (*deleter_)(A *){nullptr}; | |||
171 | }; | |||
172 | } // namespace Fortran::common | |||
173 | #endif // FORTRAN_COMMON_INDIRECTION_H_ |