From 96a67978123d846b1a828aa4ea33019651014c9b Mon Sep 17 00:00:00 2001
From: Max Lyon <max.lyon@autodesk.com>
Date: Thu, 24 Mar 2022 10:31:27 +0100
Subject: [PATCH] REFORM-955 add scope utils (#78)

* Add BASE_CONCAT and BASE_UNIQUE_NAME to BaseDefines.hh

* add Scope.hh utils containing helpers to perform actions at the end of a scope, such as calling a function or restoring a variables original value
---
 Config/BaseDefines.hh |  9 ++++++
 Utils/CMakeLists.txt  |  1 +
 Utils/Scope.hh        | 66 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 76 insertions(+)
 create mode 100644 Utils/Scope.hh

diff --git a/Config/BaseDefines.hh b/Config/BaseDefines.hh
index 1614f47..e287137 100644
--- a/Config/BaseDefines.hh
+++ b/Config/BaseDefines.hh
@@ -49,3 +49,12 @@
 #define sprintf_s snprintf
 #endif
 
+// Concatenate with one level of indirection to resolve __LINE__
+#define BASE_CONCAT_IMPL(a, b) a##b
+#define BASE_CONCAT(a, b) BASE_CONCAT_IMPL(a, b)
+
+// Create a unique variable name by combining the given name with the current
+// line. Note that this deliberately uses __LINE__ instead of __COUNTER__
+// because this allows referring to the same name multiple times within the same
+// line/macro.
+#define BASE_UNIQUE_NAME(name) BASE_CONCAT(name, __LINE__)
diff --git a/Utils/CMakeLists.txt b/Utils/CMakeLists.txt
index d8193ad..7fc0247 100644
--- a/Utils/CMakeLists.txt
+++ b/Utils/CMakeLists.txt
@@ -8,6 +8,7 @@ set(my_headers
    ${CMAKE_CURRENT_SOURCE_DIR}/OptionT.hh
    ${CMAKE_CURRENT_SOURCE_DIR}/OStringStream.hh
    ${CMAKE_CURRENT_SOURCE_DIR}/RedirectStream.hh
+   ${CMAKE_CURRENT_SOURCE_DIR}/Scope.hh
    ${CMAKE_CURRENT_SOURCE_DIR}/StopWatch.hh
    ${CMAKE_CURRENT_SOURCE_DIR}/Thread.hh
    ${CMAKE_CURRENT_SOURCE_DIR}/ThrowError.hh
diff --git a/Utils/Scope.hh b/Utils/Scope.hh
new file mode 100644
index 0000000..25c59b5
--- /dev/null
+++ b/Utils/Scope.hh
@@ -0,0 +1,66 @@
+// (C) Copyright 2022 by Autodesk, Inc.
+
+#ifndef BASE_SCOPE_HH_INCLUDED
+#define BASE_SCOPE_HH_INCLUDED
+
+#include <Base/Config/BaseDefines.hh>
+
+#include <functional>
+#include <type_traits>
+#include <utility>
+
+namespace Scope
+{
+
+// Helper class that executes a function when the objects is destroyed.
+template <typename FuncT>
+class ExitT
+{
+public:
+  explicit ExitT(const FuncT& _func) : func_(_func) {}
+  explicit ExitT(FuncT&& _func) : func_(std::move(_func)) {}
+  ~ExitT() { func_(); }
+
+private:
+  FuncT func_;
+};
+
+// Helper function to create an ExitT object that deduces the template type.
+// Note we need this because we cannot use decltype on lambdas directly.
+template <typename FuncT>
+auto make_exit(FuncT&& _func)
+{
+  return ExitT<std::remove_reference_t<decltype(_func)>>(
+      std::forward<FuncT>(_func));
+}
+
+// Call FUNC at the end of the current scope.
+#define SCOPE_ON_EXIT(FUNC) \
+  auto BASE_UNIQUE_NAME(on_exit) = Scope::make_exit(FUNC)
+
+
+// Create a backup of VAR and restore it at the end of scope.
+#define SCOPE_VARIABLE_RESTORE(VAR) \
+  SCOPE_ON_EXIT( std::bind([&VAR](const auto& _var) { VAR = _var; }, VAR))
+
+
+// Set NEW_VAL by using SETTER and restore OLD_VAL at the end of the scope.
+#define SCOPE_VARIABLE_CHANGE(SETTER, NEW_VAL, OLD_VAL) \
+  SCOPE_ON_EXIT(std::bind(SETTER, OLD_VAL)); \
+  SETTER(NEW_VAL)
+
+
+// Assign NEW_VAL to VAR and restore VAR to its original value at the end of the
+// scope.
+#define SCOPE_VARIABLE_CHANGE_SIMPLE(VAR, NEW_VAL) \
+  SCOPE_VARIABLE_RESTORE(VAR); \
+  VAR = NEW_VAL
+
+
+
+} // namespace Scope
+
+//=============================================================================
+#endif //BASE_SCOPE_HH_INCLUDED
+//=============================================================================
+
-- 
GitLab