Yarn: Add make_finally(), make_shared_finally() and defer()

These are RAII-based helpers for ensuring that logic is executed, regardless of the control flow path taken.

Bug: b/139010488
Change-Id: I7bea0e550aaccf7504221a661ed2cd04e46018f9
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/34769
Tested-by: Ben Clayton <bclayton@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
diff --git a/src/Yarn/Defer.hpp b/src/Yarn/Defer.hpp
new file mode 100644
index 0000000..565dfa1
--- /dev/null
+++ b/src/Yarn/Defer.hpp
@@ -0,0 +1,44 @@
+// Copyright 2019 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef yarn_defer_hpp
+#define yarn_defer_hpp
+
+#include "Finally.hpp"
+
+namespace yarn {
+
+#define YARN_CONCAT_(a, b) a ## b
+#define YARN_CONCAT(a, b) YARN_CONCAT_(a,b)
+
+// defer() is a macro to defer execution of a statement until the surrounding
+// scope is closed and is typically used to perform cleanup logic once a
+// function returns.
+//
+// Note: Unlike golang's defer(), the defer statement is executed when the
+// surrounding *scope* is closed, not necessarily the function.
+//
+// Example usage:
+//
+//  void sayHelloWorld()
+//  {
+//      defer(printf("world\n"));
+//      printf("hello ");
+//  }
+//
+#define defer(x) auto YARN_CONCAT(defer_, __LINE__) = yarn::make_finally([&]{ x; })
+
+} // namespace yarn
+
+#endif  // yarn_defer_hpp
diff --git a/src/Yarn/Defer_test.cpp b/src/Yarn/Defer_test.cpp
new file mode 100644
index 0000000..479022f
--- /dev/null
+++ b/src/Yarn/Defer_test.cpp
@@ -0,0 +1,40 @@
+// Copyright 2019 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "Defer.hpp"
+
+#include "Yarn_test.hpp"
+
+TEST(WithoutBoundScheduler, Defer)
+{
+    bool deferCalled = false;
+    {
+        defer(deferCalled = true);
+    }
+    ASSERT_TRUE(deferCalled);
+}
+
+TEST(WithoutBoundScheduler, DeferOrder)
+{
+    int counter = 0;
+    int a = 0, b = 0, c = 0;
+    {
+        defer(a = ++counter);
+        defer(b = ++counter);
+        defer(c = ++counter);
+    }
+    ASSERT_EQ(a, 3);
+    ASSERT_EQ(b, 2);
+    ASSERT_EQ(c, 1);
+}
\ No newline at end of file
diff --git a/src/Yarn/Finally.hpp b/src/Yarn/Finally.hpp
new file mode 100644
index 0000000..702c87b
--- /dev/null
+++ b/src/Yarn/Finally.hpp
@@ -0,0 +1,89 @@
+// Copyright 2019 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Finally can be used to execute a lambda or function when the final reference
+// to the Finally is dropped.
+//
+// The purpose of a finally is to perform cleanup or termination logic and is
+// especially useful when there are multiple early returns within a function.
+//
+// A moveable Finally can be constructed with yarn::make_finally().
+// A sharable Finally can be constructed with yarn::make_shared_finally().
+
+#ifndef yarn_finally_hpp
+#define yarn_finally_hpp
+
+#include <functional>
+#include <memory>
+
+namespace yarn {
+
+// Finally is a pure virtual base class, implemented by the templated
+// FinallyImpl.
+class Finally
+{
+public:
+    virtual ~Finally() = default;
+};
+
+// FinallyImpl implements a Finally.
+// The template parameter F is the function type to be called when the finally
+// is destructed. F must have the signature void().
+template <typename F>
+class FinallyImpl : public Finally
+{
+public:
+    inline FinallyImpl(const F& func);
+    inline FinallyImpl(F&& func);
+    inline FinallyImpl(FinallyImpl<F>&& other);
+    inline ~FinallyImpl();
+
+private:
+    FinallyImpl(const FinallyImpl<F>& other) = delete;
+    FinallyImpl<F>& operator = (const FinallyImpl<F>& other) = delete;
+    FinallyImpl<F>& operator = (FinallyImpl<F>&&) = delete;
+    F func;
+    bool valid = true;
+};
+
+template<typename F>
+FinallyImpl<F>::FinallyImpl(const F& func) : func(func) {}
+
+template<typename F>
+FinallyImpl<F>::FinallyImpl(F&& func) : func(std::move(func)) {}
+
+template<typename F>
+FinallyImpl<F>::FinallyImpl(FinallyImpl<F>&& other) : func(std::move(other.func))
+{
+    other.valid = false;
+}
+
+template<typename F>
+FinallyImpl<F>::~FinallyImpl()
+{
+    if (valid)
+    {
+        func();
+    }
+}
+
+template<typename F>
+inline FinallyImpl<F> make_finally(F&& f) { return FinallyImpl<F>(std::move(f)); }
+
+template<typename F>
+inline std::shared_ptr<Finally> make_shared_finally(F&& f) { return std::make_shared<FinallyImpl<F>>(std::move(f)); }
+
+} // namespace yarn
+
+#endif  // yarn_finally_hpp