WTF: Update std::expected to match current proposal
authorjfbastien@apple.com <jfbastien@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 4 Oct 2017 20:54:26 +0000 (20:54 +0000)
committerjfbastien@apple.com <jfbastien@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 4 Oct 2017 20:54:26 +0000 (20:54 +0000)
https://bugs.webkit.org/show_bug.cgi?id=177881

Reviewed by Mark Lam.

Source/JavaScriptCore:

Update API.

* wasm/WasmB3IRGenerator.cpp:
* wasm/WasmModule.cpp:
(JSC::Wasm::makeValidationResult):
* wasm/WasmParser.h:
* wasm/WasmValidate.cpp:
* wasm/generateWasmValidateInlinesHeader.py:
(loadMacro):
(storeMacro):

Source/WTF:

The proposal is likely to be in C++20 and I've been asked to help co-champion
it. I'm therefore updating our implementation to more closely match the current
proposal, and to make sure it'll work for us if standardized.

 - Rename UnexpectedType to Unexpected to match the proposal.
 - Remove relational operators, only equality / inequality remains.
 - Fix minor type signatures.
 - Add UnexpectedType typedef.
 - Uncomment rebind implementation.
 - Add in-place construction tag, as well as explicit error construction tag.
 - Add template unexpected constructor.
 - Note that make_unexpected isn't in the proposal anymore, but we keep it because we don't have C++17 deduction guides.
 - Remove hashing, which isn't in the proposal anymore.

* wtf/Expected.h:
(WTF::Unexpected::Unexpected):
(WTF::Unexpected::value const):
(WTF::operator==):
(WTF::operator!=):
(WTF::makeUnexpected):
(WTF::Expected::Expected):
(WTF::Expected::operator=):
(WTF::Expected::getUnexpected const):

Tools:

The proposal is likely to be in C++20 and I've been asked to help co-champion
it. I'm therefore updating our implementation to more closely match the current
proposal, and to make sure it'll work for us if standardized.

 - Rename UnexpectedType to Unexpected to match the proposal.
 - Remove relational operators, only equality / inequality remains.
 - Fix minor type signatures.
 - Add UnexpectedType typedef.
 - Uncomment rebind implementation.
 - Add in-place construction tag, as well as explicit error construction tag.
 - Add template unexpected constructor.
 - Note that make_unexpected isn't in the proposal anymore, but we keep it because we don't have C++17 deduction guides.
 - Remove hashing, which isn't in the proposal anymore.

* TestWebKitAPI/Tests/WTF/Expected.cpp:
(WTF::operator<<):
(TestWebKitAPI::TEST):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@222878 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp
Source/JavaScriptCore/wasm/WasmModule.cpp
Source/JavaScriptCore/wasm/WasmParser.h
Source/JavaScriptCore/wasm/WasmValidate.cpp
Source/JavaScriptCore/wasm/generateWasmValidateInlinesHeader.py
Source/WTF/ChangeLog
Source/WTF/wtf/Expected.h
Tools/ChangeLog
Tools/TestWebKitAPI/Tests/WTF/Expected.cpp

index 6b52ef9..f02b6aa 100644 (file)
@@ -1,5 +1,23 @@
 2017-10-04  JF Bastien  <jfbastien@apple.com>
 
+        WTF: Update std::expected to match current proposal
+        https://bugs.webkit.org/show_bug.cgi?id=177881
+
+        Reviewed by Mark Lam.
+
+        Update API.
+
+        * wasm/WasmB3IRGenerator.cpp:
+        * wasm/WasmModule.cpp:
+        (JSC::Wasm::makeValidationResult):
+        * wasm/WasmParser.h:
+        * wasm/WasmValidate.cpp:
+        * wasm/generateWasmValidateInlinesHeader.py:
+        (loadMacro):
+        (storeMacro):
+
+2017-10-04  JF Bastien  <jfbastien@apple.com>
+
         WebAssembly: address no VM / JS follow-ups
         https://bugs.webkit.org/show_bug.cgi?id=177887
 
index 42164d4..6b3c3f8 100644 (file)
@@ -162,7 +162,7 @@ public:
     static constexpr ExpressionType emptyExpression = nullptr;
 
     typedef String ErrorType;
-    typedef UnexpectedType<ErrorType> UnexpectedResult;
+    typedef Unexpected<ErrorType> UnexpectedResult;
     typedef Expected<std::unique_ptr<InternalFunction>, ErrorType> Result;
     typedef Expected<void, ErrorType> PartialResult;
     template <typename ...Args>
index 992e3d6..0b21ca2 100644 (file)
@@ -50,7 +50,7 @@ static Module::ValidationResult makeValidationResult(BBQPlan& plan)
 {
     ASSERT(!plan.hasWork());
     if (plan.failed())
-        return UnexpectedType<String>(plan.errorMessage());
+        return Unexpected<String>(plan.errorMessage());
     return Module::ValidationResult(Module::create(plan.takeModuleInformation()));
 }
 
index ff28db0..95f4db5 100644 (file)
@@ -54,7 +54,7 @@ template<typename SuccessType>
 class Parser {
 public:
     typedef String ErrorType;
-    typedef UnexpectedType<ErrorType> UnexpectedResult;
+    typedef Unexpected<ErrorType> UnexpectedResult;
     typedef Expected<void, ErrorType> PartialResult;
     typedef Expected<SuccessType, ErrorType> Result;
 
index 1a46f5c..116f9d2 100644 (file)
@@ -76,7 +76,7 @@ public:
         Type m_signature;
     };
     typedef String ErrorType;
-    typedef UnexpectedType<ErrorType> UnexpectedResult;
+    typedef Unexpected<ErrorType> UnexpectedResult;
     typedef Expected<void, ErrorType> Result;
     typedef Type ExpressionType;
     typedef ControlData ControlType;
