зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1601556 - Make Result<V, E> a literal type if V and E are literal types and PackingStrategy is not Variant. r=emilio
Also make CompactPair<A, B> a literal type if A and B are literal types, and add MaybeStorageBase that ought to be used as a basis of MaybeStorage in a follow-up patch. Differential Revision: https://phabricator.services.mozilla.com/D55930
This commit is contained in:
Родитель
f74737684e
Коммит
ae75c3faa8
|
@ -43,22 +43,22 @@ struct CompactPairHelper<A, B, AsMember, AsMember> {
|
|||
protected:
|
||||
template <typename... AArgs, std::size_t... AIndexes, typename... BArgs,
|
||||
std::size_t... BIndexes>
|
||||
CompactPairHelper(std::tuple<AArgs...>& aATuple,
|
||||
std::tuple<BArgs...>& aBTuple,
|
||||
std::index_sequence<AIndexes...>,
|
||||
std::index_sequence<BIndexes...>)
|
||||
constexpr CompactPairHelper(std::tuple<AArgs...>& aATuple,
|
||||
std::tuple<BArgs...>& aBTuple,
|
||||
std::index_sequence<AIndexes...>,
|
||||
std::index_sequence<BIndexes...>)
|
||||
: mFirstA(std::forward<AArgs>(std::get<AIndexes>(aATuple))...),
|
||||
mSecondB(std::forward<BArgs>(std::get<BIndexes>(aBTuple))...) {}
|
||||
|
||||
public:
|
||||
template <typename AArg, typename BArg>
|
||||
CompactPairHelper(AArg&& aA, BArg&& aB)
|
||||
constexpr CompactPairHelper(AArg&& aA, BArg&& aB)
|
||||
: mFirstA(std::forward<AArg>(aA)), mSecondB(std::forward<BArg>(aB)) {}
|
||||
|
||||
A& first() { return mFirstA; }
|
||||
const A& first() const { return mFirstA; }
|
||||
B& second() { return mSecondB; }
|
||||
const B& second() const { return mSecondB; }
|
||||
constexpr A& first() { return mFirstA; }
|
||||
constexpr const A& first() const { return mFirstA; }
|
||||
constexpr B& second() { return mSecondB; }
|
||||
constexpr const B& second() const { return mSecondB; }
|
||||
|
||||
void swap(CompactPairHelper& aOther) {
|
||||
std::swap(mFirstA, aOther.mFirstA);
|
||||
|
@ -75,22 +75,22 @@ struct CompactPairHelper<A, B, AsMember, AsBase> : private B {
|
|||
protected:
|
||||
template <typename... AArgs, std::size_t... AIndexes, typename... BArgs,
|
||||
std::size_t... BIndexes>
|
||||
CompactPairHelper(std::tuple<AArgs...>& aATuple,
|
||||
std::tuple<BArgs...>& aBTuple,
|
||||
std::index_sequence<AIndexes...>,
|
||||
std::index_sequence<BIndexes...>)
|
||||
constexpr CompactPairHelper(std::tuple<AArgs...>& aATuple,
|
||||
std::tuple<BArgs...>& aBTuple,
|
||||
std::index_sequence<AIndexes...>,
|
||||
std::index_sequence<BIndexes...>)
|
||||
: B(std::forward<BArgs>(std::get<BIndexes>(aBTuple))...),
|
||||
mFirstA(std::forward<AArgs>(std::get<AIndexes>(aATuple))...) {}
|
||||
|
||||
public:
|
||||
template <typename AArg, typename BArg>
|
||||
CompactPairHelper(AArg&& aA, BArg&& aB)
|
||||
constexpr CompactPairHelper(AArg&& aA, BArg&& aB)
|
||||
: B(std::forward<BArg>(aB)), mFirstA(std::forward<AArg>(aA)) {}
|
||||
|
||||
A& first() { return mFirstA; }
|
||||
const A& first() const { return mFirstA; }
|
||||
B& second() { return *this; }
|
||||
const B& second() const { return *this; }
|
||||
constexpr A& first() { return mFirstA; }
|
||||
constexpr const A& first() const { return mFirstA; }
|
||||
constexpr B& second() { return *this; }
|
||||
constexpr const B& second() const { return *this; }
|
||||
|
||||
void swap(CompactPairHelper& aOther) {
|
||||
std::swap(mFirstA, aOther.mFirstA);
|
||||
|
@ -106,22 +106,22 @@ struct CompactPairHelper<A, B, AsBase, AsMember> : private A {
|
|||
protected:
|
||||
template <typename... AArgs, std::size_t... AIndexes, typename... BArgs,
|
||||
std::size_t... BIndexes>
|
||||
CompactPairHelper(std::tuple<AArgs...>& aATuple,
|
||||
std::tuple<BArgs...>& aBTuple,
|
||||
std::index_sequence<AIndexes...>,
|
||||
std::index_sequence<BIndexes...>)
|
||||
constexpr CompactPairHelper(std::tuple<AArgs...>& aATuple,
|
||||
std::tuple<BArgs...>& aBTuple,
|
||||
std::index_sequence<AIndexes...>,
|
||||
std::index_sequence<BIndexes...>)
|
||||
: A(std::forward<AArgs>(std::get<AIndexes>(aATuple))...),
|
||||
mSecondB(std::forward<BArgs>(std::get<BIndexes>(aBTuple))...) {}
|
||||
|
||||
public:
|
||||
template <typename AArg, typename BArg>
|
||||
CompactPairHelper(AArg&& aA, BArg&& aB)
|
||||
constexpr CompactPairHelper(AArg&& aA, BArg&& aB)
|
||||
: A(std::forward<AArg>(aA)), mSecondB(std::forward<BArg>(aB)) {}
|
||||
|
||||
A& first() { return *this; }
|
||||
const A& first() const { return *this; }
|
||||
B& second() { return mSecondB; }
|
||||
const B& second() const { return mSecondB; }
|
||||
constexpr A& first() { return *this; }
|
||||
constexpr const A& first() const { return *this; }
|
||||
constexpr B& second() { return mSecondB; }
|
||||
constexpr const B& second() const { return mSecondB; }
|
||||
|
||||
void swap(CompactPairHelper& aOther) {
|
||||
std::swap(static_cast<A&>(*this), static_cast<A&>(aOther));
|
||||
|
@ -137,22 +137,22 @@ struct CompactPairHelper<A, B, AsBase, AsBase> : private A, private B {
|
|||
protected:
|
||||
template <typename... AArgs, std::size_t... AIndexes, typename... BArgs,
|
||||
std::size_t... BIndexes>
|
||||
CompactPairHelper(std::tuple<AArgs...>& aATuple,
|
||||
std::tuple<BArgs...>& aBTuple,
|
||||
std::index_sequence<AIndexes...>,
|
||||
std::index_sequence<BIndexes...>)
|
||||
constexpr CompactPairHelper(std::tuple<AArgs...>& aATuple,
|
||||
std::tuple<BArgs...>& aBTuple,
|
||||
std::index_sequence<AIndexes...>,
|
||||
std::index_sequence<BIndexes...>)
|
||||
: A(std::forward<AArgs>(std::get<AIndexes>(aATuple))...),
|
||||
B(std::forward<BArgs>(std::get<BIndexes>(aBTuple))...) {}
|
||||
|
||||
public:
|
||||
template <typename AArg, typename BArg>
|
||||
CompactPairHelper(AArg&& aA, BArg&& aB)
|
||||
constexpr CompactPairHelper(AArg&& aA, BArg&& aB)
|
||||
: A(std::forward<AArg>(aA)), B(std::forward<BArg>(aB)) {}
|
||||
|
||||
A& first() { return static_cast<A&>(*this); }
|
||||
const A& first() const { return static_cast<A&>(*this); }
|
||||
B& second() { return static_cast<B&>(*this); }
|
||||
const B& second() const { return static_cast<B&>(*this); }
|
||||
constexpr A& first() { return static_cast<A&>(*this); }
|
||||
constexpr const A& first() const { return static_cast<A&>(*this); }
|
||||
constexpr B& second() { return static_cast<B&>(*this); }
|
||||
constexpr const B& second() const { return static_cast<B&>(*this); }
|
||||
|
||||
void swap(CompactPairHelper& aOther) {
|
||||
std::swap(static_cast<A&>(*this), static_cast<A&>(aOther));
|
||||
|
@ -185,8 +185,8 @@ struct CompactPair : private detail::CompactPairHelper<A, B> {
|
|||
using Base::Base;
|
||||
|
||||
template <typename... AArgs, typename... BArgs>
|
||||
CompactPair(std::piecewise_construct_t, std::tuple<AArgs...> aFirst,
|
||||
std::tuple<BArgs...> aSecond)
|
||||
constexpr CompactPair(std::piecewise_construct_t, std::tuple<AArgs...> aFirst,
|
||||
std::tuple<BArgs...> aSecond)
|
||||
: Base(aFirst, aSecond, std::index_sequence_for<AArgs...>(),
|
||||
std::index_sequence_for<BArgs...>()) {}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "mozilla/Alignment.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/MaybeStorageBase.h"
|
||||
#include "mozilla/MemoryChecking.h"
|
||||
#include "mozilla/OperatorNewExtensions.h"
|
||||
#include "mozilla/Poison.h"
|
||||
|
@ -103,12 +104,6 @@ struct MaybePoisoner {
|
|||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
constexpr bool IsTriviallyDestructibleAndCopyable =
|
||||
std::is_trivially_destructible_v<T> &&
|
||||
(std::is_trivially_copy_constructible_v<T> ||
|
||||
!std::is_copy_constructible_v<T>);
|
||||
|
||||
template <typename T,
|
||||
bool TriviallyDestructibleAndCopyable =
|
||||
IsTriviallyDestructibleAndCopyable<T>,
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/* Internal storage class used e.g. by Maybe and Result. This file doesn't
|
||||
* contain any public declarations. */
|
||||
|
||||
#ifndef mfbt_MaybeStorageBase_h
|
||||
#define mfbt_MaybeStorageBase_h
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace mozilla::detail {
|
||||
|
||||
template <typename T>
|
||||
constexpr bool IsTriviallyDestructibleAndCopyable =
|
||||
std::is_trivially_destructible_v<T> &&
|
||||
(std::is_trivially_copy_constructible_v<T> ||
|
||||
!std::is_copy_constructible_v<T>);
|
||||
|
||||
template <typename T, bool TriviallyDestructibleAndCopyable =
|
||||
IsTriviallyDestructibleAndCopyable<T>>
|
||||
struct MaybeStorageBase;
|
||||
|
||||
struct Dummy {};
|
||||
|
||||
template <typename T>
|
||||
struct MaybeStorageBase<T, false> {
|
||||
protected:
|
||||
using NonConstT = std::remove_const_t<T>;
|
||||
|
||||
union Union {
|
||||
Union() {}
|
||||
explicit Union(const T& aVal) : val{aVal} {}
|
||||
template <typename U,
|
||||
typename = std::enable_if_t<std::is_move_constructible_v<U>>>
|
||||
explicit Union(U&& aVal) : val{std::forward<U>(aVal)} {}
|
||||
template <typename... Args>
|
||||
explicit Union(std::in_place_t, Args&&... aArgs)
|
||||
: val{std::forward<Args>(aArgs)...} {}
|
||||
|
||||
~Union() {}
|
||||
|
||||
NonConstT val;
|
||||
} mStorage;
|
||||
|
||||
public:
|
||||
MaybeStorageBase() = default;
|
||||
explicit MaybeStorageBase(const T& aVal) : mStorage{aVal} {}
|
||||
explicit MaybeStorageBase(T&& aVal) : mStorage{std::move(aVal)} {}
|
||||
template <typename... Args>
|
||||
explicit MaybeStorageBase(std::in_place_t, Args&&... aArgs)
|
||||
: mStorage{std::in_place, std::forward<Args>(aArgs)...} {}
|
||||
|
||||
const T* addr() const { return &mStorage.val; }
|
||||
T* addr() { return &mStorage.val; }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct MaybeStorageBase<T, true> {
|
||||
protected:
|
||||
using NonConstT = std::remove_const_t<T>;
|
||||
|
||||
union Union {
|
||||
constexpr Union() : dummy() {}
|
||||
constexpr explicit Union(const T& aVal) : val{aVal} {}
|
||||
constexpr explicit Union(T&& aVal) : val{std::move(aVal)} {}
|
||||
template <typename... Args>
|
||||
constexpr explicit Union(std::in_place_t, Args&&... aArgs)
|
||||
: val{std::forward<Args>(aArgs)...} {}
|
||||
|
||||
NonConstT val;
|
||||
Dummy dummy;
|
||||
} mStorage;
|
||||
|
||||
public:
|
||||
constexpr MaybeStorageBase() = default;
|
||||
constexpr explicit MaybeStorageBase(const T& aVal) : mStorage{aVal} {}
|
||||
constexpr explicit MaybeStorageBase(T&& aVal) : mStorage{std::move(aVal)} {}
|
||||
|
||||
template <typename... Args>
|
||||
constexpr explicit MaybeStorageBase(std::in_place_t, Args&&... aArgs)
|
||||
: mStorage{std::in_place, std::forward<Args>(aArgs)...} {}
|
||||
|
||||
constexpr const T* addr() const { return &mStorage.val; }
|
||||
constexpr T* addr() { return &mStorage.val; }
|
||||
};
|
||||
|
||||
} // namespace mozilla::detail
|
||||
|
||||
#endif
|
151
mfbt/Result.h
151
mfbt/Result.h
|
@ -16,6 +16,7 @@
|
|||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/CompactPair.h"
|
||||
#include "mozilla/MaybeStorageBase.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -46,28 +47,25 @@ struct UnusedZero;
|
|||
template <typename V, typename E, PackingStrategy Strategy>
|
||||
class ResultImplementation;
|
||||
|
||||
template <typename V>
|
||||
struct EmptyWrapper : V {
|
||||
constexpr EmptyWrapper() = default;
|
||||
explicit constexpr EmptyWrapper(const V&) {}
|
||||
explicit constexpr EmptyWrapper(std::in_place_t) {}
|
||||
|
||||
constexpr V* addr() { return this; }
|
||||
constexpr const V* addr() const { return this; }
|
||||
};
|
||||
|
||||
// The purpose of AlignedStorageOrEmpty is to make an empty class look like
|
||||
// std::aligned_storage_t for the purposes of the PackingStrategy::NullIsOk
|
||||
// specializations of ResultImplementation below. We can't use
|
||||
// std::aligned_storage_t itself with an empty class, since it would no longer
|
||||
// be empty.
|
||||
template <typename V, bool IsEmpty = std::is_empty_v<V>>
|
||||
struct AlignedStorageOrEmpty;
|
||||
|
||||
template <typename V>
|
||||
struct AlignedStorageOrEmpty<V, true> : V {
|
||||
constexpr V* addr() { return this; }
|
||||
constexpr const V* addr() const { return this; }
|
||||
};
|
||||
|
||||
template <typename V>
|
||||
struct AlignedStorageOrEmpty<V, false> {
|
||||
V* addr() { return reinterpret_cast<V*>(&mData); }
|
||||
const V* addr() const { return reinterpret_cast<const V*>(&mData); }
|
||||
|
||||
private:
|
||||
std::aligned_storage_t<sizeof(V), alignof(V)> mData;
|
||||
};
|
||||
using AlignedStorageOrEmpty =
|
||||
std::conditional_t<std::is_empty_v<V>, EmptyWrapper<V>,
|
||||
MaybeStorageBase<V>>;
|
||||
|
||||
template <typename V, typename E>
|
||||
class ResultImplementationNullIsOkBase {
|
||||
|
@ -85,35 +83,24 @@ class ResultImplementationNullIsOkBase {
|
|||
CompactPair<AlignedStorageOrEmpty<V>, ErrorStorageType> mValue;
|
||||
|
||||
public:
|
||||
explicit ResultImplementationNullIsOkBase(const V& aSuccessValue)
|
||||
: mValue(std::piecewise_construct, std::tuple<>(),
|
||||
std::tuple(kNullValue)) {
|
||||
if constexpr (!std::is_empty_v<V>) {
|
||||
new (mValue.first().addr()) V(aSuccessValue);
|
||||
}
|
||||
}
|
||||
explicit ResultImplementationNullIsOkBase(V&& aSuccessValue)
|
||||
: mValue(std::piecewise_construct, std::tuple<>(),
|
||||
std::tuple(kNullValue)) {
|
||||
if constexpr (!std::is_empty_v<V>) {
|
||||
new (mValue.first().addr()) V(std::move(aSuccessValue));
|
||||
}
|
||||
}
|
||||
explicit constexpr ResultImplementationNullIsOkBase(const V& aSuccessValue)
|
||||
: mValue(aSuccessValue, kNullValue) {}
|
||||
explicit constexpr ResultImplementationNullIsOkBase(V&& aSuccessValue)
|
||||
: mValue(std::move(aSuccessValue), kNullValue) {}
|
||||
template <typename... Args>
|
||||
explicit ResultImplementationNullIsOkBase(std::in_place_t, Args&&... aArgs)
|
||||
: mValue(std::piecewise_construct, std::tuple<>(),
|
||||
std::tuple(kNullValue)) {
|
||||
if constexpr (!std::is_empty_v<V>) {
|
||||
new (mValue.first().addr()) V(std::forward<Args>(aArgs)...);
|
||||
}
|
||||
}
|
||||
explicit ResultImplementationNullIsOkBase(E aErrorValue)
|
||||
explicit constexpr ResultImplementationNullIsOkBase(std::in_place_t,
|
||||
Args&&... aArgs)
|
||||
: mValue(std::piecewise_construct,
|
||||
std::tuple(std::in_place, std::forward<Args>(aArgs)...),
|
||||
std::tuple(kNullValue)) {}
|
||||
explicit constexpr ResultImplementationNullIsOkBase(E aErrorValue)
|
||||
: mValue(std::piecewise_construct, std::tuple<>(),
|
||||
std::tuple(UnusedZero<E>::Store(std::move(aErrorValue)))) {
|
||||
MOZ_ASSERT(mValue.second() != kNullValue);
|
||||
}
|
||||
|
||||
ResultImplementationNullIsOkBase(ResultImplementationNullIsOkBase&& aOther)
|
||||
constexpr ResultImplementationNullIsOkBase(
|
||||
ResultImplementationNullIsOkBase&& aOther)
|
||||
: mValue(std::piecewise_construct, std::tuple<>(),
|
||||
std::tuple(aOther.mValue.second())) {
|
||||
if constexpr (!std::is_empty_v<V>) {
|
||||
|
@ -138,15 +125,15 @@ class ResultImplementationNullIsOkBase {
|
|||
return *this;
|
||||
}
|
||||
|
||||
bool isOk() const { return mValue.second() == kNullValue; }
|
||||
constexpr bool isOk() const { return mValue.second() == kNullValue; }
|
||||
|
||||
const V& inspect() const { return *mValue.first().addr(); }
|
||||
V unwrap() { return std::move(*mValue.first().addr()); }
|
||||
constexpr const V& inspect() const { return *mValue.first().addr(); }
|
||||
constexpr V unwrap() { return std::move(*mValue.first().addr()); }
|
||||
|
||||
decltype(auto) inspectErr() const {
|
||||
constexpr decltype(auto) inspectErr() const {
|
||||
return UnusedZero<E>::Inspect(mValue.second());
|
||||
}
|
||||
E unwrapErr() { return UnusedZero<E>::Unwrap(mValue.second()); }
|
||||
constexpr E unwrapErr() { return UnusedZero<E>::Unwrap(mValue.second()); }
|
||||
};
|
||||
|
||||
template <typename V, typename E,
|
||||
|
@ -226,42 +213,40 @@ class ResultImplementation<V, E, PackingStrategy::LowBitTagIsError> {
|
|||
#endif
|
||||
|
||||
public:
|
||||
explicit ResultImplementation(V aValue) {
|
||||
explicit constexpr ResultImplementation(V aValue) : mBits(0) {
|
||||
if constexpr (!std::is_empty_v<V>) {
|
||||
std::memcpy(&mBits, &aValue, sizeof(V));
|
||||
MOZ_ASSERT((mBits & 1) == 0);
|
||||
} else {
|
||||
(void)aValue;
|
||||
mBits = 0;
|
||||
}
|
||||
}
|
||||
explicit ResultImplementation(E aErrorValue) {
|
||||
explicit constexpr ResultImplementation(E aErrorValue) : mBits(1) {
|
||||
if constexpr (!std::is_empty_v<E>) {
|
||||
std::memcpy(&mBits, &aErrorValue, sizeof(E));
|
||||
MOZ_ASSERT((mBits & 1) == 0);
|
||||
mBits |= 1;
|
||||
} else {
|
||||
(void)aErrorValue;
|
||||
mBits = 1;
|
||||
}
|
||||
}
|
||||
|
||||
bool isOk() const { return (mBits & 1) == 0; }
|
||||
constexpr bool isOk() const { return (mBits & 1) == 0; }
|
||||
|
||||
V inspect() const {
|
||||
constexpr V inspect() const {
|
||||
V res;
|
||||
std::memcpy(&res, &mBits, sizeof(V));
|
||||
return res;
|
||||
}
|
||||
V unwrap() { return inspect(); }
|
||||
constexpr V unwrap() { return inspect(); }
|
||||
|
||||
E inspectErr() const {
|
||||
constexpr E inspectErr() const {
|
||||
const auto bits = mBits ^ 1;
|
||||
E res;
|
||||
std::memcpy(&res, &bits, sizeof(E));
|
||||
return res;
|
||||
}
|
||||
E unwrapErr() { return inspectErr(); }
|
||||
constexpr E unwrapErr() { return inspectErr(); }
|
||||
};
|
||||
|
||||
// Return true if any of the struct can fit in a word.
|
||||
|
@ -294,22 +279,22 @@ class ResultImplementation<V, E, PackingStrategy::PackedVariant> {
|
|||
Impl data;
|
||||
|
||||
public:
|
||||
explicit ResultImplementation(V aValue) {
|
||||
explicit constexpr ResultImplementation(V aValue) {
|
||||
data.v = std::move(aValue);
|
||||
data.ok = true;
|
||||
}
|
||||
explicit ResultImplementation(E aErrorValue) {
|
||||
explicit constexpr ResultImplementation(E aErrorValue) {
|
||||
data.e = std::move(aErrorValue);
|
||||
data.ok = false;
|
||||
}
|
||||
|
||||
bool isOk() const { return data.ok; }
|
||||
constexpr bool isOk() const { return data.ok; }
|
||||
|
||||
const V& inspect() const { return data.v; }
|
||||
V unwrap() { return std::move(data.v); }
|
||||
constexpr const V& inspect() const { return data.v; }
|
||||
constexpr V unwrap() { return std::move(data.v); }
|
||||
|
||||
const E& inspectErr() const { return data.e; }
|
||||
E unwrapErr() { return std::move(data.e); }
|
||||
constexpr const E& inspectErr() const { return data.e; }
|
||||
constexpr E unwrapErr() { return std::move(data.e); }
|
||||
};
|
||||
|
||||
// To use nullptr as a special value, we need the counter part to exclude zero
|
||||
|
@ -398,7 +383,7 @@ struct IsResult<Result<V, E>> : std::true_type {};
|
|||
} // namespace detail
|
||||
|
||||
template <typename V, typename E>
|
||||
auto ToResult(Result<V, E>&& aValue)
|
||||
constexpr auto ToResult(Result<V, E>&& aValue)
|
||||
-> decltype(std::forward<Result<V, E>>(aValue)) {
|
||||
return std::forward<Result<V, E>>(aValue);
|
||||
}
|
||||
|
@ -461,22 +446,24 @@ class MOZ_MUST_USE_TYPE Result final {
|
|||
using err_type = E;
|
||||
|
||||
/** Create a success result. */
|
||||
MOZ_IMPLICIT Result(V&& aValue) : mImpl(std::forward<V>(aValue)) {
|
||||
MOZ_IMPLICIT constexpr Result(V&& aValue) : mImpl(std::forward<V>(aValue)) {
|
||||
MOZ_ASSERT(isOk());
|
||||
}
|
||||
|
||||
/** Create a success result. */
|
||||
MOZ_IMPLICIT Result(const V& aValue) : mImpl(aValue) { MOZ_ASSERT(isOk()); }
|
||||
MOZ_IMPLICIT constexpr Result(const V& aValue) : mImpl(aValue) {
|
||||
MOZ_ASSERT(isOk());
|
||||
}
|
||||
|
||||
/** Create a success result in-place. */
|
||||
template <typename... Args>
|
||||
explicit Result(std::in_place_t, Args&&... aArgs)
|
||||
explicit constexpr Result(std::in_place_t, Args&&... aArgs)
|
||||
: mImpl(std::in_place, std::forward<Args>(aArgs)...) {
|
||||
MOZ_ASSERT(isOk());
|
||||
}
|
||||
|
||||
/** Create an error result. */
|
||||
explicit Result(E aErrorValue) : mImpl(std::move(aErrorValue)) {
|
||||
explicit constexpr Result(E aErrorValue) : mImpl(std::move(aErrorValue)) {
|
||||
MOZ_ASSERT(isErr());
|
||||
}
|
||||
|
||||
|
@ -485,7 +472,7 @@ class MOZ_MUST_USE_TYPE Result final {
|
|||
* different but convertible error type. */
|
||||
template <typename E2,
|
||||
typename = std::enable_if_t<std::is_convertible_v<E2, E>>>
|
||||
MOZ_IMPLICIT Result(Result<V, E2>&& aOther)
|
||||
MOZ_IMPLICIT constexpr Result(Result<V, E2>&& aOther)
|
||||
: mImpl(aOther.isOk() ? Impl{aOther.unwrap()}
|
||||
: Impl{aOther.unwrapErr()}) {}
|
||||
|
||||
|
@ -494,7 +481,7 @@ class MOZ_MUST_USE_TYPE Result final {
|
|||
* Create an error result from another error result.
|
||||
*/
|
||||
template <typename E2>
|
||||
MOZ_IMPLICIT Result(GenericErrorResult<E2>&& aErrorResult)
|
||||
MOZ_IMPLICIT constexpr Result(GenericErrorResult<E2>&& aErrorResult)
|
||||
: mImpl(std::move(aErrorResult.mErrorValue)) {
|
||||
static_assert(std::is_convertible_v<E2, E>, "E2 must be convertible to E");
|
||||
MOZ_ASSERT(isErr());
|
||||
|
@ -505,7 +492,7 @@ class MOZ_MUST_USE_TYPE Result final {
|
|||
* Create an error result from another error result.
|
||||
*/
|
||||
template <typename E2>
|
||||
MOZ_IMPLICIT Result(const GenericErrorResult<E2>& aErrorResult)
|
||||
MOZ_IMPLICIT constexpr Result(const GenericErrorResult<E2>& aErrorResult)
|
||||
: mImpl(aErrorResult.mErrorValue) {
|
||||
static_assert(std::is_convertible_v<E2, E>, "E2 must be convertible to E");
|
||||
MOZ_ASSERT(isErr());
|
||||
|
@ -517,14 +504,14 @@ class MOZ_MUST_USE_TYPE Result final {
|
|||
Result& operator=(Result&&) = default;
|
||||
|
||||
/** True if this Result is a success result. */
|
||||
bool isOk() const { return mImpl.isOk(); }
|
||||
constexpr bool isOk() const { return mImpl.isOk(); }
|
||||
|
||||
/** True if this Result is an error result. */
|
||||
bool isErr() const { return !mImpl.isOk(); }
|
||||
constexpr bool isErr() const { return !mImpl.isOk(); }
|
||||
|
||||
/** Take the success value from this Result, which must be a success result.
|
||||
*/
|
||||
V unwrap() {
|
||||
constexpr V unwrap() {
|
||||
MOZ_ASSERT(isOk());
|
||||
return mImpl.unwrap();
|
||||
}
|
||||
|
@ -533,18 +520,18 @@ class MOZ_MUST_USE_TYPE Result final {
|
|||
* Take the success value from this Result, which must be a success result.
|
||||
* If it is an error result, then return the aValue.
|
||||
*/
|
||||
V unwrapOr(V aValue) {
|
||||
constexpr V unwrapOr(V aValue) {
|
||||
return MOZ_LIKELY(isOk()) ? mImpl.unwrap() : std::move(aValue);
|
||||
}
|
||||
|
||||
/** Take the error value from this Result, which must be an error result. */
|
||||
E unwrapErr() {
|
||||
constexpr E unwrapErr() {
|
||||
MOZ_ASSERT(isErr());
|
||||
return mImpl.unwrapErr();
|
||||
}
|
||||
|
||||
/** See the success value from this Result, which must be a success result. */
|
||||
decltype(auto) inspect() const {
|
||||
constexpr decltype(auto) inspect() const {
|
||||
static_assert(!std::is_reference_v<
|
||||
std::invoke_result_t<decltype(&Impl::inspect), Impl>> ||
|
||||
std::is_const_v<std::remove_reference_t<
|
||||
|
@ -554,7 +541,7 @@ class MOZ_MUST_USE_TYPE Result final {
|
|||
}
|
||||
|
||||
/** See the error value from this Result, which must be an error result. */
|
||||
decltype(auto) inspectErr() const {
|
||||
constexpr decltype(auto) inspectErr() const {
|
||||
static_assert(
|
||||
!std::is_reference_v<
|
||||
std::invoke_result_t<decltype(&Impl::inspectErr), Impl>> ||
|
||||
|
@ -574,7 +561,7 @@ class MOZ_MUST_USE_TYPE Result final {
|
|||
* if (res.isErr()) { return res.propagateErr(); }
|
||||
* }
|
||||
*/
|
||||
GenericErrorResult<E> propagateErr() {
|
||||
constexpr GenericErrorResult<E> propagateErr() {
|
||||
MOZ_ASSERT(isErr());
|
||||
return GenericErrorResult<E>{mImpl.unwrapErr()};
|
||||
}
|
||||
|
@ -608,7 +595,7 @@ class MOZ_MUST_USE_TYPE Result final {
|
|||
* MOZ_ASSERT(res2.unwrapErr() == 5);
|
||||
*/
|
||||
template <typename F>
|
||||
auto map(F f) -> Result<std::result_of_t<F(V)>, E> {
|
||||
constexpr auto map(F f) -> Result<std::result_of_t<F(V)>, E> {
|
||||
using RetResult = Result<std::result_of_t<F(V)>, E>;
|
||||
return MOZ_LIKELY(isOk()) ? RetResult(f(unwrap())) : RetResult(unwrapErr());
|
||||
}
|
||||
|
@ -641,7 +628,7 @@ class MOZ_MUST_USE_TYPE Result final {
|
|||
* MOZ_ASSERT(res2.unwrap() == 5);
|
||||
*/
|
||||
template <typename F>
|
||||
auto mapErr(F f) -> Result<V, std::result_of_t<F(E)>> {
|
||||
constexpr auto mapErr(F f) {
|
||||
using RetResult = Result<V, std::result_of_t<F(E)>>;
|
||||
return MOZ_UNLIKELY(isErr()) ? RetResult(f(unwrapErr()))
|
||||
: RetResult(unwrap());
|
||||
|
@ -737,7 +724,7 @@ class MOZ_MUST_USE_TYPE Result final {
|
|||
*/
|
||||
template <typename F, typename = std::enable_if_t<detail::IsResult<
|
||||
std::invoke_result_t<F, V&&>>::value>>
|
||||
auto andThen(F f) -> std::invoke_result_t<F, V&&> {
|
||||
constexpr auto andThen(F f) -> std::invoke_result_t<F, V&&> {
|
||||
return MOZ_LIKELY(isOk()) ? f(unwrap()) : propagateErr();
|
||||
}
|
||||
};
|
||||
|
@ -756,15 +743,15 @@ class MOZ_MUST_USE_TYPE GenericErrorResult {
|
|||
friend class Result;
|
||||
|
||||
public:
|
||||
explicit GenericErrorResult(const E& aErrorValue)
|
||||
explicit constexpr GenericErrorResult(const E& aErrorValue)
|
||||
: mErrorValue(aErrorValue) {}
|
||||
|
||||
explicit GenericErrorResult(E&& aErrorValue)
|
||||
explicit constexpr GenericErrorResult(E&& aErrorValue)
|
||||
: mErrorValue(std::move(aErrorValue)) {}
|
||||
};
|
||||
|
||||
template <typename E>
|
||||
inline auto Err(E&& aErrorValue) {
|
||||
inline constexpr auto Err(E&& aErrorValue) {
|
||||
return GenericErrorResult<std::decay_t<E>>(std::forward<E>(aErrorValue));
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#ifndef mozilla_ResultVariant_h
|
||||
#define mozilla_ResultVariant_h
|
||||
|
||||
#include "mozilla/MaybeStorageBase.h"
|
||||
#include "mozilla/Result.h"
|
||||
#include "mozilla/Variant.h"
|
||||
|
||||
|
|
|
@ -67,6 +67,7 @@ EXPORTS.mozilla = [
|
|||
"MathAlgorithms.h",
|
||||
"Maybe.h",
|
||||
"MaybeOneOf.h",
|
||||
"MaybeStorageBase.h",
|
||||
"MemoryChecking.h",
|
||||
"MemoryReporting.h",
|
||||
"NonDereferenceable.h",
|
||||
|
|
|
@ -14,6 +14,10 @@ using mozilla::Ok;
|
|||
using mozilla::Result;
|
||||
using mozilla::UniquePtr;
|
||||
|
||||
#define MOZ_STATIC_AND_RELEASE_ASSERT(expr) \
|
||||
static_assert(expr); \
|
||||
MOZ_RELEASE_ASSERT(expr)
|
||||
|
||||
enum struct TestUnusedZeroEnum : int16_t { Ok = 0, NotOk = 1 };
|
||||
|
||||
namespace mozilla::detail {
|
||||
|
@ -94,23 +98,28 @@ static_assert(sizeof(Foo32) >= sizeof(uintptr_t) ||
|
|||
sizeof(Result<Foo16, Foo32>) <= sizeof(uintptr_t),
|
||||
"Result with small types should be pointer-sized");
|
||||
|
||||
static GenericErrorResult<Failed> Fail() {
|
||||
static Failed failed;
|
||||
return Err(failed);
|
||||
}
|
||||
static_assert(std::is_literal_type_v<Result<int*, Failed>>);
|
||||
static_assert(std::is_literal_type_v<Result<Ok, Failed>>);
|
||||
static_assert(std::is_literal_type_v<Result<Ok, Foo8>>);
|
||||
static_assert(std::is_literal_type_v<Result<Foo8, Foo16>>);
|
||||
static_assert(!std::is_literal_type_v<Result<Ok, UniquePtr<int>>>);
|
||||
|
||||
static GenericErrorResult<TestUnusedZeroEnum> FailTestUnusedZeroEnum() {
|
||||
static constexpr GenericErrorResult<Failed> Fail() { return Err(Failed{}); }
|
||||
|
||||
static constexpr GenericErrorResult<TestUnusedZeroEnum>
|
||||
FailTestUnusedZeroEnum() {
|
||||
return Err(TestUnusedZeroEnum::NotOk);
|
||||
}
|
||||
|
||||
static Result<Ok, Failed> Task1(bool pass) {
|
||||
static constexpr Result<Ok, Failed> Task1(bool pass) {
|
||||
if (!pass) {
|
||||
return Fail(); // implicit conversion from GenericErrorResult to Result
|
||||
}
|
||||
return Ok();
|
||||
}
|
||||
|
||||
static Result<Ok, TestUnusedZeroEnum> Task1UnusedZeroEnumErr(bool pass) {
|
||||
static constexpr Result<Ok, TestUnusedZeroEnum> Task1UnusedZeroEnumErr(
|
||||
bool pass) {
|
||||
if (!pass) {
|
||||
return FailTestUnusedZeroEnum(); // implicit conversion from
|
||||
// GenericErrorResult to Result
|
||||
|
@ -118,14 +127,14 @@ static Result<Ok, TestUnusedZeroEnum> Task1UnusedZeroEnumErr(bool pass) {
|
|||
return Ok();
|
||||
}
|
||||
|
||||
static Result<int, Failed> Task2(bool pass, int value) {
|
||||
static constexpr Result<int, Failed> Task2(bool pass, int value) {
|
||||
MOZ_TRY(
|
||||
Task1(pass)); // converts one type of result to another in the error case
|
||||
return value; // implicit conversion from T to Result<T, E>
|
||||
}
|
||||
|
||||
static Result<int, TestUnusedZeroEnum> Task2UnusedZeroEnumErr(bool pass,
|
||||
int value) {
|
||||
static constexpr Result<int, TestUnusedZeroEnum> Task2UnusedZeroEnumErr(
|
||||
bool pass, int value) {
|
||||
MOZ_TRY(Task1UnusedZeroEnumErr(
|
||||
pass)); // converts one type of result to another in the error case
|
||||
return value; // implicit conversion from T to Result<T, E>
|
||||
|
@ -139,32 +148,34 @@ static Result<int, Failed> Task3(bool pass1, bool pass2, int value) {
|
|||
}
|
||||
|
||||
static void BasicTests() {
|
||||
MOZ_RELEASE_ASSERT(Task1(true).isOk());
|
||||
MOZ_RELEASE_ASSERT(!Task1(true).isErr());
|
||||
MOZ_RELEASE_ASSERT(!Task1(false).isOk());
|
||||
MOZ_RELEASE_ASSERT(Task1(false).isErr());
|
||||
MOZ_STATIC_AND_RELEASE_ASSERT(Task1(true).isOk());
|
||||
MOZ_STATIC_AND_RELEASE_ASSERT(!Task1(true).isErr());
|
||||
MOZ_STATIC_AND_RELEASE_ASSERT(!Task1(false).isOk());
|
||||
MOZ_STATIC_AND_RELEASE_ASSERT(Task1(false).isErr());
|
||||
|
||||
MOZ_RELEASE_ASSERT(Task1UnusedZeroEnumErr(true).isOk());
|
||||
MOZ_RELEASE_ASSERT(!Task1UnusedZeroEnumErr(true).isErr());
|
||||
MOZ_RELEASE_ASSERT(!Task1UnusedZeroEnumErr(false).isOk());
|
||||
MOZ_RELEASE_ASSERT(Task1UnusedZeroEnumErr(false).isErr());
|
||||
MOZ_RELEASE_ASSERT(TestUnusedZeroEnum::NotOk ==
|
||||
Task1UnusedZeroEnumErr(false).inspectErr());
|
||||
MOZ_RELEASE_ASSERT(TestUnusedZeroEnum::NotOk ==
|
||||
Task1UnusedZeroEnumErr(false).unwrapErr());
|
||||
MOZ_STATIC_AND_RELEASE_ASSERT(Task1UnusedZeroEnumErr(true).isOk());
|
||||
MOZ_STATIC_AND_RELEASE_ASSERT(!Task1UnusedZeroEnumErr(true).isErr());
|
||||
MOZ_STATIC_AND_RELEASE_ASSERT(!Task1UnusedZeroEnumErr(false).isOk());
|
||||
MOZ_STATIC_AND_RELEASE_ASSERT(Task1UnusedZeroEnumErr(false).isErr());
|
||||
MOZ_STATIC_AND_RELEASE_ASSERT(TestUnusedZeroEnum::NotOk ==
|
||||
Task1UnusedZeroEnumErr(false).inspectErr());
|
||||
MOZ_STATIC_AND_RELEASE_ASSERT(TestUnusedZeroEnum::NotOk ==
|
||||
Task1UnusedZeroEnumErr(false).unwrapErr());
|
||||
|
||||
// MOZ_TRY works.
|
||||
MOZ_RELEASE_ASSERT(Task2(true, 3).isOk());
|
||||
MOZ_RELEASE_ASSERT(Task2(true, 3).unwrap() == 3);
|
||||
MOZ_RELEASE_ASSERT(Task2(true, 3).unwrapOr(6) == 3);
|
||||
MOZ_STATIC_AND_RELEASE_ASSERT(Task2(true, 3).isOk());
|
||||
MOZ_STATIC_AND_RELEASE_ASSERT(Task2(true, 3).unwrap() == 3);
|
||||
MOZ_STATIC_AND_RELEASE_ASSERT(Task2(true, 3).unwrapOr(6) == 3);
|
||||
MOZ_RELEASE_ASSERT(Task2(false, 3).isErr());
|
||||
MOZ_RELEASE_ASSERT(Task2(false, 3).unwrapOr(6) == 6);
|
||||
|
||||
MOZ_RELEASE_ASSERT(Task2UnusedZeroEnumErr(true, 3).isOk());
|
||||
MOZ_RELEASE_ASSERT(Task2UnusedZeroEnumErr(true, 3).unwrap() == 3);
|
||||
MOZ_RELEASE_ASSERT(Task2UnusedZeroEnumErr(true, 3).unwrapOr(6) == 3);
|
||||
MOZ_RELEASE_ASSERT(Task2UnusedZeroEnumErr(false, 3).isErr());
|
||||
MOZ_RELEASE_ASSERT(Task2UnusedZeroEnumErr(false, 3).unwrapOr(6) == 6);
|
||||
MOZ_STATIC_AND_RELEASE_ASSERT(Task2UnusedZeroEnumErr(true, 3).isOk());
|
||||
MOZ_STATIC_AND_RELEASE_ASSERT(Task2UnusedZeroEnumErr(true, 3).unwrap() == 3);
|
||||
MOZ_STATIC_AND_RELEASE_ASSERT(Task2UnusedZeroEnumErr(true, 3).unwrapOr(6) ==
|
||||
3);
|
||||
MOZ_STATIC_AND_RELEASE_ASSERT(Task2UnusedZeroEnumErr(false, 3).isErr());
|
||||
MOZ_STATIC_AND_RELEASE_ASSERT(Task2UnusedZeroEnumErr(false, 3).unwrapOr(6) ==
|
||||
6);
|
||||
|
||||
// MOZ_TRY_VAR works.
|
||||
MOZ_RELEASE_ASSERT(Task3(true, true, 3).isOk());
|
||||
|
@ -175,13 +186,13 @@ static void BasicTests() {
|
|||
|
||||
// Lvalues should work too.
|
||||
{
|
||||
Result<Ok, Failed> res = Task1(true);
|
||||
MOZ_RELEASE_ASSERT(res.isOk());
|
||||
MOZ_RELEASE_ASSERT(!res.isErr());
|
||||
constexpr Result<Ok, Failed> res1 = Task1(true);
|
||||
MOZ_STATIC_AND_RELEASE_ASSERT(res1.isOk());
|
||||
MOZ_STATIC_AND_RELEASE_ASSERT(!res1.isErr());
|
||||
|
||||
res = Task1(false);
|
||||
MOZ_RELEASE_ASSERT(!res.isOk());
|
||||
MOZ_RELEASE_ASSERT(res.isErr());
|
||||
constexpr Result<Ok, Failed> res2 = Task1(false);
|
||||
MOZ_STATIC_AND_RELEASE_ASSERT(!res2.isOk());
|
||||
MOZ_STATIC_AND_RELEASE_ASSERT(res2.isErr());
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -210,7 +221,7 @@ static void BasicTests() {
|
|||
}
|
||||
|
||||
struct NonCopyableNonMovable {
|
||||
explicit NonCopyableNonMovable(uint32_t aValue) : mValue(aValue) {}
|
||||
explicit constexpr NonCopyableNonMovable(uint32_t aValue) : mValue(aValue) {}
|
||||
|
||||
NonCopyableNonMovable(const NonCopyableNonMovable&) = delete;
|
||||
NonCopyableNonMovable(NonCopyableNonMovable&&) = delete;
|
||||
|
@ -226,8 +237,8 @@ static void InPlaceConstructionTests() {
|
|||
static_assert(mozilla::detail::SelectResultImpl<NonCopyableNonMovable,
|
||||
Failed>::value ==
|
||||
mozilla::detail::PackingStrategy::NullIsOk);
|
||||
const Result<NonCopyableNonMovable, Failed> result{std::in_place, 42};
|
||||
MOZ_RELEASE_ASSERT(42 == result.inspect().mValue);
|
||||
constexpr Result<NonCopyableNonMovable, Failed> result{std::in_place, 42u};
|
||||
MOZ_STATIC_AND_RELEASE_ASSERT(42 == result.inspect().mValue);
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -312,6 +323,17 @@ static void MapTest() {
|
|||
MOZ_RELEASE_ASSERT(strcmp(res2.unwrap(), "hello") == 0);
|
||||
}
|
||||
|
||||
// Mapping over success values (constexpr).
|
||||
{
|
||||
constexpr uint64_t kValue = 42u;
|
||||
constexpr auto res2a = Result<int32_t, Failed>{5}.map([](int32_t x) {
|
||||
MOZ_RELEASE_ASSERT(x == 5);
|
||||
return kValue;
|
||||
});
|
||||
MOZ_STATIC_AND_RELEASE_ASSERT(res2a.isOk());
|
||||
MOZ_STATIC_AND_RELEASE_ASSERT(kValue == res2a.inspect());
|
||||
}
|
||||
|
||||
// Mapping over error values.
|
||||
{
|
||||
MyError err(1);
|
||||
|
@ -407,13 +429,13 @@ static void OrElseTest() {
|
|||
struct MyError {
|
||||
int x;
|
||||
|
||||
explicit MyError(int y) : x(y) {}
|
||||
explicit constexpr MyError(int y) : x(y) {}
|
||||
};
|
||||
|
||||
struct MyError2 {
|
||||
int a;
|
||||
|
||||
explicit MyError2(int b) : a(b) {}
|
||||
explicit constexpr MyError2(int b) : a(b) {}
|
||||
};
|
||||
|
||||
// `orElse`ing over error values, to Result<V, E> (the same error type) error
|
||||
|
@ -528,6 +550,14 @@ static void AndThenTest() {
|
|||
MOZ_RELEASE_ASSERT(r2.unwrap() == 11);
|
||||
}
|
||||
|
||||
// `andThen`ing over success results (constexpr).
|
||||
{
|
||||
constexpr Result<int, Failed> r2a = Result<int, Failed>{10}.andThen(
|
||||
[](int x) { return Result<int, Failed>(x + 1); });
|
||||
MOZ_STATIC_AND_RELEASE_ASSERT(r2a.isOk());
|
||||
MOZ_STATIC_AND_RELEASE_ASSERT(r2a.inspect() == 11);
|
||||
}
|
||||
|
||||
// `andThen`ing over error results.
|
||||
{
|
||||
Result<int, const char*> r3("error");
|
||||
|
@ -547,6 +577,16 @@ static void AndThenTest() {
|
|||
MOZ_RELEASE_ASSERT(r2.isOk());
|
||||
MOZ_RELEASE_ASSERT(r2.unwrap() == 11);
|
||||
}
|
||||
|
||||
// `andThen`ing over error results (constexpr).
|
||||
{
|
||||
constexpr Result<int, Failed> r4a =
|
||||
Result<int, Failed>{Failed{}}.andThen([](int x) {
|
||||
MOZ_RELEASE_ASSERT(false);
|
||||
return Result<int, Failed>(1);
|
||||
});
|
||||
MOZ_STATIC_AND_RELEASE_ASSERT(r4a.isErr());
|
||||
}
|
||||
}
|
||||
|
||||
using UniqueResult = Result<UniquePtr<int>, const char*>;
|
||||
|
|
|
@ -188,9 +188,8 @@ class nsAutoRef : public nsAutoRefBase<T> {
|
|||
// operator->() and disown() are provided by nsAutoRefBase<T>.
|
||||
// The default nsSimpleRef<T> provides get().
|
||||
|
||||
private:
|
||||
// No copy constructor
|
||||
explicit nsAutoRef(ThisClass& aRefToSteal);
|
||||
explicit nsAutoRef(const ThisClass& aRefToSteal) = delete;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -216,8 +215,8 @@ class nsReturnRef : public nsAutoRefBase<T> {
|
|||
MOZ_IMPLICIT nsReturnRef(RawRefOnly aRefToRelease)
|
||||
: BaseClass(aRefToRelease) {}
|
||||
|
||||
// Copy construction transfers ownership
|
||||
nsReturnRef(nsReturnRef<T>& aRefToSteal) : BaseClass(aRefToSteal) {}
|
||||
// Move construction transfers ownership
|
||||
nsReturnRef(nsReturnRef<T>&& aRefToSteal) = default;
|
||||
|
||||
MOZ_IMPLICIT nsReturnRef(const nsReturningRef<T>& aReturning)
|
||||
: BaseClass(aReturning) {}
|
||||
|
@ -428,8 +427,7 @@ class nsAutoRefBase : public nsSimpleRef<T> {
|
|||
explicit nsAutoRefBase(RawRefOnly aRefToRelease) : SimpleRef(aRefToRelease) {}
|
||||
|
||||
// Constructors that steal ownership
|
||||
explicit nsAutoRefBase(ThisClass& aRefToSteal)
|
||||
: SimpleRef(aRefToSteal.disown()) {}
|
||||
nsAutoRefBase(ThisClass&& aRefToSteal) : SimpleRef(aRefToSteal.disown()) {}
|
||||
explicit nsAutoRefBase(const nsReturningRef<T>& aReturning)
|
||||
: SimpleRef(aReturning.mReturnRef.disown()) {}
|
||||
|
||||
|
@ -444,10 +442,9 @@ class nsAutoRefBase : public nsSimpleRef<T> {
|
|||
explicit LocalSimpleRef(RawRef aRawRef) : SimpleRef(aRawRef) {}
|
||||
};
|
||||
|
||||
private:
|
||||
public:
|
||||
ThisClass& operator=(const ThisClass& aSmartRef) = delete;
|
||||
|
||||
public:
|
||||
RawRef operator->() const { return this->get(); }
|
||||
|
||||
// Transfer ownership to a raw reference.
|
||||
|
|
|
@ -241,6 +241,9 @@ class MOZ_NEEDS_NO_VTABLE_TYPE nsTHashtable {
|
|||
nsTHashtable(nsTHashtable<EntryType>&& aOther);
|
||||
nsTHashtable<EntryType>& operator=(nsTHashtable<EntryType>&& aOther);
|
||||
|
||||
nsTHashtable(const nsTHashtable<EntryType>&) = delete;
|
||||
nsTHashtable& operator=(const nsTHashtable<EntryType>&) = delete;
|
||||
|
||||
/**
|
||||
* Return the generation number for the table. This increments whenever
|
||||
* the table data items are moved.
|
||||
|
|
Загрузка…
Ссылка в новой задаче