diff options
author | Arthur Cohen <arthur.cohen@embecosm.com> | 2022-05-12 12:05:31 +0200 |
---|---|---|
committer | Arthur Cohen <arthur.cohen@embecosm.com> | 2022-05-12 12:05:31 +0200 |
commit | effc63b892b42c5645638b7b1f1002dac14d3794 (patch) | |
tree | 312ba00e8c003c5cae34f0c54bbf72e7129176dd /gcc | |
parent | d4434b511a4e650e95c7a1de6810d8748c5d8a70 (diff) | |
download | gcc-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.in | 1 | ||||
-rw-r--r-- | gcc/rust/util/rust-optional-test.cc | 104 | ||||
-rw-r--r-- | gcc/rust/util/rust-optional.h | 140 |
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 |