diff --git a/Config/BaseDefines.hh b/Config/BaseDefines.hh index 1614f47860fb63362de33455bfbac3509943c8ba..e287137a959d67b6152758f3a5f43b630aee9a36 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 d8193ad60558a13c1d39d2b5e37b4fed81d6d92e..7fc0247c9187e6d99a32f71b1a72facccdd07fbe 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 0000000000000000000000000000000000000000..25c59b5b1b17c1fcdb2008a1e64c5d5f0f08699e --- /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 +//============================================================================= +