Bug 1645328 - Add in-place constructor to Maybe. r=froydnj

Differential Revision: https://phabricator.services.mozilla.com/D79448
This commit is contained in:
Simon Giesecke 2020-06-15 09:04:02 +00:00
parent ba5f1e21d3
commit 1a13e8aef8
3 changed files with 39 additions and 4 deletions

View File

@ -265,6 +265,11 @@ struct MaybeStorage<T, false> {
explicit MaybeStorage(const T& aVal) : mStorage{aVal}, mIsSome{true} {}
explicit MaybeStorage(T&& aVal) : mStorage{std::move(aVal)}, mIsSome{true} {}
template <typename... Args>
explicit MaybeStorage(std::in_place_t, Args&&... aArgs) : mIsSome{true} {
::new (KnownNotNull, &mStorage.val) T(std::forward<Args>(aArgs)...);
}
// Copy and move operations are no-ops, since copying is moving is implemented
// by Maybe_CopyMove_Enabler.
@ -288,6 +293,9 @@ struct MaybeStorage<T, true> {
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;
char dummy;
@ -299,6 +307,10 @@ struct MaybeStorage<T, true> {
: mStorage{aVal}, mIsSome{true} {}
constexpr explicit MaybeStorage(T&& aVal)
: mStorage{std::move(aVal)}, mIsSome{true} {}
template <typename... Args>
constexpr explicit MaybeStorage(std::in_place_t, Args&&... aArgs)
: mStorage{std::in_place, std::forward<Args>(aArgs)...}, mIsSome{true} {}
};
} // namespace detail
@ -350,9 +362,6 @@ constexpr Maybe<U> Some(T&& aValue);
* Boost. The most important differences between Maybe and std::optional are:
*
* - std::optional<T> may be compared with T. We deliberately forbid that.
* - std::optional allows in-place construction without a separate call to
* |emplace()| by using a dummy |in_place_t| value to tag the appropriate
* constructor.
* - std::optional has |valueOr()|, equivalent to Maybe's |valueOr()|, but
* lacks corresponding methods for |refOr()| and |ptrOr()|.
* - std::optional lacks |map()| and |apply()|, making it less suitable for
@ -389,6 +398,10 @@ class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS Maybe
MOZ_ALLOW_TEMPORARY MOZ_IMPLICIT constexpr Maybe(Nothing) : Maybe{} {}
template <typename... Args>
constexpr explicit Maybe(std::in_place_t, Args&&... aArgs)
: detail::MaybeStorage<T>{std::in_place, std::forward<Args>(aArgs)...} {}
/**
* Maybe<T> can be copy-constructed from a Maybe<U> if T is constructible from
* a const U&.

View File

@ -156,7 +156,7 @@ struct UncopyableUnmovableValue {
~UncopyableUnmovableValue() { --sUndestroyedObjects; }
Status GetStatus() { return mStatus; }
Status GetStatus() const { return mStatus; }
private:
UncopyableUnmovableValue(const UncopyableUnmovableValue& aOther) = delete;
@ -184,6 +184,10 @@ static_assert(Some(43) == [] {
return val;
}());
static_assert(Some(43) == Some(42).map([](int val) { return val + 1; }));
static_assert(Maybe<int>(std::in_place, 43) ==
Maybe<int>(std::in_place, 42).map([](int val) {
return val + 1;
}));
struct TriviallyDestructible {
TriviallyDestructible() { // not trivially constructible
@ -261,6 +265,14 @@ static bool TestBasicFeatures() {
mayValue.reset();
MOZ_RELEASE_ASSERT(!mayValue);
{
// Check that Maybe(std::in_place, T1) calls the correct constructor.
const auto mayValueConstructed = Maybe<BasicValue>(std::in_place, 1);
MOZ_RELEASE_ASSERT(mayValueConstructed);
MOZ_RELEASE_ASSERT(mayValueConstructed->GetStatus() == eWasConstructed);
MOZ_RELEASE_ASSERT(mayValueConstructed->GetTag() == 1);
}
// Check that Some() and Nothing() work.
mayValue = Some(BasicValue(2));
MOZ_RELEASE_ASSERT(mayValue);
@ -497,6 +509,13 @@ static bool TestCopyAndMove() {
MOZ_RELEASE_ASSERT(0 == sUndestroyedObjects);
{ // Check that types that support neither moves or copies work.
{
const auto mayUncopyableUnmovableValueConstructed =
Maybe<UncopyableUnmovableValue>{std::in_place};
MOZ_RELEASE_ASSERT(mayUncopyableUnmovableValueConstructed->GetStatus() ==
eWasDefaultConstructed);
}
Maybe<UncopyableUnmovableValue> mayUncopyableUnmovableValue;
mayUncopyableUnmovableValue.emplace();
MOZ_RELEASE_ASSERT(mayUncopyableUnmovableValue->GetStatus() ==

View File

@ -101,3 +101,6 @@ USE_LIBS += [
if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
CXXFLAGS += ['-Wno-error=shadow']
CXXFLAGS += ['-O0']