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