aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorArthur Cohen <arthur.cohen@embecosm.com>2022-05-12 12:05:31 +0200
committerArthur Cohen <arthur.cohen@embecosm.com>2022-05-12 12:05:31 +0200
commiteffc63b892b42c5645638b7b1f1002dac14d3794 (patch)
tree312ba00e8c003c5cae34f0c54bbf72e7129176dd /gcc
parentd4434b511a4e650e95c7a1de6810d8748c5d8a70 (diff)
downloadgcc-effc63b892b42c5645638b7b1f1002dac14d3794.zip
gcc-effc63b892b42c5645638b7b1f1002dac14d3794.tar.gz
gcc-effc63b892b42c5645638b7b1f1002dac14d3794.tar.bz2
optional: Allow the creation of Optional<T&>
Sadly, this requires specializing the class to keep the underlying pointer of the reference.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/rust/Make-lang.in1
-rw-r--r--gcc/rust/util/rust-optional-test.cc104
-rw-r--r--gcc/rust/util/rust-optional.h140
3 files changed, 193 insertions, 52 deletions
diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in
index 738cfdf..3f911ca 100644
--- a/gcc/rust/Make-lang.in
+++ b/gcc/rust/Make-lang.in
@@ -120,6 +120,7 @@ GRS_OBJS = \
rust/rust-compile-pattern.o \
rust/rust-compile-fnparam.o \
rust/rust-base62.o \
+ rust/rust-optional-test.o \
rust/rust-compile-item.o \
rust/rust-compile-implitem.o \
rust/rust-compile-expr.o \
diff --git a/gcc/rust/util/rust-optional-test.cc b/gcc/rust/util/rust-optional-test.cc
new file mode 100644
index 0000000..9045ac3
--- /dev/null
+++ b/gcc/rust/util/rust-optional-test.cc
@@ -0,0 +1,104 @@
+// Copyright (C) 2020-2022 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/>.
+
+#include "rust-optional.h"
+
+#include "config.h"
+#include "selftest.h"
+
+static void
+rust_optional_create ()
+{
+ auto opt = Rust::Optional<int>::some (15);
+
+ ASSERT_TRUE (opt.is_some ());
+ ASSERT_EQ (opt.get (), 15);
+
+ Rust::Optional<int> const_opt = Rust::Optional<int>::some (15);
+ const int &value = const_opt.get ();
+
+ ASSERT_EQ (value, 15);
+}
+
+static void
+rust_optional_operators ()
+{
+ auto opt = Rust::Optional<int>::some (15);
+
+ // as bool
+ ASSERT_TRUE (opt);
+
+ // deref
+ ASSERT_EQ (*opt, 15);
+
+ class Methodable
+ {
+ public:
+ int method () { return 15; }
+ };
+
+ auto m_opt = Rust::Optional<Methodable>::some (Methodable ());
+ ASSERT_EQ (m_opt->method (), 15);
+}
+
+static void
+rust_optional_take ()
+{
+ auto opt = Rust::Optional<int>::some (15);
+ auto value = opt.take ();
+
+ ASSERT_EQ (value, 15);
+ ASSERT_TRUE (opt.is_none ());
+}
+
+static void
+rust_optional_map ()
+{
+ auto opt = Rust::Optional<int>::some (15);
+ auto twice = opt.map<int> ([] (int value) { return value * 2; });
+
+ ASSERT_FALSE (opt);
+ ASSERT_TRUE (twice);
+ ASSERT_EQ (*twice, 30);
+}
+
+static void
+rust_optional_reference ()
+{
+ auto value = std::vector<std::string> ();
+ value.emplace_back ("rust");
+ value.emplace_back ("+");
+ value.emplace_back ("gcc");
+ value.emplace_back ("=");
+ value.emplace_back ("<3");
+
+ auto opt = Rust::Optional<std::vector<std::string> &>::some (value);
+
+ ASSERT_EQ (opt->at (0), "rust");
+ ASSERT_EQ (opt->at (2), "gcc");
+}
+
+void
+rust_optional_test ()
+{
+ rust_optional_create ();
+ rust_optional_operators ();
+ rust_optional_take ();
+ rust_optional_map ();
+ rust_optional_reference ();
+}
diff --git a/gcc/rust/util/rust-optional.h b/gcc/rust/util/rust-optional.h
index c1b547a..5a39893 100644
--- a/gcc/rust/util/rust-optional.h
+++ b/gcc/rust/util/rust-optional.h
@@ -167,74 +167,110 @@ public:
}
};
-} // namespace Rust
+template <typename T> class Optional<T &>
+{
+private:
+ struct Empty
+ {
+ };
-#ifdef CHECKING_P
+ enum Kind
+ {
+ Some,
+ None
+ } kind;
-static void
-rust_optional_create ()
-{
- auto opt = Rust::Optional<int>::some (15);
+ union Content
+ {
+ Empty empty;
+ T *value;
- ASSERT_TRUE (opt.is_some ());
- ASSERT_EQ (opt.get (), 15);
+ Content () = default;
+ } content;
- Rust::Optional<int> const_opt = Rust::Optional<int>::some (15);
- const int &value = const_opt.get ();
+ Optional<T &> (Kind kind, Content content) : kind (kind), content (content) {}
- ASSERT_EQ (value, 15);
-}
+public:
+ Optional (const Optional &other) = default;
+ Optional (Optional &&other) = default;
-static void
-rust_optional_operators ()
-{
- auto opt = Rust::Optional<int>::some (15);
+ static Optional<T &> some (T &value)
+ {
+ Content content;
+ content.value = &value;
+
+ return Optional (Kind::Some, content);
+ }
+
+ static Optional<T &> none ()
+ {
+ Content content;
+ content.empty = Empty ();
+
+ return Optional (Kind::None, content);
+ }
+
+ bool is_some () const { return kind == Kind::Some; }
+ 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 (); }
- // as bool
- ASSERT_TRUE (opt);
+ /**
+ * 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 (); }
- // deref
- ASSERT_EQ (*opt, 15);
+ const T &get () const
+ {
+ rust_assert (is_some ());
+
+ return *content.value;
+ }
- class Methodable
+ T &get ()
{
- public:
- int method () { return 15; }
- };
+ rust_assert (is_some ());
- auto m_opt = Rust::Optional<Methodable>::some (Methodable ());
- ASSERT_EQ (m_opt->method (), 15);
-}
+ return *content.value;
+ }
-static void
-rust_optional_take ()
-{
- auto opt = Rust::Optional<int>::some (15);
- auto value = opt.take ();
+ T &take ()
+ {
+ rust_assert (is_some ());
- ASSERT_EQ (value, 15);
- ASSERT_TRUE (opt.is_none ());
-}
+ auto to_return = std::move (content.value);
-static void
-rust_optional_map ()
-{
- auto opt = Rust::Optional<int>::some (15);
- auto twice = opt.map<int> ([] (int value) { return value * 2; });
+ content.empty = Empty ();
+ kind = Kind::None;
+
+ return *to_return;
+ }
- ASSERT_FALSE (opt);
- ASSERT_TRUE (twice);
- ASSERT_EQ (*twice, 30);
-}
+ template <typename U> Optional<U &> map (std::function<U &(T &)> functor)
+ {
+ if (is_none ())
+ return Optional::none ();
-static void
-rust_optional_test ()
-{
- rust_optional_create ();
- rust_optional_operators ();
- rust_optional_take ();
- rust_optional_map ();
-}
+ auto value = functor (take ());
+
+ return Optional::some (value);
+ }
+};
+
+} // namespace Rust
+
+#ifdef CHECKING_P
+
+void
+rust_optional_test ();
#endif // !CHECKING_P