Reimplement Maybe.

This improves flexibility by avoiding the
inheritance from MaybeBase. It sprinkles a few
more std::move, e.g. for TakeJust.

Trials:
https://chromium-review.googlesource.com/c/v8/v8/+/1649178
https://chromium-review.googlesource.com/c/chromium/src/+/1648808

Change-Id: Ib3200ce491f7892404cb177e9bcb413c35414c73
diff --git a/lib/Forward_h.template b/lib/Forward_h.template
index ff5e685..746ba20 100644
--- a/lib/Forward_h.template
+++ b/lib/Forward_h.template
@@ -28,7 +28,6 @@
 class ErrorSupport;
 class FundamentalValue;
 class ListValue;
-template<typename T> class Maybe;
 class Object;
 using Response = DispatchResponse;
 class SerializedValue;
diff --git a/lib/Maybe_h.template b/lib/Maybe_h.template
index 15b0aa4..8dfee7e 100644
--- a/lib/Maybe_h.template
+++ b/lib/Maybe_h.template
@@ -13,12 +13,13 @@
 namespace {{namespace}} {
 {% endfor %}
 
+namespace detail {
 template<typename T>
-class Maybe {
+class PtrMaybe {
 public:
-    Maybe() : m_value() { }
-    Maybe(std::unique_ptr<T> value) : m_value(std::move(value)) { }
-    Maybe(Maybe&& other) noexcept : m_value(std::move(other.m_value)) {}
+    PtrMaybe() = default;
+    PtrMaybe(std::unique_ptr<T> value) : m_value(std::move(value)) { }
+    PtrMaybe(PtrMaybe&& other) noexcept : m_value(std::move(other.m_value)) {}
     void operator=(std::unique_ptr<T> value) { m_value = std::move(value); }
     T* fromJust() const { DCHECK(m_value); return m_value.get(); }
     T* fromMaybe(T* defaultValue) const { return m_value ? m_value.get() : defaultValue; }
@@ -29,68 +30,45 @@
 };
 
 template<typename T>
-class MaybeBase {
+class ValueMaybe {
 public:
-    MaybeBase() : m_isJust(false) { }
-    MaybeBase(T value) : m_isJust(true), m_value(value) { }
-    MaybeBase(MaybeBase&& other) noexcept
+    ValueMaybe() : m_isJust(false), m_value() { }
+    ValueMaybe(T value) : m_isJust(true), m_value(std::move(value)) { }
+    ValueMaybe(ValueMaybe&& other) noexcept
         : m_isJust(other.m_isJust),
           m_value(std::move(other.m_value)) {}
     void operator=(T value) { m_value = value; m_isJust = true; }
-    T fromJust() const { DCHECK(m_isJust); return m_value; }
-    T fromMaybe(const T& defaultValue) const { return m_isJust ? m_value : defaultValue; }
+    const T& fromJust() const { DCHECK(m_isJust); return m_value; }
+    const T& fromMaybe(const T& defaultValue) const { return m_isJust ? m_value : defaultValue; }
     bool isJust() const { return m_isJust; }
-    T takeJust() { DCHECK(m_isJust); return m_value; }
-
-protected:
+    T takeJust() { DCHECK(m_isJust); return std::move(m_value); }
+private:
     bool m_isJust;
     T m_value;
 };
 
-template<>
-class Maybe<bool> : public MaybeBase<bool> {
-public:
-    Maybe() { m_value = false; }
-    Maybe(bool value) : MaybeBase(value) { }
-    Maybe(Maybe&& other) noexcept : MaybeBase(std::move(other)) {}
-    using MaybeBase::operator=;
-};
+template <typename T>
+struct MaybeTypedef { typedef PtrMaybe<T> type; };
 
-template<>
-class Maybe<int> : public MaybeBase<int> {
-public:
-    Maybe() { m_value = 0; }
-    Maybe(int value) : MaybeBase(value) { }
-    Maybe(Maybe&& other) noexcept : MaybeBase(std::move(other)) {}
-    using MaybeBase::operator=;
-};
+template <>
+struct MaybeTypedef<bool> { typedef ValueMaybe<bool> type; };
 
-template<>
-class Maybe<double> : public MaybeBase<double> {
-public:
-    Maybe() { m_value = 0; }
-    Maybe(double value) : MaybeBase(value) { }
-    Maybe(Maybe&& other) noexcept : MaybeBase(std::move(other)) {}
-    using MaybeBase::operator=;
-};
+template <>
+struct MaybeTypedef<int> { typedef ValueMaybe<int> type; };
 
-template<>
-class Maybe<String> : public MaybeBase<String> {
-public:
-    Maybe() { }
-    Maybe(const String& value) : MaybeBase(value) { }
-    Maybe(Maybe&& other) noexcept : MaybeBase(std::move(other)) {}
-    using MaybeBase::operator=;
-};
+template <>
+struct MaybeTypedef<double> { typedef ValueMaybe<double> type; };
 
-template<>
-class Maybe<Binary> : public MaybeBase<Binary> {
-public:
-    Maybe() { }
-    Maybe(Binary value) : MaybeBase(value) { }
-    Maybe(Maybe&& other) noexcept : MaybeBase(std::move(other)) {}
-    using MaybeBase::operator=;
-};
+template <>
+struct MaybeTypedef<String> { typedef ValueMaybe<String> type; };
+
+template <>
+struct MaybeTypedef<Binary> { typedef ValueMaybe<Binary> type; };
+
+}  // namespace detail
+
+template <typename T>
+using Maybe = typename detail::MaybeTypedef<T>::type;
 
 {% for namespace in config.protocol.namespace %}
 } // namespace {{namespace}}