зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1613363 - Maybe<T> should preserve trivial copy-constructability and destructability of T. r=froydnj
Differential Revision: https://phabricator.services.mozilla.com/D68173 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
0cc5c6e63f
Коммит
d3deabac64
|
@ -263,6 +263,10 @@ nsresult HTMLEditor::DoInsertHTMLWithContext(
|
|||
EditorRawDOMPoint streamEndPoint =
|
||||
streamStartParent ? EditorRawDOMPoint(streamEndParent, streamEndOffset)
|
||||
: EditorRawDOMPoint::AtEndOf(fragmentAsNode);
|
||||
|
||||
Unused << streamStartPoint;
|
||||
Unused << streamEndPoint;
|
||||
|
||||
HTMLEditor::CollectTopMostChildNodesCompletelyInRange(
|
||||
EditorRawDOMPoint(streamStartParent, streamStartOffset),
|
||||
EditorRawDOMPoint(streamEndParent, streamEndOffset),
|
||||
|
|
|
@ -208,6 +208,7 @@ wr::WrSpaceAndClipChain ClipManager::SwitchItem(nsDisplayItem* aItem) {
|
|||
leafmostASR = ActiveScrolledRoot::PickDescendant(leafmostASR, clip->mASR);
|
||||
}
|
||||
Maybe<wr::WrSpaceAndClip> leafmostId = DefineScrollLayers(leafmostASR, aItem);
|
||||
Unused << leafmostId;
|
||||
|
||||
// Define all the clips in the item's clip chain, and obtain a clip chain id
|
||||
// for it.
|
||||
|
|
|
@ -59,8 +59,8 @@ const gfx::IntRect AnimationState::UpdateStateInternal(
|
|||
// If mHasBeenDecoded is false then we'll get another UpdateState call
|
||||
// when the decode finishes.
|
||||
if (mHasBeenDecoded) {
|
||||
Maybe<uint32_t> frameCount = FrameCount();
|
||||
MOZ_ASSERT(frameCount.isSome());
|
||||
const DebugOnly<Maybe<uint32_t>> frameCount = FrameCount();
|
||||
MOZ_ASSERT(static_cast<const Maybe<uint32_t>&>(frameCount).isSome());
|
||||
mIsCurrentlyDecoded = aResult.Surface().IsFullyDecoded();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -592,7 +592,6 @@ bool EmitterScope::enterFunction(BytecodeEmitter* bce, FunctionBox* funbox) {
|
|||
|
||||
// Resolve body-level bindings, if there are any.
|
||||
auto bindings = funbox->functionScopeBindings();
|
||||
Maybe<uint32_t> lastLexicalSlot;
|
||||
if (bindings) {
|
||||
NameLocationMap& cache = *nameCache_;
|
||||
|
||||
|
|
290
mfbt/Maybe.h
290
mfbt/Maybe.h
|
@ -104,14 +104,15 @@ struct MaybePoisoner {
|
|||
}
|
||||
};
|
||||
|
||||
template <typename T, bool Copyable = std::is_copy_constructible_v<T>,
|
||||
template <typename T,
|
||||
bool TriviallyCopyable = std::is_trivially_copy_constructible_v<T>,
|
||||
bool Copyable = std::is_copy_constructible_v<T>,
|
||||
bool Movable = std::is_move_constructible_v<T>>
|
||||
class Maybe_CopyMove_Enabler;
|
||||
|
||||
#define MOZ_MAYBE_COPY_OPS() \
|
||||
Maybe_CopyMove_Enabler(const Maybe_CopyMove_Enabler& aOther) { \
|
||||
downcast(*this).mIsSome = false; \
|
||||
if (downcast(aOther).mIsSome) { \
|
||||
if (downcast(aOther).isSome()) { \
|
||||
downcast(*this).emplace(*downcast(aOther)); \
|
||||
} \
|
||||
} \
|
||||
|
@ -122,9 +123,7 @@ class Maybe_CopyMove_Enabler;
|
|||
|
||||
#define MOZ_MAYBE_MOVE_OPS() \
|
||||
Maybe_CopyMove_Enabler(Maybe_CopyMove_Enabler&& aOther) { \
|
||||
downcast(*this).mIsSome = false; \
|
||||
\
|
||||
if (downcast(aOther).mIsSome) { \
|
||||
if (downcast(aOther).isSome()) { \
|
||||
downcast(*this).emplace(std::move(*downcast(aOther))); \
|
||||
downcast(aOther).reset(); \
|
||||
} \
|
||||
|
@ -134,16 +133,36 @@ class Maybe_CopyMove_Enabler;
|
|||
return downcast(*this).template operator=<T>(std::move(downcast(aOther))); \
|
||||
}
|
||||
|
||||
#define MOZ_MAYBE_DOWNCAST() \
|
||||
static Maybe<T>& downcast(Maybe_CopyMove_Enabler& aObj) { \
|
||||
return static_cast<Maybe<T>&>(aObj); \
|
||||
} \
|
||||
static const Maybe<T>& downcast(const Maybe_CopyMove_Enabler& aObj) { \
|
||||
return static_cast<const Maybe<T>&>(aObj); \
|
||||
#define MOZ_MAYBE_DOWNCAST() \
|
||||
static constexpr Maybe<T>& downcast(Maybe_CopyMove_Enabler& aObj) { \
|
||||
return static_cast<Maybe<T>&>(aObj); \
|
||||
} \
|
||||
static constexpr const Maybe<T>& downcast( \
|
||||
const Maybe_CopyMove_Enabler& aObj) { \
|
||||
return static_cast<const Maybe<T>&>(aObj); \
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class Maybe_CopyMove_Enabler<T, true, true> {
|
||||
class Maybe_CopyMove_Enabler<T, true, true, true> {
|
||||
public:
|
||||
Maybe_CopyMove_Enabler() = default;
|
||||
|
||||
Maybe_CopyMove_Enabler(const Maybe_CopyMove_Enabler&) = default;
|
||||
Maybe_CopyMove_Enabler& operator=(const Maybe_CopyMove_Enabler&) = default;
|
||||
constexpr Maybe_CopyMove_Enabler(Maybe_CopyMove_Enabler&& aOther) {
|
||||
downcast(aOther).reset();
|
||||
}
|
||||
constexpr Maybe_CopyMove_Enabler& operator=(Maybe_CopyMove_Enabler&& aOther) {
|
||||
downcast(aOther).reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
MOZ_MAYBE_DOWNCAST()
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class Maybe_CopyMove_Enabler<T, false, true, true> {
|
||||
public:
|
||||
Maybe_CopyMove_Enabler() = default;
|
||||
|
||||
|
@ -155,7 +174,7 @@ class Maybe_CopyMove_Enabler<T, true, true> {
|
|||
};
|
||||
|
||||
template <typename T>
|
||||
class Maybe_CopyMove_Enabler<T, false, true> {
|
||||
class Maybe_CopyMove_Enabler<T, false, false, true> {
|
||||
public:
|
||||
Maybe_CopyMove_Enabler() = default;
|
||||
|
||||
|
@ -166,7 +185,7 @@ class Maybe_CopyMove_Enabler<T, false, true> {
|
|||
};
|
||||
|
||||
template <typename T>
|
||||
class Maybe_CopyMove_Enabler<T, true, false> {
|
||||
class Maybe_CopyMove_Enabler<T, false, true, false> {
|
||||
public:
|
||||
Maybe_CopyMove_Enabler() = default;
|
||||
|
||||
|
@ -177,7 +196,7 @@ class Maybe_CopyMove_Enabler<T, true, false> {
|
|||
};
|
||||
|
||||
template <typename T>
|
||||
class Maybe_CopyMove_Enabler<T, false, false> {
|
||||
class Maybe_CopyMove_Enabler<T, false, false, false> {
|
||||
public:
|
||||
Maybe_CopyMove_Enabler() = default;
|
||||
|
||||
|
@ -191,8 +210,75 @@ class Maybe_CopyMove_Enabler<T, false, false> {
|
|||
#undef MOZ_MAYBE_MOVE_OPS
|
||||
#undef MOZ_MAYBE_DOWNCAST
|
||||
|
||||
template <typename T, bool TriviallyDestructibleAndCopyable =
|
||||
std::is_trivially_destructible_v<T>&&
|
||||
std::is_trivially_copy_constructible_v<T>>
|
||||
struct MaybeStorage;
|
||||
|
||||
template <typename T>
|
||||
struct MaybeStorage<T, false> {
|
||||
using NonConstT = typename RemoveConst<T>::Type;
|
||||
|
||||
union Union {
|
||||
Union() {}
|
||||
constexpr explicit Union(const T& aVal) : val{aVal} {}
|
||||
template <typename U,
|
||||
typename = std::enable_if_t<std::is_move_constructible_v<U>>>
|
||||
constexpr explicit Union(U&& aVal) : val{std::forward<U>(aVal)} {}
|
||||
|
||||
~Union() {}
|
||||
|
||||
NonConstT val;
|
||||
char dummy;
|
||||
} mStorage;
|
||||
char mIsSome = false; // not bool -- guarantees minimal space consumption
|
||||
|
||||
MaybeStorage() = default;
|
||||
explicit MaybeStorage(const T& aVal) : mStorage{aVal}, mIsSome{true} {}
|
||||
explicit MaybeStorage(T&& aVal) : mStorage{std::move(aVal)}, mIsSome{true} {}
|
||||
|
||||
// Copy and move operations are no-ops, since copying is moving is implemented
|
||||
// by Maybe_CopyMove_Enabler.
|
||||
|
||||
MaybeStorage(const MaybeStorage&) {}
|
||||
MaybeStorage& operator=(const MaybeStorage&) { return *this; }
|
||||
MaybeStorage(MaybeStorage&&) {}
|
||||
MaybeStorage& operator=(MaybeStorage&&) { return *this; }
|
||||
|
||||
~MaybeStorage() {
|
||||
if (mIsSome) {
|
||||
mStorage.val.T::~T();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct MaybeStorage<T, true> {
|
||||
using NonConstT = typename RemoveConst<T>::Type;
|
||||
|
||||
union Union {
|
||||
constexpr Union() : dummy() {}
|
||||
constexpr explicit Union(const T& aVal) : val{aVal} {}
|
||||
constexpr explicit Union(T&& aVal) : val{std::move(aVal)} {}
|
||||
|
||||
NonConstT val;
|
||||
char dummy;
|
||||
} mStorage;
|
||||
char mIsSome = false; // not bool -- guarantees minimal space consumption
|
||||
|
||||
MaybeStorage() = default;
|
||||
constexpr explicit MaybeStorage(const T& aVal)
|
||||
: mStorage{aVal}, mIsSome{true} {}
|
||||
constexpr explicit MaybeStorage(T&& aVal)
|
||||
: mStorage{std::move(aVal)}, mIsSome{true} {}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename T, typename U = typename std::remove_cv<
|
||||
typename std::remove_reference<T>::type>::type>
|
||||
constexpr Maybe<U> Some(T&& aValue);
|
||||
|
||||
/*
|
||||
* Maybe is a container class which contains either zero or one elements. It
|
||||
* serves two roles. It can represent values which are *semantically* optional,
|
||||
|
@ -249,33 +335,31 @@ class Maybe_CopyMove_Enabler<T, false, false> {
|
|||
*/
|
||||
template <class T>
|
||||
class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS Maybe
|
||||
: public detail::Maybe_CopyMove_Enabler<T> {
|
||||
template <typename, bool, bool>
|
||||
: private detail::MaybeStorage<T>,
|
||||
public detail::Maybe_CopyMove_Enabler<T> {
|
||||
template <typename, bool, bool, bool>
|
||||
friend class detail::Maybe_CopyMove_Enabler;
|
||||
|
||||
using NonConstT = typename RemoveConst<T>::Type;
|
||||
union Union {
|
||||
Union() {}
|
||||
~Union() {}
|
||||
template <typename U, typename V>
|
||||
friend constexpr Maybe<V> Some(U&& aValue);
|
||||
|
||||
Union(const Union&) {}
|
||||
Union& operator=(const Union&) { return *this; }
|
||||
Union(Union&&) {}
|
||||
Union& operator=(Union&&) { return *this; }
|
||||
struct SomeGuard {};
|
||||
|
||||
NonConstT val;
|
||||
} mStorage;
|
||||
char mIsSome; // not bool -- guarantees minimal space consumption
|
||||
template <typename U>
|
||||
constexpr Maybe(U&& aValue, SomeGuard)
|
||||
: detail::MaybeStorage<T>{std::forward<U>(aValue)} {}
|
||||
|
||||
using detail::MaybeStorage<T>::mIsSome;
|
||||
using detail::MaybeStorage<T>::mStorage;
|
||||
|
||||
void poisonData() { detail::MaybePoisoner<T>::poison(&mStorage.val); }
|
||||
|
||||
public:
|
||||
using ValueType = T;
|
||||
|
||||
MOZ_ALLOW_TEMPORARY Maybe() : mIsSome(false) {}
|
||||
~Maybe() { reset(); }
|
||||
MOZ_ALLOW_TEMPORARY constexpr Maybe() = default;
|
||||
|
||||
MOZ_ALLOW_TEMPORARY MOZ_IMPLICIT Maybe(Nothing) : mIsSome(false) {}
|
||||
MOZ_ALLOW_TEMPORARY MOZ_IMPLICIT constexpr Maybe(Nothing) : Maybe{} {}
|
||||
|
||||
/**
|
||||
* Maybe<T> can be copy-constructed from a Maybe<U> if T is constructible from
|
||||
|
@ -283,7 +367,7 @@ class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS Maybe
|
|||
*/
|
||||
template <typename U,
|
||||
typename = std::enable_if_t<std::is_constructible_v<T, const U&>>>
|
||||
MOZ_IMPLICIT Maybe(const Maybe<U>& aOther) : mIsSome(false) {
|
||||
MOZ_IMPLICIT Maybe(const Maybe<U>& aOther) {
|
||||
if (aOther.isSome()) {
|
||||
emplace(*aOther);
|
||||
}
|
||||
|
@ -295,7 +379,7 @@ class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS Maybe
|
|||
*/
|
||||
template <typename U,
|
||||
typename = std::enable_if_t<std::is_constructible_v<T, U&&>>>
|
||||
MOZ_IMPLICIT Maybe(Maybe<U>&& aOther) : mIsSome(false) {
|
||||
MOZ_IMPLICIT Maybe(Maybe<U>&& aOther) {
|
||||
if (aOther.isSome()) {
|
||||
emplace(std::move(*aOther));
|
||||
aOther.reset();
|
||||
|
@ -340,20 +424,20 @@ class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS Maybe
|
|||
}
|
||||
|
||||
/* Methods that check whether this Maybe contains a value */
|
||||
explicit operator bool() const { return isSome(); }
|
||||
bool isSome() const { return mIsSome; }
|
||||
bool isNothing() const { return !mIsSome; }
|
||||
constexpr explicit operator bool() const { return isSome(); }
|
||||
constexpr bool isSome() const { return mIsSome; }
|
||||
constexpr bool isNothing() const { return !mIsSome; }
|
||||
|
||||
/* Returns the contents of this Maybe<T> by value. Unsafe unless |isSome()|.
|
||||
*/
|
||||
T value() const;
|
||||
constexpr T value() const;
|
||||
|
||||
/*
|
||||
* Returns the contents of this Maybe<T> by value. If |isNothing()|, returns
|
||||
* the default value provided.
|
||||
*/
|
||||
template <typename V>
|
||||
T valueOr(V&& aDefault) const {
|
||||
constexpr T valueOr(V&& aDefault) const {
|
||||
if (isSome()) {
|
||||
return ref();
|
||||
}
|
||||
|
@ -365,7 +449,7 @@ class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS Maybe
|
|||
* the value returned from the function or functor provided.
|
||||
*/
|
||||
template <typename F>
|
||||
T valueOrFrom(F&& aFunc) const {
|
||||
constexpr T valueOrFrom(F&& aFunc) const {
|
||||
if (isSome()) {
|
||||
return ref();
|
||||
}
|
||||
|
@ -415,25 +499,25 @@ class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS Maybe
|
|||
return aFunc();
|
||||
}
|
||||
|
||||
T* operator->();
|
||||
const T* operator->() const;
|
||||
constexpr T* operator->();
|
||||
constexpr const T* operator->() const;
|
||||
|
||||
/* Returns the contents of this Maybe<T> by ref. Unsafe unless |isSome()|. */
|
||||
T& ref();
|
||||
const T& ref() const;
|
||||
constexpr T& ref();
|
||||
constexpr const T& ref() const;
|
||||
|
||||
/*
|
||||
* Returns the contents of this Maybe<T> by ref. If |isNothing()|, returns
|
||||
* the default value provided.
|
||||
*/
|
||||
T& refOr(T& aDefault) {
|
||||
constexpr T& refOr(T& aDefault) {
|
||||
if (isSome()) {
|
||||
return ref();
|
||||
}
|
||||
return aDefault;
|
||||
}
|
||||
|
||||
const T& refOr(const T& aDefault) const {
|
||||
constexpr const T& refOr(const T& aDefault) const {
|
||||
if (isSome()) {
|
||||
return ref();
|
||||
}
|
||||
|
@ -445,7 +529,7 @@ class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS Maybe
|
|||
* value returned from the function or functor provided.
|
||||
*/
|
||||
template <typename F>
|
||||
T& refOrFrom(F&& aFunc) {
|
||||
constexpr T& refOrFrom(F&& aFunc) {
|
||||
if (isSome()) {
|
||||
return ref();
|
||||
}
|
||||
|
@ -453,20 +537,20 @@ class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS Maybe
|
|||
}
|
||||
|
||||
template <typename F>
|
||||
const T& refOrFrom(F&& aFunc) const {
|
||||
constexpr const T& refOrFrom(F&& aFunc) const {
|
||||
if (isSome()) {
|
||||
return ref();
|
||||
}
|
||||
return aFunc();
|
||||
}
|
||||
|
||||
T& operator*();
|
||||
const T& operator*() const;
|
||||
constexpr T& operator*();
|
||||
constexpr const T& operator*() const;
|
||||
|
||||
/* If |isSome()|, runs the provided function or functor on the contents of
|
||||
* this Maybe. */
|
||||
template <typename Func>
|
||||
Maybe& apply(Func&& aFunc) {
|
||||
constexpr Maybe& apply(Func&& aFunc) {
|
||||
if (isSome()) {
|
||||
std::forward<Func>(aFunc)(ref());
|
||||
}
|
||||
|
@ -474,7 +558,7 @@ class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS Maybe
|
|||
}
|
||||
|
||||
template <typename Func>
|
||||
const Maybe& apply(Func&& aFunc) const {
|
||||
constexpr const Maybe& apply(Func&& aFunc) const {
|
||||
if (isSome()) {
|
||||
std::forward<Func>(aFunc)(ref());
|
||||
}
|
||||
|
@ -487,29 +571,29 @@ class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS Maybe
|
|||
* value type as what the provided function would have returned.
|
||||
*/
|
||||
template <typename Func>
|
||||
auto map(Func&& aFunc) {
|
||||
Maybe<decltype(std::forward<Func>(aFunc)(ref()))> val;
|
||||
constexpr auto map(Func&& aFunc) {
|
||||
if (isSome()) {
|
||||
val.emplace(std::forward<Func>(aFunc)(ref()));
|
||||
return Some(std::forward<Func>(aFunc)(ref()));
|
||||
}
|
||||
return val;
|
||||
return Maybe<decltype(std::forward<Func>(aFunc)(ref()))>{};
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
auto map(Func&& aFunc) const {
|
||||
Maybe<decltype(std::forward<Func>(aFunc)(ref()))> val;
|
||||
constexpr auto map(Func&& aFunc) const {
|
||||
if (isSome()) {
|
||||
val.emplace(std::forward<Func>(aFunc)(ref()));
|
||||
return Some(std::forward<Func>(aFunc)(ref()));
|
||||
}
|
||||
return val;
|
||||
return Maybe<decltype(std::forward<Func>(aFunc)(ref()))>{};
|
||||
}
|
||||
|
||||
/* If |isSome()|, empties this Maybe and destroys its contents. */
|
||||
void reset() {
|
||||
constexpr void reset() {
|
||||
if (isSome()) {
|
||||
ref().T::~T();
|
||||
if constexpr (!std::is_trivially_destructible_v<T>) {
|
||||
ref().T::~T();
|
||||
poisonData();
|
||||
}
|
||||
mIsSome = false;
|
||||
poisonData();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -518,11 +602,12 @@ class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS Maybe
|
|||
* arguments to |emplace()| are the parameters to T's constructor.
|
||||
*/
|
||||
template <typename... Args>
|
||||
void emplace(Args&&... aArgs);
|
||||
constexpr void emplace(Args&&... aArgs);
|
||||
|
||||
template <typename U>
|
||||
std::enable_if_t<std::is_same_v<T, U> && std::is_copy_constructible_v<U> &&
|
||||
!std::is_move_constructible_v<U>>
|
||||
constexpr std::enable_if_t<std::is_same_v<T, U> &&
|
||||
std::is_copy_constructible_v<U> &&
|
||||
!std::is_move_constructible_v<U>>
|
||||
emplace(U&& aArgs) {
|
||||
emplace(aArgs);
|
||||
}
|
||||
|
@ -547,9 +632,9 @@ class Maybe<T&> {
|
|||
void emplace(T& aRef) { mValue = &aRef; }
|
||||
|
||||
/* Methods that check whether this Maybe contains a value */
|
||||
explicit operator bool() const { return isSome(); }
|
||||
bool isSome() const { return mValue; }
|
||||
bool isNothing() const { return !mValue; }
|
||||
constexpr explicit operator bool() const { return isSome(); }
|
||||
constexpr bool isSome() const { return mValue; }
|
||||
constexpr bool isNothing() const { return !mValue; }
|
||||
|
||||
T& ref() const {
|
||||
MOZ_DIAGNOSTIC_ASSERT(isSome());
|
||||
|
@ -605,63 +690,63 @@ class Maybe<T&> {
|
|||
};
|
||||
|
||||
template <typename T>
|
||||
T Maybe<T>::value() const {
|
||||
MOZ_DIAGNOSTIC_ASSERT(mIsSome);
|
||||
constexpr T Maybe<T>::value() const {
|
||||
MOZ_DIAGNOSTIC_ASSERT(isSome());
|
||||
return ref();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T* Maybe<T>::ptr() {
|
||||
MOZ_DIAGNOSTIC_ASSERT(mIsSome);
|
||||
MOZ_DIAGNOSTIC_ASSERT(isSome());
|
||||
return &ref();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const T* Maybe<T>::ptr() const {
|
||||
MOZ_DIAGNOSTIC_ASSERT(mIsSome);
|
||||
MOZ_DIAGNOSTIC_ASSERT(isSome());
|
||||
return &ref();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T* Maybe<T>::operator->() {
|
||||
MOZ_DIAGNOSTIC_ASSERT(mIsSome);
|
||||
constexpr T* Maybe<T>::operator->() {
|
||||
MOZ_DIAGNOSTIC_ASSERT(isSome());
|
||||
return ptr();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const T* Maybe<T>::operator->() const {
|
||||
MOZ_DIAGNOSTIC_ASSERT(mIsSome);
|
||||
constexpr const T* Maybe<T>::operator->() const {
|
||||
MOZ_DIAGNOSTIC_ASSERT(isSome());
|
||||
return ptr();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T& Maybe<T>::ref() {
|
||||
MOZ_DIAGNOSTIC_ASSERT(mIsSome);
|
||||
constexpr T& Maybe<T>::ref() {
|
||||
MOZ_DIAGNOSTIC_ASSERT(isSome());
|
||||
return mStorage.val;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const T& Maybe<T>::ref() const {
|
||||
MOZ_DIAGNOSTIC_ASSERT(mIsSome);
|
||||
constexpr const T& Maybe<T>::ref() const {
|
||||
MOZ_DIAGNOSTIC_ASSERT(isSome());
|
||||
return mStorage.val;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T& Maybe<T>::operator*() {
|
||||
MOZ_DIAGNOSTIC_ASSERT(mIsSome);
|
||||
constexpr T& Maybe<T>::operator*() {
|
||||
MOZ_DIAGNOSTIC_ASSERT(isSome());
|
||||
return ref();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const T& Maybe<T>::operator*() const {
|
||||
MOZ_DIAGNOSTIC_ASSERT(mIsSome);
|
||||
constexpr const T& Maybe<T>::operator*() const {
|
||||
MOZ_DIAGNOSTIC_ASSERT(isSome());
|
||||
return ref();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename... Args>
|
||||
void Maybe<T>::emplace(Args&&... aArgs) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(!mIsSome);
|
||||
constexpr void Maybe<T>::emplace(Args&&... aArgs) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(!isSome());
|
||||
::new (KnownNotNull, &mStorage.val) T(std::forward<Args>(aArgs)...);
|
||||
mIsSome = true;
|
||||
}
|
||||
|
@ -676,16 +761,13 @@ void Maybe<T>::emplace(Args&&... aArgs) {
|
|||
* if you need to construct a Maybe value that holds a const, volatile, or
|
||||
* reference value, you need to use emplace() instead.
|
||||
*/
|
||||
template <typename T, typename U = typename std::remove_cv<
|
||||
typename std::remove_reference<T>::type>::type>
|
||||
Maybe<U> Some(T&& aValue) {
|
||||
Maybe<U> value;
|
||||
value.emplace(std::forward<T>(aValue));
|
||||
return value;
|
||||
template <typename T, typename U>
|
||||
constexpr Maybe<U> Some(T&& aValue) {
|
||||
return {std::forward<T>(aValue), typename Maybe<U>::SomeGuard{}};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Maybe<T&> SomeRef(T& aValue) {
|
||||
constexpr Maybe<T&> SomeRef(T& aValue) {
|
||||
Maybe<T&> value;
|
||||
value.emplace(aValue);
|
||||
return value;
|
||||
|
@ -706,7 +788,7 @@ Maybe<typename RemoveCV<typename RemoveReference<T>::Type>::Type> ToMaybe(
|
|||
* - both are Some, and the values they contain are equal.
|
||||
*/
|
||||
template <typename T>
|
||||
bool operator==(const Maybe<T>& aLHS, const Maybe<T>& aRHS) {
|
||||
constexpr bool operator==(const Maybe<T>& aLHS, const Maybe<T>& aRHS) {
|
||||
static_assert(!std::is_reference_v<T>,
|
||||
"operator== is not defined for Maybe<T&>, compare values or "
|
||||
"addresses explicitly instead");
|
||||
|
@ -717,7 +799,7 @@ bool operator==(const Maybe<T>& aLHS, const Maybe<T>& aRHS) {
|
|||
}
|
||||
|
||||
template <typename T>
|
||||
bool operator!=(const Maybe<T>& aLHS, const Maybe<T>& aRHS) {
|
||||
constexpr bool operator!=(const Maybe<T>& aLHS, const Maybe<T>& aRHS) {
|
||||
return !(aLHS == aRHS);
|
||||
}
|
||||
|
||||
|
@ -726,22 +808,22 @@ bool operator!=(const Maybe<T>& aLHS, const Maybe<T>& aRHS) {
|
|||
* if (maybeValue == Nothing()) { ... }
|
||||
*/
|
||||
template <typename T>
|
||||
bool operator==(const Maybe<T>& aLHS, const Nothing& aRHS) {
|
||||
constexpr bool operator==(const Maybe<T>& aLHS, const Nothing& aRHS) {
|
||||
return aLHS.isNothing();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool operator!=(const Maybe<T>& aLHS, const Nothing& aRHS) {
|
||||
constexpr bool operator!=(const Maybe<T>& aLHS, const Nothing& aRHS) {
|
||||
return !(aLHS == aRHS);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool operator==(const Nothing& aLHS, const Maybe<T>& aRHS) {
|
||||
constexpr bool operator==(const Nothing& aLHS, const Maybe<T>& aRHS) {
|
||||
return aRHS.isNothing();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool operator!=(const Nothing& aLHS, const Maybe<T>& aRHS) {
|
||||
constexpr bool operator!=(const Nothing& aLHS, const Maybe<T>& aRHS) {
|
||||
return !(aLHS == aRHS);
|
||||
}
|
||||
|
||||
|
@ -750,7 +832,7 @@ bool operator!=(const Nothing& aLHS, const Maybe<T>& aRHS) {
|
|||
* Nothing comes before anything else.
|
||||
*/
|
||||
template <typename T>
|
||||
bool operator<(const Maybe<T>& aLHS, const Maybe<T>& aRHS) {
|
||||
constexpr bool operator<(const Maybe<T>& aLHS, const Maybe<T>& aRHS) {
|
||||
if (aLHS.isNothing()) {
|
||||
return aRHS.isSome();
|
||||
}
|
||||
|
@ -761,17 +843,17 @@ bool operator<(const Maybe<T>& aLHS, const Maybe<T>& aRHS) {
|
|||
}
|
||||
|
||||
template <typename T>
|
||||
bool operator>(const Maybe<T>& aLHS, const Maybe<T>& aRHS) {
|
||||
constexpr bool operator>(const Maybe<T>& aLHS, const Maybe<T>& aRHS) {
|
||||
return !(aLHS < aRHS || aLHS == aRHS);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool operator<=(const Maybe<T>& aLHS, const Maybe<T>& aRHS) {
|
||||
constexpr bool operator<=(const Maybe<T>& aLHS, const Maybe<T>& aRHS) {
|
||||
return aLHS < aRHS || aLHS == aRHS;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool operator>=(const Maybe<T>& aLHS, const Maybe<T>& aRHS) {
|
||||
constexpr bool operator>=(const Maybe<T>& aLHS, const Maybe<T>& aRHS) {
|
||||
return !(aLHS < aRHS);
|
||||
}
|
||||
|
||||
|
|
|
@ -170,6 +170,29 @@ struct UncopyableUnmovableValue {
|
|||
Status mStatus;
|
||||
};
|
||||
|
||||
static_assert(std::is_literal_type_v<Maybe<int>>);
|
||||
static_assert(std::is_trivially_copy_constructible_v<Maybe<int>>);
|
||||
static_assert(std::is_trivially_copy_assignable_v<Maybe<int>>);
|
||||
|
||||
static_assert(42 == Some(42).value());
|
||||
static_assert(42 == Some(42).valueOr(43));
|
||||
static_assert(42 == Maybe<int>{}.valueOr(42));
|
||||
static_assert(42 == Some(42).valueOrFrom([] { return 43; }));
|
||||
static_assert(42 == Maybe<int>{}.valueOrFrom([] { return 42; }));
|
||||
static_assert(Some(43) == [] {
|
||||
auto val = Some(42);
|
||||
val.apply([](int& val) { val += 1; });
|
||||
return val;
|
||||
}());
|
||||
static_assert(Some(43) == Some(42).map([](int val) { return val + 1; }));
|
||||
|
||||
struct TriviallyDestructible {
|
||||
TriviallyDestructible() { // not trivially constructible
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(std::is_trivially_destructible_v<Maybe<TriviallyDestructible>>);
|
||||
|
||||
static bool TestBasicFeatures() {
|
||||
// Check that a Maybe<T> is initialized to Nothing.
|
||||
Maybe<BasicValue> mayValue;
|
||||
|
@ -254,96 +277,225 @@ static bool TestBasicFeatures() {
|
|||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void TestCopyMaybe() {
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(0 == sUndestroyedObjects);
|
||||
|
||||
Maybe<T> src = Some(T());
|
||||
Maybe<T> dstCopyConstructed = src;
|
||||
|
||||
MOZ_RELEASE_ASSERT(2 == sUndestroyedObjects);
|
||||
MOZ_RELEASE_ASSERT(dstCopyConstructed->GetStatus() == eWasCopyConstructed);
|
||||
}
|
||||
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(0 == sUndestroyedObjects);
|
||||
|
||||
Maybe<T> src = Some(T());
|
||||
Maybe<T> dstCopyAssigned;
|
||||
dstCopyAssigned = src;
|
||||
|
||||
MOZ_RELEASE_ASSERT(2 == sUndestroyedObjects);
|
||||
MOZ_RELEASE_ASSERT(dstCopyAssigned->GetStatus() == eWasCopyConstructed);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void TestMoveMaybe() {
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(0 == sUndestroyedObjects);
|
||||
|
||||
Maybe<T> src = Some(T());
|
||||
Maybe<T> dstMoveConstructed = std::move(src);
|
||||
|
||||
MOZ_RELEASE_ASSERT(1 == sUndestroyedObjects);
|
||||
MOZ_RELEASE_ASSERT(dstMoveConstructed->GetStatus() == eWasMoveConstructed);
|
||||
}
|
||||
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(0 == sUndestroyedObjects);
|
||||
|
||||
Maybe<T> src = Some(T());
|
||||
Maybe<T> dstMoveAssigned;
|
||||
dstMoveAssigned = std::move(src);
|
||||
|
||||
MOZ_RELEASE_ASSERT(1 == sUndestroyedObjects);
|
||||
MOZ_RELEASE_ASSERT(dstMoveAssigned->GetStatus() == eWasMoveConstructed);
|
||||
}
|
||||
}
|
||||
|
||||
static bool TestCopyAndMove() {
|
||||
// Check that we get moves when possible for types that can support both moves
|
||||
// and copies.
|
||||
Maybe<BasicValue> mayBasicValue = Some(BasicValue(1));
|
||||
MOZ_RELEASE_ASSERT(mayBasicValue->GetStatus() == eWasMoveConstructed);
|
||||
MOZ_RELEASE_ASSERT(mayBasicValue->GetTag() == 1);
|
||||
mayBasicValue = Some(BasicValue(2));
|
||||
MOZ_RELEASE_ASSERT(mayBasicValue->GetStatus() == eWasMoveAssigned);
|
||||
MOZ_RELEASE_ASSERT(mayBasicValue->GetTag() == 2);
|
||||
mayBasicValue.reset();
|
||||
mayBasicValue.emplace(BasicValue(3));
|
||||
MOZ_RELEASE_ASSERT(mayBasicValue->GetStatus() == eWasMoveConstructed);
|
||||
MOZ_RELEASE_ASSERT(mayBasicValue->GetTag() == 3);
|
||||
MOZ_RELEASE_ASSERT(0 == sUndestroyedObjects);
|
||||
|
||||
// Check that we get copies when moves aren't possible.
|
||||
Maybe<BasicValue> mayBasicValue2 = Some(*mayBasicValue);
|
||||
MOZ_RELEASE_ASSERT(mayBasicValue2->GetStatus() == eWasCopyConstructed);
|
||||
MOZ_RELEASE_ASSERT(mayBasicValue2->GetTag() == 3);
|
||||
mayBasicValue->SetTag(4);
|
||||
mayBasicValue2 = mayBasicValue;
|
||||
// This test should work again when we fix bug 1052940.
|
||||
// MOZ_RELEASE_ASSERT(mayBasicValue2->GetStatus() == eWasCopyAssigned);
|
||||
MOZ_RELEASE_ASSERT(mayBasicValue2->GetTag() == 4);
|
||||
mayBasicValue->SetTag(5);
|
||||
mayBasicValue2.reset();
|
||||
mayBasicValue2.emplace(*mayBasicValue);
|
||||
MOZ_RELEASE_ASSERT(mayBasicValue2->GetStatus() == eWasCopyConstructed);
|
||||
MOZ_RELEASE_ASSERT(mayBasicValue2->GetTag() == 5);
|
||||
{
|
||||
// Check that we get moves when possible for types that can support both
|
||||
// moves and copies.
|
||||
{
|
||||
Maybe<BasicValue> mayBasicValue = Some(BasicValue(1));
|
||||
MOZ_RELEASE_ASSERT(1 == sUndestroyedObjects);
|
||||
MOZ_RELEASE_ASSERT(mayBasicValue->GetStatus() == eWasMoveConstructed);
|
||||
MOZ_RELEASE_ASSERT(mayBasicValue->GetTag() == 1);
|
||||
mayBasicValue = Some(BasicValue(2));
|
||||
MOZ_RELEASE_ASSERT(1 == sUndestroyedObjects);
|
||||
MOZ_RELEASE_ASSERT(mayBasicValue->GetStatus() == eWasMoveAssigned);
|
||||
MOZ_RELEASE_ASSERT(mayBasicValue->GetTag() == 2);
|
||||
mayBasicValue.reset();
|
||||
MOZ_RELEASE_ASSERT(0 == sUndestroyedObjects);
|
||||
mayBasicValue.emplace(BasicValue(3));
|
||||
MOZ_RELEASE_ASSERT(1 == sUndestroyedObjects);
|
||||
MOZ_RELEASE_ASSERT(mayBasicValue->GetStatus() == eWasMoveConstructed);
|
||||
MOZ_RELEASE_ASSERT(mayBasicValue->GetTag() == 3);
|
||||
|
||||
// Check that std::move() works. (Another sanity check for move support.)
|
||||
Maybe<BasicValue> mayBasicValue3 = Some(std::move(*mayBasicValue));
|
||||
MOZ_RELEASE_ASSERT(mayBasicValue3->GetStatus() == eWasMoveConstructed);
|
||||
MOZ_RELEASE_ASSERT(mayBasicValue3->GetTag() == 5);
|
||||
MOZ_RELEASE_ASSERT(mayBasicValue->GetStatus() == eWasMovedFrom);
|
||||
mayBasicValue2->SetTag(6);
|
||||
mayBasicValue3 = Some(std::move(*mayBasicValue2));
|
||||
MOZ_RELEASE_ASSERT(mayBasicValue3->GetStatus() == eWasMoveAssigned);
|
||||
MOZ_RELEASE_ASSERT(mayBasicValue3->GetTag() == 6);
|
||||
MOZ_RELEASE_ASSERT(mayBasicValue2->GetStatus() == eWasMovedFrom);
|
||||
Maybe<BasicValue> mayBasicValue4;
|
||||
mayBasicValue4.emplace(std::move(*mayBasicValue3));
|
||||
MOZ_RELEASE_ASSERT(mayBasicValue4->GetStatus() == eWasMoveConstructed);
|
||||
MOZ_RELEASE_ASSERT(mayBasicValue4->GetTag() == 6);
|
||||
MOZ_RELEASE_ASSERT(mayBasicValue3->GetStatus() == eWasMovedFrom);
|
||||
// Check that we get copies when moves aren't possible.
|
||||
Maybe<BasicValue> mayBasicValue2 = Some(*mayBasicValue);
|
||||
MOZ_RELEASE_ASSERT(mayBasicValue2->GetStatus() == eWasCopyConstructed);
|
||||
MOZ_RELEASE_ASSERT(mayBasicValue2->GetTag() == 3);
|
||||
mayBasicValue->SetTag(4);
|
||||
mayBasicValue2 = mayBasicValue;
|
||||
// This test should work again when we fix bug 1052940.
|
||||
// MOZ_RELEASE_ASSERT(mayBasicValue2->GetStatus() == eWasCopyAssigned);
|
||||
MOZ_RELEASE_ASSERT(mayBasicValue2->GetTag() == 4);
|
||||
mayBasicValue->SetTag(5);
|
||||
mayBasicValue2.reset();
|
||||
mayBasicValue2.emplace(*mayBasicValue);
|
||||
MOZ_RELEASE_ASSERT(mayBasicValue2->GetStatus() == eWasCopyConstructed);
|
||||
MOZ_RELEASE_ASSERT(mayBasicValue2->GetTag() == 5);
|
||||
|
||||
// Check that we always get copies for types that don't support moves.
|
||||
Maybe<UnmovableValue> mayUnmovableValue = Some(UnmovableValue());
|
||||
MOZ_RELEASE_ASSERT(mayUnmovableValue->GetStatus() == eWasCopyConstructed);
|
||||
mayUnmovableValue = Some(UnmovableValue());
|
||||
MOZ_RELEASE_ASSERT(mayUnmovableValue->GetStatus() == eWasCopyAssigned);
|
||||
mayUnmovableValue.reset();
|
||||
mayUnmovableValue.emplace(UnmovableValue());
|
||||
MOZ_RELEASE_ASSERT(mayUnmovableValue->GetStatus() == eWasCopyConstructed);
|
||||
// Check that std::move() works. (Another sanity check for move support.)
|
||||
Maybe<BasicValue> mayBasicValue3 = Some(std::move(*mayBasicValue));
|
||||
MOZ_RELEASE_ASSERT(mayBasicValue3->GetStatus() == eWasMoveConstructed);
|
||||
MOZ_RELEASE_ASSERT(mayBasicValue3->GetTag() == 5);
|
||||
MOZ_RELEASE_ASSERT(mayBasicValue->GetStatus() == eWasMovedFrom);
|
||||
mayBasicValue2->SetTag(6);
|
||||
mayBasicValue3 = Some(std::move(*mayBasicValue2));
|
||||
MOZ_RELEASE_ASSERT(mayBasicValue3->GetStatus() == eWasMoveAssigned);
|
||||
MOZ_RELEASE_ASSERT(mayBasicValue3->GetTag() == 6);
|
||||
MOZ_RELEASE_ASSERT(mayBasicValue2->GetStatus() == eWasMovedFrom);
|
||||
Maybe<BasicValue> mayBasicValue4;
|
||||
mayBasicValue4.emplace(std::move(*mayBasicValue3));
|
||||
MOZ_RELEASE_ASSERT(mayBasicValue4->GetStatus() == eWasMoveConstructed);
|
||||
MOZ_RELEASE_ASSERT(mayBasicValue4->GetTag() == 6);
|
||||
MOZ_RELEASE_ASSERT(mayBasicValue3->GetStatus() == eWasMovedFrom);
|
||||
}
|
||||
|
||||
static_assert(std::is_copy_constructible_v<Maybe<UnmovableValue>>);
|
||||
static_assert(std::is_copy_assignable_v<Maybe<UnmovableValue>>);
|
||||
// XXX Why do these static_asserts not hold?
|
||||
// static_assert(!std::is_move_constructible_v<Maybe<UnmovableValue>>);
|
||||
// static_assert(!std::is_move_assignable_v<Maybe<UnmovableValue>>);
|
||||
TestCopyMaybe<BasicValue>();
|
||||
TestMoveMaybe<BasicValue>();
|
||||
}
|
||||
|
||||
// Check that types that only support moves, but not copies, work.
|
||||
Maybe<UncopyableValue> mayUncopyableValue = Some(UncopyableValue());
|
||||
MOZ_RELEASE_ASSERT(mayUncopyableValue->GetStatus() == eWasMoveConstructed);
|
||||
mayUncopyableValue = Some(UncopyableValue());
|
||||
MOZ_RELEASE_ASSERT(mayUncopyableValue->GetStatus() == eWasMoveAssigned);
|
||||
mayUncopyableValue.reset();
|
||||
mayUncopyableValue.emplace(UncopyableValue());
|
||||
MOZ_RELEASE_ASSERT(mayUncopyableValue->GetStatus() == eWasMoveConstructed);
|
||||
mayUncopyableValue = Nothing();
|
||||
MOZ_RELEASE_ASSERT(0 == sUndestroyedObjects);
|
||||
|
||||
static_assert(!std::is_copy_constructible_v<Maybe<UncopyableValue>>);
|
||||
static_assert(!std::is_copy_assignable_v<Maybe<UncopyableValue>>);
|
||||
static_assert(std::is_move_constructible_v<Maybe<UncopyableValue>>);
|
||||
static_assert(std::is_move_assignable_v<Maybe<UncopyableValue>>);
|
||||
{
|
||||
// Check that we always get copies for types that don't support moves.
|
||||
{
|
||||
Maybe<UnmovableValue> mayUnmovableValue = Some(UnmovableValue());
|
||||
MOZ_RELEASE_ASSERT(mayUnmovableValue->GetStatus() == eWasCopyConstructed);
|
||||
mayUnmovableValue = Some(UnmovableValue());
|
||||
MOZ_RELEASE_ASSERT(mayUnmovableValue->GetStatus() == eWasCopyAssigned);
|
||||
mayUnmovableValue.reset();
|
||||
mayUnmovableValue.emplace(UnmovableValue());
|
||||
MOZ_RELEASE_ASSERT(mayUnmovableValue->GetStatus() == eWasCopyConstructed);
|
||||
}
|
||||
|
||||
// Check that types that support neither moves or copies work.
|
||||
Maybe<UncopyableUnmovableValue> mayUncopyableUnmovableValue;
|
||||
mayUncopyableUnmovableValue.emplace();
|
||||
MOZ_RELEASE_ASSERT(mayUncopyableUnmovableValue->GetStatus() ==
|
||||
eWasDefaultConstructed);
|
||||
mayUncopyableUnmovableValue.reset();
|
||||
mayUncopyableUnmovableValue.emplace(0);
|
||||
MOZ_RELEASE_ASSERT(mayUncopyableUnmovableValue->GetStatus() ==
|
||||
eWasConstructed);
|
||||
mayUncopyableUnmovableValue = Nothing();
|
||||
TestCopyMaybe<UnmovableValue>();
|
||||
|
||||
static_assert(!std::is_copy_constructible_v<Maybe<UncopyableUnmovableValue>>);
|
||||
static_assert(!std::is_copy_assignable_v<Maybe<UncopyableUnmovableValue>>);
|
||||
static_assert(!std::is_move_constructible_v<Maybe<UncopyableUnmovableValue>>);
|
||||
static_assert(!std::is_move_assignable_v<Maybe<UncopyableUnmovableValue>>);
|
||||
static_assert(std::is_copy_constructible_v<Maybe<UnmovableValue>>);
|
||||
static_assert(std::is_copy_assignable_v<Maybe<UnmovableValue>>);
|
||||
// XXX Why do these static_asserts not hold?
|
||||
// static_assert(!std::is_move_constructible_v<Maybe<UnmovableValue>>);
|
||||
// static_assert(!std::is_move_assignable_v<Maybe<UnmovableValue>>);
|
||||
}
|
||||
|
||||
MOZ_RELEASE_ASSERT(0 == sUndestroyedObjects);
|
||||
|
||||
{
|
||||
// Check that types that only support moves, but not copies, work.
|
||||
{
|
||||
Maybe<UncopyableValue> mayUncopyableValue = Some(UncopyableValue());
|
||||
MOZ_RELEASE_ASSERT(mayUncopyableValue->GetStatus() ==
|
||||
eWasMoveConstructed);
|
||||
mayUncopyableValue = Some(UncopyableValue());
|
||||
MOZ_RELEASE_ASSERT(mayUncopyableValue->GetStatus() == eWasMoveAssigned);
|
||||
mayUncopyableValue.reset();
|
||||
mayUncopyableValue.emplace(UncopyableValue());
|
||||
MOZ_RELEASE_ASSERT(mayUncopyableValue->GetStatus() ==
|
||||
eWasMoveConstructed);
|
||||
mayUncopyableValue = Nothing();
|
||||
}
|
||||
|
||||
TestMoveMaybe<BasicValue>();
|
||||
|
||||
static_assert(!std::is_copy_constructible_v<Maybe<UncopyableValue>>);
|
||||
static_assert(!std::is_copy_assignable_v<Maybe<UncopyableValue>>);
|
||||
static_assert(std::is_move_constructible_v<Maybe<UncopyableValue>>);
|
||||
static_assert(std::is_move_assignable_v<Maybe<UncopyableValue>>);
|
||||
}
|
||||
|
||||
MOZ_RELEASE_ASSERT(0 == sUndestroyedObjects);
|
||||
|
||||
{ // Check that types that support neither moves or copies work.
|
||||
Maybe<UncopyableUnmovableValue> mayUncopyableUnmovableValue;
|
||||
mayUncopyableUnmovableValue.emplace();
|
||||
MOZ_RELEASE_ASSERT(mayUncopyableUnmovableValue->GetStatus() ==
|
||||
eWasDefaultConstructed);
|
||||
mayUncopyableUnmovableValue.reset();
|
||||
mayUncopyableUnmovableValue.emplace(0);
|
||||
MOZ_RELEASE_ASSERT(mayUncopyableUnmovableValue->GetStatus() ==
|
||||
eWasConstructed);
|
||||
mayUncopyableUnmovableValue = Nothing();
|
||||
|
||||
static_assert(
|
||||
!std::is_copy_constructible_v<Maybe<UncopyableUnmovableValue>>);
|
||||
static_assert(!std::is_copy_assignable_v<Maybe<UncopyableUnmovableValue>>);
|
||||
static_assert(
|
||||
!std::is_move_constructible_v<Maybe<UncopyableUnmovableValue>>);
|
||||
static_assert(!std::is_move_assignable_v<Maybe<UncopyableUnmovableValue>>);
|
||||
}
|
||||
|
||||
{
|
||||
// Test copy and move with a trivially copyable and trivially destructible
|
||||
// type.
|
||||
{
|
||||
constexpr Maybe<int> src = Some(42);
|
||||
constexpr Maybe<int> dstCopyConstructed = src;
|
||||
|
||||
static_assert(src.isSome());
|
||||
static_assert(dstCopyConstructed.isSome());
|
||||
static_assert(42 == *src);
|
||||
static_assert(42 == *dstCopyConstructed);
|
||||
static_assert(42 == dstCopyConstructed.value());
|
||||
}
|
||||
|
||||
{
|
||||
const Maybe<int> src = Some(42);
|
||||
Maybe<int> dstCopyAssigned;
|
||||
dstCopyAssigned = src;
|
||||
|
||||
MOZ_RELEASE_ASSERT(src.isSome());
|
||||
MOZ_RELEASE_ASSERT(dstCopyAssigned.isSome());
|
||||
MOZ_RELEASE_ASSERT(42 == *src);
|
||||
MOZ_RELEASE_ASSERT(42 == *dstCopyAssigned);
|
||||
}
|
||||
|
||||
{
|
||||
Maybe<int> src = Some(42);
|
||||
const Maybe<int> dstMoveConstructed = std::move(src);
|
||||
|
||||
MOZ_RELEASE_ASSERT(!src.isSome());
|
||||
MOZ_RELEASE_ASSERT(dstMoveConstructed.isSome());
|
||||
MOZ_RELEASE_ASSERT(42 == *dstMoveConstructed);
|
||||
}
|
||||
|
||||
{
|
||||
Maybe<int> src = Some(42);
|
||||
Maybe<int> dstMoveAssigned;
|
||||
dstMoveAssigned = std::move(src);
|
||||
|
||||
MOZ_RELEASE_ASSERT(!src.isSome());
|
||||
MOZ_RELEASE_ASSERT(dstMoveAssigned.isSome());
|
||||
MOZ_RELEASE_ASSERT(42 == *dstMoveAssigned);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче