aboutsummaryrefslogtreecommitdiff
path: root/gcc/rust/util/rust-optional.h
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/rust/util/rust-optional.h')
-rw-r--r--gcc/rust/util/rust-optional.h288
1 files changed, 0 insertions, 288 deletions
diff --git a/gcc/rust/util/rust-optional.h b/gcc/rust/util/rust-optional.h
deleted file mode 100644
index bdfbd28..0000000
--- a/gcc/rust/util/rust-optional.h
+++ /dev/null
@@ -1,288 +0,0 @@
-// Copyright (C) 2020-2023 Free Software Foundation, Inc.
-
-// This file is part of GCC.
-
-// GCC is free software; you can redistribute it and/or modify it under
-// the terms of the GNU General Public License as published by the Free
-// Software Foundation; either version 3, or (at your option) any later
-// version.
-
-// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
-// WARRANTY; without even the implied warranty of MERCHANTABILITY or
-// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-// for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with GCC; see the file COPYING3. If not see
-// <http://www.gnu.org/licenses/>.
-
-#ifndef RUST_OPTIONAL_H
-#define RUST_OPTIONAL_H
-
-#include "config.h"
-#include "rust-system.h"
-
-#include "selftest.h"
-
-namespace Rust {
-
-/**
- * Tagged union to try and simulate a sum type. This is safer and more ergonomic
- * than one of the two alternatives we're currently using in the compiler:
- *
- * 1. Storing a raw pointer, which can be `nullptr` or valid
- *
- * This is wildly unsafe, and usable in conjunction with local references, stack
- * variables, or pointers managed elsewhere, which can cause crashes, hard to
- * debug issues or undefined behavior. Likewise, if you do not check for the
- * pointer's validity, this will cause a crash.
- *
- * 2. Storing an extra boolean alongside the object
- *
- * This causes implementors to use a "dummy object": Either an empty version or
- * an error version. But what happens if what you really wanted to store was
- * the empty or error version? You can also easily incorporate logic bugs if you
- * forget to check for the associated boolean.
- *
- * The `Optional<T>` type has the same "ergonomic" cost: You need to check
- * whether your option is valid or not. However, the main advantage is that it
- * is more restrictive: You can only acess the member it contains "safely".
- * It is similar to storing a value + an associated boolean, but has the
- * advantage of making up only one member in your class.
- * You also benefit from some helper methods such as `map()`.
- *
- * You also get helper functions and operator overloading to "seamlessly"
- * replace raw pointer alternatives.
- *
- * ```c++
- * MyType *raw_pointer = something_that_can_fail();
- * if (raw_pointer)
- * raw_pointer->method();
- *
- * // or
- *
- * Optional<MyType> opt = something_that_can_fail2();
- * if (opt)
- * opt->method();
- *
- * // equivalent to
- *
- * if (opt.is_some())
- * opt.get().method();
- * ```
- */
-template <typename T> class Optional
-{
-private:
- struct tag_some
- {
- };
- struct tag_none
- {
- };
-
- bool field_is_some;
-
- union
- {
- T value;
- // prevents initialization warnings
- // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80635#c53
- // FIXME: remove
- volatile char unused;
- };
-
- Optional (tag_some, const T &value) : field_is_some (true), value (value) {}
- Optional (tag_some, T &&value) : field_is_some (true), value (value) {}
-
- Optional (tag_none) : field_is_some (false) {}
-
-public:
- Optional (const Optional &other)
- {
- if ((field_is_some = other.field_is_some))
- new (&value) T (other.value);
- }
-
- Optional (Optional &&other)
- {
- if ((field_is_some = other.field_is_some))
- new (&value) T (other.value);
- }
-
- Optional &operator= (const Optional &other)
- {
- if (is_some ())
- value.~T ();
- if ((field_is_some = other.field_is_some))
- new (&value) T (other.value);
- return *this;
- }
-
- Optional &operator= (Optional &&other)
- {
- if (is_some ())
- value.~T ();
- if ((field_is_some = other.field_is_some))
- new (&value) T (other.value);
- return *this;
- }
-
- ~Optional ()
- {
- if (is_some ())
- value.~T ();
- }
-
- static Optional some (const T &value)
- {
- return Optional (tag_some (), value);
- }
-
- static Optional some (T &&value) { return Optional (tag_some (), value); }
-
- static Optional none () { return Optional (tag_none ()); }
-
- bool is_some () const { return field_is_some; }
- bool is_none () const { return !is_some (); }
-
- /**
- * Enable boolean-like comparisons.
- */
- operator bool () { return is_some (); }
-
- /**
- * Enables dereferencing to access the contained value
- */
- T &operator* () { return get (); }
- const T &operator* () const { return get (); }
- T *operator-> () { return &get (); }
- const T *operator-> () const { return &get (); }
-
- const T &get () const
- {
- rust_assert (is_some ());
-
- return value;
- }
-
- T &get ()
- {
- rust_assert (is_some ());
-
- return value;
- }
-
- T take ()
- {
- rust_assert (is_some ());
-
- T to_return = std::move (value);
- value.~T ();
-
- field_is_some = false;
-
- return to_return;
- }
-
- template <typename U> Optional<U> map (std::function<U (T)> functor)
- {
- if (is_none ())
- return Optional::none ();
-
- auto value = functor (take ());
-
- return Optional::some (value);
- }
-};
-
-template <typename T> class Optional<T &>
-{
-private:
- T *inner;
-
- Optional (T *inner) : inner (inner) {}
-
-public:
- static Optional<T &> some (T &value) { return Optional (&value); }
-
- static Optional<T &> none () { return Optional (nullptr); }
-
- bool is_some () const { return inner; }
- bool is_none () const { return !is_some (); }
-
- // FIXME: Can we factor this in a single class?
-
- /**
- * Enable boolean-like comparisons.
- */
- operator bool () { return is_some (); }
-
- /**
- * Enables dereferencing to access the contained value
- */
- T &operator* () { return get (); }
- const T &operator* () const { return get (); }
- T *operator-> () { return &get (); }
- const T *operator-> () const { return &get (); }
-
- T &get () const
- {
- rust_assert (is_some ());
-
- return *inner;
- }
-
- T &take ()
- {
- rust_assert (is_some ());
-
- T *to_return = inner;
- inner = nullptr;
-
- return *to_return;
- }
-
- template <typename U> Optional<U &> map (std::function<U &(T &)> functor)
- {
- if (is_none ())
- return Optional::none ();
-
- auto value = functor (take ());
-
- return Optional::some (value);
- }
-};
-
-template <typename T, typename U>
-bool
-operator== (const Optional<T> &t, const Optional<U> &u)
-{
- if (t.is_some ())
- return u.is_some () && t.get () == u.get ();
- else
- return u.is_none ();
-}
-
-} // namespace Rust
-
-namespace std {
-
-template <typename T> struct hash<Rust::Optional<T>>
-{
- size_t operator() (const Rust::Optional<T> &op) const
- {
- return op.is_some () ? std::hash<T> () (op.get ()) : 0;
- }
-};
-
-} // namespace std
-
-#ifdef CHECKING_P
-
-void
-rust_optional_test ();
-
-#endif // !CHECKING_P
-
-#endif // !RUST_OPTIONAL_H