exception: Add wrapper to ignore lambda failures

Change-Id: I2bd720775b233a29083ac5b572bdec1671f6c634
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/src/stdplus/exception.cpp b/src/stdplus/exception.cpp
index d51bd16..4635e84 100644
--- a/src/stdplus/exception.cpp
+++ b/src/stdplus/exception.cpp
@@ -1,5 +1,19 @@
 #include <stdplus/exception.hpp>
 
+// These will only be used if the compiler doesn't support them
+int __builtin_LINE()
+{
+    return -1;
+}
+const char* __builtin_FILE()
+{
+    return "<unknown>";
+}
+const char* __builtin_FUNCTION()
+{
+    return "<unknown>";
+}
+
 namespace stdplus
 {
 namespace exception
diff --git a/src/stdplus/exception.hpp b/src/stdplus/exception.hpp
index efeb4c3..7b300f6 100644
--- a/src/stdplus/exception.hpp
+++ b/src/stdplus/exception.hpp
@@ -1,5 +1,12 @@
 #pragma once
+#include <fmt/format.h>
 #include <system_error>
+#include <utility>
+
+// Forward declare builtins in case they are unsupported
+int __builtin_LINE();
+const char* __builtin_FILE();
+const char* __builtin_FUNCTION();
 
 namespace stdplus
 {
@@ -18,5 +25,32 @@
     Eof(const std::string& what);
 };
 
+auto ignore(auto&& f, const char* file = __builtin_FILE(),
+            int line = __builtin_LINE(),
+            const char* func = __builtin_FUNCTION())
+{
+    return [f = std::move(f), file, line, func](auto&&... args) mutable {
+        try
+        {
+            return f(std::forward<decltype(args)>(args)...);
+        }
+        catch (const std::exception& e)
+        {
+            fmt::print(stderr, "Ignoring({}:{} {}): {}\n", file, line, func,
+                       e.what());
+        }
+        catch (...)
+        {
+            fmt::print(stderr, "Ignoring({}:{} {}): Invalid Error\n", file,
+                       line, func);
+        }
+        using Ret = std::invoke_result_t<decltype(f), decltype(args)...>;
+        if constexpr (!std::is_same_v<void, Ret>)
+        {
+            return Ret();
+        }
+    };
+}
+
 } // namespace exception
 } // namespace stdplus
diff --git a/test/exception.cpp b/test/exception.cpp
new file mode 100644
index 0000000..6b4a26f
--- /dev/null
+++ b/test/exception.cpp
@@ -0,0 +1,23 @@
+#include <gtest/gtest.h>
+#include <stdplus/exception.hpp>
+
+namespace stdplus
+{
+namespace exception
+{
+
+TEST(Exception, IgnoreNoError)
+{
+    ignore([] {})();
+    ignore([]() mutable { throw std::runtime_error("Boom"); })();
+    EXPECT_EQ(int(), ignore([]() -> int { throw 1; })());
+    auto x = std::make_unique<int>(1);
+    auto y = std::make_unique<int>(2);
+    auto z = std::make_unique<int>(3);
+    EXPECT_EQ(3, ignore([x = std::move(x)](auto&& v) { return *v + *x; })(y));
+    EXPECT_EQ(5, ignore([z = std::move(z)](auto v) { return *v + *z; })(
+                     std::move(y)));
+}
+
+} // namespace exception
+} // namespace stdplus
diff --git a/test/meson.build b/test/meson.build
index df694b6..cd89f27 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -21,6 +21,7 @@
 endif
 
 gtests = [
+  'exception',
   'handle/copyable',
   'handle/managed',
   'util/cexec',