handle: Support for releasing management of values

Sometimes we want to be able to break the value out of the container and
unmanage it.

Change-Id: I1ded8571561760f7adf8bbf9a24cf21c989e4898
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/src/stdplus/handle/managed.hpp b/src/stdplus/handle/managed.hpp
index 9b9bfb5..de6a9f1 100644
--- a/src/stdplus/handle/managed.hpp
+++ b/src/stdplus/handle/managed.hpp
@@ -161,6 +161,31 @@
             reset(std::nullopt);
         }
 
+        /** @brief Releases the managed value and transfers ownership
+         *         to the caller.
+         *
+         *  @throws std::bad_optional_access if it has no object
+         *  @return The value that was managed
+         */
+        [[nodiscard]] constexpr T release()
+        {
+            T ret = std::move(maybeT.value());
+            maybeT = std::nullopt;
+            return ret;
+        }
+
+        /** @brief Releases the managed value and transfers ownership
+         *         to the caller.
+         *
+         *  @return Maybe the value that was managed
+         */
+        [[nodiscard]] constexpr std::optional<T> maybe_release() noexcept
+        {
+            std::optional<T> ret = std::move(maybeT);
+            maybeT = std::nullopt;
+            return ret;
+        }
+
         /** @brief Reference the contained data
          *
          *  @return A reference to the contained data
diff --git a/test/handle/managed.cpp b/test/handle/managed.cpp
index b3ba6a6..155ba59 100644
--- a/test/handle/managed.cpp
+++ b/test/handle/managed.cpp
@@ -48,10 +48,13 @@
     SimpleHandle h(std::nullopt);
     EXPECT_FALSE(h);
     EXPECT_THROW(h.value(), std::bad_optional_access);
+    EXPECT_THROW((void)h.release(), std::bad_optional_access);
     h.reset();
     EXPECT_FALSE(h.has_value());
     EXPECT_THROW(h.value(), std::bad_optional_access);
+    EXPECT_THROW((void)h.release(), std::bad_optional_access);
     EXPECT_EQ(std::nullopt, h.maybe_value());
+    EXPECT_EQ(std::nullopt, h.maybe_release());
 }
 
 TEST_F(ManagedHandleTest, EmptyWithStorage)
@@ -164,6 +167,24 @@
     dropped.clear();
 }
 
+TEST_F(ManagedHandleTest, Release)
+{
+    constexpr int expected = 3;
+    int val = expected;
+    SimpleHandle h(std::move(val));
+    EXPECT_EQ(expected, h.release());
+    EXPECT_FALSE(h);
+}
+
+TEST_F(ManagedHandleTest, MaybeRelease)
+{
+    constexpr int expected = 3;
+    int val = expected;
+    SimpleHandle h(std::move(val));
+    EXPECT_EQ(expected, h.maybe_release());
+    EXPECT_FALSE(h);
+}
+
 TEST_F(ManagedHandleTest, MoveConstructWithStorage)
 {
     constexpr int expected = 3;