]> git.ipfire.org Git - thirdparty/ccache.git/commitdiff
enhance: Add util::throw_on_error functions
authorJoel Rosdahl <joel@rosdahl.net>
Thu, 8 Sep 2022 11:53:58 +0000 (13:53 +0200)
committerJoel Rosdahl <joel@rosdahl.net>
Wed, 21 Sep 2022 15:06:28 +0000 (17:06 +0200)
src/util/expected.hpp
unittest/test_util_expected.cpp

index e0320da8b1044232bb8a3bf3b8e49018c3c55eb7..03bebd5a4051710d65b73f0ebd29ec93be5c8f50 100644 (file)
@@ -34,12 +34,20 @@ typename T::value_type value_or_throw(const T& value);
 template<typename E, typename T>
 typename T::value_type value_or_throw(T&& value);
 
-// As above for with `prefix` added to the error message.
+// Like above for with `prefix` added to the error message.
 template<typename E, typename T>
 typename T::value_type value_or_throw(const T& value, std::string_view prefix);
 template<typename E, typename T>
 typename T::value_type value_or_throw(T&& value, std::string_view prefix);
 
+// Throw an exception of type `E` with a `T::error_type` as the argument if
+// `value` is false.
+template<typename E, typename T> void throw_on_error(const T& value);
+
+// Like above for with `prefix` added to the error message.
+template<typename E, typename T>
+void throw_on_error(const T& value, std::string_view prefix);
+
 #define TRY(x_)                                                                \
   do {                                                                         \
     const auto result = x_;                                                    \
@@ -94,4 +102,23 @@ value_or_throw(T&& value, std::string_view prefix)
   }
 }
 
+template<typename E, typename T>
+inline void
+throw_on_error(const T& value)
+{
+  if (!value) {
+    throw E(value.error());
+  }
+}
+
+// Like above for with `prefix` added to the error message.
+template<typename E, typename T>
+inline void
+throw_on_error(const T& value, std::string_view prefix)
+{
+  if (!value) {
+    throw E(FMT("{}{}", prefix, value.error()));
+  }
+}
+
 } // namespace util
index 723f92efdaafee708831e3e1f28f78bd94d45409..585b1ab6a87223044738dfdd2fadfd0947110a05 100644 (file)
@@ -33,16 +33,17 @@ class TestException : public std::runtime_error
 
 TEST_CASE("util::value_or_throw")
 {
+  using util::throw_on_error;
   using util::value_or_throw;
 
   SUBCASE("const ref")
   {
     const nonstd::expected<int, const char*> with_value = 42;
-    const nonstd::expected<int, const char*> without_value =
+    const nonstd::expected<int, const char*> with_error =
       nonstd::make_unexpected("no value");
 
     CHECK(value_or_throw<TestException>(with_value) == 42);
-    CHECK_THROWS_WITH(value_or_throw<TestException>(without_value), "no value");
+    CHECK_THROWS_WITH(value_or_throw<TestException>(with_error), "no value");
   }
 
   SUBCASE("move")
@@ -50,22 +51,22 @@ TEST_CASE("util::value_or_throw")
     const std::string value = "value";
     nonstd::expected<std::unique_ptr<std::string>, const char*> with_value =
       std::make_unique<std::string>(value);
-    const nonstd::expected<int, const char*> without_value =
+    const nonstd::expected<int, const char*> with_error =
       nonstd::make_unexpected("no value");
 
     CHECK(*value_or_throw<TestException>(std::move(with_value)) == value);
-    CHECK_THROWS_WITH(value_or_throw<TestException>(std::move(without_value)),
+    CHECK_THROWS_WITH(value_or_throw<TestException>(std::move(with_error)),
                       "no value");
   }
 
   SUBCASE("const ref with prefix")
   {
     const nonstd::expected<int, const char*> with_value = 42;
-    const nonstd::expected<int, const char*> without_value =
+    const nonstd::expected<int, const char*> with_error =
       nonstd::make_unexpected("no value");
 
     CHECK(value_or_throw<TestException>(with_value, "prefix: ") == 42);
-    CHECK_THROWS_WITH(value_or_throw<TestException>(without_value, "prefix: "),
+    CHECK_THROWS_WITH(value_or_throw<TestException>(with_error, "prefix: "),
                       "prefix: no value");
   }
 
@@ -74,13 +75,34 @@ TEST_CASE("util::value_or_throw")
     const std::string value = "value";
     nonstd::expected<std::unique_ptr<std::string>, const char*> with_value =
       std::make_unique<std::string>(value);
-    const nonstd::expected<int, const char*> without_value =
+    const nonstd::expected<int, const char*> with_error =
       nonstd::make_unexpected("no value");
 
     CHECK(*value_or_throw<TestException>(std::move(with_value), "prefix: ")
           == value);
     CHECK_THROWS_WITH(
-      value_or_throw<TestException>(std::move(without_value), "prefix: "),
+      value_or_throw<TestException>(std::move(with_error), "prefix: "),
       "prefix: no value");
   }
+
+  SUBCASE("void T::value_type")
+  {
+    const nonstd::expected<void, const char*> without_error;
+    const nonstd::expected<void, const char*> with_error =
+      nonstd::make_unexpected("no value");
+
+    CHECK_NOTHROW(throw_on_error<TestException>(without_error));
+    CHECK_THROWS_WITH(throw_on_error<TestException>(with_error), "no value");
+  }
+
+  SUBCASE("void T::value_type with prefix")
+  {
+    const nonstd::expected<void, const char*> without_error;
+    const nonstd::expected<void, const char*> with_error =
+      nonstd::make_unexpected("no value");
+
+    CHECK_NOTHROW(throw_on_error<TestException>(without_error, "prefix: "));
+    CHECK_THROWS_WITH(throw_on_error<TestException>(with_error, "prefix: "),
+                      "prefix: no value");
+  }
 }