Bug 1324828 - Add the `mozilla::Result::map` method; r=froydnj
authorNick Fitzgerald <fitzgen@gmail.com>
Wed, 21 Dec 2016 13:05:56 -0800
changeset 326969 261f9a8cc0fa4c253964b82597fa92eb578cc711
parent 326968 8303c228d2d9d5c0bb314e1ae1190c2a874f3849
child 326970 ba0c8f91cc85279768f4a7cdbff16879535a2509
push id31116
push userkwierso@gmail.com
push dateFri, 23 Dec 2016 02:37:16 +0000
treeherdermozilla-central@2785aaf276ba [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfroydnj
bugs1324828
milestone53.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 1324828 - Add the `mozilla::Result::map` method; r=froydnj
mfbt/Result.h
mfbt/tests/TestResult.cpp
--- a/mfbt/Result.h
+++ b/mfbt/Result.h
@@ -215,16 +215,47 @@ public:
     return mImpl.unwrap();
   }
 
   /** Get the error value from this Result, which must be an error result. */
   E unwrapErr() const {
     MOZ_ASSERT(isErr());
     return mImpl.unwrapErr();
   }
+
+  /**
+   * Map a function V -> W over this result's success variant. If this result is
+   * an error, do not invoke the function and return a copy of the error.
+   *
+   * Mapping over success values invokes the function to produce a new success
+   * value:
+   *
+   *     // Map Result<int, E> to another Result<int, E>
+   *     Result<int, E> res(5);
+   *     Result<int, E> res2 = res.map([](int x) { return x * x; });
+   *     MOZ_ASSERT(res2.unwrap() == 25);
+   *
+   *     // Map Result<const char*, E> to Result<size_t, E>
+   *     Result<const char*, E> res("hello, map!");
+   *     Result<size_t, E> res2 = res.map(strlen);
+   *     MOZ_ASSERT(res2.unwrap() == 11);
+   *
+   * Mapping over an error does not invoke the function and copies the error:
+   *
+   *     Result<V, int> res(5);
+   *     MOZ_ASSERT(res.isErr());
+   *     Result<W, int> res2 = res.map([](V v) { ... });
+   *     MOZ_ASSERT(res2.isErr());
+   *     MOZ_ASSERT(res2.unwrapErr() == 5);
+   */
+  template<typename F>
+  auto map(F f) const -> Result<decltype(f(*((V*) nullptr))), E> {
+      using RetResult = Result<decltype(f(*((V*) nullptr))), E>;
+      return isOk() ? RetResult(f(unwrap())) : RetResult(unwrapErr());
+  }
 };
 
 /**
  * A type that auto-converts to an error Result. This is like a Result without
  * a success type. It's the best return type for functions that always return
  * an error--functions designed to build and populate error objects. It's also
  * useful in error-handling macros; see MOZ_TRY for an example.
  */
--- a/mfbt/tests/TestResult.cpp
+++ b/mfbt/tests/TestResult.cpp
@@ -1,14 +1,15 @@
 /* -*- Mode: C++; tab-width: 8; 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/. */
 
+#include <string.h>
 #include "mozilla/Result.h"
 
 using mozilla::GenericErrorResult;
 using mozilla::MakeGenericErrorResult;
 using mozilla::Ok;
 using mozilla::Result;
 
 struct Failed
@@ -155,18 +156,58 @@ static void
 ReferenceTest()
 {
   struct MyError { int x = 0; };
   MyError merror;
   Result<int, MyError&> res(merror);
   MOZ_RELEASE_ASSERT(&res.unwrapErr() == &merror);
 }
 
+static void
+MapTest()
+{
+  struct MyError {
+    int x;
+
+    explicit MyError(int y) : x(y) { }
+  };
+
+  // Mapping over success values.
+  Result<int, MyError> res(5);
+  bool invoked = false;
+  auto res2 = res.map([&invoked](int x) {
+    MOZ_RELEASE_ASSERT(x == 5);
+    invoked = true;
+    return "hello";
+  });
+  MOZ_RELEASE_ASSERT(res2.isOk());
+  MOZ_RELEASE_ASSERT(invoked);
+  MOZ_RELEASE_ASSERT(strcmp(res2.unwrap(), "hello") == 0);
+
+  // Mapping over error values.
+  MyError err(1);
+  Result<char, MyError> res3(err);
+  MOZ_RELEASE_ASSERT(res3.isErr());
+  Result<char, MyError> res4 = res3.map([](int x) {
+    MOZ_RELEASE_ASSERT(false);
+    return 'a';
+  });
+  MOZ_RELEASE_ASSERT(res4.isErr());
+  MOZ_RELEASE_ASSERT(res4.unwrapErr().x == err.x);
+
+  // Function pointers instead of lamdbas as the mapping function.
+  Result<const char*, MyError> res5("hello");
+  auto res6 = res5.map(strlen);
+  MOZ_RELEASE_ASSERT(res6.isOk());
+  MOZ_RELEASE_ASSERT(res6.unwrap() == 5);
+}
+
 /* * */
 
 int main()
 {
   BasicTests();
   TypeConversionTests();
   EmptyValueTest();
   ReferenceTest();
+  MapTest();
   return 0;
 }