Bug 1639637 - Add Maybe method to move out contents leaving Nothing() behind. r=froydnj
authorJon Bauman <jbauman@mozilla.com>
Fri, 22 May 2020 19:46:07 +0000
changeset 531756 c74722b0c0d5cde29b435e228a290eea157377a1
parent 531755 bbcc193fe0f0389a417ab4e047dc62b4837bf6b1
child 531757 281d0e9102251f66f7d7635b389ff65e4bf6ea54
push id37443
push usercbrindusan@mozilla.com
push dateSat, 23 May 2020 21:42:57 +0000
treeherdermozilla-central@9a2f741cef6a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfroydnj
bugs1639637
milestone78.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1639637 - Add Maybe method to move out contents leaving Nothing() behind. r=froydnj Add take() and extract() methods returning Maybe<T> and T respectively. Differential Revision: https://phabricator.services.mozilla.com/D76526
mfbt/Maybe.h
mfbt/tests/TestMaybe.cpp
--- a/mfbt/Maybe.h
+++ b/mfbt/Maybe.h
@@ -1,9 +1,9 @@
-/* -*- 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
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* A class for optional values and in-place lazy construction. */
 
 #ifndef mozilla_Maybe_h
@@ -455,16 +455,34 @@ class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_
   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()|.
    */
   constexpr T value() const;
 
+  /**
+   * Move the contents of this Maybe<T> 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<T>
+   * and leaving |Nothing()| in its place.
+   */
+  Maybe<T> take() { return std::exchange(*this, Nothing()); }
+
   /*
    * Returns the contents of this Maybe<T> by value. If |isNothing()|, returns
    * the default value provided.
    */
   template <typename V>
   constexpr T valueOr(V&& aDefault) const {
     if (isSome()) {
       return ref();
--- a/mfbt/tests/TestMaybe.cpp
+++ b/mfbt/tests/TestMaybe.cpp
@@ -297,16 +297,31 @@ static bool TestBasicFeatures() {
   MOZ_RELEASE_ASSERT(mayCValue1Ref == mayCValue1);
   MOZ_RELEASE_ASSERT(*mayCValue1Ref == BasicValue(5));
   Maybe<const BasicValue> mayCValue2;
   mayCValue2.emplace(6);
   MOZ_RELEASE_ASSERT(mayCValue2);
   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;
 }
 
 template <typename T>
 static void TestCopyMaybe() {
   {
     MOZ_RELEASE_ASSERT(0 == sUndestroyedObjects);
 
@@ -346,16 +361,36 @@ static void TestMoveMaybe() {
 
     Maybe<T> src = Some(T());
     Maybe<T> dstMoveAssigned;
     dstMoveAssigned = std::move(src);
 
     MOZ_RELEASE_ASSERT(1 == sUndestroyedObjects);
     MOZ_RELEASE_ASSERT(dstMoveAssigned->GetStatus() == eWasMoveConstructed);
   }
+
+  {
+    MOZ_RELEASE_ASSERT(0 == sUndestroyedObjects);
+
+    Maybe<T> src = Some(T());
+    Maybe<T> dstMoveConstructed = src.take();
+
+    MOZ_RELEASE_ASSERT(1 == sUndestroyedObjects);
+    MOZ_RELEASE_ASSERT(dstMoveConstructed->GetStatus() == eWasMoveConstructed);
+  }
+
+  {
+    MOZ_RELEASE_ASSERT(0 == sUndestroyedObjects);
+
+    Maybe<T> src = Some(T());
+    T dstMoveConstructed = src.extract();
+
+    MOZ_RELEASE_ASSERT(1 == sUndestroyedObjects);
+    MOZ_RELEASE_ASSERT(dstMoveConstructed.GetStatus() == eWasMoveConstructed);
+  }
 }
 
 static bool TestCopyAndMove() {
   MOZ_RELEASE_ASSERT(0 == sUndestroyedObjects);
 
   {
     // Check that we get moves when possible for types that can support both
     // moves and copies.