diff --git a/include/gsl.h b/include/gsl.h index f4c8857..adc14e2 100644 --- a/include/gsl.h +++ b/include/gsl.h @@ -40,25 +40,97 @@ using std::shared_ptr; // // Final_act allows you to ensure something gets run at the end of a scope -template -class Final_act +template +class Final_act_noexcept { -public: - explicit Final_act(F f) : f_(f) {} - - Final_act(const Final_act&& other) : f_(other.f_) {} - Final_act(const Final_act&) = delete; - Final_act& operator=(const Final_act&) = delete; - - ~Final_act() { f_(); } + F_t f; + bool run; -private: - F f_; +public: + explicit Final_act_noexcept(F_t f_) : f(f_), run(true) { } + + ~Final_act_noexcept() + { + if (!run) return; + f(); + } + + Final_act_noexcept(const Final_act_noexcept& s) = delete; + Final_act_noexcept(Final_act_noexcept&& s) + : f(std::move(s.f)), run(s.run) + { s.run = false; } + + Final_act_noexcept& operator=(const Final_act_noexcept& s) = delete; + + Final_act_noexcept& operator=(Final_act_noexcept&& s) + { + f = std::move(s.f); + run = s.run; + s.run = false; + return *this; + } + + void release() { run = false; } }; +// Final_act allows you to ensure something gets run at the end of a scope +template +class Final_act +{ + F_t f; + bool run; + +public: + explicit Final_act(F_t f_) : f(f_), run(true) { } + + ~Final_act() + { + if (!run) + return; + + try { f(); } + catch (...) { } + } + + Final_act(const Final_act& s) = delete; + + Final_act(Final_act&& s) : f(std::move(s.f)), run(s.run) + { + s.run = false; + } + + Final_act& operator=(const Final_act& s) = delete; + + Final_act& operator=(Final_act&& s) + { + f = std::move(s.f); + run = s.run; + s.run = false; + return *this; + } + + void release() { run = false; } +}; + +template +struct if_type_else_type { }; + +template +struct if_type_else_type { typedef T type; }; + +template +struct if_type_else_type { typedef U type; }; + +template +using if_type_else_type_t = typename if_type_else_type::type; + // finally() - convenience function to generate a Final_act -template -Final_act finally(F f) { return Final_act(f); } +template ()()), + Final_act_noexcept, Final_act>> +auto finally(F_t f) { + return Final_act_t(std::move(f)); +} // narrow_cast(): a searchable way to do narrowing casts of values template diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index dee4e28..72c31b5 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -87,6 +87,20 @@ add_test( COMMAND bounds_tests ) +add_executable(final_act_tests + final_act_tests.cpp +) +target_link_libraries(final_act_tests + UnitTest++ +) +install(TARGETS final_act_tests + RUNTIME DESTINATION bin +) +add_test( + NAME final_act_tests + COMMAND final_act_tests +) + add_executable(maybenull_tests maybenull_tests.cpp ) diff --git a/tests/final_act_tests.cpp b/tests/final_act_tests.cpp new file mode 100644 index 0000000..d1ed029 --- /dev/null +++ b/tests/final_act_tests.cpp @@ -0,0 +1,70 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +/////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include + +using namespace std; +using namespace Guide; + +struct Increment { + int* i_; + + Increment(int& i) : i_(&i) {} + + void operator()() const noexcept { ++*i_; } +}; + +struct ThrowOnInvocation { + class Exception : public exception {}; + void operator()() const { throw Exception(); } +}; + +SUITE(finallyTests) { + TEST(SingleInvocationOnConvenienceConstruction) { + int i = 0; + { auto f = finally(Increment(i)); } + CHECK(i == 1); + } + + TEST(SingleInvocationOnMoveConstruction) { + int i = 0; + { + auto f = Final_act(Increment(i)); + auto ff(move(f)); + } + CHECK(i == 1); + } + + TEST(NoexceptFinalActIsCreated) { + int i = 0; + auto f = finally(Increment(i)); + CHECK((is_same>::value)); + } + + TEST(FinalActDoesNotThrow) { + bool exceptionCaught = false; + try { + finally(ThrowOnInvocation()); + } catch (...) { + exceptionCaught = true; + } + CHECK(!exceptionCaught); + } +} + +int main(int, const char* []) { return UnitTest::RunAllTests(); }