Require target lra in gcc.dg/pr108095.c
[official-gcc.git] / gcc / rust / util / rust-optional.h
blobd7349820b3877f1b27237d2870fa553d4cf31cca
1 // Copyright (C) 2020-2023 Free Software Foundation, Inc.
3 // This file is part of GCC.
5 // GCC is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU General Public License as published by the Free
7 // Software Foundation; either version 3, or (at your option) any later
8 // version.
10 // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 // for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with GCC; see the file COPYING3. If not see
17 // <http://www.gnu.org/licenses/>.
19 #ifndef RUST_OPTIONAL_H
20 #define RUST_OPTIONAL_H
22 #include "config.h"
23 #include "rust-system.h"
25 #include "selftest.h"
27 namespace Rust {
29 /**
30 * Tagged union to try and simulate a sum type. This is safer and more ergonomic
31 * than one of the two alternatives we're currently using in the compiler:
33 * 1. Storing a raw pointer, which can be `nullptr` or valid
35 * This is wildly unsafe, and usable in conjunction with local references, stack
36 * variables, or pointers managed elsewhere, which can cause crashes, hard to
37 * debug issues or undefined behavior. Likewise, if you do not check for the
38 * pointer's validity, this will cause a crash.
40 * 2. Storing an extra boolean alongside the object
42 * This causes implementors to use a "dummy object": Either an empty version or
43 * an error version. But what happens if what you really wanted to store was
44 * the empty or error version? You can also easily incorporate logic bugs if you
45 * forget to check for the associated boolean.
47 * The `Optional<T>` type has the same "ergonomic" cost: You need to check
48 * whether your option is valid or not. However, the main advantage is that it
49 * is more restrictive: You can only acess the member it contains "safely".
50 * It is similar to storing a value + an associated boolean, but has the
51 * advantage of making up only one member in your class.
52 * You also benefit from some helper methods such as `map()`.
54 * You also get helper functions and operator overloading to "seamlessly"
55 * replace raw pointer alternatives.
57 * ```c++
58 * MyType *raw_pointer = something_that_can_fail();
59 * if (raw_pointer)
60 * raw_pointer->method();
62 * // or
64 * Optional<MyType> opt = something_that_can_fail2();
65 * if (opt)
66 * opt->method();
68 * // equivalent to
70 * if (opt.is_some())
71 * opt.get().method();
72 * ```
74 template <typename T> class Optional
76 private:
77 struct Empty
81 enum Kind
83 Some,
84 None
85 } kind;
87 union Content
89 Empty empty;
90 T value;
92 Content () = default;
93 } content;
95 Optional<T> (Kind kind, Content content) : kind (kind), content (content) {}
97 public:
98 Optional (const Optional &other) = default;
99 Optional &operator= (const Optional &other) = default;
100 Optional (Optional &&other) = default;
102 static Optional<T> some (T value)
104 Content content;
105 content.value = value;
107 return Optional (Kind::Some, content);
110 static Optional<T> none ()
112 Content content;
113 content.empty = Empty ();
115 return Optional (Kind::None, content);
118 bool is_some () const { return kind == Kind::Some; }
119 bool is_none () const { return !is_some (); }
122 * Enable boolean-like comparisons.
124 operator bool () { return is_some (); }
127 * Enables dereferencing to access the contained value
129 T &operator* () { return get (); }
130 const T &operator* () const { return get (); }
131 T *operator-> () { return &get (); }
132 const T *operator-> () const { return &get (); }
134 const T &get () const
136 rust_assert (is_some ());
138 return content.value;
141 T &get ()
143 rust_assert (is_some ());
145 return content.value;
148 T take ()
150 rust_assert (is_some ());
152 auto to_return = std::move (content.value);
154 content.empty = Empty ();
155 kind = Kind::None;
157 return to_return;
160 template <typename U> Optional<U> map (std::function<U (T)> functor)
162 if (is_none ())
163 return Optional::none ();
165 auto value = functor (take ());
167 return Optional::some (value);
171 template <typename T> class Optional<T &>
173 private:
174 struct Empty
178 enum Kind
180 Some,
181 None
182 } kind;
184 union Content
186 Empty empty;
187 T *value;
189 Content () = default;
190 } content;
192 Optional<T &> (Kind kind, Content content) : kind (kind), content (content) {}
194 public:
195 Optional (const Optional &other) = default;
196 Optional (Optional &&other) = default;
197 Optional &operator= (Optional &&other) = default;
199 static Optional<T &> some (T &value)
201 Content content;
202 content.value = &value;
204 return Optional (Kind::Some, content);
207 static Optional<T &> none ()
209 Content content;
210 content.empty = Empty ();
212 return Optional (Kind::None, content);
215 bool is_some () const { return kind == Kind::Some; }
216 bool is_none () const { return !is_some (); }
218 // FIXME: Can we factor this in a single class?
221 * Enable boolean-like comparisons.
223 operator bool () { return is_some (); }
226 * Enables dereferencing to access the contained value
228 T &operator* () { return get (); }
229 const T &operator* () const { return get (); }
230 T *operator-> () { return &get (); }
231 const T *operator-> () const { return &get (); }
233 const T &get () const
235 rust_assert (is_some ());
237 return *content.value;
240 T &get ()
242 rust_assert (is_some ());
244 return *content.value;
247 T &take ()
249 rust_assert (is_some ());
251 auto to_return = std::move (content.value);
253 content.empty = Empty ();
254 kind = Kind::None;
256 return *to_return;
259 template <typename U> Optional<U &> map (std::function<U &(T &)> functor)
261 if (is_none ())
262 return Optional::none ();
264 auto value = functor (take ());
266 return Optional::some (value);
270 } // namespace Rust
272 #ifdef CHECKING_P
274 void
275 rust_optional_test ();
277 #endif // !CHECKING_P
279 #endif // !RUST_OPTIONAL_H