From 60cca031c9e3e0099d64de173445dc7654e3820e Mon Sep 17 00:00:00 2001 From: Zbigniew Kostrzewa Date: Thu, 18 Jul 2013 13:36:45 +0200 Subject: [PATCH] Add ScopeGuard utility [Issue#] N/A [Bug] N/A [Cause] N/A [Solution] ScopeGuard is utility class that allows to register a piece of code to be executed when control exits a scope in which ScopeGuard object has been created. Implementation based on: * Scope guard pointer from Loki library http://loki-lib.cvs.sourceforge.net/loki-lib/loki/include/loki/ScopeGuard.h?view=markup * Scope guard implementation in folly library https://github.com/facebook/folly/blob/master/folly/ScopeGuard.h * Lecture "Systematic Error Handling in C++" conducted by Andrei Alexandrescu http://channel9.msdn.com/Shows/Going+Deep/C-and-Beyond-2012-Andrei-Alexandrescu-Systematic-Error-Handling-in-C [Verification] 1. Build repository 2. Run command `wrt-commons-tests-core --output=text --regexp='ScopeGuard*'` [Notes] It will be utilized e.g. in wrt-installer for guarding detaching from WRT DB. Change-Id: I13cdd15b9c9c83a927faeee658d88340052ef66d --- modules/core/config.cmake | 1 + modules/core/include/dpl/preprocessor.h | 6 ++ modules/core/include/dpl/scope_guard.h | 109 ++++++++++++++++++++++++++++ tests/core/CMakeLists.txt | 1 + tests/core/test_scope_guard.cpp | 124 ++++++++++++++++++++++++++++++++ 5 files changed, 241 insertions(+) create mode 100644 modules/core/include/dpl/scope_guard.h create mode 100644 tests/core/test_scope_guard.cpp diff --git a/modules/core/config.cmake b/modules/core/config.cmake index b929c35..35bbbf3 100644 --- a/modules/core/config.cmake +++ b/modules/core/config.cmake @@ -110,6 +110,7 @@ SET(DPL_CORE_HEADERS ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/preprocessor.h ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/read_write_mutex.h ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/recursive_mutex.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/scope_guard.h ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/scoped_resource.h ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/scoped_array.h ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/scoped_close.h diff --git a/modules/core/include/dpl/preprocessor.h b/modules/core/include/dpl/preprocessor.h index 0118d76..6fca34c 100644 --- a/modules/core/include/dpl/preprocessor.h +++ b/modules/core/include/dpl/preprocessor.h @@ -26,4 +26,10 @@ #define DPL_MACRO_CONCAT_IMPL(x, y) x##y #define DPL_MACRO_CONCAT(x, y) DPL_MACRO_CONCAT_IMPL(x, y) +#ifdef __COUNTER__ +#define DPL_ANONYMOUS_VARIABLE(name) DPL_MACRO_CONCAT(name, __COUNTER__) +#else +#define DPL_ANONYMOUS_VARIABLE(name) DPL_MACRO_CONCAT(name, __LINE__) +#endif + #endif //DPL_PREPROCESSOR_H diff --git a/modules/core/include/dpl/scope_guard.h b/modules/core/include/dpl/scope_guard.h new file mode 100644 index 0000000..2471937 --- /dev/null +++ b/modules/core/include/dpl/scope_guard.h @@ -0,0 +1,109 @@ +/* + * Copyright 2013 Facebook, Inc. + * + * 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. + */ +/*! + * @file scope_guard.h + * @author Zbigniew Kostrzewa (z.kostrzewa@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of scope guard RAII + */ +#ifndef DPL_SCOPE_GUARD_H_ +#define DPL_SCOPE_GUARD_H_ + +#include +#include +#include +#include +#include + +namespace DPL { +template +class ScopeGuard +{ + public: + explicit ScopeGuard(const FunctionType& function) + : m_function{function}, + m_released{false} + {} + + explicit ScopeGuard(FunctionType&& function) + : m_function{std::move(function)}, + m_released{false} + {} + + ScopeGuard(ScopeGuard&& other) + : m_function{std::move(other.m_function)}, + m_released{other.m_released} + { + other.Release(); + } + + ScopeGuard(const ScopeGuard&) = delete; + + ~ScopeGuard() + { + if (!m_released) + { + Execute(); + } + } + + ScopeGuard& operator=(const ScopeGuard&) = delete; + + void Release() + { + m_released = true; + } + + void* operator new(size_t) = delete; + + private: + // FIXME change to noexcept when available + void Execute() throw() + { + m_function(); + } + + FunctionType m_function; + bool m_released; +}; + +template +ScopeGuard::type> +MakeScopeGuard(FunctionType&& function) +{ + return ScopeGuard::type>( + std::forward(function)); +} + +namespace detail { +enum class ScopeGuardOnExit {}; + +template +ScopeGuard::type> +operator+(detail::ScopeGuardOnExit, FunctionType&& function) +{ + return ScopeGuard::type>( + std::forward(function)); +} +} +} + +// FIXME provide support for compilers not supporting variadic macros +#define DPL_SCOPE_EXIT(...) \ + auto DPL_ANONYMOUS_VARIABLE(DPL_SCOPE_EXIT_STATE) \ + = ::DPL::detail::ScopeGuardOnExit() + [__VA_ARGS__]() + +#endif // DPL_SCOPE_GUARD_H_ diff --git a/tests/core/CMakeLists.txt b/tests/core/CMakeLists.txt index 4348519..18665eb 100644 --- a/tests/core/CMakeLists.txt +++ b/tests/core/CMakeLists.txt @@ -51,6 +51,7 @@ SET(DPL_TESTS_CORE_SOURCES ${TESTS_DIR}/core/test_thread.cpp ${TESTS_DIR}/core/test_type_list.cpp ${TESTS_DIR}/core/test_zip_input.cpp + ${TESTS_DIR}/core/test_scope_guard.cpp ) WRT_TEST_ADD_INTERNAL_DEPENDENCIES(${TARGET_NAME} ${TARGET_DPL_EFL}) diff --git a/tests/core/test_scope_guard.cpp b/tests/core/test_scope_guard.cpp new file mode 100644 index 0000000..7c09645 --- /dev/null +++ b/tests/core/test_scope_guard.cpp @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd 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. + */ +/* + * @file test_scope_guard.cpp + * @author Zbigniew Kostrzewa (z.kostrzewa@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of test scope guard + */ +#include +#include + +namespace { +bool g_guardCalled = false; + +void regularFunction() +{ + g_guardCalled = true; +} + +struct Functor +{ + explicit Functor(bool& guardCalled) + : m_guardCalled(guardCalled) + {} + + void operator()() + { + m_guardCalled = true; + } + + bool& m_guardCalled; +}; +} + +RUNNER_TEST_GROUP_INIT(DPL) + +/* +Name: ScopeGuard_MakeScopeGuard_RegularFunction +Description: tests scope guard, created explicitly, with regular function +Expected: guard should be called +*/ +RUNNER_TEST(ScopeGuard_MakeScopeGuard_RegularFunction) +{ + g_guardCalled = false; + { + auto guard = DPL::MakeScopeGuard(regularFunction); + } + RUNNER_ASSERT(g_guardCalled); +} + +/* +Name: ScopeGuard_MakeScopeGuard_Functor +Description: tests scope guard, created explicitly, with a functor +Expected: guard should be called +*/ +RUNNER_TEST(ScopeGuard_MakeScopeGuard_Functor) +{ + g_guardCalled = false; + { + auto guard = DPL::MakeScopeGuard(Functor(g_guardCalled)); + } + RUNNER_ASSERT(g_guardCalled); +} + +/* +Name: ScopeGuard_MakeScopeGuard_Lambda +Description: tests scope guard, created explicitly, with a lambda +Expected: guard should be called +*/ +RUNNER_TEST(ScopeGuard_MakeScopeGuard_Lambda) +{ + g_guardCalled = false; + { + auto guard = DPL::MakeScopeGuard( + [&g_guardCalled](){ g_guardCalled = true; }); + } + RUNNER_ASSERT(g_guardCalled); +} + +/* +Name: ScopeGuard_Macro +Description: tests scope guard, created implicitly, with a lambda +Expected: guard should be called +*/ +RUNNER_TEST(ScopeGuard_Macro) +{ + g_guardCalled = false; + { + DPL_SCOPE_EXIT(&g_guardCalled) + { + g_guardCalled = true; + }; + } + RUNNER_ASSERT(g_guardCalled); +} + +/* +Name: ScopeGuard_Release +Description: tests scope guard releasing API +Expected: guard should not be called +*/ +RUNNER_TEST(ScopeGuard_Release) +{ + g_guardCalled = false; + { + auto guard = DPL::MakeScopeGuard( + [&g_guardCalled](){ g_guardCalled = true; }); + guard.Release(); + } + RUNNER_ASSERT(!g_guardCalled); +} -- 2.7.4