/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* 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/. */
constexpr Maybe<UncopyableValueLiteralType> someUncopyableAssigned = [] { auto res = Maybe<UncopyableValueLiteralType>{};
res = Some(UncopyableValueLiteralType{42}); return res;
}();
static_assert(someUncopyableAssigned.isSome());
static_assert(42 == someUncopyableAssigned->mValue);
staticbool TestBasicFeatures() { // Check that a Maybe<T> is initialized to Nothing.
Maybe<BasicValue> mayValue;
static_assert(std::is_same_v<BasicValue, decltype(mayValue)::ValueType>, "Should have BasicValue ValueType");
MOZ_RELEASE_ASSERT(!mayValue);
MOZ_RELEASE_ASSERT(!mayValue.isSome());
MOZ_RELEASE_ASSERT(mayValue.isNothing());
// Check that emplace() default constructs and the accessors work.
mayValue.emplace();
MOZ_RELEASE_ASSERT(mayValue);
MOZ_RELEASE_ASSERT(mayValue.isSome());
MOZ_RELEASE_ASSERT(!mayValue.isNothing());
MOZ_RELEASE_ASSERT(*mayValue == BasicValue());
static_assert(std::is_same_v<BasicValue&, decltype(*mayValue)>, "operator*() should return a BasicValue&");
MOZ_RELEASE_ASSERT(mayValue.value() == BasicValue());
static_assert(std::is_same_v<BasicValue, decltype(mayValue.value())>, "value() should return a BasicValue");
MOZ_RELEASE_ASSERT(mayValue.ref() == BasicValue());
static_assert(std::is_same_v<BasicValue&, decltype(mayValue.ref())>, "ref() should return a BasicValue&");
MOZ_RELEASE_ASSERT(mayValue.ptr() != nullptr);
static_assert(std::is_same_v<BasicValue*, decltype(mayValue.ptr())>, "ptr() should return a BasicValue*");
MOZ_RELEASE_ASSERT(mayValue->GetStatus() == eWasDefaultConstructed);
// Check that reset() works.
mayValue.reset();
MOZ_RELEASE_ASSERT(!mayValue);
MOZ_RELEASE_ASSERT(!mayValue.isSome());
MOZ_RELEASE_ASSERT(mayValue.isNothing());
// Check that emplace(T1) calls the correct constructor.
mayValue.emplace(1);
MOZ_RELEASE_ASSERT(mayValue);
MOZ_RELEASE_ASSERT(mayValue->GetStatus() == eWasConstructed);
MOZ_RELEASE_ASSERT(mayValue->GetTag() == 1);
mayValue.reset();
MOZ_RELEASE_ASSERT(!mayValue);
// Check that accessors work through rvalue-references.
MOZ_RELEASE_ASSERT(Some(BasicValue()));
MOZ_RELEASE_ASSERT(Some(BasicValue()).isSome());
MOZ_RELEASE_ASSERT(!Some(BasicValue()).isNothing());
MOZ_RELEASE_ASSERT(*Some(BasicValue()) == BasicValue());
static_assert(std::is_same_v<BasicValue&&, decltype(*Some(BasicValue()))>, "operator*() should return a BasicValue&&");
MOZ_RELEASE_ASSERT(Some(BasicValue()).value() == BasicValue());
static_assert(
std::is_same_v<BasicValue, decltype(Some(BasicValue()).value())>, "value() should return a BasicValue");
MOZ_RELEASE_ASSERT(Some(BasicValue()).ref() == BasicValue());
static_assert(
std::is_same_v<BasicValue&&, decltype(Some(BasicValue()).ref())>, "ref() should return a BasicValue&&");
MOZ_RELEASE_ASSERT(Some(BasicValue()).ptr() != nullptr);
static_assert(std::is_same_v<BasicValue*, decltype(Some(BasicValue()).ptr())>, "ptr() should return a BasicValue*");
MOZ_RELEASE_ASSERT(Some(BasicValue())->GetStatus() == eWasMoveConstructed);
// Check that accessors work through const-rvalue-references. auto MakeConstMaybe = []() -> const Maybe<BasicValue> { return Some(BasicValue());
};
MOZ_RELEASE_ASSERT(MakeConstMaybe());
MOZ_RELEASE_ASSERT(MakeConstMaybe().isSome());
MOZ_RELEASE_ASSERT(!MakeConstMaybe().isNothing());
MOZ_RELEASE_ASSERT(*MakeConstMaybe() == BasicValue());
static_assert(std::is_same_v<const BasicValue&&, decltype(*MakeConstMaybe())>, "operator*() should return a const BasicValue&&");
MOZ_RELEASE_ASSERT(MakeConstMaybe().value() == BasicValue());
static_assert(std::is_same_v<BasicValue, decltype(MakeConstMaybe().value())>, "value() should return a BasicValue");
MOZ_RELEASE_ASSERT(MakeConstMaybe().ref() == BasicValue());
static_assert(
std::is_same_v<const BasicValue&&, decltype(MakeConstMaybe().ref())>, "ref() should return a const BasicValue&&");
MOZ_RELEASE_ASSERT(MakeConstMaybe().ptr() != nullptr);
static_assert(
std::is_same_v<const BasicValue*, decltype(MakeConstMaybe().ptr())>, "ptr() should return a const BasicValue*");
MOZ_RELEASE_ASSERT(MakeConstMaybe()->GetStatus() == eWasMoveConstructed);
MOZ_RELEASE_ASSERT(BasicValue(*MakeConstMaybe()).GetStatus() ==
eWasConstMoveConstructed);
// Check that take works
mayValue = Some(BasicValue(6));
Maybe taken = mayValue.take();
MOZ_RELEASE_ASSERT(taken->GetStatus() == eWasMoveConstructed);
MOZ_RELEASE_ASSERT(taken == Some(BasicValue(6)));
MOZ_RELEASE_ASSERT(!mayValue.isSome());
MOZ_RELEASE_ASSERT(mayValue.take() == Nothing());
// Check that extract works
mayValue = Some(BasicValue(7));
BasicValue extracted = mayValue.extract();
MOZ_RELEASE_ASSERT(extracted.GetStatus() == eWasMoveConstructed);
MOZ_RELEASE_ASSERT(extracted == BasicValue(7));
MOZ_RELEASE_ASSERT(!mayValue.isSome());
{ // 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 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.reset();
mayUnmovableValue.emplace(UnmovableValue());
MOZ_RELEASE_ASSERT(mayUnmovableValue->GetStatus() == eWasCopyConstructed);
}
staticbool TestFunctionalAccessors() {
BasicValue value(9);
sStaticBasicValue = new BasicValue(9);
// Check that the 'some' case of functional accessors works.
Maybe<BasicValue> someValue = Some(BasicValue(3));
MOZ_RELEASE_ASSERT(someValue.valueOr(value) == BasicValue(3));
static_assert(std::is_same_v<BasicValue, decltype(someValue.valueOr(value))>, "valueOr should return a BasicValue");
MOZ_RELEASE_ASSERT(someValue.valueOrFrom(&MakeBasicValue) == BasicValue(3));
static_assert(
std::is_same_v<BasicValue,
decltype(someValue.valueOrFrom(&MakeBasicValue))>, "valueOrFrom should return a BasicValue");
MOZ_RELEASE_ASSERT(someValue.ptrOr(&value) != &value);
static_assert(std::is_same_v<BasicValue*, decltype(someValue.ptrOr(&value))>, "ptrOr should return a BasicValue*");
MOZ_RELEASE_ASSERT(*someValue.ptrOrFrom(&MakeBasicValuePtr) == BasicValue(3));
static_assert(
std::is_same_v<BasicValue*,
decltype(someValue.ptrOrFrom(&MakeBasicValuePtr))>, "ptrOrFrom should return a BasicValue*");
MOZ_RELEASE_ASSERT(someValue.refOr(value) == BasicValue(3));
static_assert(std::is_same_v<BasicValue&, decltype(someValue.refOr(value))>, "refOr should return a BasicValue&");
MOZ_RELEASE_ASSERT(someValue.refOrFrom(&MakeBasicValueRef) == BasicValue(3));
static_assert(
std::is_same_v<BasicValue&,
decltype(someValue.refOrFrom(&MakeBasicValueRef))>, "refOrFrom should return a BasicValue&");
// Check that the 'some' case works through a const reference. const Maybe<BasicValue>& someValueCRef = someValue;
MOZ_RELEASE_ASSERT(someValueCRef.valueOr(value) == BasicValue(3));
static_assert(
std::is_same_v<BasicValue, decltype(someValueCRef.valueOr(value))>, "valueOr should return a BasicValue");
MOZ_RELEASE_ASSERT(someValueCRef.valueOrFrom(&MakeBasicValue) ==
BasicValue(3));
static_assert(
std::is_same_v<BasicValue,
decltype(someValueCRef.valueOrFrom(&MakeBasicValue))>, "valueOrFrom should return a BasicValue");
MOZ_RELEASE_ASSERT(someValueCRef.ptrOr(&value) != &value);
static_assert(
std::is_same_v<const BasicValue*, decltype(someValueCRef.ptrOr(&value))>, "ptrOr should return a const BasicValue*");
MOZ_RELEASE_ASSERT(*someValueCRef.ptrOrFrom(&MakeBasicValuePtr) ==
BasicValue(3));
static_assert(
std::is_same_v<const BasicValue*,
decltype(someValueCRef.ptrOrFrom(&MakeBasicValuePtr))>, "ptrOrFrom should return a const BasicValue*");
MOZ_RELEASE_ASSERT(someValueCRef.refOr(value) == BasicValue(3));
static_assert(
std::is_same_v<const BasicValue&, decltype(someValueCRef.refOr(value))>, "refOr should return a const BasicValue&");
MOZ_RELEASE_ASSERT(someValueCRef.refOrFrom(&MakeBasicValueRef) ==
BasicValue(3));
static_assert(
std::is_same_v<const BasicValue&,
decltype(someValueCRef.refOrFrom(&MakeBasicValueRef))>, "refOrFrom should return a const BasicValue&");
// Check that the 'none' case of functional accessors works.
Maybe<BasicValue> noneValue;
MOZ_RELEASE_ASSERT(noneValue.valueOr(value) == BasicValue(9));
static_assert(std::is_same_v<BasicValue, decltype(noneValue.valueOr(value))>, "valueOr should return a BasicValue");
MOZ_RELEASE_ASSERT(noneValue.valueOrFrom(&MakeBasicValue) == BasicValue(9));
static_assert(
std::is_same_v<BasicValue,
decltype(noneValue.valueOrFrom(&MakeBasicValue))>, "valueOrFrom should return a BasicValue");
MOZ_RELEASE_ASSERT(noneValue.ptrOr(&value) == &value);
static_assert(std::is_same_v<BasicValue*, decltype(noneValue.ptrOr(&value))>, "ptrOr should return a BasicValue*");
MOZ_RELEASE_ASSERT(*noneValue.ptrOrFrom(&MakeBasicValuePtr) == BasicValue(9));
static_assert(
std::is_same_v<BasicValue*,
decltype(noneValue.ptrOrFrom(&MakeBasicValuePtr))>, "ptrOrFrom should return a BasicValue*");
MOZ_RELEASE_ASSERT(noneValue.refOr(value) == BasicValue(9));
static_assert(std::is_same_v<BasicValue&, decltype(noneValue.refOr(value))>, "refOr should return a BasicValue&");
MOZ_RELEASE_ASSERT(noneValue.refOrFrom(&MakeBasicValueRef) == BasicValue(9));
static_assert(
std::is_same_v<BasicValue&,
decltype(noneValue.refOrFrom(&MakeBasicValueRef))>, "refOrFrom should return a BasicValue&");
// Check that the 'none' case works through a const reference. const Maybe<BasicValue>& noneValueCRef = noneValue;
MOZ_RELEASE_ASSERT(noneValueCRef.valueOr(value) == BasicValue(9));
static_assert(
std::is_same_v<BasicValue, decltype(noneValueCRef.valueOr(value))>, "valueOr should return a BasicValue");
MOZ_RELEASE_ASSERT(noneValueCRef.valueOrFrom(&MakeBasicValue) ==
BasicValue(9));
static_assert(
std::is_same_v<BasicValue,
decltype(noneValueCRef.valueOrFrom(&MakeBasicValue))>, "valueOrFrom should return a BasicValue");
MOZ_RELEASE_ASSERT(noneValueCRef.ptrOr(&value) == &value);
static_assert(
std::is_same_v<const BasicValue*, decltype(noneValueCRef.ptrOr(&value))>, "ptrOr should return a const BasicValue*");
MOZ_RELEASE_ASSERT(*noneValueCRef.ptrOrFrom(&MakeBasicValuePtr) ==
BasicValue(9));
static_assert(
std::is_same_v<const BasicValue*,
decltype(noneValueCRef.ptrOrFrom(&MakeBasicValuePtr))>, "ptrOrFrom should return a const BasicValue*");
MOZ_RELEASE_ASSERT(noneValueCRef.refOr(value) == BasicValue(9));
static_assert(
std::is_same_v<const BasicValue&, decltype(noneValueCRef.refOr(value))>, "refOr should return a const BasicValue&");
MOZ_RELEASE_ASSERT(noneValueCRef.refOrFrom(&MakeBasicValueRef) ==
BasicValue(9));
static_assert(
std::is_same_v<const BasicValue&,
decltype(noneValueCRef.refOrFrom(&MakeBasicValueRef))>, "refOrFrom should return a const BasicValue&");
// Clean up so the undestroyed objects count stays accurate. delete sStaticBasicValue;
sStaticBasicValue = nullptr;
// Check that apply works with a const reference. const Maybe<BasicValue>& mayValueCRef = mayValue;
gFunctionWasApplied = false;
mayValueCRef.apply(&AccessValue);
MOZ_RELEASE_ASSERT(gFunctionWasApplied);
// Check that apply works with functors.
IncrementTagFunctor tagIncrementer;
MOZ_RELEASE_ASSERT(tagIncrementer.mBy.GetStatus() == eWasConstructed);
mayValue = Some(BasicValue(1));
mayValue.apply(tagIncrementer);
MOZ_RELEASE_ASSERT(mayValue->GetTag() == 2);
MOZ_RELEASE_ASSERT(tagIncrementer.mBy.GetStatus() == eWasConstructed);
// Check that map works with a const reference.
mayValue->SetTag(2); const Maybe<BasicValue>& mayValueCRef = mayValue;
MOZ_RELEASE_ASSERT(mayValueCRef.map(&TimesTwo) == Some(4));
static_assert(
std::is_same_v<Maybe<int>, decltype(mayValueCRef.map(&TimesTwo))>, "map(TimesTwo) should return a Maybe");
// Check that map works with functors.
MultiplyTagFunctor tagMultiplier;
MOZ_RELEASE_ASSERT(tagMultiplier.mBy.GetStatus() == eWasConstructed);
MOZ_RELEASE_ASSERT(mayValue.map(tagMultiplier) == Some(4));
MOZ_RELEASE_ASSERT(tagMultiplier.mBy.GetStatus() == eWasConstructed);
// Check that a non-null pointer translates into a Some value.
Maybe<BasicValue> mayValue = ToMaybe(&value);
static_assert(std::is_same_v<Maybe<BasicValue>, decltype(ToMaybe(&value))>, "ToMaybe should return a Maybe");
MOZ_RELEASE_ASSERT(mayValue.isSome());
MOZ_RELEASE_ASSERT(mayValue->GetTag() == 1);
MOZ_RELEASE_ASSERT(mayValue->GetStatus() == eWasCopyConstructed);
MOZ_RELEASE_ASSERT(value.GetStatus() != eWasMovedFrom);
// Check that a null pointer translates into a Nothing value.
mayValue = ToMaybe(nullPointer);
static_assert(
std::is_same_v<Maybe<BasicValue>, decltype(ToMaybe(nullPointer))>, "ToMaybe should return a Maybe");
MOZ_RELEASE_ASSERT(mayValue.isNothing());
// Check that Maybe<> can wrap a superclass that happens to also be a concrete // class (i.e. that the compiler doesn't warn when we invoke the superclass's // destructor explicitly in |reset()|. class MySuperClass { virtualvoid VirtualMethod() { /* do nothing */ }
};
class MyDerivedClass : public MySuperClass { void VirtualMethod() override { /* do nothing */ }
};
// Check that andThen works with a const reference. const Maybe<BasicValue>& mayValueCRef = mayValue;
gFunctionWasApplied = false;
otherValue = mayValueCRef.andThen(&AccessValueAndReturnOther);
MOZ_RELEASE_ASSERT(gFunctionWasApplied);
MOZ_RELEASE_ASSERT(*otherValue == 42);
// Check that andThen works with functors.
IncrementAndReturnTagFunctor tagIncrementer;
MOZ_RELEASE_ASSERT(tagIncrementer.mBy.GetStatus() == eWasConstructed);
mayValue = Some(BasicValue(1));
otherValue = mayValue.andThen(tagIncrementer);
MOZ_RELEASE_ASSERT(mayValue->GetTag() == 2);
MOZ_RELEASE_ASSERT(*otherValue == 2);
MOZ_RELEASE_ASSERT(tagIncrementer.mBy.GetStatus() == eWasConstructed);
// Check that andThen and orElse can propagate a non-copyable value created // mid-chain.
Maybe<UncopyableValue> mayValue;
Maybe<UncopyableValue> movedValue = std::move(mayValue)
.andThen(moveAlong)
.orElse(createValue)
.andThen(moveAlong);
MOZ_RELEASE_ASSERT(mayValue.isNothing());
MOZ_RELEASE_ASSERT(movedValue->GetStatus() == eWasMoveConstructed);
// Check that andThen and orElse can propagate a non-copyable value created // pre-chain.
mayValue = Some(UncopyableValue{});
movedValue = std::move(mayValue)
.andThen(moveAlong)
.orElse(justNothing)
.andThen(moveAlong);
MOZ_RELEASE_ASSERT(mayValue.isNothing());
MOZ_RELEASE_ASSERT(movedValue->GetStatus() == eWasMoveAssigned);
// Check that andThen and orElse can propagate a reference.
{
UncopyableValue val{};
UncopyableValue otherVal{}; constauto passAlong = [](UncopyableValue& aValue) { return SomeRef(aValue);
}; constauto fallbackToOther = [&]() { return SomeRef(otherVal); };
Maybe<UncopyableValue&> mayRef = SomeRef(val);
Maybe<UncopyableValue&> chainedRef =
mayRef.andThen(passAlong).orElse(fallbackToOther).andThen(passAlong);
MOZ_RELEASE_ASSERT(&val != &otherVal, "Distinct values should not compare equal");
MOZ_RELEASE_ASSERT(&*mayRef == &*chainedRef, "Chain should pass along the same reference");
}
// Check that andThen and orElse can propagate a const reference.
{ const UncopyableValue val{}; const UncopyableValue otherVal{}; constauto passAlong = [](const UncopyableValue& aValue) { return SomeRef(aValue);
}; constauto fallbackToOther = [&]() { return SomeRef(otherVal); };
Maybe<const UncopyableValue&> mayRef = SomeRef(val);
Maybe<const UncopyableValue&> chainedRef =
mayRef.andThen(passAlong).orElse(fallbackToOther).andThen(passAlong);
MOZ_RELEASE_ASSERT(&val != &otherVal, "Distinct values should not compare equal");
MOZ_RELEASE_ASSERT(&*mayRef == &*chainedRef, "Chain should pass along the same reference");
}
returntrue;
}
// These are quasi-implementation details, but we assert them here to prevent // backsliding to earlier times when Maybe<T> for smaller T took up more space // than T's alignment required.
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.