Warning: This file is not a C or C++ file. It does not have highlighting.
1 | //===-- include/flang/Common/unwrap.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_UNWRAP_H_ |
10 | #define FORTRAN_COMMON_UNWRAP_H_ |
11 | |
12 | #include "indirection.h" |
13 | #include "reference-counted.h" |
14 | #include "reference.h" |
15 | #include "variant.h" |
16 | #include "visit.h" |
17 | #include <memory> |
18 | #include <optional> |
19 | #include <type_traits> |
20 | |
21 | // Given a nest of variants, optionals, &/or pointers, Unwrap<>() isolates |
22 | // a packaged value of a specific type if it is present and returns a pointer |
23 | // thereto; otherwise, it returns a null pointer. It's analogous to |
24 | // std::get_if<>() but it accepts a reference argument and is recursive. |
25 | // The target type parameter cannot be omitted. |
26 | // |
27 | // Be advised: If the target type parameter is not const-qualified, but the |
28 | // isolated value is const-qualified, the result of Unwrap<> will be a |
29 | // pointer to a const-qualified value. |
30 | // |
31 | // Further: const-qualified alternatives in instances of non-const-qualified |
32 | // variants will not be returned from Unwrap if the target type is not |
33 | // const-qualified. |
34 | // |
35 | // UnwrapCopy<>() is a variation of Unwrap<>() that returns an optional copy |
36 | // of the value if one is present with the desired type. |
37 | |
38 | namespace Fortran::common { |
39 | |
40 | // Utility: Produces "const A" if B is const and A is not already so. |
41 | template <typename A, typename B> |
42 | using Constify = std::conditional_t<std::is_const_v<B> && !std::is_const_v<A>, |
43 | std::add_const_t<A>, A>; |
44 | |
45 | // Unwrap's mutually-recursive template functions are packaged in a struct |
46 | // to avoid a need for prototypes. |
47 | struct UnwrapperHelper { |
48 | |
49 | // Base case |
50 | template <typename A, typename B> |
51 | static auto Unwrap(B &x) -> Constify<A, B> * { |
52 | if constexpr (std::is_same_v<std::decay_t<A>, std::decay_t<B>>) { |
53 | return &x; |
54 | } else { |
55 | return nullptr; |
56 | } |
57 | } |
58 | |
59 | // Implementations of specializations |
60 | template <typename A, typename B> |
61 | static auto Unwrap(B *p) -> Constify<A, B> * { |
62 | if (p) { |
63 | return Unwrap<A>(*p); |
64 | } else { |
65 | return nullptr; |
66 | } |
67 | } |
68 | |
69 | template <typename A, typename B> |
70 | static auto Unwrap(const std::unique_ptr<B> &p) -> Constify<A, B> * { |
71 | if (p.get()) { |
72 | return Unwrap<A>(*p); |
73 | } else { |
74 | return nullptr; |
75 | } |
76 | } |
77 | |
78 | template <typename A, typename B> |
79 | static auto Unwrap(const std::shared_ptr<B> &p) -> Constify<A, B> * { |
80 | if (p.get()) { |
81 | return Unwrap<A>(*p); |
82 | } else { |
83 | return nullptr; |
84 | } |
85 | } |
86 | |
87 | template <typename A, typename B> |
88 | static auto Unwrap(std::optional<B> &x) -> Constify<A, B> * { |
89 | if (x) { |
90 | return Unwrap<A>(*x); |
91 | } else { |
92 | return nullptr; |
93 | } |
94 | } |
95 | |
96 | template <typename A, typename B> |
97 | static auto Unwrap(const std::optional<B> &x) -> Constify<A, B> * { |
98 | if (x) { |
99 | return Unwrap<A>(*x); |
100 | } else { |
101 | return nullptr; |
102 | } |
103 | } |
104 | |
105 | template <typename A, typename... Bs> |
106 | static A *Unwrap(std::variant<Bs...> &u) { |
107 | return common::visit( |
108 | [](auto &x) -> A * { |
109 | using Ty = std::decay_t<decltype(Unwrap<A>(x))>; |
110 | if constexpr (!std::is_const_v<std::remove_pointer_t<Ty>> || |
111 | std::is_const_v<A>) { |
112 | return Unwrap<A>(x); |
113 | } |
114 | return nullptr; |
115 | }, |
116 | u); |
117 | } |
118 | |
119 | template <typename A, typename... Bs> |
120 | static auto Unwrap(const std::variant<Bs...> &u) -> std::add_const_t<A> * { |
121 | return common::visit( |
122 | [](const auto &x) -> std::add_const_t<A> * { return Unwrap<A>(x); }, u); |
123 | } |
124 | |
125 | template <typename A, typename B> |
126 | static auto Unwrap(const Reference<B> &ref) -> Constify<A, B> * { |
127 | return Unwrap<A>(*ref); |
128 | } |
129 | |
130 | template <typename A, typename B, bool COPY> |
131 | static auto Unwrap(const Indirection<B, COPY> &p) -> Constify<A, B> * { |
132 | return Unwrap<A>(p.value()); |
133 | } |
134 | |
135 | template <typename A, typename B> |
136 | static auto Unwrap(const CountedReference<B> &p) -> Constify<A, B> * { |
137 | if (p.get()) { |
138 | return Unwrap<A>(*p); |
139 | } else { |
140 | return nullptr; |
141 | } |
142 | } |
143 | }; |
144 | |
145 | template <typename A, typename B> auto Unwrap(B &x) -> Constify<A, B> * { |
146 | return UnwrapperHelper::Unwrap<A>(x); |
147 | } |
148 | |
149 | // Returns a copy of a wrapped value, if present, otherwise a vacant optional. |
150 | template <typename A, typename B> std::optional<A> UnwrapCopy(const B &x) { |
151 | if (const A * p{Unwrap<A>(x)}) { |
152 | return std::make_optional<A>(*p); |
153 | } else { |
154 | return std::nullopt; |
155 | } |
156 | } |
157 | } // namespace Fortran::common |
158 | #endif // FORTRAN_COMMON_UNWRAP_H_ |
159 |
Warning: This file is not a C or C++ file. It does not have highlighting.