Diff
Modified: trunk/Source/WTF/ChangeLog (208669 => 208670)
--- trunk/Source/WTF/ChangeLog 2016-11-13 18:31:14 UTC (rev 208669)
+++ trunk/Source/WTF/ChangeLog 2016-11-13 19:28:36 UTC (rev 208670)
@@ -1,3 +1,55 @@
+2016-11-13 JF Bastien <[email protected]>
+
+ Implement WTF::Expected
+ https://bugs.webkit.org/show_bug.cgi?id=164526
+
+ Reviewed by Yusuke Suzuki.
+
+ std::expected isn't in C++17, and may be in C++20. It's a nice
+ complement to std::any / std::optional because it's a type-tagged
+ union which has a single expected result but could also contain an
+ error.
+
+ This would be useful in the WebAssembly parser, for example.
+
+ Using this implementation will allow us to provide feedback to the
+ standards committee and guide std::expected's design before it
+ gets standardized. I've already sent a bunch of feedback to the
+ author based on my experience implementing this.
+
+ This could supplement WTF::Either and WTF::ExceptionOr.
+
+ * WTF.xcodeproj/project.pbxproj:
+ * wtf/Compiler.h: Add RELAXED_CONSTEXPR
+ * wtf/Expected.h: Added.
+ (WTF::UnexpectedType::UnexpectedType):
+ (WTF::UnexpectedType::value):
+ (WTF::operator==):
+ (WTF::operator!=):
+ (WTF::operator<):
+ (WTF::operator>):
+ (WTF::operator<=):
+ (WTF::operator>=):
+ (WTF::makeUnexpected):
+ (WTF::ExpectedDetail::Throw):
+ (WTF::ExpectedDetail::ConstexprBase::ConstexprBase):
+ (WTF::ExpectedDetail::Base::Base):
+ (WTF::ExpectedDetail::Base::~Base):
+ (WTF::Expected::Expected):
+ (WTF::Expected::operator=):
+ (WTF::Expected::swap):
+ (WTF::Expected::operator->):
+ (WTF::Expected::operator*):
+ (WTF::Expected::operator bool):
+ (WTF::Expected::hasValue):
+ (WTF::Expected::value):
+ (WTF::Expected::error):
+ (WTF::Expected::getUnexpected):
+ (WTF::Expected::valueOr):
+ (WTF::swap):
+ (WTF::makeExpected):
+ (WTF::makeExpectedFromError):
+
2016-11-11 Alex Christensen <[email protected]>
Allow mutable lambdas in HashMap::ensure
Modified: trunk/Source/WTF/WTF.xcodeproj/project.pbxproj (208669 => 208670)
--- trunk/Source/WTF/WTF.xcodeproj/project.pbxproj 2016-11-13 18:31:14 UTC (rev 208669)
+++ trunk/Source/WTF/WTF.xcodeproj/project.pbxproj 2016-11-13 19:28:36 UTC (rev 208670)
@@ -328,6 +328,7 @@
A8A47486151A825B004123FF /* WTFThreadData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A8A4737A151A825B004123FF /* WTFThreadData.cpp */; };
A8A47487151A825B004123FF /* WTFThreadData.h in Headers */ = {isa = PBXBuildFile; fileRef = A8A4737B151A825B004123FF /* WTFThreadData.h */; };
A8A4748C151A8264004123FF /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = A8A4748B151A8264004123FF /* config.h */; };
+ AD7C434B1DD2A4A70026888B /* Expected.h in Headers */ = {isa = PBXBuildFile; fileRef = AD7C434A1DD2A4A70026888B /* Expected.h */; };
B38FD7BD168953E80065C969 /* FeatureDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = B38FD7BC168953E80065C969 /* FeatureDefines.h */; };
C4F8A93719C65EB400B2B15D /* Stopwatch.h in Headers */ = {isa = PBXBuildFile; fileRef = C4F8A93619C65EB400B2B15D /* Stopwatch.h */; };
C8B0E1A1E01A486EB95E0D11 /* IndexSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 3137E1D7DBD84AC38FAE4D34 /* IndexSet.h */; };
@@ -695,6 +696,7 @@
A8A4737A151A825B004123FF /* WTFThreadData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WTFThreadData.cpp; sourceTree = "<group>"; };
A8A4737B151A825B004123FF /* WTFThreadData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WTFThreadData.h; sourceTree = "<group>"; };
A8A4748B151A8264004123FF /* config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = config.h; sourceTree = "<group>"; };
+ AD7C434A1DD2A4A70026888B /* Expected.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Expected.h; sourceTree = "<group>"; };
B38FD7BC168953E80065C969 /* FeatureDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FeatureDefines.h; sourceTree = "<group>"; };
C4F8A93619C65EB400B2B15D /* Stopwatch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Stopwatch.h; sourceTree = "<group>"; };
CD5497AA15857D0300B5BC30 /* MediaTime.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MediaTime.cpp; sourceTree = "<group>"; };
@@ -848,6 +850,7 @@
A876DBD6151816E500DADB95 /* wtf */ = {
isa = PBXGroup;
children = (
+ AD7C434A1DD2A4A70026888B /* Expected.h */,
2CDED0F018115C3F004DBA70 /* cf */,
E4A0AD3B1A96251900536DF6 /* cocoa */,
A8A47281151A825A004123FF /* dtoa */,
@@ -1457,6 +1460,7 @@
A8A4743E151A825B004123FF /* StringConcatenate.h in Headers */,
A8A4742C151A825B004123FF /* StringExtras.h in Headers */,
A8A4743F151A825B004123FF /* StringHash.h in Headers */,
+ AD7C434B1DD2A4A70026888B /* Expected.h in Headers */,
A748745417A0BDAE00FA04CB /* StringHashDumpContext.h in Headers */,
A8A47441151A825B004123FF /* StringImpl.h in Headers */,
A8A47442151A825B004123FF /* StringOperators.h in Headers */,
Modified: trunk/Source/WTF/wtf/Compiler.h (208669 => 208670)
--- trunk/Source/WTF/wtf/Compiler.h 2016-11-13 18:31:14 UTC (rev 208669)
+++ trunk/Source/WTF/wtf/Compiler.h 2016-11-13 19:28:36 UTC (rev 208670)
@@ -72,7 +72,7 @@
#endif
#endif
-#endif
+#endif // defined(__clang__)
/* COMPILER(GCC_OR_CLANG) - GNU Compiler Collection or Clang */
#if defined(__GNUC__)
@@ -144,6 +144,20 @@
#define WTF_COMPILER_SUPPORTS_EABI 1
#endif
+/* RELAXED_CONSTEXPR */
+
+#if defined(__cpp_constexpr) && __cpp_constexpr >= 201304
+#define WTF_COMPILER_SUPPORTS_RELAXED_CONSTEXPR 1
+#endif
+
+#if !defined(RELAXED_CONSTEXPR)
+#if COMPILER_SUPPORTS(RELAXED_CONSTEXPR)
+#define RELAXED_CONSTEXPR constexpr
+#else
+#define RELAXED_CONSTEXPR
+#endif
+#endif
+
#define ASAN_ENABLED COMPILER_HAS_CLANG_FEATURE(address_sanitizer)
#if ASAN_ENABLED
Added: trunk/Source/WTF/wtf/Expected.h (0 => 208670)
--- trunk/Source/WTF/wtf/Expected.h (rev 0)
+++ trunk/Source/WTF/wtf/Expected.h 2016-11-13 19:28:36 UTC (rev 208670)
@@ -0,0 +1,442 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// WTF::Expected is based on std::expected, as described here: http://wg21.link/p0323r1
+// The specification expects to throw. This implementation doesn't support exceptions, uses RELEASE_ASSERT instead.
+
+#pragma once
+
+#include <cstdlib>
+#include <functional>
+#include <initializer_list>
+#include <type_traits>
+#include <utility>
+#include <wtf/Assertions.h>
+#include <wtf/Compiler.h>
+#include <wtf/Optional.h>
+#include <wtf/StdLibExtras.h>
+
+namespace WTF {
+
+template <class E>
+class UnexpectedType {
+public:
+ UnexpectedType() = delete;
+ constexpr explicit UnexpectedType(const E& e) : val(e) { }
+ constexpr explicit UnexpectedType(E&& e) : val(WTFMove(e)) { }
+ constexpr const E& value() const { return val; }
+ RELAXED_CONSTEXPR E& value() { return val; }
+
+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 UnexpectedType<std::decay_t<E>> makeUnexpected(E&& v) { return UnexpectedType<typename std::decay<E>::type>(std::forward<E>(v)); }
+
+struct UnexpectTag {
+ UnexpectTag() = delete;
+};
+constexpr UnexpectTag Unexpect { };
+
+namespace ExpectedDetail {
+
+// Invoked where std::Expected would instead throw.
+NO_RETURN_DUE_TO_CRASH void Throw() { RELEASE_ASSERT_NOT_REACHED(); }
+
+static constexpr enum class ValueTagType { } ValueTag { };
+static constexpr enum class ErrorTagType { } ErrorTag { };
+
+template<class T, std::enable_if_t<std::is_trivially_destructible<T>::value>* = nullptr> void destroy(T& 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>
+union ConstexprStorage {
+ typedef T ValueType;
+ typedef E ErrorType;
+ char dummy;
+ ValueType val;
+ ErrorType err;
+ constexpr ConstexprStorage() : dummy() { }
+ constexpr ConstexprStorage(ValueTagType) : val() { }
+ constexpr ConstexprStorage(ErrorTagType) : err() { }
+ constexpr ConstexprStorage(ValueTagType, const ValueType& v) : val(v) { }
+ constexpr ConstexprStorage(ErrorTagType, const ErrorType& e) : err(e) { }
+ ~ConstexprStorage() = default;
+};
+
+template <class T, class E>
+union Storage {
+ typedef T ValueType;
+ typedef E ErrorType;
+ char dummy;
+ ValueType val;
+ ErrorType err;
+ constexpr Storage() : dummy() { }
+ constexpr Storage(ValueTagType) : val() { }
+ constexpr Storage(ErrorTagType) : err() { }
+ constexpr Storage(ValueTagType, const ValueType& val) : val(val) { }
+ constexpr Storage(ErrorTagType, const ErrorType& err) : err(err) { }
+ ~Storage() { }
+};
+
+template <class E>
+union ConstexprStorage<void, E> {
+ typedef void ValueType;
+ typedef E ErrorType;
+ char dummy;
+ ErrorType err;
+ constexpr ConstexprStorage() : dummy() { }
+ constexpr ConstexprStorage(ValueTagType) : dummy() { }
+ constexpr ConstexprStorage(ErrorTagType) : err() { }
+ constexpr ConstexprStorage(ErrorTagType, const ErrorType& e) : err(e) { }
+ ~ConstexprStorage() = default;
+};
+
+template <class E>
+union Storage<void, E> {
+ typedef void ValueType;
+ typedef E ErrorType;
+ char dummy;
+ ErrorType err;
+ constexpr Storage() : dummy() { }
+ constexpr Storage(ValueTagType) : dummy() { }
+ constexpr Storage(ErrorTagType) : err() { }
+ constexpr Storage(ErrorTagType, const ErrorType& err) : err(err) { }
+ ~Storage() { }
+};
+
+template <class T, class E>
+struct ConstexprBase {
+ typedef T ValueType;
+ typedef E ErrorType;
+ ConstexprStorage<ValueType, ErrorType> s;
+ bool has;
+ constexpr ConstexprBase() : s(), has(true) { }
+ constexpr ConstexprBase(ValueTagType tag) : s(tag), has(true) { }
+ constexpr ConstexprBase(ErrorTagType tag) : s(tag), has(false) { }
+ constexpr ConstexprBase(ValueTagType tag, const ValueType& val) : s(tag, val), has(true) { }
+ constexpr ConstexprBase(ErrorTagType tag, const ErrorType& err) : s(tag, err), has(false) { }
+ ~ConstexprBase() = default;
+};
+
+template <class T, class E>
+struct Base {
+ typedef T ValueType;
+ typedef E ErrorType;
+ Storage<ValueType, ErrorType> s;
+ bool has;
+ constexpr Base() : s(), has(true) { }
+ constexpr Base(ValueTagType tag) : s(tag), has(true) { }
+ constexpr Base(ErrorTagType tag) : s(tag), has(false) { }
+ constexpr Base(ValueTagType tag, const ValueType& val) : s(tag, val), has(true) { }
+ constexpr Base(ErrorTagType tag, const ErrorType& err) : s(tag, err), has(false) { }
+ Base(const Base& o)
+ : has(o.has)
+ {
+ if (has)
+ ::new (&s.val) ValueType(o.s.val);
+ else
+ ::new (&s.err) ErrorType(o.s.err);
+ }
+ Base(Base&& o)
+ : has(o.has)
+ {
+ if (has)
+ ::new (&s.val) ValueType(WTFMove(o.s.val));
+ else
+ ::new (&s.err) ErrorType(WTFMove(o.s.err));
+ }
+ ~Base()
+ {
+ if (has)
+ destroy(s.val);
+ else
+ destroy(s.err);
+ }
+};
+
+template <class E>
+struct ConstexprBase<void, E> {
+ typedef void ValueType;
+ typedef E ErrorType;
+ ConstexprStorage<ValueType, ErrorType> s;
+ bool has;
+ constexpr ConstexprBase() : s(), has(true) { }
+ constexpr ConstexprBase(ValueTagType tag) : s(tag), has(true) { }
+ constexpr ConstexprBase(ErrorTagType tag) : s(tag), has(false) { }
+ constexpr ConstexprBase(ErrorTagType tag, const ErrorType& err) : s(tag, err), has(false) { }
+ ~ConstexprBase() = default;
+};
+
+template <class E>
+struct Base<void, E> {
+ typedef void ValueType;
+ typedef E ErrorType;
+ Storage<ValueType, ErrorType> s;
+ bool has;
+ constexpr Base() : s(), has(true) { }
+ constexpr Base(ValueTagType tag) : s(tag), has(true) { }
+ constexpr Base(ErrorTagType tag) : s(tag), has(false) { }
+ constexpr Base(ErrorTagType tag, const ErrorType& err) : s(tag, err), has(false) { }
+ Base(const Base& o)
+ : has(o.has)
+ {
+ if (!has)
+ ::new (&s.err) ErrorType(o.s.err);
+ }
+ Base(Base&& o)
+ : has(o.has)
+ {
+ if (!has)
+ ::new (&s.err) ErrorType(WTFMove(o.s.err));
+ }
+ ~Base()
+ {
+ if (!has)
+ destroy(s.err);
+ }
+};
+
+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),
+ ConstexprBase<typename std::remove_const<T>::type, typename std::remove_const<E>::type>,
+ Base<typename std::remove_const<T>::type, typename std::remove_const<E>::type>
+>::type;
+
+} // namespace ExpectedDetail
+
+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;
+
+private:
+ typedef Expected<ValueType, ErrorType> type;
+
+public:
+ // 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, WTFMove(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()) { }
+ 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&&...);
+
+ ~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&&...);
+
+ void swap(Expected& o)
+ {
+ using std::swap;
+ if (base::has && o.has)
+ swap(base::s.val, o.s.val);
+ else if (base::has && !o.has) {
+ ErrorType e(WTFMove(o.s.err));
+ ::new (&o.s.val) ValueType(WTFMove(base::s.val));
+ ::new (&base::s.err) ErrorType(e);
+ swap(base::has, o.has);
+ } else if (!base::has && o.has) {
+ ValueType v(WTFMove(o.s.val));
+ ::new (&o.s.err) ErrorType(WTFMove(base::s.err));
+ ::new (&base::s.val) ValueType(v);
+ swap(base::has, o.has);
+ } else
+ swap(base::s.err, o.s.err);
+ }
+
+ constexpr const ValueType* operator->() const { return &base::s.val; }
+ ValueType* operator->() { return &base::s.val; }
+ constexpr const ValueType& operator*() const & { return base::s.val; }
+ ValueType& operator*() & { return base::s.val; }
+ constexpr const ValueType&& operator*() const && { return WTFMove(base::s.val); }
+ RELAXED_CONSTEXPR ValueType&& operator*() && { return WTFMove(base::s.val); }
+ constexpr explicit operator bool() const { return base::has; }
+ constexpr bool hasValue() const { return base::has; }
+ constexpr const ValueType& value() const & { return base::has ? base::s.val : (ExpectedDetail::Throw(), base::s.val); }
+ RELAXED_CONSTEXPR ValueType& value() & { return base::has ? base::s.val : (ExpectedDetail::Throw(), base::s.val); }
+ constexpr const ValueType&& value() const && { return base::has ? base::s.val : (ExpectedDetail::Throw(), base::s.val); }
+ RELAXED_CONSTEXPR ValueType&& value() && { return base::has ? base::s.val : (ExpectedDetail::Throw(), base::s.val); }
+ constexpr const ErrorType& error() const & { return !base::has ? base::s.err : (ExpectedDetail::Throw(), base::s.err); }
+ 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)); }
+};
+
+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;
+
+private:
+ typedef Expected<ValueType, ErrorType> type;
+
+public:
+ // template <class U> struct rebind { typedef Expected<U, ErrorType> type; };
+
+ 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()) { }
+ template <class Err> constexpr Expected(UnexpectedType<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.
+ // void emplace();
+
+ void swap(Expected& o)
+ {
+ using std::swap;
+ if (base::has && o.has) {
+ // Do nothing.
+ } else if (base::has && !o.has) {
+ ErrorType e(WTFMove(o.s.err));
+ ::new (&base::s.err) ErrorType(e);
+ swap(base::has, o.has);
+ } else if (!base::has && o.has) {
+ ::new (&o.s.err) ErrorType(WTFMove(base::s.err));
+ swap(base::has, o.has);
+ } else
+ swap(base::s.err, o.s.err);
+ }
+
+ constexpr explicit operator bool() const { return base::has; }
+ constexpr bool hasValue() const { return base::has; }
+ void value() const { !base::has ? ExpectedDetail::Throw() : void(); }
+ constexpr const E& error() const & { return !base::has ? base::s.err : (ExpectedDetail::Throw(), base::s.err); }
+ E& error() & { return !base::has ? base::s.err : (ExpectedDetail::Throw(), base::s.err); } // Not in the current paper.
+ 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); }
+};
+
+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 = WTF::NulloptTag> 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 = WTF::NulloptTag> constexpr Expected<typename std::result_of<F>::type, E> makeExpected_from_call(F f);
+
+Expected<void, WTF::NulloptTag> makeExpected() { return Expected<void, WTF::NulloptTag>(); }
+
+} // 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::makeUnexpected;
+using WTF::Unexpect;
+using WTF::Expected;
+using WTF::makeExpected;
+using WTF::makeExpectedFromError;
Modified: trunk/Tools/ChangeLog (208669 => 208670)
--- trunk/Tools/ChangeLog 2016-11-13 18:31:14 UTC (rev 208669)
+++ trunk/Tools/ChangeLog 2016-11-13 19:28:36 UTC (rev 208670)
@@ -1,3 +1,34 @@
+2016-11-13 JF Bastien <[email protected]>
+
+ Implement WTF::Expected
+ https://bugs.webkit.org/show_bug.cgi?id=164526
+
+ Reviewed by Yusuke Suzuki.
+
+ std::expected isn't in C++17, and may be in C++20. It's a nice
+ complement to std::any / std::optional because it's a type-tagged
+ union which has a single expected result but could also contain an
+ error.
+
+ This would be useful in the WebAssembly parser, for example.
+
+ Using this implementation will allow us to provide feedback to the
+ standards committee and guide std::expected's design before it
+ gets standardized. I've already sent a bunch of feedback to the
+ author based on my experience implementing this.
+
+ This could supplement WTF::Either and WTF::ExceptionOr.
+
+ * TestWebKitAPI/CMakeLists.txt:
+ * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+ * TestWebKitAPI/Tests/WTF/Expected.cpp: Added.
+ (WTF::operator<<):
+ (TestWebKitAPI::TEST):
+ (TestWebKitAPI::foo::foo):
+ (TestWebKitAPI::foo::~foo):
+ (TestWebKitAPI::foo::operator==):
+ (TestWebKitAPI::operator<<):
+
2016-11-12 Simon Fraser <[email protected]>
Add a way to get the UI-side scrolling tree as text via UIScriptController
Modified: trunk/Tools/DumpRenderTree/PlatformMac.cmake (208669 => 208670)
--- trunk/Tools/DumpRenderTree/PlatformMac.cmake 2016-11-13 18:31:14 UTC (rev 208669)
+++ trunk/Tools/DumpRenderTree/PlatformMac.cmake 2016-11-13 19:28:36 UTC (rev 208670)
@@ -76,7 +76,7 @@
mac/ObjCController.m
mac/ObjCPlugin.m
mac/ObjCPluginFunction.m
- mac/TextInputController.m
+ mac/TextInputControllerMac.m
)
list(APPEND DumpRenderTree_Cpp_SOURCES
Modified: trunk/Tools/TestWebKitAPI/CMakeLists.txt (208669 => 208670)
--- trunk/Tools/TestWebKitAPI/CMakeLists.txt 2016-11-13 18:31:14 UTC (rev 208669)
+++ trunk/Tools/TestWebKitAPI/CMakeLists.txt 2016-11-13 19:28:36 UTC (rev 208670)
@@ -50,6 +50,7 @@
${TESTWEBKITAPI_DIR}/Tests/WTF/DateMath.cpp
${TESTWEBKITAPI_DIR}/Tests/WTF/Deque.cpp
${TESTWEBKITAPI_DIR}/Tests/WTF/EnumTraits.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/Expected.cpp
${TESTWEBKITAPI_DIR}/Tests/WTF/HashCountedSet.cpp
${TESTWEBKITAPI_DIR}/Tests/WTF/HashMap.cpp
${TESTWEBKITAPI_DIR}/Tests/WTF/HashSet.cpp
@@ -61,6 +62,7 @@
${TESTWEBKITAPI_DIR}/Tests/WTF/MediaTime.cpp
${TESTWEBKITAPI_DIR}/Tests/WTF/MetaAllocator.cpp
${TESTWEBKITAPI_DIR}/Tests/WTF/NakedPtr.cpp
+ ${TESTWEBKITAPI_DIR}/Tests/WTF/Optional.cpp
${TESTWEBKITAPI_DIR}/Tests/WTF/OptionSet.cpp
${TESTWEBKITAPI_DIR}/Tests/WTF/ParkingLot.cpp
${TESTWEBKITAPI_DIR}/Tests/WTF/RedBlackTree.cpp
Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (208669 => 208670)
--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj 2016-11-13 18:31:14 UTC (rev 208669)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj 2016-11-13 19:28:36 UTC (rev 208670)
@@ -455,6 +455,7 @@
AD57AC201DA7465000FF1BDE /* DidRemoveFrameFromHiearchyInPageCache_Bundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AD57AC1E1DA7464D00FF1BDE /* DidRemoveFrameFromHiearchyInPageCache_Bundle.cpp */; };
AD57AC211DA7465B00FF1BDE /* DidRemoveFrameFromHiearchyInPageCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AD57AC1F1DA7464D00FF1BDE /* DidRemoveFrameFromHiearchyInPageCache.cpp */; };
AD57AC221DA7466E00FF1BDE /* many-iframes.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = AD57AC1D1DA7463800FF1BDE /* many-iframes.html */; };
+ AD7C434D1DD2A54E0026888B /* Expected.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AD7C434C1DD2A5470026888B /* Expected.cpp */; };
ADCEBBA61D9AE229002E283A /* Consume.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ADCEBBA51D99D4CF002E283A /* Consume.cpp */; };
B55AD1D5179F3B3000AC1494 /* PreventImageLoadWithAutoResizing_Bundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B55AD1D3179F3ABF00AC1494 /* PreventImageLoadWithAutoResizing_Bundle.cpp */; };
B55F11B71517D03300915916 /* attributedStringCustomFont.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = B55F11B01517A2C400915916 /* attributedStringCustomFont.html */; };
@@ -1112,6 +1113,7 @@
AD57AC1D1DA7463800FF1BDE /* many-iframes.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "many-iframes.html"; sourceTree = "<group>"; };
AD57AC1E1DA7464D00FF1BDE /* DidRemoveFrameFromHiearchyInPageCache_Bundle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DidRemoveFrameFromHiearchyInPageCache_Bundle.cpp; sourceTree = "<group>"; };
AD57AC1F1DA7464D00FF1BDE /* DidRemoveFrameFromHiearchyInPageCache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DidRemoveFrameFromHiearchyInPageCache.cpp; sourceTree = "<group>"; };
+ AD7C434C1DD2A5470026888B /* Expected.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Expected.cpp; sourceTree = "<group>"; };
ADCEBBA51D99D4CF002E283A /* Consume.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Consume.cpp; sourceTree = "<group>"; };
B4039F9C15E6D8B3007255D6 /* MathExtras.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MathExtras.cpp; sourceTree = "<group>"; };
B55AD1D1179F336600AC1494 /* PreventImageLoadWithAutoResizing.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = PreventImageLoadWithAutoResizing.mm; path = WebKit2ObjC/PreventImageLoadWithAutoResizing.mm; sourceTree = "<group>"; };
@@ -1799,6 +1801,7 @@
BC9096461255618900083756 /* WTF */ = {
isa = PBXGroup;
children = (
+ AD7C434C1DD2A5470026888B /* Expected.cpp */,
C0991C4F143C7D68007998F2 /* cf */,
7CBBA07519BB8A0900BBF025 /* darwin */,
BC029B1A1486B23800817DA9 /* ns */,
@@ -2331,6 +2334,7 @@
7C83DEFE1D0A590C00FEBCF3 /* NakedPtr.cpp in Sources */,
7C83DF011D0A590C00FEBCF3 /* Optional.cpp in Sources */,
ADCEBBA61D9AE229002E283A /* Consume.cpp in Sources */,
+ AD7C434D1DD2A54E0026888B /* Expected.cpp in Sources */,
7C83DF021D0A590C00FEBCF3 /* OSObjectPtr.cpp in Sources */,
7C83DF591D0A590C00FEBCF3 /* ParkingLot.cpp in Sources */,
7C83DF131D0A590C00FEBCF3 /* RedBlackTree.cpp in Sources */,
Added: trunk/Tools/TestWebKitAPI/Tests/WTF/Expected.cpp (0 => 208670)
--- trunk/Tools/TestWebKitAPI/Tests/WTF/Expected.cpp (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WTF/Expected.cpp 2016-11-13 19:28:36 UTC (rev 208670)
@@ -0,0 +1,470 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <string>
+#include <unordered_map>
+
+#include <wtf/Expected.h>
+
+namespace WTF {
+
+template <class E> std::ostream& operator<<(std::ostream& os, const UnexpectedType<E>& u)
+{
+ return os << u.value();
+}
+
+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)
+{
+ if (e.hasValue())
+ return os << "";
+ return os << e.error();
+}
+
+}
+
+namespace TestWebKitAPI {
+
+constexpr const char* oops = "oops";
+constexpr const char* foof = "foof";
+
+TEST(WTF_Expected, UnexpectedType)
+{
+ {
+ auto u = UnexpectedType<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);
+ EXPECT_EQ(c.value(), oops);
+ }
+ {
+ auto s = makeUnexpected(std::string(oops));
+ EXPECT_EQ(s.value(), oops);
+ }
+ {
+ constexpr auto s0 = makeUnexpected(oops);
+ constexpr auto s1(s0);
+ EXPECT_EQ(s0, s1);
+ }
+}
+
+struct foo {
+ int v;
+ foo(int v)
+ : v(v)
+ { }
+ ~foo() { }
+ bool operator==(const foo& y) const { return v == y.v; }
+ friend std::ostream& operator<<(std::ostream&, const foo&);
+};
+std::ostream& operator<<(std::ostream& os, const foo& f) { return os << f.v; }
+
+TEST(WTF_Expected, expected)
+{
+ typedef Expected<int, const char*> E;
+ typedef Expected<int, const void*> EV;
+ typedef Expected<foo, const char*> FooChar;
+ typedef Expected<foo, std::string> FooString;
+ {
+ auto e = E();
+ EXPECT_TRUE(e.hasValue());
+ EXPECT_EQ(e.value(), 0);
+ EXPECT_EQ(e.valueOr(3.14), 0);
+ }
+ {
+ constexpr E e;
+ EXPECT_TRUE(e.hasValue());
+ EXPECT_EQ(e.value(), 0);
+ EXPECT_EQ(e.valueOr(3.14), 0);
+ }
+ {
+ auto e = E(42);
+ EXPECT_TRUE(e.hasValue());
+ EXPECT_EQ(e.value(), 42);
+ EXPECT_EQ(e.valueOr(3.14), 42);
+ const auto e2(e);
+ EXPECT_TRUE(e2.hasValue());
+ EXPECT_EQ(e2.value(), 42);
+ EXPECT_EQ(e2.valueOr(3.14), 42);
+ E e3;
+ e3 = e2;
+ EXPECT_TRUE(e3.hasValue());
+ EXPECT_EQ(e3.value(), 42);
+ EXPECT_EQ(e3.valueOr(3.14), 42);
+ const E e4 = e2;
+ EXPECT_TRUE(e4.hasValue());
+ EXPECT_EQ(e4.value(), 42);
+ EXPECT_EQ(e4.valueOr(3.14), 42);
+ }
+ {
+ constexpr E c(42);
+ EXPECT_TRUE(c.hasValue());
+ EXPECT_EQ(c.value(), 42);
+ EXPECT_EQ(c.valueOr(3.14), 42);
+ constexpr const auto c2(c);
+ EXPECT_TRUE(c2.hasValue());
+ EXPECT_EQ(c2.value(), 42);
+ EXPECT_EQ(c2.valueOr(3.14), 42);
+ }
+ {
+ auto u = E(makeUnexpected(oops));
+ EXPECT_FALSE(u.hasValue());
+ EXPECT_EQ(u.error(), oops);
+ EXPECT_EQ(u.getUnexpected().value(), oops);
+ EXPECT_EQ(u.valueOr(3.14), 3);
+ }
+ {
+ auto uv = EV(makeUnexpected(oops));
+ EXPECT_FALSE(uv.hasValue());
+ EXPECT_EQ(uv.error(), oops);
+ EXPECT_EQ(uv.getUnexpected().value(), oops);
+ EXPECT_EQ(uv.valueOr(3.14), 3);
+ }
+ {
+ E e = makeUnexpected(oops);
+ EXPECT_FALSE(e.hasValue());
+ EXPECT_EQ(e.error(), oops);
+ EXPECT_EQ(e.getUnexpected().value(), oops);
+ EXPECT_EQ(e.valueOr(3.14), 3);
+ }
+ {
+ auto e = makeExpectedFromError<int, const char*>(oops);
+ EXPECT_FALSE(e.hasValue());
+ EXPECT_EQ(e.error(), oops);
+ EXPECT_EQ(e.getUnexpected().value(), oops);
+ EXPECT_EQ(e.valueOr(3.14), 3);
+ }
+ {
+ auto e = makeExpectedFromError<int, const void*>(oops);
+ EXPECT_FALSE(e.hasValue());
+ EXPECT_EQ(e.error(), oops);
+ EXPECT_EQ(e.getUnexpected().value(), oops);
+ EXPECT_EQ(e.valueOr(3.14), 3);
+ }
+ {
+ auto e = FooChar(42);
+ EXPECT_EQ(e->v, 42);
+ EXPECT_EQ((*e).v, 42);
+ }
+ {
+ auto e0 = E(42);
+ auto e1 = E(1024);
+ swap(e0, e1);
+ EXPECT_EQ(e0.value(), 1024);
+ EXPECT_EQ(e1.value(), 42);
+ }
+ {
+ auto e0 = E(makeUnexpected(oops));
+ auto e1 = E(makeUnexpected(foof));
+ swap(e0, e1);
+ EXPECT_EQ(e0.error(), foof);
+ EXPECT_EQ(e1.error(), oops);
+ }
+ {
+ FooChar c(foo(42));
+ EXPECT_EQ(c->v, 42);
+ EXPECT_EQ((*c).v, 42);
+ }
+ {
+ FooString s(foo(42));
+ EXPECT_EQ(s->v, 42);
+ EXPECT_EQ((*s).v, 42);
+ const char* message = "very long failure string, for very bad failure cases";
+ FooString e0(makeUnexpected<std::string>(message));
+ FooString e1(makeUnexpected<std::string>(message));
+ FooString e2(makeUnexpected<std::string>(std::string()));
+ EXPECT_EQ(e0.error(), std::string(message));
+ EXPECT_EQ(e0, e1);
+ EXPECT_NE(e0, e2);
+ FooString* e4 = new FooString(makeUnexpected<std::string>(message));
+ FooString* e5 = new FooString(*e4);
+ EXPECT_EQ(e0, *e4);
+ delete e4;
+ EXPECT_EQ(e0, *e5);
+ delete e5;
+ }
+}
+
+TEST(WTF_Expected, Expected_void)
+{
+ typedef Expected<void, const char*> E;
+ typedef Expected<void, const void*> EV;
+ typedef Expected<void, std::string> String;
+ {
+ auto e = E();
+ EXPECT_TRUE(e.hasValue());
+ const auto e2(e);
+ EXPECT_TRUE(e2.hasValue());
+ EXPECT_EQ(e, e2);
+ E e3;
+ e3 = e2;
+ EXPECT_TRUE(e3.hasValue());
+ EXPECT_EQ(e, e3);
+ }
+ {
+ constexpr E c;
+ EXPECT_TRUE(c.hasValue());
+ constexpr const auto c2(c);
+ EXPECT_TRUE(c2.hasValue());
+ EXPECT_EQ(c, c2);
+ }
+ {
+ auto u = E(makeUnexpected(oops));
+ EXPECT_FALSE(u.hasValue());
+ EXPECT_EQ(u.error(), oops);
+ EXPECT_EQ(u.getUnexpected().value(), oops);
+ }
+ {
+ auto uv = EV(makeUnexpected(oops));
+ EXPECT_FALSE(uv.hasValue());
+ EXPECT_EQ(uv.error(), oops);
+ EXPECT_EQ(uv.getUnexpected().value(), oops);
+ }
+ {
+ E e = makeUnexpected(oops);
+ EXPECT_FALSE(e.hasValue());
+ EXPECT_EQ(e.error(), oops);
+ EXPECT_EQ(e.getUnexpected().value(), oops);
+ }
+ {
+ auto e = makeExpectedFromError<void, const char*>(oops);
+ EXPECT_FALSE(e.hasValue());
+ EXPECT_EQ(e.error(), oops);
+ EXPECT_EQ(e.getUnexpected().value(), oops);
+ }
+ {
+ auto e = makeExpectedFromError<void, const void*>(oops);
+ EXPECT_FALSE(e.hasValue());
+ EXPECT_EQ(e.error(), oops);
+ EXPECT_EQ(e.getUnexpected().value(), oops);
+ }
+ {
+ auto e0 = E();
+ auto e1 = E();
+ swap(e0, e1);
+ EXPECT_EQ(e0, e1);
+ }
+ {
+ auto e0 = E(makeUnexpected(oops));
+ auto e1 = E(makeUnexpected(foof));
+ swap(e0, e1);
+ EXPECT_EQ(e0.error(), foof);
+ EXPECT_EQ(e1.error(), oops);
+ }
+ {
+ const char* message = "very long failure string, for very bad failure cases";
+ String e0(makeUnexpected<std::string>(message));
+ String e1(makeUnexpected<std::string>(message));
+ String e2(makeUnexpected<std::string>(std::string()));
+ EXPECT_EQ(e0.error(), std::string(message));
+ EXPECT_EQ(e0, e1);
+ EXPECT_NE(e0, e2);
+ String* e4 = new String(makeUnexpected<std::string>(message));
+ String* e5 = new String(*e4);
+ EXPECT_EQ(e0, *e4);
+ delete e4;
+ EXPECT_EQ(e0, *e5);
+ delete e5;
+ }
+}
+
+TEST(WTF_Expected, comparison)
+{
+ typedef Expected<int, const char*> Ex;
+ typedef Expected<int, int> Er;
+
+ // 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 {
+ ~NonTrivialDtor() { ++count; }
+ static int count;
+};
+int NonTrivialDtor::count = 0;
+
+TEST(WTF_Expected, destructors)
+{
+ typedef Expected<NonTrivialDtor, const char*> NT;
+ typedef Expected<const char*, NonTrivialDtor> TN;
+ typedef Expected<NonTrivialDtor, NonTrivialDtor> NN;
+ typedef Expected<void, NonTrivialDtor> VN;
+ EXPECT_EQ(NonTrivialDtor::count, 0);
+ { NT nt; }
+ EXPECT_EQ(NonTrivialDtor::count, 1);
+ { NT nt = makeUnexpected(oops); }
+ EXPECT_EQ(NonTrivialDtor::count, 1);
+ { TN tn; }
+ EXPECT_EQ(NonTrivialDtor::count, 1);
+ { TN tn = makeUnexpected(NonTrivialDtor()); }
+ EXPECT_EQ(NonTrivialDtor::count, 4);
+ { NN nn; }
+ EXPECT_EQ(NonTrivialDtor::count, 5);
+ { NN nn = makeUnexpected(NonTrivialDtor()); }
+ EXPECT_EQ(NonTrivialDtor::count, 8);
+ { VN vn; }
+ EXPECT_EQ(NonTrivialDtor::count, 8);
+ { VN vn = makeUnexpected(NonTrivialDtor()); }
+ 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);
+}
+
+} // namespace TestWebkitAPI