From c3c1e322ada6c8d8633e8d2e577a43d3749f5bdd Mon Sep 17 00:00:00 2001 From: Jon Bauman Date: Fri, 22 May 2020 19:46:07 +0000 Subject: [PATCH] Bug 1639637 - Add Maybe method to move out contents leaving Nothing() behind. r=froydnj Add take() and extract() methods returning Maybe and T respectively. Differential Revision: https://phabricator.services.mozilla.com/D76526 --- mfbt/Maybe.h | 20 +++++++++++++++++++- mfbt/tests/TestMaybe.cpp | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/mfbt/Maybe.h b/mfbt/Maybe.h index c10109c6a577..4d26f7af9111 100644 --- a/mfbt/Maybe.h +++ b/mfbt/Maybe.h @@ -1,4 +1,4 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* -*- 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 @@ -460,6 +460,24 @@ class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS Maybe */ constexpr T value() const; + /** + * Move the contents of this Maybe out of internal storage and return it + * without calling the destructor. The internal storage is also reset to + * avoid multiple calls. Unsafe unless |isSome()|. + */ + T extract() { + MOZ_DIAGNOSTIC_ASSERT(isSome()); + auto v = std::move(mStorage.val); + reset(); + return v; + } + + /** + * Returns the value (possibly |Nothing()|) by moving it out of this Maybe + * and leaving |Nothing()| in its place. + */ + Maybe take() { return std::exchange(*this, Nothing()); } + /* * Returns the contents of this Maybe by value. If |isNothing()|, returns * the default value provided. diff --git a/mfbt/tests/TestMaybe.cpp b/mfbt/tests/TestMaybe.cpp index 0de89d1deb95..42929b1be69c 100644 --- a/mfbt/tests/TestMaybe.cpp +++ b/mfbt/tests/TestMaybe.cpp @@ -302,6 +302,21 @@ static bool TestBasicFeatures() { MOZ_RELEASE_ASSERT(mayCValue2.isSome()); MOZ_RELEASE_ASSERT(*mayCValue2 == BasicValue(6)); + // 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()); + return true; } @@ -351,6 +366,26 @@ static void TestMoveMaybe() { MOZ_RELEASE_ASSERT(1 == sUndestroyedObjects); MOZ_RELEASE_ASSERT(dstMoveAssigned->GetStatus() == eWasMoveConstructed); } + + { + MOZ_RELEASE_ASSERT(0 == sUndestroyedObjects); + + Maybe src = Some(T()); + Maybe dstMoveConstructed = src.take(); + + MOZ_RELEASE_ASSERT(1 == sUndestroyedObjects); + MOZ_RELEASE_ASSERT(dstMoveConstructed->GetStatus() == eWasMoveConstructed); + } + + { + MOZ_RELEASE_ASSERT(0 == sUndestroyedObjects); + + Maybe src = Some(T()); + T dstMoveConstructed = src.extract(); + + MOZ_RELEASE_ASSERT(1 == sUndestroyedObjects); + MOZ_RELEASE_ASSERT(dstMoveConstructed.GetStatus() == eWasMoveConstructed); + } } static bool TestCopyAndMove() {