index 6c9990b..18053d3 100755 (executable)
@@ -63,7 +63,7 @@ def unaryMacro(name):
 template<> auto Validate::addOp<OpType::""" + toCpp(name) + """>(ExpressionType value, ExpressionType& result) -> Result
 {
     if (UNLIKELY(value != """ + cppType(op["parameter"][0]) + """))
-        return UnexpectedType<Result::ErrorType>("validation failed: """ + name + """ value type mismatch");
+        return Unexpected<Result::ErrorType>("validation failed: """ + name + """ value type mismatch");
 
     result = """ + cppType(op["return"][0]) + """;
     return { };
@@ -77,10 +77,10 @@ def binaryMacro(name):
 template<> auto Validate::addOp<OpType::""" + toCpp(name) + """>(ExpressionType left, ExpressionType right, ExpressionType& result) -> Result
 {
     if (UNLIKELY(left != """ + cppType(op["parameter"][0]) + """))
-        return UnexpectedType<Result::ErrorType>("validation failed: """ + name + """ left value type mismatch");
+        return Unexpected<Result::ErrorType>("validation failed: """ + name + """ left value type mismatch");
 
     if (UNLIKELY(right != """ + cppType(op["parameter"][1]) + """))
-        return UnexpectedType<Result::ErrorType>("validation failed: """ + name + """ right value type mismatch");
+        return Unexpected<Result::ErrorType>("validation failed: """ + name + """ right value type mismatch");
 
     result = """ + cppType(op["return"][0]) + """;
     return { };
@@ -92,7 +92,7 @@ def loadMacro(name):
     return """
     case LoadOpType::""" + toCpp(name) + """: {
         if (UNLIKELY(pointer != """ + cppType(op["parameter"][0]) + """))
-            return UnexpectedType<Result::ErrorType>("validation failed: """ + name + """ pointer type mismatch");
+            return Unexpected<Result::ErrorType>("validation failed: """ + name + """ pointer type mismatch");
 
         result = """ + cppType(op["return"][0]) + """;
         return { };
@@ -104,10 +104,10 @@ def storeMacro(name):
     return """
     case StoreOpType::""" + toCpp(name) + """: {
         if (UNLIKELY(pointer != """ + cppType(op["parameter"][0]) + """))
-            return UnexpectedType<Result::ErrorType>("validation failed: """ + name + """ pointer type mismatch");
+            return Unexpected<Result::ErrorType>("validation failed: """ + name + """ pointer type mismatch");
 
         if (UNLIKELY(value != """ + cppType(op["parameter"][1]) + """))
-            return UnexpectedType<Result::ErrorType>("validation failed: """ + name + """ value type mismatch");
+            return Unexpected<Result::ErrorType>("validation failed: """ + name + """ value type mismatch");
 
         return { };
     }"""
@@ -139,7 +139,7 @@ namespace JSC { namespace Wasm {
 auto Validate::load(LoadOpType op, ExpressionType pointer, ExpressionType& result, uint32_t) -> Result
 {
     if (UNLIKELY(!hasMemory()))
-        return UnexpectedType<Result::ErrorType>("validation failed: load instruction without memory");
+        return Unexpected<Result::ErrorType>("validation failed: load instruction without memory");
 
     switch (op) {
 """ + loadCases + """
@@ -150,7 +150,7 @@ auto Validate::load(LoadOpType op, ExpressionType pointer, ExpressionType& resul
 auto Validate::store(StoreOpType op, ExpressionType pointer, ExpressionType value, uint32_t) -> Result
 {
     if (UNLIKELY(!hasMemory()))
-        return UnexpectedType<Result::ErrorType>("validation failed: store instruction without memory");
+        return Unexpected<Result::ErrorType>("validation failed: store instruction without memory");
 
     switch (op) {
 """ + storeCases + """
index ac03b67..5ddc500 100644 (file)
@@ -1,3 +1,34 @@
+2017-10-04  JF Bastien  <jfbastien@apple.com>
+
+        WTF: Update std::expected to match current proposal
+        https://bugs.webkit.org/show_bug.cgi?id=177881
+
+        Reviewed by Mark Lam.
+
+        The proposal is likely to be in C++20 and I've been asked to help co-champion
+        it. I'm therefore updating our implementation to more closely match the current
+        proposal, and to make sure it'll work for us if standardized.
+
+         - Rename UnexpectedType to Unexpected to match the proposal.
+         - Remove relational operators, only equality / inequality remains.
+         - Fix minor type signatures.
+         - Add UnexpectedType typedef.
+         - Uncomment rebind implementation.
+         - Add in-place construction tag, as well as explicit error construction tag.
+         - Add template unexpected constructor.
+         - Note that make_unexpected isn't in the proposal anymore, but we keep it because we don't have C++17 deduction guides.
+         - Remove hashing, which isn't in the proposal anymore.
+
+        * wtf/Expected.h:
+        (WTF::Unexpected::Unexpected):
+        (WTF::Unexpected::value const):
+        (WTF::operator==):
+        (WTF::operator!=):
+        (WTF::makeUnexpected):
+        (WTF::Expected::Expected):
+        (WTF::Expected::operator=):
+        (WTF::Expected::getUnexpected const):
+
 2017-10-04  Ryan Haddad  <ryanhaddad@apple.com>
 
         Unreviewed, rolling out r222840.
index a376cd0..250aea7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 
 namespace WTF {
 
-template <class E>
-class UnexpectedType {
+template<class E>
+class Unexpected {
 public:
-    UnexpectedType() = delete;
-    constexpr explicit UnexpectedType(const E& e) : val(e) { }
-    constexpr explicit UnexpectedType(E&& e) : val(std::forward<E>(e)) { }
-    constexpr const E& value() const& { return val; }
+    Unexpected() = delete;
+    constexpr explicit Unexpected(const E& e) : val(e) { }
+    constexpr explicit Unexpected(E&& e) : val(std::forward<E>(e)) { }
+    constexpr const E& value() const & { return val; }
     RELAXED_CONSTEXPR E& value() & { return val; }
     RELAXED_CONSTEXPR E&& value() && { return WTFMove(val); }
 
@@ -52,19 +52,21 @@ private:
     E val;
 };
 
-template <class E> constexpr bool operator==(const UnexpectedType<E>& lhs, const UnexpectedType<E>& rhs) { return lhs.value() == rhs.value(); }
-template <class E> constexpr bool operator!=(const UnexpectedType<E>& lhs, const UnexpectedType<E>& rhs) { return lhs.value() != rhs.value(); }
-template <class E> constexpr bool operator<(const UnexpectedType<E>& lhs, const UnexpectedType<E>& rhs) { return lhs.value() < rhs.value(); }
-template <class E> constexpr bool operator>(const UnexpectedType<E>& lhs, const UnexpectedType<E>& rhs) { return lhs.value() > rhs.value(); }
-template <class E> constexpr bool operator<=(const UnexpectedType<E>& lhs, const UnexpectedType<E>& rhs) { return lhs.value() <= rhs.value(); }
-template <class E> constexpr bool operator>=(const UnexpectedType<E>& lhs, const UnexpectedType<E>& rhs) { return lhs.value() >= rhs.value(); }
+template<class E> constexpr bool operator==(const Unexpected<E>& lhs, const Unexpected<E>& rhs) { return lhs.value() == rhs.value(); }
+template<class E> constexpr bool operator!=(const Unexpected<E>& lhs, const Unexpected<E>& rhs) { return lhs.value() != rhs.value(); }
 
-template <class E> constexpr UnexpectedType<std::decay_t<E>> makeUnexpected(E&& v) { return UnexpectedType<typename std::decay<E>::type>(std::forward<E>(v)); }
+template<class E> constexpr Unexpected<std::decay_t<E>> makeUnexpected(E&& v) { return Unexpected<typename std::decay<E>::type>(std::forward<E>(v)); }
 
 struct UnexpectTag {
-    UnexpectTag() = delete;
+    UnexpectTag() = default;
 };
-constexpr UnexpectTag Unexpect { };
+constexpr UnexpectTag Unexpect { }; // FIXME This is an inline variable for C++17 and later.
+
+// FIXME this should just be std::in_place_t which we also define in optional and variant.
+struct InPlaceTag {
+    InPlaceTag() = default;
+};
+constexpr InPlaceTag InPlace { };
 
 namespace ExpectedDetail {
 
@@ -77,10 +79,11 @@ static constexpr enum class ErrorTagType { } ErrorTag { };
 template<class T, std::enable_if_t<std::is_trivially_destructible<T>::value>* = nullptr> void destroy(T&) { }
 template<class T, std::enable_if_t<!std::is_trivially_destructible<T>::value && (std::is_class<T>::value || std::is_union<T>::value)>* = nullptr> void destroy(T& t) { t.~T(); }
 
-template <class T, class E>
+template<class T, class E>
 union ConstexprStorage {
     typedef T ValueType;
     typedef E ErrorType;
+    typedef Unexpected<E> UnexpectedType;
     char dummy;
     ValueType val;
     ErrorType err;
@@ -92,10 +95,11 @@ union ConstexprStorage {
     ~ConstexprStorage() = default;
 };
 
-template <class T, class E>
+template<class T, class E>
 union Storage {
     typedef T ValueType;
     typedef E ErrorType;
+    typedef Unexpected<E> UnexpectedType;
     char dummy;
     ValueType val;
     ErrorType err;
@@ -109,10 +113,11 @@ union Storage {
     ~Storage() { }
 };
 
-template <class E>
+template<class E>
 union ConstexprStorage<void, E> {
     typedef void ValueType;
     typedef E ErrorType;
+    typedef Unexpected<E> UnexpectedType;
     char dummy;
     ErrorType err;
     constexpr ConstexprStorage() : dummy() { }
@@ -122,10 +127,11 @@ union ConstexprStorage<void, E> {
     ~ConstexprStorage() = default;
 };
 
-template <class E>
+template<class E>
 union Storage<void, E> {
     typedef void ValueType;
     typedef E ErrorType;
+    typedef Unexpected<E> UnexpectedType;
     char dummy;
     ErrorType err;
     constexpr Storage() : dummy() { }
@@ -136,10 +142,11 @@ union Storage<void, E> {
     ~Storage() { }
 };
 
-template <class T, class E>
+template<class T, class E>
 struct ConstexprBase {
     typedef T ValueType;
     typedef E ErrorType;
+    typedef Unexpected<E> UnexpectedType;
     ConstexprStorage<ValueType, ErrorType> s;
     bool has;
     constexpr ConstexprBase() : s(), has(true) { }
@@ -150,10 +157,11 @@ struct ConstexprBase {
     ~ConstexprBase() = default;
 };
 
-template <class T, class E>
+template<class T, class E>
 struct Base {
     typedef T ValueType;
     typedef E ErrorType;
+    typedef Unexpected<E> UnexpectedType;
     Storage<ValueType, ErrorType> s;
     bool has;
     constexpr Base() : s(), has(true) { }
@@ -188,10 +196,11 @@ struct Base {
     }
 };
 
-template <class E>
+template<class E>
 struct ConstexprBase<void, E> {
     typedef void ValueType;
     typedef E ErrorType;
+    typedef Unexpected<E> UnexpectedType;
     ConstexprStorage<ValueType, ErrorType> s;
     bool has;
     constexpr ConstexprBase() : s(), has(true) { }
@@ -202,10 +211,11 @@ struct ConstexprBase<void, E> {
     ~ConstexprBase() = default;
 };
 
-template <class E>
+template<class E>
 struct Base<void, E> {
     typedef void ValueType;
     typedef E ErrorType;
+    typedef Unexpected<E> UnexpectedType;
     Storage<ValueType, ErrorType> s;
     bool has;
     constexpr Base() : s(), has(true) { }
@@ -232,7 +242,7 @@ struct Base<void, E> {
     }
 };
 
-template <class T, class E>
+template<class T, class E>
 using BaseSelect = typename std::conditional<
     ((std::is_void<T>::value || std::is_trivially_destructible<T>::value)
         && std::is_trivially_destructible<E>::value),
@@ -242,42 +252,47 @@ using BaseSelect = typename std::conditional<
 
 } // namespace ExpectedDetail
 
-template <class T, class E>
+template<class T, class E>
 class Expected : private ExpectedDetail::BaseSelect<T, E> {
     typedef ExpectedDetail::BaseSelect<T, E> base;
 
 public:
     typedef typename base::ValueType ValueType;
     typedef typename base::ErrorType ErrorType;
+    typedef typename base::UnexpectedType UnexpectedType;
 
 private:
     typedef Expected<ValueType, ErrorType> type;
 
 public:
-    // template <class U> struct rebind { using type = Expected<U, ErrorType>; };
+    template<class U> struct rebind {
+        using type = Expected<U, ErrorType>;
+    };
 
     constexpr Expected() : base(ExpectedDetail::ValueTag) { }
     Expected(const Expected&) = default;
     Expected(Expected&&) = default;
+
     constexpr Expected(const ValueType& e) : base(ExpectedDetail::ValueTag, e) { }
     constexpr Expected(ValueType&& e) : base(ExpectedDetail::ValueTag, std::forward<ValueType>(e)) { }
-    // template <class... Args> constexpr explicit Expected(in_place_t, Args&&...);
-    // template <class U, class... Args> constexpr explicit Expected(in_place_t, std::initializer_list<U>, Args&&...);
-    constexpr Expected(UnexpectedType<ErrorType> const& u) : base(ExpectedDetail::ErrorTag, u.value()) { }
-    constexpr Expected(UnexpectedType<ErrorType>&& u) : base(ExpectedDetail::ErrorTag, std::forward<UnexpectedType<E>>(u).value()) { }
-    template <class Err> constexpr Expected(UnexpectedType<Err> const& u) : base(ExpectedDetail::ErrorTag, u.value()) { }
-    // template <class... Args> constexpr explicit Expected(UnexpectTag, Args&&...);
-    // template <class U, class... Args> constexpr explicit Expected(UnexpectTag, std::initializer_list<U>, Args&&...);
+    template<class... Args> constexpr explicit Expected(InPlaceTag, Args&&... args) : base(ExpectedDetail::ValueTag, ValueType(std::forward<Args>(args)...)) { }
+    // template<class U, class... Args> constexpr explicit Expected(in_place_t, std::initializer_list<U>, Args&&...);
+    constexpr Expected(const UnexpectedType& u) : base(ExpectedDetail::ErrorTag, u.value()) { }
+    constexpr Expected(UnexpectedType&& u) : base(ExpectedDetail::ErrorTag, std::forward<UnexpectedType>(u).value()) { }
+    template<class Err> constexpr Expected(const Unexpected<Err>& u) : base(ExpectedDetail::ErrorTag, u.value()) { }
+    template<class Err> constexpr Expected(Unexpected<Err>&& u) : base(ExpectedDetail::ErrorTag, std::forward<Err>(u.value())) { }
+    template<class... Args> constexpr explicit Expected(UnexpectTag, Args&&... args) : base(ExpectedDetail::ValueTag, UnexpectedType(std::forward<Args>(args)...)) { }
+    // template<class U, class... Args> constexpr explicit Expected(UnexpectTag, std::initializer_list<U>, Args&&...);
 
     ~Expected() = default;
 
     Expected& operator=(const Expected& e) { type(e).swap(*this); return *this; }
     Expected& operator=(Expected&& e) { type(WTFMove(e)).swap(*this); return *this; }
-    template <class U> Expected& operator=(U&& u) { type(WTFMove(u)).swap(*this); return *this; }
-    Expected& operator=(const UnexpectedType<ErrorType>& u) { type(u).swap(*this); return *this; }
-    Expected& operator=(UnexpectedType<ErrorType>&& u) { type(WTFMove(u)).swap(*this); return *this; }
-    // template <class... Args> void emplace(Args&&...);
-    // template <class U, class... Args> void emplace(std::initializer_list<U>, Args&&...);
+    template<class U> Expected& operator=(U&& u) { type(WTFMove(u)).swap(*this); return *this; }
+    Expected& operator=(const UnexpectedType& u) { type(u).swap(*this); return *this; }
+    Expected& operator=(UnexpectedType&& u) { type(WTFMove(u)).swap(*this); return *this; }
+    // template<class... Args> void emplace(Args&&...);
+    // template<class U, class... Args> void emplace(std::initializer_list<U>, Args&&...);
 
     void swap(Expected& o)
     {
@@ -318,39 +333,42 @@ public:
     ErrorType& error() & { return !base::has ? base::s.err : (ExpectedDetail::Throw(), base::s.err); }
     RELAXED_CONSTEXPR ErrorType&& error() && { return !base::has ? base::s.err : (ExpectedDetail::Throw(), base::s.err); }
     constexpr const ErrorType&& error() const && { return !base::has ? base::s.err : (ExpectedDetail::Throw(), base::s.err); }
-    constexpr UnexpectedType<ErrorType> getUnexpected() const { return UnexpectedType<ErrorType>(base::s.err); }
-    template <class U> constexpr ValueType valueOr(U&& u) const & { return base::has ? **this : static_cast<ValueType>(std::forward<U>(u)); }
-    template <class U> ValueType valueOr(U&& u) && { return base::has ? WTFMove(**this) : static_cast<ValueType>(std::forward<U>(u)); }
+    constexpr UnexpectedType getUnexpected() const { return UnexpectedType(base::s.err); }
+    template<class U> constexpr ValueType valueOr(U&& u) const & { return base::has ? **this : static_cast<ValueType>(std::forward<U>(u)); }
+    template<class U> ValueType valueOr(U&& u) && { return base::has ? WTFMove(**this) : static_cast<ValueType>(std::forward<U>(u)); }
 };
 
-template <class E>
+template<class E>
 class Expected<void, E> : private ExpectedDetail::BaseSelect<void, E> {
     typedef ExpectedDetail::BaseSelect<void, E> base;
 
 public:
     typedef typename base::ValueType ValueType;
     typedef typename base::ErrorType ErrorType;
+    typedef typename base::UnexpectedType UnexpectedType;
 
 private:
     typedef Expected<ValueType, ErrorType> type;
 
 public:
-    // template <class U> struct rebind { typedef Expected<U, ErrorType> type; };
+    template<class U> struct rebind {
+        using type = Expected<U, ErrorType>;
+    };
 
     constexpr Expected() : base(ExpectedDetail::ValueTag) { }
     Expected(const Expected&) = default;
     Expected(Expected&&) = default;
     // constexpr explicit Expected(in_place_t);
-    constexpr Expected(UnexpectedType<E> const& u) : base(ExpectedDetail::ErrorTag, u.value()) { }
-    constexpr Expected(UnexpectedType<E>&& u) : base(ExpectedDetail::ErrorTag, std::forward<UnexpectedType<E>>(u).value()) { }
-    template <class Err> constexpr Expected(UnexpectedType<Err> const& u) : base(ExpectedDetail::ErrorTag, u.value()) { }
+    constexpr Expected(UnexpectedType const& u) : base(ExpectedDetail::ErrorTag, u.value()) { }
+    constexpr Expected(UnexpectedType&& u) : base(ExpectedDetail::ErrorTag, std::forward<UnexpectedType>(u).value()) { }
+    template<class Err> constexpr Expected(Unexpected<Err> const& u) : base(ExpectedDetail::ErrorTag, u.value()) { }
 
     ~Expected() = default;
 
     Expected& operator=(const Expected& e) { type(e).swap(*this); return *this; }
     Expected& operator=(Expected&& e) { type(WTFMove(e)).swap(*this); return *this; }
-    Expected& operator=(const UnexpectedType<E>& u) { type(u).swap(*this); return *this; } // Not in the current paper.
-    Expected& operator=(UnexpectedType<E>&& u) { type(WTFMove(u)).swap(*this); return *this; } // Not in the current paper.
+    Expected& operator=(const UnexpectedType& u) { type(u).swap(*this); return *this; } // Not in the current paper.
+    Expected& operator=(UnexpectedType&& u) { type(WTFMove(u)).swap(*this); return *this; } // Not in the current paper.
     // void emplace();
 
     void swap(Expected& o)
@@ -377,76 +395,41 @@ public:
     RELAXED_CONSTEXPR E&& error() && { return !base::has ? base::s.err : (ExpectedDetail::Throw(), base::s.err); }
     constexpr const E&& error() const && { return !base::has ? base::s.err : (ExpectedDetail::Throw(), base::s.err); } // Not in the current paper.
     // constexpr E& error() &;
-    constexpr UnexpectedType<E> getUnexpected() const { return UnexpectedType<E>(base::s.err); }
+    constexpr UnexpectedType getUnexpected() const { return UnexpectedType(base::s.err); }
 };
 
-template <class T, class E> constexpr bool operator==(const Expected<T, E>& x, const Expected<T, E>& y) { return bool(x) == bool(y) && (x ? x.value() == y.value() : x.error() == y.error()); }
-template <class T, class E> constexpr bool operator!=(const Expected<T, E>& x, const Expected<T, E>& y) { return !(x == y); }
-template <class T, class E> constexpr bool operator<(const Expected<T, E>& x, const Expected<T, E>& y) { return (!bool(x) && bool(y)) ? false : ((bool(x) && !bool(y)) ? true : ((bool(x) && bool(y)) ? x.value() < y.value() : x.error() < y.error())); }
-template <class T, class E> constexpr bool operator>(const Expected<T, E>& x, const Expected<T, E>& y) { return !(x == y) && !(x < y); }
-template <class T, class E> constexpr bool operator<=(const Expected<T, E>& x, const Expected<T, E>& y) { return (x == y) || (x < y); }
-template <class T, class E> constexpr bool operator>=(const Expected<T, E>& x, const Expected<T, E>& y) { return (x == y) || (x > y); }
-
-template <class E> constexpr bool operator==(const Expected<void, E>& x, const Expected<void, E>& y) { return bool(x) == bool(y) && (x ? true : x.error() == y.error()); } // Not in the current paper.
-template <class E> constexpr bool operator<(const Expected<void, E>& x, const Expected<void, E>& y) { return (!bool(x) && bool(y)) ? false : ((bool(x) && !bool(y)) ? true : ((bool(x) && bool(y)) ? false : x.error() < y.error())); } // Not in the current paper.
-
-template <class T, class E> constexpr bool operator==(const Expected<T, E>& x, const T& y) { return x == Expected<T, E>(y); }
-template <class T, class E> constexpr bool operator==(const T& x, const Expected<T, E>& y) { return Expected<T, E>(x) == y; }
-template <class T, class E> constexpr bool operator!=(const Expected<T, E>& x, const T& y) { return x != Expected<T, E>(y); }
-template <class T, class E> constexpr bool operator!=(const T& x, const Expected<T, E>& y) { return Expected<T, E>(x) != y; }
-template <class T, class E> constexpr bool operator<(const Expected<T, E>& x, const T& y) { return x < Expected<T, E>(y); }
-template <class T, class E> constexpr bool operator<(const T& x, const Expected<T, E>& y) { return Expected<T, E>(x) < y; }
-template <class T, class E> constexpr bool operator<=(const Expected<T, E>& x, const T& y) { return x <= Expected<T, E>(y); }
-template <class T, class E> constexpr bool operator<=(const T& x, const Expected<T, E>& y) { return Expected<T, E>(x) <= y; }
-template <class T, class E> constexpr bool operator>(const Expected<T, E>& x, const T& y) { return x > Expected<T, E>(y); }
-template <class T, class E> constexpr bool operator>(const T& x, const Expected<T, E>& y) { return Expected<T, E>(x) > y; }
-template <class T, class E> constexpr bool operator>=(const Expected<T, E>& x, const T& y) { return x >= Expected<T, E>(y); }
-template <class T, class E> constexpr bool operator>=(const T& x, const Expected<T, E>& y) { return Expected<T, E>(x) >= y; }
-
-template <class T, class E> constexpr bool operator==(const Expected<T, E>& x, const UnexpectedType<E>& y) { return x == Expected<T, E>(y); }
-template <class T, class E> constexpr bool operator==(const UnexpectedType<E>& x, const Expected<T, E>& y) { return Expected<T, E>(x) == y; }
-template <class T, class E> constexpr bool operator!=(const Expected<T, E>& x, const UnexpectedType<E>& y) { return x != Expected<T, E>(y); }
-template <class T, class E> constexpr bool operator!=(const UnexpectedType<E>& x, const Expected<T, E>& y) { return Expected<T, E>(x) != y; }
-template <class T, class E> constexpr bool operator<(const Expected<T, E>& x, const UnexpectedType<E>& y) { return x < Expected<T, E>(y); }
-template <class T, class E> constexpr bool operator<(const UnexpectedType<E>& x, const Expected<T, E>& y) {  return Expected<T, E>(x) < y; }
-template <class T, class E> constexpr bool operator<=(const Expected<T, E>& x, const UnexpectedType<E>& y) { return x <= Expected<T, E>(y); }
-template <class T, class E> constexpr bool operator<=(const UnexpectedType<E>& x, const Expected<T, E>& y) { return Expected<T, E>(x) <= y; }
-template <class T, class E> constexpr bool operator>(const Expected<T, E>& x, const UnexpectedType<E>& y) { return x > Expected<T, E>(y); }
-template <class T, class E> constexpr bool operator>(const UnexpectedType<E>& x, const Expected<T, E>& y) { return Expected<T, E>(x) > y; }
-template <class T, class E> constexpr bool operator>=(const Expected<T, E>& x, const UnexpectedType<E>& y) { return x >= Expected<T, E>(y); }
-template <class T, class E> constexpr bool operator>=(const UnexpectedType<E>& x, const Expected<T, E>& y) { return Expected<T, E>(x) >= y; }
-
-template <typename T, typename E> void swap(Expected<T, E>& x, Expected<T, E>& y) { x.swap(y); }
-
-template <class T, class E = std::nullopt_t> constexpr Expected<std::decay_t<T>, E> makeExpected(T&& v)
+template<class T, class E> constexpr bool operator==(const Expected<T, E>& x, const Expected<T, E>& y) { return bool(x) == bool(y) && (x ? x.value() == y.value() : x.error() == y.error()); }
+template<class T, class E> constexpr bool operator!=(const Expected<T, E>& x, const Expected<T, E>& y) { return !(x == y); }
+
+template<class E> constexpr bool operator==(const Expected<void, E>& x, const Expected<void, E>& y) { return bool(x) == bool(y) && (x ? true : x.error() == y.error()); }
+
+template<class T, class E> constexpr bool operator==(const Expected<T, E>& x, const T& y) { return x == Expected<T, E>(y); }
+template<class T, class E> constexpr bool operator==(const T& x, const Expected<T, E>& y) { return Expected<T, E>(x) == y; }
+template<class T, class E> constexpr bool operator!=(const Expected<T, E>& x, const T& y) { return x != Expected<T, E>(y); }
+template<class T, class E> constexpr bool operator!=(const T& x, const Expected<T, E>& y) { return Expected<T, E>(x) != y; }
+
+template<class T, class E> constexpr bool operator==(const Expected<T, E>& x, const Unexpected<E>& y) { return x == Expected<T, E>(y); }
+template<class T, class E> constexpr bool operator==(const Unexpected<E>& x, const Expected<T, E>& y) { return Expected<T, E>(x) == y; }
+template<class T, class E> constexpr bool operator!=(const Expected<T, E>& x, const Unexpected<E>& y) { return x != Expected<T, E>(y); }
+template<class T, class E> constexpr bool operator!=(const Unexpected<E>& x, const Expected<T, E>& y) { return Expected<T, E>(x) != y; }
+
+template<typename T, typename E> void swap(Expected<T, E>& x, Expected<T, E>& y) { x.swap(y); }
+
+// Note: this isn't in the current proposal because it relies on C++17 deduction guides instead.
+template<class T, class E = std::nullopt_t> constexpr Expected<std::decay_t<T>, E> makeExpected(T&& v)
 {
     return Expected<typename std::decay<T>::type, E>(std::forward<T>(v));
 }
-template <class T, class E> constexpr Expected<T, std::decay_t<E>> makeExpectedFromError(E&& e) { return Expected<T, std::decay_t<E>>(makeUnexpected(e)); }
-template <class T, class E, class U> constexpr Expected<T, E> makeExpectedFromError(U&& u) { return Expected<T, E>(makeUnexpected(E { std::forward<U>(u) } )); }
-// template <class F, class E = std::nullopt_t> constexpr Expected<typename std::result_of<F>::type, E> makeExpected_from_call(F f);
+template<class T, class E> constexpr Expected<T, std::decay_t<E>> makeExpectedFromError(E&& e) { return Expected<T, std::decay_t<E>>(makeUnexpected(e)); }
+template<class T, class E, class U> constexpr Expected<T, E> makeExpectedFromError(U&& u) { return Expected<T, E>(makeUnexpected(E { std::forward<U>(u) } )); }
+// template<class F, class E = std::nullopt_t> constexpr Expected<typename std::result_of<F>::type, E> makeExpected_from_call(F f);
 
 inline Expected<void, std::nullopt_t> makeExpected() { return Expected<void, std::nullopt_t>(); }
 
 } // namespace WTF
 
-namespace std {
-
-template <class T, class E> struct hash<WTF::Expected<T, E>> {
-    typedef WTF::Expected<T, E> argument_type;
-    typedef std::size_t result_type;
-    result_type operator()(argument_type const& e) const { return e ? hash<typename argument_type::ValueType> { } (e.value()) : hash<typename argument_type::ErrorType> { } (e.error()); }
-};
-
-template <class E> struct hash<WTF::Expected<void, E>> {
-    typedef WTF::Expected<void, E> argument_type;
-    typedef std::size_t result_type;
-    result_type operator()(argument_type const& e) const { return e ? 0 : hash<typename argument_type::ErrorType> { } (e.error()); }
-};
-
-}
-
-using WTF::UnexpectedType;
+using WTF::InPlace;
+using WTF::Unexpected;
 using WTF::makeUnexpected;
 using WTF::Unexpect;
 using WTF::Expected;
index 04114e7..c0f7df9 100644 (file)
@@ -1,3 +1,28 @@
+2017-10-04  JF Bastien  <jfbastien@apple.com>
+
+        WTF: Update std::expected to match current proposal
+        https://bugs.webkit.org/show_bug.cgi?id=177881
+
+        Reviewed by Mark Lam.
+
+        The proposal is likely to be in C++20 and I've been asked to help co-champion
+        it. I'm therefore updating our implementation to more closely match the current
+        proposal, and to make sure it'll work for us if standardized.
+
+         - Rename UnexpectedType to Unexpected to match the proposal.
+         - Remove relational operators, only equality / inequality remains.
+         - Fix minor type signatures.
+         - Add UnexpectedType typedef.
+         - Uncomment rebind implementation.
+         - Add in-place construction tag, as well as explicit error construction tag.
+         - Add template unexpected constructor.
+         - Note that make_unexpected isn't in the proposal anymore, but we keep it because we don't have C++17 deduction guides.
+         - Remove hashing, which isn't in the proposal anymore.
+
+        * TestWebKitAPI/Tests/WTF/Expected.cpp:
+        (WTF::operator<<):
+        (TestWebKitAPI::TEST):
+
 2017-10-04  Lucas Forschler  <lforschler@apple.com>
 
         https://bugs.webkit.org/show_bug.cgi?id=177888
index 73654c5..81a8961 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 #include "RefLogger.h"
 
 #include <string>
-#include <unordered_map>
 
 #include <wtf/Expected.h>
 #include <wtf/Ref.h>
 
 namespace WTF {
 
-template <class E> std::ostream& operator<<(std::ostream& os, const UnexpectedType<E>& u)
+template<typename T0, typename T1> std::ostream& operator<<(std::ostream& os, const std::pair<T0, T1>& p)
+{
+    return os << '(' << p.first << ", " << p.second << ')';
+}
+
+template<class E> std::ostream& operator<<(std::ostream& os, const Unexpected<E>& u)
 {
     return os << u.value();
 }
 
-template <class T, class E> std::ostream& operator<<(std::ostream& os, const Expected<T, E>& e)
+template<class T, class E> std::ostream& operator<<(std::ostream& os, const Expected<T, E>& e)
 {
     if (e.hasValue())
         return os << e.value();
     return os << e.error();
 }
 
-template <class E> std::ostream& operator<<(std::ostream& os, const Expected<void, E>& e)
+template<class E> std::ostream& operator<<(std::ostream& os, const Expected<void, E>& e)
 {
     if (e.hasValue())
         return os << "";
@@ -61,19 +65,15 @@ namespace TestWebKitAPI {
 constexpr const char* oops = "oops";
 constexpr const char* foof = "foof";
 
-TEST(WTF_Expected, UnexpectedType)
+TEST(WTF_Expected, Unexpected)
 {
     {
-        auto u = UnexpectedType<int>(42);
+        auto u = Unexpected<int>(42);
         EXPECT_EQ(u.value(), 42);
         constexpr auto c = makeUnexpected(42);
         EXPECT_EQ(c.value(), 42);
         EXPECT_EQ(u, c);
         EXPECT_FALSE(u != c);
-        EXPECT_FALSE(u < c);
-        EXPECT_FALSE(u > c);
-        EXPECT_LE(u, c);
-        EXPECT_GE(u, c);
     }
     {
         auto c = makeUnexpected(oops);
@@ -227,7 +227,7 @@ TEST(WTF_Expected, expected)
     }
 }
 
-TEST(WTF_Expected, Expected_void)
+TEST(WTF_Expected, void)
 {
     typedef Expected<void, const char*> E;
     typedef Expected<void, const void*> EV;
@@ -308,6 +308,10 @@ TEST(WTF_Expected, Expected_void)
         EXPECT_EQ(e0, *e5);
         delete e5;
     }
+    {
+        typedef Expected<std::pair<int, int>, std::string> Et;
+        EXPECT_EQ(Et(WTF::InPlace, 1, 2), Et(WTF::InPlace, 1, 2));
+    }
 }
 
 TEST(WTF_Expected, comparison)
@@ -318,99 +322,43 @@ TEST(WTF_Expected, comparison)
     // Two Expected, no errors.
     EXPECT_EQ(Ex(42), Ex(42));
     EXPECT_NE(Ex(42), Ex(1024));
-    EXPECT_LT(Ex(42), Ex(1024));
-    EXPECT_GT(Ex(1024), Ex(42));
-    EXPECT_LE(Ex(42), Ex(42));
-    EXPECT_GE(Ex(42), Ex(42));
-    EXPECT_LE(Ex(42), Ex(1024));
-    EXPECT_GE(Ex(1024), Ex(42));
 
     EXPECT_FALSE(Ex(42) == Ex(1024));
     EXPECT_FALSE(Ex(42) != Ex(42));
-    EXPECT_FALSE(Ex(1024) < Ex(42));
-    EXPECT_FALSE(Ex(42) > Ex(1024));
-    EXPECT_FALSE(Ex(1024) < Ex(42));
-    EXPECT_FALSE(Ex(42) >= Ex(1024));
 
     // Two Expected, half errors.
     EXPECT_FALSE(Ex(42) == Ex(makeUnexpected(oops)));
     EXPECT_NE(Ex(42), Ex(makeUnexpected(oops)));
-    EXPECT_LT(Ex(42), Ex(makeUnexpected(oops)));
-    EXPECT_FALSE(Ex(42) > Ex(makeUnexpected(oops)));
-    EXPECT_LE(Ex(42), Ex(makeUnexpected(oops)));
-    EXPECT_FALSE(Ex(42) >= Ex(makeUnexpected(oops)));
 
     EXPECT_FALSE(Ex(makeUnexpected(oops)) == Ex(42));
     EXPECT_NE(Ex(makeUnexpected(oops)), Ex(42));
-    EXPECT_FALSE(Ex(makeUnexpected(oops)) < Ex(42));
-    EXPECT_GT(Ex(makeUnexpected(oops)), Ex(42));
-    EXPECT_FALSE(Ex(makeUnexpected(oops)) <= Ex(42));
-    EXPECT_GE(Ex(makeUnexpected(oops)), Ex(42));
 
     // Two Expected, all errors.
     EXPECT_EQ(Er(42), Er(42));
     EXPECT_NE(Er(42), Er(1024));
-    EXPECT_LT(Er(42), Er(1024));
-    EXPECT_GT(Er(1024), Er(42));
-    EXPECT_LE(Er(42), Er(42));
-    EXPECT_GE(Er(42), Er(42));
-    EXPECT_LE(Er(42), Er(1024));
-    EXPECT_GE(Er(1024), Er(42));
 
     EXPECT_FALSE(Er(42) == Er(1024));
     EXPECT_FALSE(Er(42) != Er(42));
-    EXPECT_FALSE(Er(1024) < Er(42));
-    EXPECT_FALSE(Er(42) > Er(1024));
-    EXPECT_FALSE(Er(1024) <= Er(42));
-    EXPECT_FALSE(Er(42) >= Er(1024));
 
     // One Expected, one value.
     EXPECT_EQ(Ex(42), 42);
     EXPECT_NE(Ex(42), 0);
-    EXPECT_LT(Ex(42), 1024);
-    EXPECT_GT(Ex(1024), 42);
-    EXPECT_LE(Ex(42), 42);
-    EXPECT_GE(Ex(42), 42);
-    EXPECT_LE(Ex(42), 1024);
-    EXPECT_GE(Ex(1024), 42);
 
     EXPECT_FALSE(Ex(42) == 0);
     EXPECT_FALSE(Ex(42) != 42);
-    EXPECT_FALSE(Ex(1024) < 42);
-    EXPECT_FALSE(Ex(42) > 1024);
-    EXPECT_FALSE(Ex(1024) < 42);
-    EXPECT_FALSE(Ex(42) >= 1024);
 
     EXPECT_EQ(42, Ex(42));
     EXPECT_NE(42, Ex(1024));
-    EXPECT_LT(42, Ex(1024));
-    EXPECT_GT(1024, Ex(42));
-    EXPECT_LE(42, Ex(42));
-    EXPECT_GE(42, Ex(42));
-    EXPECT_LE(42, Ex(1024));
-    EXPECT_GE(1024, Ex(42));
 
     EXPECT_FALSE(42 == Ex(1024));
     EXPECT_FALSE(42 != Ex(42));
-    EXPECT_FALSE(1024 < Ex(42));
-    EXPECT_FALSE(42 > Ex(1024));
-    EXPECT_FALSE(1024 <= Ex(42));
-    EXPECT_FALSE(42 >= Ex(1024));
 
     // One Expected, one unexpected.
     EXPECT_FALSE(Ex(42) == makeUnexpected(oops));
     EXPECT_NE(Ex(42), makeUnexpected(oops));
-    EXPECT_LT(Ex(42), makeUnexpected(oops));
-    EXPECT_FALSE(Ex(42) > makeUnexpected(oops));
-    EXPECT_LE(Ex(42), makeUnexpected(oops));
-    EXPECT_FALSE(Ex(42) >= makeUnexpected(oops));
 
     EXPECT_FALSE(makeUnexpected(oops) == Ex(42));
     EXPECT_NE(makeUnexpected(oops), Ex(42));
-    EXPECT_FALSE(makeUnexpected(oops) < Ex(42));
-    EXPECT_GT(makeUnexpected(oops), Ex(42));
-    EXPECT_FALSE(makeUnexpected(oops) <= Ex(42));
-    EXPECT_GE(makeUnexpected(oops), Ex(42));
 }
 
 struct NonTrivialDtor {
@@ -444,32 +392,6 @@ TEST(WTF_Expected, destructors)
     EXPECT_EQ(NonTrivialDtor::count, 11);
 }
 
-TEST(WTF_Expected, hash)
-{
-    typedef Expected<int, const char*> E;
-    std::unordered_map<E, int> m;
-    m.insert({ E(42), 42 });
-    m.insert({ E(makeUnexpected(oops)), 5 });
-    m.insert({ E(1024), 1024 });
-    m.insert({ E(makeUnexpected(foof)), 0xf00f });
-    EXPECT_EQ(m[E(42)], 42);
-    EXPECT_EQ(m[E(1024)], 1024);
-    EXPECT_EQ(m[E(makeUnexpected(oops))], 5);
-    EXPECT_EQ(m[E(makeUnexpected(foof))], 0xf00f);
-}
-
-TEST(WTF_Expected, hash_void)
-{
-    typedef Expected<void, const char*> E;
-    std::unordered_map<E, int> m;
-    m.insert({ E(), 42 });
-    m.insert({ E(makeUnexpected(oops)), 5 });
-    m.insert({ E(makeUnexpected(foof)), 0xf00f });
-    EXPECT_EQ(m[E()], 42);
-    EXPECT_EQ(m[E(makeUnexpected(oops))], 5);
-    EXPECT_EQ(m[E(makeUnexpected(foof))], 0xf00f);
-}
-
 TEST(WTF_Expected, Ref)
 {
     {