Warning: This file is not a C or C++ file. It does not have highlighting.

1//===-- include/flang/Common/optional.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// Implementation of std::optional borrowed from LLVM's
10// libc/src/__support/CPP/optional.h with modifications (e.g. value_or, emplace
11// methods were added).
12//
13// The implementation defines optional in Fortran::common namespace.
14// This standalone implementation may be used if the target
15// does not support std::optional implementation (e.g. CUDA device env),
16// otherwise, Fortran::common::optional is an alias for std::optional.
17//
18// TODO: using libcu++ is the best option for CUDA, but there is a couple
19// of issues:
20// * Older CUDA toolkits' libcu++ implementations do not support optional.
21// * The include paths need to be set up such that all STD header files
22// are taken from libcu++.
23// * cuda:: namespace need to be forced for all std:: references.
24//
25//===----------------------------------------------------------------------===//
26#ifndef FORTRAN_COMMON_OPTIONAL_H
27#define FORTRAN_COMMON_OPTIONAL_H
28
29#include "flang/Common/api-attrs.h"
30#include <optional>
31#include <type_traits>
32
33#if !defined(STD_OPTIONAL_UNSUPPORTED) && \
34 (defined(__CUDACC__) || defined(__CUDA__)) && defined(__CUDA_ARCH__)
35#define STD_OPTIONAL_UNSUPPORTED 1
36#endif
37
38#define FORTRAN_OPTIONAL_INLINE_WITH_ATTRS inline RT_API_ATTRS
39#define FORTRAN_OPTIONAL_INLINE inline
40#define FORTRAN_OPTIONAL_INLINE_VAR inline
41
42namespace Fortran::common {
43
44#if STD_OPTIONAL_UNSUPPORTED
45// Trivial nullopt_t struct.
46struct nullopt_t {
47 constexpr explicit nullopt_t() = default;
48};
49
50// nullopt that can be used and returned.
51FORTRAN_OPTIONAL_INLINE_VAR constexpr nullopt_t nullopt{};
52
53// This is very simple implementation of the std::optional class. It makes
54// several assumptions that the underlying type is trivially constructible,
55// copyable, or movable.
56template <typename T> class optional {
57 template <typename U, bool = !std::is_trivially_destructible<U>::value>
58 struct OptionalStorage {
59 union {
60 char empty;
61 U stored_value;
62 };
63
64 bool in_use = false;
65
66 FORTRAN_OPTIONAL_INLINE_WITH_ATTRS ~OptionalStorage() { reset(); }
67
68 FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr OptionalStorage() : empty() {}
69
70 template <typename... Args>
71 FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr explicit OptionalStorage(
72 std::in_place_t, Args &&...args)
73 : stored_value(std::forward<Args>(args)...) {}
74
75 FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr void reset() {
76 if (in_use)
77 stored_value.~U();
78 in_use = false;
79 }
80 };
81
82 // The only difference is that this type U doesn't have a nontrivial
83 // destructor.
84 template <typename U> struct OptionalStorage<U, false> {
85 union {
86 char empty;
87 U stored_value;
88 };
89
90 bool in_use = false;
91
92 FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr OptionalStorage() : empty() {}
93
94 template <typename... Args>
95 FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr explicit OptionalStorage(
96 std::in_place_t, Args &&...args)
97 : stored_value(std::forward<Args>(args)...) {}
98
99 FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr void reset() {
100 in_use = false;
101 }
102 };
103
104 OptionalStorage<T> storage;
105
106public:
107 // The default methods do not use RT_API_ATTRS, which causes
108 // warnings in CUDA compilation of form:
109 // __device__/__host__ annotation is ignored on a function .* that is
110 // explicitly defaulted on its first declaration
111 FORTRAN_OPTIONAL_INLINE constexpr optional() = default;
112 FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr optional(nullopt_t) {}
113
114 FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr optional(const T &t)
115 : storage(std::in_place, t) {
116 storage.in_use = true;
117 }
118 FORTRAN_OPTIONAL_INLINE constexpr optional(const optional &) = default;
119
120 FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr optional(T &&t)
121 : storage(std::in_place, std::move(t)) {
122 storage.in_use = true;
123 }
124 FORTRAN_OPTIONAL_INLINE constexpr optional(optional &&O) = default;
125
126 template <typename... ArgTypes>
127 FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr optional(
128 std::in_place_t, ArgTypes &&...Args)
129 : storage(std::in_place, std::forward<ArgTypes>(Args)...) {
130 storage.in_use = true;
131 }
132
133 FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr optional &operator=(T &&t) {
134 storage.stored_value = std::move(t);
135 storage.in_use = true;
136 return *this;
137 }
138
139 FORTRAN_OPTIONAL_INLINE constexpr optional &operator=(optional &&) = default;
140
141 FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr optional &operator=(const T &t) {
142 storage.stored_value = t;
143 storage.in_use = true;
144 return *this;
145 }
146
147 FORTRAN_OPTIONAL_INLINE constexpr optional &operator=(
148 const optional &) = default;
149
150 FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr void reset() { storage.reset(); }
151
152 FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr const T &value() const & {
153 return storage.stored_value;
154 }
155
156 FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr T &value() & {
157 return storage.stored_value;
158 }
159
160 FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr explicit operator bool() const {
161 return storage.in_use;
162 }
163 FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr bool has_value() const {
164 return storage.in_use;
165 }
166 FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr const T *operator->() const {
167 return &storage.stored_value;
168 }
169 FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr T *operator->() {
170 return &storage.stored_value;
171 }
172 FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr const T &operator*() const & {
173 return storage.stored_value;
174 }
175 FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr T &operator*() & {
176 return storage.stored_value;
177 }
178
179 FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr T &&value() && {
180 return std::move(storage.stored_value);
181 }
182 FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr T &&operator*() && {
183 return std::move(storage.stored_value);
184 }
185
186 template <typename VT>
187 FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr T value_or(
188 VT &&default_value) const & {
189 return storage.in_use ? storage.stored_value
190 : static_cast<T>(std::forward<VT>(default_value));
191 }
192
193 template <typename VT>
194 FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr T value_or(
195 VT &&default_value) && {
196 return storage.in_use ? std::move(storage.stored_value)
197 : static_cast<T>(std::forward<VT>(default_value));
198 }
199
200 template <typename... ArgTypes>
201 FORTRAN_OPTIONAL_INLINE_WITH_ATTRS
202 std::enable_if_t<std::is_constructible_v<T, ArgTypes &&...>, T &>
203 emplace(ArgTypes &&...args) {
204 reset();
205 new (reinterpret_cast<void *>(std::addressof(storage.stored_value)))
206 T(std::forward<ArgTypes>(args)...);
207 storage.in_use = true;
208 return value();
209 }
210
211 template <typename U = T,
212 std::enable_if_t<(std::is_constructible_v<T, U &&> &&
213 !std::is_same_v<std::decay_t<U>, std::in_place_t> &&
214 !std::is_same_v<std::decay_t<U>, optional> &&
215 std::is_convertible_v<U &&, T>),
216 bool> = true>
217 FORTRAN_OPTIONAL_INLINE_WITH_ATTRS constexpr optional(U &&value) {
218 new (reinterpret_cast<void *>(std::addressof(storage.stored_value)))
219 T(std::forward<U>(value));
220 storage.in_use = true;
221 }
222
223 template <typename U = T,
224 std::enable_if_t<(std::is_constructible_v<T, U &&> &&
225 !std::is_same_v<std::decay_t<U>, std::in_place_t> &&
226 !std::is_same_v<std::decay_t<U>, optional> &&
227 !std::is_convertible_v<U &&, T>),
228 bool> = false>
229 FORTRAN_OPTIONAL_INLINE_WITH_ATTRS explicit constexpr optional(U &&value) {
230 new (reinterpret_cast<void *>(std::addressof(storage.stored_value)))
231 T(std::forward<U>(value));
232 storage.in_use = true;
233 }
234};
235#else // !STD_OPTIONAL_UNSUPPORTED
236using std::nullopt;
237using std::nullopt_t;
238using std::optional;
239#endif // !STD_OPTIONAL_UNSUPPORTED
240
241} // namespace Fortran::common
242
243#endif // FORTRAN_COMMON_OPTIONAL_H
244

Warning: This file is not a C or C++ file. It does not have highlighting.

source code of flang/include/flang/Common/optional.h