├── .github └── workflows │ └── ci.yml ├── CMakeLists.txt ├── LICENSE ├── README.md ├── appveyor.yml ├── build.jam ├── config ├── Jamfile └── has_sufficient_cxx11_type_traits.cpp ├── doc ├── .gitignore ├── Jamfile ├── changelog.qbk ├── gen_references.xsl ├── scope.qbk ├── scope_guards.qbk ├── tmp │ ├── .gitignore │ └── boost-no-inspect └── unique_resource.qbk ├── include └── boost │ └── scope │ ├── defer.hpp │ ├── detail │ ├── compact_storage.hpp │ ├── config.hpp │ ├── footer.hpp │ ├── header.hpp │ ├── is_nonnull_default_constructible.hpp │ ├── is_not_like.hpp │ ├── move_or_copy_assign_ref.hpp │ ├── move_or_copy_construct_ref.hpp │ └── type_traits │ │ ├── conjunction.hpp │ │ ├── disjunction.hpp │ │ ├── is_final.hpp │ │ ├── is_invocable.hpp │ │ ├── is_nothrow_invocable.hpp │ │ ├── is_nothrow_swappable.hpp │ │ ├── is_swappable.hpp │ │ └── negation.hpp │ ├── error_code_checker.hpp │ ├── exception_checker.hpp │ ├── fd_deleter.hpp │ ├── fd_resource_traits.hpp │ ├── scope_exit.hpp │ ├── scope_fail.hpp │ ├── scope_success.hpp │ ├── unique_fd.hpp │ ├── unique_resource.hpp │ └── unique_resource_fwd.hpp ├── index.html ├── meta └── libraries.json └── test ├── CMakeLists.txt ├── Jamfile ├── common └── function_types.hpp ├── compile ├── self_contained_header.cpp └── unallocated_resource_win_invalid_handle_value.cpp ├── compile_fail ├── defer_guard_noncopyable.cpp ├── defer_guard_nonmoveable.cpp ├── scope_exit_cond_def_cted_fptr.cpp ├── scope_exit_noncopyable.cpp ├── scope_fail_noncopyable.cpp ├── scope_success_noncopyable.cpp ├── unique_resource_bad_rtraits_isalloc_throwing.cpp ├── unique_resource_bad_rtraits_mkdef_nonassignable.cpp ├── unique_resource_bad_rtraits_mkdef_nonconstructible.cpp ├── unique_resource_bad_rtraits_mkdef_throwing.cpp ├── unique_resource_bad_rtraits_reduced_mkdef_nonconstructible.cpp ├── unique_resource_del_def_cted_fptr.cpp ├── unique_resource_non_deducible_def_res.cpp ├── unique_resource_noncopyable.cpp ├── unique_resource_ref_ctor_rv.cpp └── unique_resource_ref_reset_rv.cpp └── run ├── defer_guard.cpp ├── scope_exit.cpp ├── scope_fail.cpp ├── scope_success.cpp ├── unique_fd.cpp └── unique_resource.cpp /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Andrey Semashev 2 | # 3 | # Distributed under the Boost Software License, Version 1.0. 4 | # (See accompanying file LICENSE_1_0.txt or copy at 5 | # https://www.boost.org/LICENSE_1_0.txt) 6 | 7 | cmake_minimum_required(VERSION 3.5...3.20) 8 | 9 | project(boost_scope VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX) 10 | 11 | add_library(boost_scope INTERFACE) 12 | add_library(Boost::scope ALIAS boost_scope) 13 | 14 | target_include_directories(boost_scope INTERFACE include) 15 | 16 | target_link_libraries(boost_scope 17 | INTERFACE 18 | Boost::config 19 | Boost::core 20 | Boost::type_traits 21 | ) 22 | 23 | target_compile_features(boost_scope 24 | INTERFACE 25 | cxx_constexpr 26 | cxx_noexcept 27 | cxx_rvalue_references 28 | cxx_decltype 29 | cxx_alias_templates 30 | cxx_variadic_templates 31 | cxx_variadic_macros 32 | cxx_defaulted_functions 33 | cxx_deleted_functions 34 | cxx_default_function_template_args 35 | cxx_delegating_constructors 36 | ) 37 | 38 | if (BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt") 39 | add_subdirectory(test) 40 | endif() 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Boost Software License - Version 1.0 - August 17th, 2003 2 | 3 | Permission is hereby granted, free of charge, to any person or organization 4 | obtaining a copy of the software and accompanying documentation covered by 5 | this license (the "Software") to use, reproduce, display, distribute, 6 | execute, and transmit the Software, and to prepare derivative works of the 7 | Software, and to permit third-parties to whom the Software is furnished to 8 | do so, all subject to the following: 9 | 10 | The copyright notices in the Software and this entire statement, including 11 | the above license grant, this restriction and the following disclaimer, 12 | must be included in all copies of the Software, in whole or in part, and 13 | all derivative works of the Software, unless such copies or derivative 14 | works are solely in the form of machine-executable object code generated by 15 | a source language processor. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Boost.Scope 2 | 3 | Boost.Scope provides a number of scope guard utilities and a `unique_resource` wrapper, similar to those described in 4 | [C++ Extensions for Library Fundamentals, Version 3](https://github.com/cplusplus/fundamentals-ts/releases/tag/n4908), 5 | Section 3.3 Scope guard support \[scopeguard\]. The implementation also provides a few non-standard extensions. 6 | 7 | ### Directories 8 | 9 | * **doc** - QuickBook documentation sources 10 | * **include** - Interface headers of Boost.Scope 11 | * **test** - Boost.Scope unit tests 12 | 13 | ### More information 14 | 15 | * Read the [documentation](https://www.boost.org/libs/scope/). 16 | * [Report bugs](https://github.com/boostorg/scope/issues/new). Be sure to mention Boost version, platform and compiler you're using. A small compilable code sample to reproduce the problem is always good as well. 17 | * Submit your patches as [pull requests](https://github.com/boostorg/scope/compare) against **develop** branch. Note that by submitting patches you agree to license your modifications under the [Boost Software License, Version 1.0](https://www.boost.org/LICENSE_1_0.txt). 18 | 19 | ### Build status 20 | 21 | Branch | GitHub Actions | AppVeyor | Test Matrix | Dependencies | 22 | :-------------: | -------------- | -------- | ----------- | ------------ | 23 | [`master`](https://github.com/boostorg/scope/tree/master) | [![GitHub Actions](https://github.com/boostorg/scope/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/boostorg/scope/actions?query=branch%3Amaster) | [![AppVeyor](https://ci.appveyor.com/api/projects/status/7dr1fo39o27subn1/branch/master?svg=true)](https://ci.appveyor.com/project/Lastique/scope/branch/master) | [![Tests](https://img.shields.io/badge/matrix-master-brightgreen.svg)](https://regression.boost.io/master/developer/scope.html) | [![Dependencies](https://img.shields.io/badge/deps-master-brightgreen.svg)](https://pdimov.github.io/boostdep-report/master/scope.html) 24 | [`develop`](https://github.com/boostorg/scope/tree/develop) | [![GitHub Actions](https://github.com/boostorg/scope/actions/workflows/ci.yml/badge.svg?branch=develop)](https://github.com/boostorg/scope/actions?query=branch%3Adevelop) | [![AppVeyor](https://ci.appveyor.com/api/projects/status/7dr1fo39o27subn1/branch/develop?svg=true)](https://ci.appveyor.com/project/Lastique/scope/branch/develop) | [![Tests](https://img.shields.io/badge/matrix-develop-brightgreen.svg)](https://regression.boost.io/develop/developer/scope.html) | [![Dependencies](https://img.shields.io/badge/deps-develop-brightgreen.svg)](https://pdimov.github.io/boostdep-report/develop/scope.html) 25 | 26 | ### License 27 | 28 | Distributed under the [Boost Software License, Version 1.0](https://www.boost.org/LICENSE_1_0.txt). 29 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Andrey Semashev 2 | # 3 | # Distributed under the Boost Software License, Version 1.0. 4 | # (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) 5 | 6 | version: 1.0.{build}-{branch} 7 | 8 | shallow_clone: true 9 | 10 | branches: 11 | only: 12 | - master 13 | - develop 14 | - /feature\/.*/ 15 | 16 | environment: 17 | matrix: 18 | - TOOLSET: msvc-14.0 19 | ADDRMD: 32,64 20 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 21 | - TOOLSET: msvc-14.1 22 | CXXSTD: 14,17,latest 23 | ADDRMD: 32,64 24 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 25 | - TOOLSET: msvc-14.2 26 | ADDRMD: 32,64 27 | CXXSTD: 14,17,20,latest 28 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 29 | - TOOLSET: msvc-14.3 30 | ADDRMD: 32,64 31 | CXXSTD: 14,17,20,latest 32 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022 33 | - TOOLSET: clang-win 34 | ADDRMD: 32 35 | CXXSTD: 14,17,latest 36 | ENV_SCRIPT: C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars32.bat 37 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 38 | - TOOLSET: clang-win 39 | ADDRMD: 64 40 | CXXSTD: 14,17,latest 41 | ENV_SCRIPT: C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat 42 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 43 | - TOOLSET: gcc 44 | CXXSTD: 11,14,1z 45 | ADDPATH: C:\cygwin\bin; 46 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 47 | - TOOLSET: gcc 48 | CXXSTD: 11,14,1z 49 | ADDPATH: C:\cygwin64\bin; 50 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 51 | - TOOLSET: gcc 52 | CXXSTD: 11,14,17 53 | ADDPATH: C:\mingw-w64\x86_64-7.3.0-posix-seh-rt_v5-rev0\mingw64\bin; 54 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 55 | - TOOLSET: gcc 56 | CXXSTD: 11,14,17,2a 57 | ADDPATH: C:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin; 58 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 59 | - TEST_CMAKE: 1 60 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 61 | 62 | install: 63 | - set GIT_FETCH_JOBS=8 64 | - set BOOST_BRANCH=develop 65 | - if "%APPVEYOR_REPO_BRANCH%" == "master" set BOOST_BRANCH=master 66 | - cd .. 67 | - git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root 68 | - cd boost-root 69 | - git submodule init tools/build 70 | - git submodule init tools/boostdep 71 | - git submodule init tools/boost_install 72 | - git submodule init libs/headers 73 | - git submodule init libs/config 74 | - git submodule update --jobs %GIT_FETCH_JOBS% 75 | - xcopy /s /e /q %APPVEYOR_BUILD_FOLDER% libs\scope 76 | - python tools/boostdep/depinst/depinst.py --git_args "--jobs %GIT_FETCH_JOBS%" scope 77 | - cmd /c bootstrap 78 | - b2 -d0 headers 79 | 80 | build: off 81 | 82 | test_script: 83 | - PATH=%ADDPATH%%PATH% 84 | - if not "%ENV_SCRIPT%" == "" call "%ENV_SCRIPT%" 85 | - if not "%CXXSTD%" == "" set CXXSTD=cxxstd=%CXXSTD% 86 | - if not "%ADDRMD%" == "" set ADDRMD=address-model=%ADDRMD% 87 | - if not "%THREADING%" == "" set THREADING=threading=%THREADING% 88 | - b2 -j %NUMBER_OF_PROCESSORS% libs/scope/test toolset=%TOOLSET% %CXXSTD% %ADDRMD% %THREADING% 89 | 90 | for: 91 | - matrix: 92 | only: [TEST_CMAKE: 1] 93 | test_script: 94 | - mkdir __build_static__ 95 | - cd __build_static__ 96 | - cmake -DBOOST_INCLUDE_LIBRARIES=scope -DBUILD_TESTING=ON .. 97 | - cmake --build . --config Release --target tests -j %NUMBER_OF_PROCESSORS% 98 | - ctest -C Release --output-on-failure --no-tests=error -j %NUMBER_OF_PROCESSORS% 99 | - cd .. 100 | - mkdir __build_shared__ 101 | - cd __build_shared__ 102 | - cmake -DBOOST_INCLUDE_LIBRARIES=scope -DBUILD_SHARED_LIBS=ON -DBUILD_TESTING=ON .. 103 | - cmake --build . --config Release --target tests -j %NUMBER_OF_PROCESSORS% 104 | - ctest -C Release --output-on-failure --no-tests=error -j %NUMBER_OF_PROCESSORS% 105 | -------------------------------------------------------------------------------- /build.jam: -------------------------------------------------------------------------------- 1 | # Copyright René Ferdinand Rivera Morell 2024 2 | # Copyright Andrey Semashev 2025 3 | # 4 | # Distributed under the Boost Software License, Version 1.0. 5 | # (See accompanying file LICENSE_1_0.txt or copy at 6 | # http://www.boost.org/LICENSE_1_0.txt) 7 | 8 | require-b2 5.2 ; 9 | 10 | import-search /boost/config/checks ; 11 | import config : requires ; 12 | 13 | constant boost_dependencies : 14 | /boost/assert//boost_assert 15 | /boost/config//boost_config 16 | /boost/core//boost_core 17 | /boost/type_traits//boost_type_traits ; 18 | 19 | local cxx_requirements = 20 | [ requires 21 | exceptions 22 | sfinae_expr 23 | cxx11_constexpr 24 | cxx11_noexcept 25 | cxx11_decltype 26 | cxx11_rvalue_references 27 | cxx11_template_aliases 28 | cxx11_variadic_templates 29 | cxx11_defaulted_functions 30 | cxx11_deleted_functions 31 | cxx11_function_template_default_args 32 | ] 33 | [ check-target-builds config//has_sufficient_cxx11_type_traits "has sufficient for Boost.Scope" : : no ] 34 | ; 35 | 36 | project /boost/scope 37 | : common-requirements 38 | include 39 | ; 40 | 41 | explicit 42 | [ alias boost_scope : : $(cxx_requirements) : : $(cxx_requirements) $(boost_dependencies) ] 43 | [ alias all : boost_scope test ] 44 | ; 45 | 46 | call-if : boost-library scope 47 | ; 48 | 49 | -------------------------------------------------------------------------------- /config/Jamfile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright Andrey Semashev 2025. 3 | # Distributed under the Boost Software License, Version 1.0. 4 | # (See accompanying file LICENSE_1_0.txt or copy at 5 | # http://www.boost.org/LICENSE_1_0.txt) 6 | # 7 | 8 | obj has_sufficient_cxx11_type_traits : has_sufficient_cxx11_type_traits.cpp : /boost/config//boost_config ; 9 | explicit has_sufficient_cxx11_type_traits ; 10 | -------------------------------------------------------------------------------- /config/has_sufficient_cxx11_type_traits.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Andrey Semashev 2025. 3 | * Distributed under the Boost Software License, Version 1.0. 4 | * (See accompanying file LICENSE_1_0.txt or copy at 5 | * http://www.boost.org/LICENSE_1_0.txt) 6 | */ 7 | 8 | // The test verifies that the compiler provides a header that is 9 | // sufficient for Boost.Scope needs. 10 | 11 | #include 12 | 13 | int main(int, char*[]) 14 | { 15 | using std::integral_constant; 16 | using std::true_type; 17 | using std::false_type; 18 | using std::conditional; 19 | using std::enable_if; 20 | 21 | using std::decay; 22 | 23 | using std::is_class; 24 | using std::is_reference; 25 | 26 | using std::is_constructible; 27 | using std::is_nothrow_constructible; 28 | using std::is_move_constructible; 29 | using std::is_nothrow_move_constructible; 30 | using std::is_default_constructible; 31 | using std::is_nothrow_default_constructible; 32 | using std::is_assignable; 33 | using std::is_nothrow_assignable; 34 | using std::is_move_assignable; 35 | using std::is_nothrow_move_assignable; 36 | 37 | return 0; 38 | } 39 | -------------------------------------------------------------------------------- /doc/.gitignore: -------------------------------------------------------------------------------- 1 | html 2 | -------------------------------------------------------------------------------- /doc/Jamfile: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Andrey Semashev 2 | # 3 | # Distributed under the Boost Software License, Version 1.0. 4 | # (See accompanying file LICENSE_1_0.txt or copy at 5 | # https://www.boost.org/LICENSE_1_0.txt) 6 | 7 | using quickbook ; 8 | using boostbook ; 9 | using doxygen ; 10 | using xsltproc ; 11 | 12 | import set ; 13 | import doxygen ; 14 | import xsltproc ; 15 | import notfile ; 16 | import path ; 17 | import project ; 18 | 19 | project boost/libs/scope/doc ; 20 | 21 | local doxygen_params = 22 | RECURSIVE=YES 23 | ALPHABETICAL_INDEX=YES 24 | REPEAT_BRIEF=YES 25 | ALWAYS_DETAILED_SEC=YES 26 | BRIEF_MEMBER_DESC=NO 27 | ABBREVIATE_BRIEF=YES 28 | INHERIT_DOCS=YES 29 | HIDE_UNDOC_MEMBERS=YES 30 | HIDE_UNDOC_CLASSES=YES 31 | HIDE_SCOPE_NAMES=YES 32 | EXTRACT_ALL=NO 33 | EXTRACT_PRIVATE=NO 34 | BUILTIN_STL_SUPPORT=YES 35 | ENABLE_PREPROCESSING=YES 36 | MACRO_EXPANSION=YES 37 | TAB_SIZE=4 38 | SOURCE_BROWSER=YES 39 | VERBATIM_HEADERS=NO 40 | # SEARCH_INCLUDES=YES 41 | # "INCLUDE_PATH=../../.." 42 | # EXCLUDE_SYMBOLS="detail detail::*" 43 | "PREDEFINED=BOOST_SCOPE_DOXYGEN \\ 44 | BOOST_SCOPE_DETAIL_DOC_ALT(alt, ...)=alt \\ 45 | BOOST_SCOPE_DETAIL_DOC_HIDDEN(...)=... \\ 46 | BOOST_SCOPE_DETAIL_DOC(...)=__VA_ARGS__ \\ 47 | BOOST_NO_CXX17_DEDUCTION_GUIDES=1 \\ 48 | BOOST_SYMBOL_VISIBLE= \\ 49 | BOOST_FORCEINLINE=inline \\ 50 | BOOST_INLINE_VARIABLE=inline \\ 51 | BOOST_CXX14_CONSTEXPR=constexpr" 52 | boost.doxygen.detailns=detail 53 | # boost.doxygen.detail=implementation_ 54 | ; 55 | 56 | 57 | local top_level_includes = 58 | [ glob 59 | ../include/boost/scope/*.hpp 60 | ] ; 61 | 62 | 63 | # This rule generates *.qbk files with macros with references to files, classes, etc. from the doxygen resulting *.xml files. 64 | rule gen-references ( target : source : properties * ) 65 | { 66 | DEPENDS target : source ; 67 | local source-path = [ path.make [ on $(source) return $(LOCATE) ] ] ; 68 | STYLESHEET on $(target) = [ path.native [ path.join [ path.parent $(source-path) ] gen_references.xsl ] ] ; 69 | local target-name = $(source:B) ; 70 | TARGET on $(target) = [ path.native [ path.join $(source-path) $(target-name:S=.qbk) ] ] ; 71 | } 72 | actions gen-references 73 | { 74 | $(NAME:E=xsltproc) -o "$(TARGET)" "$(STYLESHEET)" "$(>)" 75 | } 76 | 77 | 78 | doxygen top_level_reference 79 | : 80 | $(top_level_includes) 81 | : 82 | $(doxygen_params) 83 | "boost.doxygen.reftitle=Reference" 84 | tmp 85 | ; 86 | 87 | notfile top_level_refs : @gen-references : top_level_reference.xml ; 88 | 89 | 90 | xml scope_doc 91 | : 92 | scope.qbk 93 | : 94 | top_level_refs 95 | ; 96 | 97 | boostbook scope 98 | : 99 | scope_doc 100 | : 101 | "boost.root=../../../.." 102 | "boost.libraries=../../../libs/libraries.htm" 103 | "nav.layout=none" 104 | "boost.image=Boost" 105 | "navig.graphics=1" 106 | "chunk.section.depth=1" 107 | "boost.compact.function=0" 108 | pdf:"boost.url.prefix=https://www.boost.org/doc/libs/release/libs/scope/doc/html" 109 | ; 110 | 111 | ############################################################################### 112 | alias boostdoc ; 113 | explicit boostdoc ; 114 | alias boostrelease : scope ; 115 | explicit boostrelease ; 116 | -------------------------------------------------------------------------------- /doc/changelog.qbk: -------------------------------------------------------------------------------- 1 | [/ 2 | / Copyright 2023-2024 Andrey Semashev 3 | / 4 | / Distributed under the Boost Software License, Version 1.0. 5 | / (See accompanying file LICENSE_1_0.txt or copy at 6 | / https://www.boost.org/LICENSE_1_0.txt) 7 | / 8 | / This document is a part of Boost.Scope library documentation. 9 | /] 10 | 11 | [section:changelog Changelog] 12 | 13 | [heading Boost 1.85] 14 | 15 | The library has been accepted into Boost. Updates according to Boost [@https://lists.boost.org/Archives/boost/2024/01/255717.php 16 | review] comments and conditions: 17 | 18 | * Renamed `scope_final` to `defer_guard` and `BOOST_SCOPE_FINAL` to `BOOST_SCOPE_DEFER`. Thanks to Peter Dimov for the 19 | [@https://lists.boost.org/Archives/boost/2023/12/255501.php suggestion] during the review. The name "defer" is being 20 | used in other programming languages (Go, Swift and even [@https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2895.htm proposed] 21 | for inclusion in C) for the functionality similar to `scope_final`. 22 | * Removed `release` member from the scope guard types. This method was equivalent to `set_active(false)` and existed 23 | for compatibility with the C++ Extensions for Library Fundamentals TS. Boost review conclusion indicated that conformance 24 | with the TS is not a worthy goal. 25 | * In `unique_resource`, added `explicit operator bool` as a way to test if the resource in an allocated state, similar 26 | to the `allocated` method. This was suggested by Dmitry Arkhipov before the review. Note that the operator does not 27 | test the resource value, which is similar to `std::optional`. 28 | * Added [link scope.unique_resource.simplified_resource_traits `unallocated_resource`] class template for simplifying 29 | declaration of resource traits for `unique_resource`. The idea of a more compact `unique_resource` declaration was 30 | presented by Janko Dedic in his [@https://lists.boost.org/Archives/boost/2023/11/255424.php review]. 31 | * Added documentation sections describing differences between Boost.Scope and Library Fundamentals TS (see 32 | [link scope.scope_guards.comparison_with_library_fundamentals_ts here] and 33 | [link scope.unique_resource.comparison_with_library_fundamentals_ts here]). 34 | * [link scope.unique_resource `unique_resource`] move constructor was modified to preserve the original state of the 35 | source argument in case of exception. This deviates from the TS behavior, which specifies to invoke the deleter on 36 | the move-constructed resource, but it means the move constructor now maintains strong exception guarantee. 37 | * Enforced compile-time correctness checks for [link scope.unique_resource `unique_resource`] resource traits specified 38 | by user. Improved description of requirements for the resource traits. 39 | * Many documentation improvements. 40 | 41 | [heading 0.1] 42 | 43 | Initial release for Boost review. 44 | 45 | [endsect] 46 | -------------------------------------------------------------------------------- /doc/gen_references.xsl: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | 16 | [/ 17 | / Copyright 2023 Andrey Semashev 18 | / 19 | / Distributed under the Boost Software License, Version 1.0. 20 | / (See accompanying file LICENSE_1_0.txt or copy at 21 | / https://www.boost.org/LICENSE_1_0.txt) 22 | / 23 | / This document is a part of Boost.Scope library documentation. 24 | / 25 | / This document was automatically generated, DO NOT EDIT! 26 | /] 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | [template [][headerref ]] 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | :: 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | [template [][classref ]] 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /doc/scope.qbk: -------------------------------------------------------------------------------- 1 | [library Boost.Scope 2 | [quickbook 1.7] 3 | [authors [Semashev, Andrey]] 4 | [copyright 2022-2024 Andrey Semashev] 5 | [license 6 | Distributed under the Boost Software License, Version 1.0. 7 | (See accompanying file LICENSE_1_0.txt or copy at 8 | [@https://www.boost.org/LICENSE_1_0.txt]). 9 | ] 10 | [id scope] 11 | [source-mode c++] 12 | ] 13 | 14 | [c++] 15 | 16 | [/ Links to external resources /] 17 | [def __boost_config__ [@https://www.boost.org/doc/libs/release/libs/config/doc/html/index.html Boost.Config]] 18 | [def __boost_core__ [@https://www.boost.org/doc/libs/release/libs/core/doc/html/index.html Boost.Core]] 19 | [def __boost_core_functor__ [@https://www.boost.org/doc/libs/release/libs/core/doc/html/core/functor.html `functor`]] 20 | [def __boost_function__ [@https://www.boost.org/doc/libs/release/doc/html/function.html Boost.Function]] 21 | [def __boost_outcome__ [@https://www.boost.org/doc/libs/release/libs/outcome/doc/html/index.html Boost.Outcome]] 22 | [def __boost_scope_exit__ [@https://www.boost.org/doc/libs/release/libs/scope_exit/doc/html/index.html Boost.ScopeExit]] 23 | [def __boost_smart_ptr__ [@https://www.boost.org/doc/libs/release/libs/smart_ptr/doc/html/smart_ptr.html Boost.SmartPtr]] 24 | [def __boost_system__ [@https://www.boost.org/doc/libs/release/libs/system/doc/html/system.html Boost.System]] 25 | 26 | [template github_issue[key][@https://github.com/boostorg/scope/issues/[key] #[key]]] 27 | [template github_pr[key][@https://github.com/boostorg/scope/pull/[key] PR#[key]]] 28 | 29 | [/ Auto-generated macros that refer to Reference sections /] 30 | [import tmp/top_level_reference.qbk] 31 | 32 | [section:intro Introduction] 33 | 34 | The Boost.Scope library is a collection of utilities helping with code execution upon leaving a scope and automatic resource management. The library contains 35 | components that are similar to those specified in the [@https://cplusplus.github.io/fundamentals-ts/v3.html C++ Extensions for Library Fundamentals, Version 3] 36 | technical specification (or TS, for short), in the [@https://cplusplus.github.io/fundamentals-ts/v3.html#scope.syn ``] standard library header, 37 | originally defined in [@https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0052r10.pdf P0052R10]. The library also contains extensions to the TS that 38 | improve usability and efficiency of the components. 39 | 40 | The components provided by the library can be divided into two categories: 41 | 42 | * A set of scope guards that allow executing arbitrary code when the scope guard is destroyed, 43 | * A generic resource wrapper that automatically frees the owned resource upon destruction. 44 | 45 | The library defines its components in namespace `boost::scope`. For brevity, the namespace qualification may be omitted in this documentation; readers should assume 46 | that unqualified names like `scope_exit` or `unique_resource` are defined in `boost::scope`. 47 | 48 | Scope guards allow the user to execute a piece of code (an action) upon leaving the scope where the scope guard is declared. Depending on the scope guard, the action 49 | can be executed unconditionally, upon leaving the scope normally or due to an exception, or even according to a user-specified condition. This can be useful in 50 | a variety of use cases, some of which are illustrated below. 51 | 52 | [table Syntax overview of Boost.Scope scope guards 53 | [[C++11][C++17]] 54 | [[ 55 | ``` 56 | class adder 57 | { 58 | int x, y; 59 | 60 | public: 61 | // Computes a sum of integers 62 | int compute() 63 | { 64 | // Reset variables on return or exception 65 | auto cleanup = boost::scope::make_scope_exit([this] 66 | { 67 | x = 0; 68 | y = 0; 69 | }); 70 | 71 | long long int sum = static_cast< long long int >(x) + 72 | static_cast< long long int >(y); 73 | if (sum < std::numeric_limits< int >::min() || 74 | sum > std::numeric_limits< int >::max()) 75 | { 76 | throw std::overflow_error("Integer overflow"); 77 | } 78 | 79 | return static_cast< int >(sum); 80 | } 81 | }; 82 | ``` 83 | ] 84 | [ 85 | ``` 86 | class adder 87 | { 88 | int x, y; 89 | 90 | public: 91 | // Computes a sum of integers 92 | int compute() 93 | { 94 | // Reset variables on return or exception. 95 | // Anonymous scope guard. 96 | BOOST_SCOPE_DEFER [this] 97 | { 98 | x = 0; 99 | y = 0; 100 | }; 101 | 102 | long long int sum = static_cast< long long int >(x) + 103 | static_cast< long long int >(y); 104 | if (sum < std::numeric_limits< int >::min() || 105 | sum > std::numeric_limits< int >::max()) 106 | { 107 | throw std::overflow_error("Integer overflow"); 108 | } 109 | 110 | return static_cast< int >(sum); 111 | } 112 | }; 113 | ``` 114 | ]] 115 | [[ 116 | ``` 117 | template< typename Object > 118 | class collection 119 | { 120 | std::set< Object > objects; 121 | 122 | public: 123 | // Adds a new object to the collection 124 | Object& add_object() 125 | { 126 | auto it = objects.emplace(); 127 | 128 | // Revert object insertion on exception 129 | auto cleanup = boost::scope::make_scope_fail([this, it] 130 | { 131 | objects.erase(it); 132 | }); 133 | 134 | // Throws on error 135 | it->on_added(*this); 136 | 137 | return *it; 138 | } 139 | }; 140 | ``` 141 | ] 142 | [ 143 | ``` 144 | template< typename Object > 145 | class collection 146 | { 147 | std::set< Object > objects; 148 | 149 | public: 150 | // Adds a new object to the collection 151 | Object& add_object() 152 | { 153 | auto it = objects.emplace(); 154 | 155 | // Revert object insertion on exception 156 | boost::scope::scope_fail cleanup{[this, it] 157 | { 158 | objects.erase(it); 159 | }}; 160 | 161 | // Throws on error 162 | it->on_added(*this); 163 | 164 | return *it; 165 | } 166 | }; 167 | ``` 168 | ]] 169 | [[ 170 | ``` 171 | // Writes a list of strings to the file, in CSV format 172 | bool save_as_csv(std::vector< std::string > const& strings, 173 | std::string const& filename) 174 | { 175 | std::ofstream file(filename.c_str(), 176 | std::ios_base::out | std::ios_base::trunc); 177 | if (!file.is_open()) 178 | return false; 179 | 180 | // Set a scope guard to remove the partially written file 181 | // in case of error - exception or not 182 | auto remove_guard = boost::scope::make_scope_exit([&file, &filename] 183 | { 184 | file.close(); // close the file to allow remove() to succeed on Windows 185 | std::remove(filename.c_str()); 186 | }); 187 | 188 | bool first = true; 189 | for (auto const& str : strings) 190 | { 191 | if (!first) 192 | file << ','; 193 | else 194 | first = false; 195 | 196 | file << '"' << str << '"'; 197 | 198 | if (file.fail()) 199 | return false; 200 | } 201 | 202 | file << std::endl; 203 | if (file.fail()) 204 | return false; 205 | 206 | // Commit the operation 207 | remove_guard.set_active(false); 208 | 209 | return true; 210 | } 211 | ``` 212 | ] 213 | [ 214 | ``` 215 | // Writes a list of strings to the file, in CSV format 216 | bool save_as_csv(std::vector< std::string > const& strings, 217 | std::string const& filename) 218 | { 219 | std::ofstream file(filename.c_str(), 220 | std::ios_base::out | std::ios_base::trunc); 221 | if (!file.is_open()) 222 | return false; 223 | 224 | // Set a scope guard to remove the partially written file 225 | // in case of error - exception or not 226 | boost::scope::scope_exit remove_guard{[&file, &filename] 227 | { 228 | file.close(); // close the file to allow remove() to succeed on Windows 229 | std::remove(filename.c_str()); 230 | }}; 231 | 232 | bool first = true; 233 | for (auto const& str : strings) 234 | { 235 | if (!first) 236 | file << ','; 237 | else 238 | first = false; 239 | 240 | file << '"' << str << '"'; 241 | 242 | if (file.fail()) 243 | return false; 244 | } 245 | 246 | file << std::endl; 247 | if (file.fail()) 248 | return false; 249 | 250 | // Commit the operation 251 | remove_guard.set_active(false); 252 | 253 | return true; 254 | } 255 | ``` 256 | ]] 257 | ] 258 | 259 | There is some overlap between scope guards provided by this library and __boost_scope_exit__. Compared to __boost_scope_exit__, Boost.Scope offers simpler syntax 260 | (especially with C++17 capable compilers) and new features for specific use cases. Detailed comparison between scope guards provided by Boost.Scope and 261 | __boost_scope_exit__ is given in a [link scope.scope_guards.comparison_with_boost_scope_exit separate section]. 262 | 263 | Unique resource wrapper provided by Boost.Scope is a generalization of smart pointers like `std::unique_ptr` and `boost::scoped_ptr` from __boost_smart_ptr__. While 264 | smart pointers are suitable for managing resources represented by pointers (e.g. objects in dynamically allocated memory), unique resource wrapper can be used 265 | with many more kinds of resource types, such as integers (e.g. POSIX file descriptors) and user-defined types. 266 | 267 | // Fills the buffer with random bytes from system RNG. Returns 0 on success, otherwise an error code. 268 | int get_random_bytes(unsigned char* bytes, std::size_t size) 269 | { 270 | // Open RNG device and wrap the returned POSIX file descriptor in unique_resource. 271 | // This wrapper will automatically close the file descriptor upon destruction by invoking fd_deleter on it. 272 | boost::scope::unique_resource< int, boost::scope::fd_deleter, boost::scope::fd_resource_traits > fd(open("/dev/urandom", O_RDONLY)); 273 | 274 | // fd_resource_traits allows the unique_resource to recognize when open() returns a valid file descriptor 275 | // and when it fails and returns -1. In the latter case, the constructed unique_resource is unallocated, 276 | // which we test below. 277 | if (!fd) 278 | return errno; 279 | 280 | // Read random bytes until the buffer is filled or an error occurs 281 | std::size_t read_size = 0u; 282 | while (read_size < size) 283 | { 284 | ssize_t res = read(fd.get(), bytes + read_size, size - read_size); 285 | if (res < 0) 286 | { 287 | int err = errno; 288 | if (err == EINTR) 289 | continue; 290 | 291 | return err; 292 | } 293 | 294 | if (res == 0) 295 | return ENODATA; 296 | 297 | read_size += res; 298 | } 299 | 300 | return 0; 301 | } 302 | 303 | [endsect] 304 | 305 | [section:install_compat Installation and compatibility] 306 | 307 | This library is header-only, it does not require separate compilation. You can add the path to Boost headers to your project, include the required Boost.Scope header 308 | and then use the component provided by that header in your code. 309 | 310 | The library requires a C++11 compiler at the minimum. For certain fetures, C++17 support is required. The following compilers were tested with the library: 311 | 312 | * gcc 4.8 and newer 313 | * clang 3.5 and newer 314 | * MSVC 14.0 and newer 315 | 316 | The library components are agnostic to the operating system. 317 | 318 | [endsect] 319 | 320 | [include scope_guards.qbk] 321 | [include unique_resource.qbk] 322 | 323 | [xinclude tmp/top_level_reference.xml] 324 | 325 | [include changelog.qbk] 326 | -------------------------------------------------------------------------------- /doc/tmp/.gitignore: -------------------------------------------------------------------------------- 1 | *.qbk 2 | *.xml 3 | -------------------------------------------------------------------------------- /doc/tmp/boost-no-inspect: -------------------------------------------------------------------------------- 1 | This file tells boost inspect to ignore this directory and any sub-directories 2 | -------------------------------------------------------------------------------- /include/boost/scope/defer.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://www.boost.org/LICENSE_1_0.txt) 5 | * 6 | * Copyright (c) 2022-2024 Andrey Semashev 7 | */ 8 | /*! 9 | * \file scope/defer.hpp 10 | * 11 | * This header contains definition of \c defer_guard template. 12 | */ 13 | 14 | #ifndef BOOST_SCOPE_DEFER_HPP_INCLUDED_ 15 | #define BOOST_SCOPE_DEFER_HPP_INCLUDED_ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #ifdef BOOST_HAS_PRAGMA_ONCE 26 | #pragma once 27 | #endif 28 | 29 | namespace boost { 30 | namespace scope { 31 | 32 | template< typename Func > 33 | class defer_guard; 34 | 35 | namespace detail { 36 | 37 | // Workaround for clang < 5.0 which can't pass defer_guard as a template template parameter from within defer_guard definition 38 | template< typename T > 39 | using is_not_like_defer_guard = detail::is_not_like< T, defer_guard >; 40 | 41 | } // namespace detail 42 | 43 | /*! 44 | * \brief Defer guard that invokes a function upon leaving the scope. 45 | * 46 | * The scope guard wraps a function object callable with no arguments 47 | * that can be one of: 48 | * 49 | * \li A user-defined class with a public `operator()`. 50 | * \li An lvalue reference to such class. 51 | * \li An lvalue reference or pointer to function taking no arguments. 52 | * 53 | * The defer guard unconditionally invokes the wrapped function object 54 | * on destruction. 55 | */ 56 | template< typename Func > 57 | class defer_guard 58 | { 59 | //! \cond 60 | private: 61 | struct data 62 | { 63 | Func m_func; 64 | 65 | template< typename F, typename = typename std::enable_if< std::is_constructible< Func, F >::value >::type > 66 | explicit data(F&& func, std::true_type) noexcept : 67 | m_func(static_cast< F&& >(func)) 68 | { 69 | } 70 | 71 | template< typename F, typename = typename std::enable_if< std::is_constructible< Func, F >::value >::type > 72 | explicit data(F&& func, std::false_type) try : 73 | m_func(static_cast< F&& >(func)) 74 | { 75 | } 76 | catch (...) 77 | { 78 | func(); 79 | } 80 | }; 81 | 82 | data m_data; 83 | 84 | //! \endcond 85 | public: 86 | /*! 87 | * \brief Constructs a defer guard with a given callable function object. 88 | * 89 | * **Requires:** \c Func is constructible from \a func. 90 | * 91 | * **Effects:** If \c Func is nothrow constructible from `F&&` then constructs \c Func from 92 | * `std::forward< F >(func)`, otherwise constructs from `func`. 93 | * 94 | * If \c Func construction throws, invokes \a func before returning with the exception. 95 | * 96 | * **Throws:** Nothing, unless construction of the function object throws. 97 | * 98 | * \param func The callable function object to invoke on destruction. 99 | */ 100 | template< 101 | typename F 102 | //! \cond 103 | , typename = typename std::enable_if< detail::conjunction< 104 | std::is_constructible< 105 | data, 106 | typename detail::move_or_copy_construct_ref< F, Func >::type, 107 | typename std::is_nothrow_constructible< Func, typename detail::move_or_copy_construct_ref< F, Func >::type >::type 108 | >, 109 | detail::is_not_like_defer_guard< F > 110 | >::value >::type 111 | //! \endcond 112 | > 113 | defer_guard(F&& func) 114 | noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN( 115 | std::is_nothrow_constructible< 116 | data, 117 | typename detail::move_or_copy_construct_ref< F, Func >::type, 118 | typename std::is_nothrow_constructible< Func, typename detail::move_or_copy_construct_ref< F, Func >::type >::type 119 | >::value 120 | )) : 121 | m_data 122 | ( 123 | static_cast< typename detail::move_or_copy_construct_ref< F, Func >::type >(func), 124 | typename std::is_nothrow_constructible< Func, typename detail::move_or_copy_construct_ref< F, Func >::type >::type() 125 | ) 126 | { 127 | } 128 | 129 | defer_guard(defer_guard const&) = delete; 130 | defer_guard& operator= (defer_guard const&) = delete; 131 | 132 | /*! 133 | * \brief Invokes the wrapped callable function object and destroys the callable. 134 | * 135 | * **Throws:** Nothing, unless invoking the callable throws. 136 | */ 137 | ~defer_guard() noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(detail::is_nothrow_invocable< Func& >::value)) 138 | { 139 | m_data.m_func(); 140 | } 141 | }; 142 | 143 | #if !defined(BOOST_NO_CXX17_DEDUCTION_GUIDES) 144 | template< typename Func > 145 | defer_guard(Func) -> defer_guard< Func >; 146 | #endif // !defined(BOOST_NO_CXX17_DEDUCTION_GUIDES) 147 | 148 | } // namespace scope 149 | 150 | //! \cond 151 | #if defined(BOOST_MSVC) 152 | #define BOOST_SCOPE_DETAIL_UNIQUE_VAR_TAG __COUNTER__ 153 | #else 154 | #define BOOST_SCOPE_DETAIL_UNIQUE_VAR_TAG __LINE__ 155 | #endif 156 | //! \endcond 157 | 158 | /*! 159 | * \brief The macro creates a uniquely named defer guard. 160 | * 161 | * The macro should be followed by a function object that should be called 162 | * on leaving the current scope. Usage example: 163 | * 164 | * ``` 165 | * BOOST_SCOPE_DEFER [] 166 | * { 167 | * std::cout << "Hello world!" << std::endl; 168 | * }; 169 | * ``` 170 | * 171 | * \note Using this macro requires C++17. 172 | */ 173 | #define BOOST_SCOPE_DEFER \ 174 | boost::scope::defer_guard BOOST_JOIN(_boost_defer_guard_, BOOST_SCOPE_DETAIL_UNIQUE_VAR_TAG) = 175 | 176 | } // namespace boost 177 | 178 | #include 179 | 180 | #endif // BOOST_SCOPE_DEFER_HPP_INCLUDED_ 181 | -------------------------------------------------------------------------------- /include/boost/scope/detail/compact_storage.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://www.boost.org/LICENSE_1_0.txt) 5 | * 6 | * Copyright (c) 2022 Andrey Semashev 7 | */ 8 | /*! 9 | * \file scope/detail/compact_storage.hpp 10 | * 11 | * This header contains utility helpers for implementing compact storage 12 | * for class members. In particular, it allows to leverage empty base optimization (EBO). 13 | */ 14 | 15 | #ifndef BOOST_SCOPE_DETAIL_COMPACT_STORAGE_HPP_INCLUDED_ 16 | #define BOOST_SCOPE_DETAIL_COMPACT_STORAGE_HPP_INCLUDED_ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #ifdef BOOST_HAS_PRAGMA_ONCE 26 | #pragma once 27 | #endif 28 | 29 | namespace boost { 30 | namespace scope { 31 | namespace detail { 32 | 33 | //! The class allows to place data members in the tail padding of type \a T if the user's class derives from it 34 | template< 35 | typename T, 36 | typename Tag = void, 37 | bool = detail::conjunction< std::is_class< T >, detail::negation< detail::is_final< T > > >::value 38 | > 39 | class compact_storage : 40 | private T 41 | { 42 | public: 43 | template< typename... Args > 44 | constexpr compact_storage(Args&&... args) noexcept(std::is_nothrow_constructible< T, Args... >::value) : 45 | T(static_cast< Args&& >(args)...) 46 | { 47 | } 48 | 49 | compact_storage(compact_storage&&) = default; 50 | compact_storage& operator= (compact_storage&&) = default; 51 | 52 | compact_storage(compact_storage const&) = default; 53 | compact_storage& operator= (compact_storage const&) = default; 54 | 55 | T& get() noexcept 56 | { 57 | return *static_cast< T* >(this); 58 | } 59 | 60 | T const& get() const noexcept 61 | { 62 | return *static_cast< const T* >(this); 63 | } 64 | }; 65 | 66 | template< typename T, typename Tag > 67 | class compact_storage< T, Tag, false > 68 | { 69 | private: 70 | T m_data; 71 | 72 | public: 73 | template< typename... Args > 74 | constexpr compact_storage(Args&&... args) noexcept(std::is_nothrow_constructible< T, Args... >::value) : 75 | m_data(static_cast< Args&& >(args)...) 76 | { 77 | } 78 | 79 | compact_storage(compact_storage&&) = default; 80 | compact_storage& operator= (compact_storage&&) = default; 81 | 82 | compact_storage(compact_storage const&) = default; 83 | compact_storage& operator= (compact_storage const&) = default; 84 | 85 | T& get() noexcept 86 | { 87 | return m_data; 88 | } 89 | 90 | T const& get() const noexcept 91 | { 92 | return m_data; 93 | } 94 | }; 95 | 96 | } // namespace detail 97 | } // namespace scope 98 | } // namespace boost 99 | 100 | #include 101 | 102 | #endif // BOOST_SCOPE_DETAIL_COMPACT_STORAGE_HPP_INCLUDED_ 103 | -------------------------------------------------------------------------------- /include/boost/scope/detail/config.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://www.boost.org/LICENSE_1_0.txt) 5 | * 6 | * Copyright (c) 2023 Andrey Semashev 7 | */ 8 | /*! 9 | * \file scope/detail/config.hpp 10 | * 11 | * This header contains Boost.Scope common configuration. 12 | */ 13 | 14 | #ifndef BOOST_SCOPE_DETAIL_CONFIG_HPP_INCLUDED_ 15 | #define BOOST_SCOPE_DETAIL_CONFIG_HPP_INCLUDED_ 16 | 17 | #include 18 | #include 19 | 20 | #ifdef BOOST_HAS_PRAGMA_ONCE 21 | #pragma once 22 | #endif 23 | 24 | #if !(defined(__cpp_noexcept_function_type) && __cpp_noexcept_function_type >= 201510l) && !defined(_NOEXCEPT_TYPES_SUPPORTED) 25 | #define BOOST_SCOPE_NO_CXX17_NOEXCEPT_FUNCTION_TYPES 26 | #endif 27 | 28 | #if !defined(BOOST_SCOPE_DETAIL_DOC_ALT) 29 | #if !defined(BOOST_SCOPE_DOXYGEN) 30 | #define BOOST_SCOPE_DETAIL_DOC_ALT(alt, ...) __VA_ARGS__ 31 | #else 32 | #define BOOST_SCOPE_DETAIL_DOC_ALT(alt, ...) alt 33 | #endif 34 | #endif 35 | 36 | #if !defined(BOOST_SCOPE_DETAIL_DOC_HIDDEN) 37 | #define BOOST_SCOPE_DETAIL_DOC_HIDDEN(...) BOOST_SCOPE_DETAIL_DOC_ALT(..., __VA_ARGS__) 38 | #endif 39 | 40 | #if !defined(BOOST_SCOPE_DETAIL_DOC) 41 | #if !defined(BOOST_SCOPE_DOXYGEN) 42 | #define BOOST_SCOPE_DETAIL_DOC(...) 43 | #else 44 | #define BOOST_SCOPE_DETAIL_DOC(...) __VA_ARGS__ 45 | #endif 46 | #endif 47 | 48 | #include 49 | 50 | #endif // BOOST_SCOPE_DETAIL_CONFIG_HPP_INCLUDED_ 51 | -------------------------------------------------------------------------------- /include/boost/scope/detail/footer.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://www.boost.org/LICENSE_1_0.txt) 5 | * 6 | * Copyright (c) 2023 Andrey Semashev 7 | */ 8 | 9 | #if !defined(BOOST_SCOPE_ENABLE_WARNINGS) 10 | 11 | #if defined(_MSC_VER) && !defined(__clang__) 12 | 13 | #pragma warning(pop) 14 | 15 | #elif (defined(__GNUC__) && !(defined(__INTEL_COMPILER) || defined(__ICL) || defined(__ICC) || defined(__ECC)) \ 16 | && (__GNUC__ * 100 + __GNUC_MINOR__) >= 406) || defined(__clang__) 17 | 18 | #pragma GCC diagnostic pop 19 | 20 | #endif 21 | 22 | #endif // !defined(BOOST_SCOPE_ENABLE_WARNINGS) 23 | -------------------------------------------------------------------------------- /include/boost/scope/detail/header.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://www.boost.org/LICENSE_1_0.txt) 5 | * 6 | * Copyright (c) 2023 Andrey Semashev 7 | */ 8 | 9 | #if !defined(BOOST_SCOPE_ENABLE_WARNINGS) 10 | 11 | #if defined(_MSC_VER) && !defined(__clang__) 12 | 13 | #pragma warning(push, 3) 14 | // unreferenced formal parameter 15 | #pragma warning(disable: 4100) 16 | // conditional expression is constant 17 | #pragma warning(disable: 4127) 18 | // function marked as __forceinline not inlined 19 | #pragma warning(disable: 4714) 20 | // decorated name length exceeded, name was truncated 21 | #pragma warning(disable: 4503) 22 | // qualifier applied to function type has no meaning; ignored 23 | #pragma warning(disable: 4180) 24 | // qualifier applied to reference type; ignored 25 | #pragma warning(disable: 4181) 26 | // unreachable code 27 | #pragma warning(disable: 4702) 28 | // destructor never returns, potential memory leak 29 | #pragma warning(disable: 4722) 30 | 31 | #elif (defined(__GNUC__) && !(defined(__INTEL_COMPILER) || defined(__ICL) || defined(__ICC) || defined(__ECC)) \ 32 | && (__GNUC__ * 100 + __GNUC_MINOR__) >= 406) || defined(__clang__) 33 | 34 | // Note: clang-cl goes here as well, as it seems to support gcc-style warning control pragmas. 35 | 36 | #pragma GCC diagnostic push 37 | // unused parameter 'arg' 38 | #pragma GCC diagnostic ignored "-Wunused-parameter" 39 | // unused function 'foo' 40 | #pragma GCC diagnostic ignored "-Wunused-function" 41 | 42 | #if defined(__clang__) 43 | // template argument uses unnamed type 44 | #pragma clang diagnostic ignored "-Wunnamed-type-template-args" 45 | #endif // defined(__clang__) 46 | 47 | #endif 48 | 49 | #endif // !defined(BOOST_SCOPE_ENABLE_WARNINGS) 50 | -------------------------------------------------------------------------------- /include/boost/scope/detail/is_nonnull_default_constructible.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://www.boost.org/LICENSE_1_0.txt) 5 | * 6 | * Copyright (c) 2023 Andrey Semashev 7 | */ 8 | /*! 9 | * \file scope/detail/is_nonnull_default_constructible.hpp 10 | * 11 | * This header contains definition of \c is_nonnull_default_constructible 12 | * and \c is_nothrow_nonnull_default_constructible type traits. The type 13 | * traits are useful for preventing default-construction of pointers to 14 | * functions where a default-constructed function object is expected. 15 | * Without it, default- or value-constructing a pointer to function would 16 | * produce a function object that is not callable. 17 | */ 18 | 19 | #ifndef BOOST_SCOPE_DETAIL_IS_NONNULL_DEFAULT_CONSTRUCTIBLE_HPP_INCLUDED_ 20 | #define BOOST_SCOPE_DETAIL_IS_NONNULL_DEFAULT_CONSTRUCTIBLE_HPP_INCLUDED_ 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | #ifdef BOOST_HAS_PRAGMA_ONCE 27 | #pragma once 28 | #endif 29 | 30 | namespace boost { 31 | namespace scope { 32 | namespace detail { 33 | 34 | //! The type trait checks if \c T is not a pointer and is default-constructible 35 | template< typename T > 36 | struct is_nonnull_default_constructible : 37 | public std::is_default_constructible< T > 38 | { 39 | }; 40 | 41 | template< typename T > 42 | struct is_nonnull_default_constructible< T* > : 43 | public std::false_type 44 | { 45 | }; 46 | 47 | //! The type trait checks if \c T is not a pointer and is nothrow-default-constructible 48 | template< typename T > 49 | struct is_nothrow_nonnull_default_constructible : 50 | public std::is_nothrow_default_constructible< T > 51 | { 52 | }; 53 | 54 | template< typename T > 55 | struct is_nothrow_nonnull_default_constructible< T* > : 56 | public std::false_type 57 | { 58 | }; 59 | 60 | } // namespace detail 61 | } // namespace scope 62 | } // namespace boost 63 | 64 | #include 65 | 66 | #endif // BOOST_SCOPE_DETAIL_IS_NONNULL_DEFAULT_CONSTRUCTIBLE_HPP_INCLUDED_ 67 | -------------------------------------------------------------------------------- /include/boost/scope/detail/is_not_like.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://www.boost.org/LICENSE_1_0.txt) 5 | * 6 | * Copyright (c) 2023 Andrey Semashev 7 | */ 8 | /*! 9 | * \file scope/detail/is_not_like.hpp 10 | * 11 | * This header contains definition of \c is_not_like type trait. 12 | */ 13 | 14 | #ifndef BOOST_SCOPE_DETAIL_IS_NOT_LIKE_HPP_INCLUDED_ 15 | #define BOOST_SCOPE_DETAIL_IS_NOT_LIKE_HPP_INCLUDED_ 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | #ifdef BOOST_HAS_PRAGMA_ONCE 22 | #pragma once 23 | #endif 24 | 25 | namespace boost { 26 | namespace scope { 27 | namespace detail { 28 | 29 | //! The type trait checks if \c T is not a possibly cv-reference-qualified specialization of \c Template 30 | template< typename T, template< typename... > class Template > 31 | struct is_not_like : public std::true_type { }; 32 | template< typename T, template< typename... > class Template > 33 | struct is_not_like< T&, Template > : public is_not_like< T, Template > { }; 34 | template< template< typename... > class Template, typename... Ts > 35 | struct is_not_like< Template< Ts... >, Template > : public std::false_type { }; 36 | template< template< typename... > class Template, typename... Ts > 37 | struct is_not_like< const Template< Ts... >, Template > : public std::false_type { }; 38 | template< template< typename... > class Template, typename... Ts > 39 | struct is_not_like< volatile Template< Ts... >, Template > : public std::false_type { }; 40 | template< template< typename... > class Template, typename... Ts > 41 | struct is_not_like< const volatile Template< Ts... >, Template > : public std::false_type { }; 42 | 43 | } // namespace detail 44 | } // namespace scope 45 | } // namespace boost 46 | 47 | #include 48 | 49 | #endif // BOOST_SCOPE_DETAIL_IS_NOT_LIKE_HPP_INCLUDED_ 50 | -------------------------------------------------------------------------------- /include/boost/scope/detail/move_or_copy_assign_ref.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://www.boost.org/LICENSE_1_0.txt) 5 | * 6 | * Copyright (c) 2022 Andrey Semashev 7 | */ 8 | /*! 9 | * \file scope/detail/move_or_copy_assign_ref.hpp 10 | * 11 | * This header contains definition of \c move_or_copy_assign_ref type trait. 12 | */ 13 | 14 | #ifndef BOOST_SCOPE_DETAIL_MOVE_OR_COPY_ASSIGN_REF_HPP_INCLUDED_ 15 | #define BOOST_SCOPE_DETAIL_MOVE_OR_COPY_ASSIGN_REF_HPP_INCLUDED_ 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | #ifdef BOOST_HAS_PRAGMA_ONCE 22 | #pragma once 23 | #endif 24 | 25 | namespace boost { 26 | namespace scope { 27 | namespace detail { 28 | 29 | //! The type trait produces an rvalue reference to \a From if \a To has a non-throwing assignment from a \a From rvalue and an lvalue reference otherwise. 30 | template< typename From, typename To = From > 31 | struct move_or_copy_assign_ref 32 | { 33 | using type = typename std::conditional< 34 | std::is_nothrow_assignable< To, From >::value, 35 | From&&, 36 | From const& 37 | >::type; 38 | }; 39 | 40 | template< typename From, typename To > 41 | struct move_or_copy_assign_ref< From&, To > 42 | { 43 | using type = From&; 44 | }; 45 | 46 | } // namespace detail 47 | } // namespace scope 48 | } // namespace boost 49 | 50 | #include 51 | 52 | #endif // BOOST_SCOPE_DETAIL_MOVE_OR_COPY_ASSIGN_REF_HPP_INCLUDED_ 53 | -------------------------------------------------------------------------------- /include/boost/scope/detail/move_or_copy_construct_ref.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://www.boost.org/LICENSE_1_0.txt) 5 | * 6 | * Copyright (c) 2022 Andrey Semashev 7 | */ 8 | /*! 9 | * \file scope/detail/move_or_copy_construct_ref.hpp 10 | * 11 | * This header contains definition of \c move_or_copy_construct_ref type trait. 12 | */ 13 | 14 | #ifndef BOOST_SCOPE_DETAIL_MOVE_OR_COPY_CONSTRUCT_REF_HPP_INCLUDED_ 15 | #define BOOST_SCOPE_DETAIL_MOVE_OR_COPY_CONSTRUCT_REF_HPP_INCLUDED_ 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | #ifdef BOOST_HAS_PRAGMA_ONCE 22 | #pragma once 23 | #endif 24 | 25 | namespace boost { 26 | namespace scope { 27 | namespace detail { 28 | 29 | //! The type trait produces an rvalue reference to \a From if \a To has a non-throwing constructor from a \a From rvalue and an lvalue reference otherwise. 30 | template< typename From, typename To = From > 31 | struct move_or_copy_construct_ref 32 | { 33 | using type = typename std::conditional< 34 | std::is_nothrow_constructible< To, From >::value, 35 | From&&, 36 | From const& 37 | >::type; 38 | }; 39 | 40 | template< typename From, typename To > 41 | struct move_or_copy_construct_ref< From&, To > 42 | { 43 | using type = From&; 44 | }; 45 | 46 | } // namespace detail 47 | } // namespace scope 48 | } // namespace boost 49 | 50 | #include 51 | 52 | #endif // BOOST_SCOPE_DETAIL_MOVE_OR_COPY_CONSTRUCT_REF_HPP_INCLUDED_ 53 | -------------------------------------------------------------------------------- /include/boost/scope/detail/type_traits/conjunction.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://www.boost.org/LICENSE_1_0.txt) 5 | * 6 | * Copyright (c) 2023 Andrey Semashev 7 | */ 8 | /*! 9 | * \file scope/detail/type_traits/conjunction.hpp 10 | * 11 | * This header contains definition of \c conjunction type trait. 12 | */ 13 | 14 | #ifndef BOOST_SCOPE_DETAIL_TYPE_TRAITS_CONJUNCTION_HPP_INCLUDED_ 15 | #define BOOST_SCOPE_DETAIL_TYPE_TRAITS_CONJUNCTION_HPP_INCLUDED_ 16 | 17 | #include 18 | #include 19 | 20 | #ifdef BOOST_HAS_PRAGMA_ONCE 21 | #pragma once 22 | #endif 23 | 24 | #if (defined(__cpp_lib_logical_traits) && (__cpp_lib_logical_traits >= 201510l)) || \ 25 | (defined(BOOST_MSSTL_VERSION) && (BOOST_MSSTL_VERSION >= 140) && (_MSC_FULL_VER >= 190023918) && (BOOST_CXX_VERSION >= 201703l)) 26 | 27 | namespace boost { 28 | namespace scope { 29 | namespace detail { 30 | 31 | using std::conjunction; 32 | 33 | } // namespace detail 34 | } // namespace scope 35 | } // namespace boost 36 | 37 | #else 38 | 39 | #include 40 | 41 | namespace boost { 42 | namespace scope { 43 | namespace detail { 44 | 45 | using boost::conjunction; 46 | 47 | } // namespace detail 48 | } // namespace scope 49 | } // namespace boost 50 | 51 | #endif 52 | 53 | #endif // BOOST_SCOPE_DETAIL_TYPE_TRAITS_CONJUNCTION_HPP_INCLUDED_ 54 | -------------------------------------------------------------------------------- /include/boost/scope/detail/type_traits/disjunction.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://www.boost.org/LICENSE_1_0.txt) 5 | * 6 | * Copyright (c) 2023 Andrey Semashev 7 | */ 8 | /*! 9 | * \file scope/detail/type_traits/disjunction.hpp 10 | * 11 | * This header contains definition of \c disjunction type trait. 12 | */ 13 | 14 | #ifndef BOOST_SCOPE_DETAIL_TYPE_TRAITS_DISJUNCTION_HPP_INCLUDED_ 15 | #define BOOST_SCOPE_DETAIL_TYPE_TRAITS_DISJUNCTION_HPP_INCLUDED_ 16 | 17 | #include 18 | #include 19 | 20 | #ifdef BOOST_HAS_PRAGMA_ONCE 21 | #pragma once 22 | #endif 23 | 24 | #if (defined(__cpp_lib_logical_traits) && (__cpp_lib_logical_traits >= 201510l)) || \ 25 | (defined(BOOST_MSSTL_VERSION) && (BOOST_MSSTL_VERSION >= 140) && (_MSC_FULL_VER >= 190023918) && (BOOST_CXX_VERSION >= 201703l)) 26 | 27 | namespace boost { 28 | namespace scope { 29 | namespace detail { 30 | 31 | using std::disjunction; 32 | 33 | } // namespace detail 34 | } // namespace scope 35 | } // namespace boost 36 | 37 | #else 38 | 39 | #include 40 | 41 | namespace boost { 42 | namespace scope { 43 | namespace detail { 44 | 45 | using boost::disjunction; 46 | 47 | } // namespace detail 48 | } // namespace scope 49 | } // namespace boost 50 | 51 | #endif 52 | 53 | #endif // BOOST_SCOPE_DETAIL_TYPE_TRAITS_DISJUNCTION_HPP_INCLUDED_ 54 | -------------------------------------------------------------------------------- /include/boost/scope/detail/type_traits/is_final.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://www.boost.org/LICENSE_1_0.txt) 5 | * 6 | * Copyright (c) 2023 Andrey Semashev 7 | */ 8 | /*! 9 | * \file scope/detail/type_traits/is_final.hpp 10 | * 11 | * This header contains definition of \c is_final type trait. 12 | */ 13 | 14 | #ifndef BOOST_SCOPE_DETAIL_TYPE_TRAITS_IS_FINAL_HPP_INCLUDED_ 15 | #define BOOST_SCOPE_DETAIL_TYPE_TRAITS_IS_FINAL_HPP_INCLUDED_ 16 | 17 | #include 18 | #include 19 | 20 | #ifdef BOOST_HAS_PRAGMA_ONCE 21 | #pragma once 22 | #endif 23 | 24 | #if (defined(__cpp_lib_is_final) && (__cpp_lib_is_final >= 201402l)) || \ 25 | (defined(BOOST_MSSTL_VERSION) && (BOOST_MSSTL_VERSION >= 140) && (BOOST_CXX_VERSION >= 201402l)) 26 | 27 | namespace boost { 28 | namespace scope { 29 | namespace detail { 30 | 31 | using std::is_final; 32 | 33 | } // namespace detail 34 | } // namespace scope 35 | } // namespace boost 36 | 37 | #else 38 | 39 | #include 40 | 41 | namespace boost { 42 | namespace scope { 43 | namespace detail { 44 | 45 | using boost::is_final; 46 | 47 | } // namespace detail 48 | } // namespace scope 49 | } // namespace boost 50 | 51 | #endif 52 | 53 | #endif // BOOST_SCOPE_DETAIL_TYPE_TRAITS_IS_FINAL_HPP_INCLUDED_ 54 | -------------------------------------------------------------------------------- /include/boost/scope/detail/type_traits/is_invocable.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://www.boost.org/LICENSE_1_0.txt) 5 | * 6 | * Copyright (c) 2023 Andrey Semashev 7 | */ 8 | /*! 9 | * \file scope/detail/type_traits/is_invocable.hpp 10 | * 11 | * This header contains definition of \c is_invocable type trait. 12 | */ 13 | 14 | #ifndef BOOST_SCOPE_DETAIL_TYPE_TRAITS_IS_INVOCABLE_HPP_INCLUDED_ 15 | #define BOOST_SCOPE_DETAIL_TYPE_TRAITS_IS_INVOCABLE_HPP_INCLUDED_ 16 | 17 | #include 18 | #include 19 | 20 | #ifdef BOOST_HAS_PRAGMA_ONCE 21 | #pragma once 22 | #endif 23 | 24 | #if (defined(__cpp_lib_is_invocable) && (__cpp_lib_is_invocable >= 201703l)) || \ 25 | (defined(BOOST_MSSTL_VERSION) && (BOOST_MSSTL_VERSION >= 140) && (BOOST_CXX_VERSION >= 201703l)) 26 | 27 | namespace boost { 28 | namespace scope { 29 | namespace detail { 30 | 31 | using std::is_invocable; 32 | 33 | } // namespace detail 34 | } // namespace scope 35 | } // namespace boost 36 | 37 | #else 38 | 39 | #include // std::declval 40 | 41 | namespace boost { 42 | namespace scope { 43 | namespace detail { 44 | 45 | // A simplified implementation that does not support member function pointers 46 | template< typename Func, typename... Args > 47 | struct is_invocable_impl 48 | { 49 | template< typename F = Func, typename = decltype(std::declval< F >()(std::declval< Args >()...)) > 50 | static std::true_type _check_invocable(int); 51 | static std::false_type _check_invocable(...); 52 | 53 | using type = decltype(is_invocable_impl::_check_invocable(0)); 54 | }; 55 | 56 | template< typename Func, typename... Args > 57 | struct is_invocable : public is_invocable_impl< Func, Args... >::type { }; 58 | 59 | } // namespace detail 60 | } // namespace scope 61 | } // namespace boost 62 | 63 | #endif 64 | 65 | #endif // BOOST_SCOPE_DETAIL_TYPE_TRAITS_IS_INVOCABLE_HPP_INCLUDED_ 66 | -------------------------------------------------------------------------------- /include/boost/scope/detail/type_traits/is_nothrow_invocable.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://www.boost.org/LICENSE_1_0.txt) 5 | * 6 | * Copyright (c) 2023 Andrey Semashev 7 | */ 8 | /*! 9 | * \file scope/detail/type_traits/is_nothrow_invocable.hpp 10 | * 11 | * This header contains definition of \c is_nothrow_invocable type trait. 12 | */ 13 | 14 | #ifndef BOOST_SCOPE_DETAIL_TYPE_TRAITS_IS_NOTHROW_INVOCABLE_HPP_INCLUDED_ 15 | #define BOOST_SCOPE_DETAIL_TYPE_TRAITS_IS_NOTHROW_INVOCABLE_HPP_INCLUDED_ 16 | 17 | #include 18 | #include 19 | 20 | #ifdef BOOST_HAS_PRAGMA_ONCE 21 | #pragma once 22 | #endif 23 | 24 | #if (defined(__cpp_lib_is_invocable) && (__cpp_lib_is_invocable >= 201703l)) || \ 25 | (defined(BOOST_MSSTL_VERSION) && (BOOST_MSSTL_VERSION >= 140) && (BOOST_CXX_VERSION >= 201703l)) 26 | 27 | namespace boost { 28 | namespace scope { 29 | namespace detail { 30 | 31 | using std::is_nothrow_invocable; 32 | 33 | } // namespace detail 34 | } // namespace scope 35 | } // namespace boost 36 | 37 | #else 38 | 39 | #include // std::declval 40 | #include 41 | 42 | namespace boost { 43 | namespace scope { 44 | namespace detail { 45 | 46 | template< bool, typename Func, typename... Args > 47 | struct is_nothrow_invocable_impl 48 | { 49 | using type = std::false_type; 50 | }; 51 | 52 | template< typename Func, typename... Args > 53 | struct is_nothrow_invocable_impl< true, Func, Args... > 54 | { 55 | using type = std::integral_constant< bool, noexcept(std::declval< Func >()(std::declval< Args >()...)) >; 56 | }; 57 | 58 | template< typename Func, typename... Args > 59 | struct is_nothrow_invocable : 60 | public is_nothrow_invocable_impl< detail::is_invocable< Func, Args... >::value, Func, Args... >::type 61 | { 62 | }; 63 | 64 | } // namespace detail 65 | } // namespace scope 66 | } // namespace boost 67 | 68 | #endif 69 | 70 | #endif // BOOST_SCOPE_DETAIL_TYPE_TRAITS_IS_NOTHROW_INVOCABLE_HPP_INCLUDED_ 71 | -------------------------------------------------------------------------------- /include/boost/scope/detail/type_traits/is_nothrow_swappable.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://www.boost.org/LICENSE_1_0.txt) 5 | * 6 | * Copyright (c) 2023 Andrey Semashev 7 | */ 8 | /*! 9 | * \file scope/detail/type_traits/is_nothrow_swappable.hpp 10 | * 11 | * This header contains definition of \c is_nothrow_swappable type trait. 12 | */ 13 | 14 | #ifndef BOOST_SCOPE_DETAIL_TYPE_TRAITS_IS_NOTHROW_SWAPPABLE_HPP_INCLUDED_ 15 | #define BOOST_SCOPE_DETAIL_TYPE_TRAITS_IS_NOTHROW_SWAPPABLE_HPP_INCLUDED_ 16 | 17 | #include 18 | #include 19 | 20 | #ifdef BOOST_HAS_PRAGMA_ONCE 21 | #pragma once 22 | #endif 23 | 24 | #if (defined(__cpp_lib_is_swappable) && (__cpp_lib_is_swappable >= 201603l)) || \ 25 | (defined(BOOST_MSSTL_VERSION) && (BOOST_MSSTL_VERSION >= 140) && (_MSC_FULL_VER >= 190024210) && (BOOST_CXX_VERSION >= 201703l)) 26 | 27 | namespace boost { 28 | namespace scope { 29 | namespace detail { 30 | 31 | using std::is_nothrow_swappable; 32 | 33 | } // namespace detail 34 | } // namespace scope 35 | } // namespace boost 36 | 37 | #else 38 | 39 | #include 40 | 41 | namespace boost { 42 | namespace scope { 43 | namespace detail { 44 | 45 | using boost::is_nothrow_swappable; 46 | 47 | } // namespace detail 48 | } // namespace scope 49 | } // namespace boost 50 | 51 | #endif 52 | 53 | #endif // BOOST_SCOPE_DETAIL_TYPE_TRAITS_IS_NOTHROW_SWAPPABLE_HPP_INCLUDED_ 54 | -------------------------------------------------------------------------------- /include/boost/scope/detail/type_traits/is_swappable.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://www.boost.org/LICENSE_1_0.txt) 5 | * 6 | * Copyright (c) 2023 Andrey Semashev 7 | */ 8 | /*! 9 | * \file scope/detail/type_traits/is_swappable.hpp 10 | * 11 | * This header contains definition of \c is_swappable type trait. 12 | */ 13 | 14 | #ifndef BOOST_SCOPE_DETAIL_TYPE_TRAITS_IS_SWAPPABLE_HPP_INCLUDED_ 15 | #define BOOST_SCOPE_DETAIL_TYPE_TRAITS_IS_SWAPPABLE_HPP_INCLUDED_ 16 | 17 | #include 18 | #include 19 | 20 | #ifdef BOOST_HAS_PRAGMA_ONCE 21 | #pragma once 22 | #endif 23 | 24 | #if (defined(__cpp_lib_is_swappable) && (__cpp_lib_is_swappable >= 201603l)) || \ 25 | (defined(BOOST_MSSTL_VERSION) && (BOOST_MSSTL_VERSION >= 140) && (_MSC_FULL_VER >= 190024210) && (BOOST_CXX_VERSION >= 201703l)) 26 | 27 | namespace boost { 28 | namespace scope { 29 | namespace detail { 30 | 31 | using std::is_swappable; 32 | 33 | } // namespace detail 34 | } // namespace scope 35 | } // namespace boost 36 | 37 | #else 38 | 39 | #include 40 | 41 | namespace boost { 42 | namespace scope { 43 | namespace detail { 44 | 45 | using boost::is_swappable; 46 | 47 | } // namespace detail 48 | } // namespace scope 49 | } // namespace boost 50 | 51 | #endif 52 | 53 | #endif // BOOST_SCOPE_DETAIL_TYPE_TRAITS_IS_SWAPPABLE_HPP_INCLUDED_ 54 | -------------------------------------------------------------------------------- /include/boost/scope/detail/type_traits/negation.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://www.boost.org/LICENSE_1_0.txt) 5 | * 6 | * Copyright (c) 2023 Andrey Semashev 7 | */ 8 | /*! 9 | * \file scope/detail/type_traits/negation.hpp 10 | * 11 | * This header contains definition of \c negation type trait. 12 | */ 13 | 14 | #ifndef BOOST_SCOPE_DETAIL_TYPE_TRAITS_NEGATION_HPP_INCLUDED_ 15 | #define BOOST_SCOPE_DETAIL_TYPE_TRAITS_NEGATION_HPP_INCLUDED_ 16 | 17 | #include 18 | #include 19 | 20 | #ifdef BOOST_HAS_PRAGMA_ONCE 21 | #pragma once 22 | #endif 23 | 24 | #if (defined(__cpp_lib_logical_traits) && (__cpp_lib_logical_traits >= 201510l)) || \ 25 | (defined(BOOST_MSSTL_VERSION) && (BOOST_MSSTL_VERSION >= 140) && (_MSC_FULL_VER >= 190023918) && (BOOST_CXX_VERSION >= 201703l)) 26 | 27 | namespace boost { 28 | namespace scope { 29 | namespace detail { 30 | 31 | using std::negation; 32 | 33 | } // namespace detail 34 | } // namespace scope 35 | } // namespace boost 36 | 37 | #else 38 | 39 | #include 40 | 41 | namespace boost { 42 | namespace scope { 43 | namespace detail { 44 | 45 | using boost::negation; 46 | 47 | } // namespace detail 48 | } // namespace scope 49 | } // namespace boost 50 | 51 | #endif 52 | 53 | #endif // BOOST_SCOPE_DETAIL_TYPE_TRAITS_NEGATION_HPP_INCLUDED_ 54 | -------------------------------------------------------------------------------- /include/boost/scope/error_code_checker.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://www.boost.org/LICENSE_1_0.txt) 5 | * 6 | * Copyright (c) 2023 Andrey Semashev 7 | */ 8 | /*! 9 | * \file scope/error_code_checker.hpp 10 | * 11 | * This header contains definition of \c error_code_checker type. 12 | */ 13 | 14 | #ifndef BOOST_SCOPE_ERROR_CODE_CHECKER_HPP_INCLUDED_ 15 | #define BOOST_SCOPE_ERROR_CODE_CHECKER_HPP_INCLUDED_ 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | #ifdef BOOST_HAS_PRAGMA_ONCE 22 | #pragma once 23 | #endif 24 | 25 | namespace boost { 26 | namespace scope { 27 | 28 | /*! 29 | * \brief A predicate for checking whether an error code indicates error. 30 | * 31 | * The predicate captures a reference to an external error code object, which it 32 | * tests for an error indication when called. The error code object must remain 33 | * valid for the whole lifetime duration of the predicate. 34 | * 35 | * For an error code object `ec`, an expression `!ec` must be valid, never throw exceptions, 36 | * and return a value contextually convertible to `bool`. If the returned value converts 37 | * to `false`, then this is taken as an error indication, and the predicate returns `true`. 38 | * Otherwise, the predicate returns `false`. 39 | * 40 | * A few examples of error code types: 41 | * 42 | * \li `std::error_code` or `boost::system::error_code`, 43 | * \li `std::expected`, `boost::outcome_v2::basic_outcome` or `boost::outcome_v2::basic_result`, 44 | * \li `int`, where the value of 0 indicates no error, 45 | * \li `bool`, where the value of `false` indicates no error, 46 | * \li `T*`, where a null pointer indicates no error. 47 | * 48 | * \tparam ErrorCode Error code type. 49 | */ 50 | template< typename ErrorCode > 51 | class error_code_checker 52 | { 53 | public: 54 | //! Predicate result type 55 | using result_type = bool; 56 | 57 | private: 58 | ErrorCode* m_error_code; 59 | 60 | public: 61 | /*! 62 | * \brief Constructs the predicate. 63 | * 64 | * Upon construction, the predicate saves a reference to the external error code object. 65 | * The referenced object must remain valid for the whole lifetime duration of the predicate. 66 | * 67 | * **Throws:** Nothing. 68 | */ 69 | explicit error_code_checker(ErrorCode& ec) noexcept : 70 | m_error_code(boost::addressof(ec)) 71 | { 72 | } 73 | 74 | /*! 75 | * \brief Checks if the error code indicates error. 76 | * 77 | * **Throws:** Nothing. 78 | * 79 | * \returns As if `!!ec`, where `ec` is the error code object passed to the predicate constructor. 80 | */ 81 | result_type operator()() const noexcept 82 | { 83 | return !!(*m_error_code); 84 | } 85 | }; 86 | 87 | /*! 88 | * \brief Creates a predicate for checking whether an exception is being thrown 89 | * 90 | * **Throws:** Nothing. 91 | */ 92 | template< typename ErrorCode > 93 | inline error_code_checker< ErrorCode > check_error_code(ErrorCode& ec) noexcept 94 | { 95 | return error_code_checker< ErrorCode >(ec); 96 | } 97 | 98 | } // namespace scope 99 | } // namespace boost 100 | 101 | #include 102 | 103 | #endif // BOOST_SCOPE_ERROR_CODE_CHECKER_HPP_INCLUDED_ 104 | -------------------------------------------------------------------------------- /include/boost/scope/exception_checker.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://www.boost.org/LICENSE_1_0.txt) 5 | * 6 | * Copyright (c) 2023 Andrey Semashev 7 | */ 8 | /*! 9 | * \file scope/exception_checker.hpp 10 | * 11 | * This header contains definition of \c exception_checker type. 12 | */ 13 | 14 | #ifndef BOOST_SCOPE_EXCEPTION_CHECKER_HPP_INCLUDED_ 15 | #define BOOST_SCOPE_EXCEPTION_CHECKER_HPP_INCLUDED_ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #ifdef BOOST_HAS_PRAGMA_ONCE 23 | #pragma once 24 | #endif 25 | 26 | namespace boost { 27 | namespace scope { 28 | 29 | /*! 30 | * \brief A predicate for checking whether an exception is being thrown. 31 | * 32 | * On construction, the predicate captures the current number of uncaught exceptions, 33 | * which it then compares with the number of uncaught exceptions at the point when it 34 | * is called. If the number increased then a new exception is detected and the predicate 35 | * returns \c true. 36 | * 37 | * \note This predicate is designed for a specific use case with scope guards created on 38 | * the stack. It is incompatible with C++20 coroutines and similar facilities (e.g. 39 | * fibers and userspace context switching), where the thread of execution may be 40 | * suspended after the predicate captures the number of uncaught exceptions and 41 | * then resumed in a different context, where the number of uncaught exceptions 42 | * has changed. Similarly, it is incompatible with usage patterns where the predicate 43 | * is cached after construction and is invoked after the thread has left the scope 44 | * where the predicate was constructed (e.g. when the predicate is stored as a class 45 | * data member or a namespace-scope variable). 46 | */ 47 | class exception_checker 48 | { 49 | public: 50 | //! Predicate result type 51 | using result_type = bool; 52 | 53 | private: 54 | unsigned int m_uncaught_count; 55 | 56 | public: 57 | /*! 58 | * \brief Constructs the predicate. 59 | * 60 | * Upon construction, the predicate saves the current number of uncaught exceptions. 61 | * This information will be used when calling the predicate to detect if a new 62 | * exception is being thrown. 63 | * 64 | * **Throws:** Nothing. 65 | */ 66 | exception_checker() noexcept : 67 | m_uncaught_count(boost::core::uncaught_exceptions()) 68 | { 69 | } 70 | 71 | /*! 72 | * \brief Checks if an exception is being thrown. 73 | * 74 | * **Throws:** Nothing. 75 | * 76 | * \returns \c true if the number of uncaught exceptions at the point of call is 77 | * greater than that at the point of construction of the predicate, 78 | * otherwise \c false. 79 | */ 80 | result_type operator()() const noexcept 81 | { 82 | const unsigned int uncaught_count = boost::core::uncaught_exceptions(); 83 | // If this assertion fails, the predicate is likely being used in an unsupported 84 | // way, where it is called in a different scope or thread context from where 85 | // it was constructed. 86 | BOOST_ASSERT((uncaught_count - m_uncaught_count) <= 1u); 87 | return uncaught_count > m_uncaught_count; 88 | } 89 | }; 90 | 91 | /*! 92 | * \brief Creates a predicate for checking whether an exception is being thrown 93 | * 94 | * **Throws:** Nothing. 95 | */ 96 | inline exception_checker check_exception() noexcept 97 | { 98 | return exception_checker(); 99 | } 100 | 101 | } // namespace scope 102 | } // namespace boost 103 | 104 | #include 105 | 106 | #endif // BOOST_SCOPE_EXCEPTION_CHECKER_HPP_INCLUDED_ 107 | -------------------------------------------------------------------------------- /include/boost/scope/fd_deleter.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://www.boost.org/LICENSE_1_0.txt) 5 | * 6 | * Copyright (c) 2023 Andrey Semashev 7 | */ 8 | /*! 9 | * \file scope/fd_deleter.hpp 10 | * 11 | * This header contains definition of a deleter function object for 12 | * POSIX-like file descriptors for use with \c unique_resource. 13 | */ 14 | 15 | #ifndef BOOST_SCOPE_FD_DELETER_HPP_INCLUDED_ 16 | #define BOOST_SCOPE_FD_DELETER_HPP_INCLUDED_ 17 | 18 | #include 19 | 20 | #if !defined(BOOST_WINDOWS) 21 | #include 22 | #if defined(hpux) || defined(_hpux) || defined(__hpux) 23 | #include 24 | #endif 25 | #else // !defined(BOOST_WINDOWS) 26 | #include 27 | #endif // !defined(BOOST_WINDOWS) 28 | 29 | #include 30 | 31 | #ifdef BOOST_HAS_PRAGMA_ONCE 32 | #pragma once 33 | #endif 34 | 35 | namespace boost { 36 | namespace scope { 37 | 38 | //! POSIX-like file descriptor deleter 39 | struct fd_deleter 40 | { 41 | using result_type = void; 42 | 43 | //! Closes the file descriptor 44 | result_type operator() (int fd) const noexcept 45 | { 46 | #if !defined(BOOST_WINDOWS) 47 | #if defined(hpux) || defined(_hpux) || defined(__hpux) 48 | // Some systems don't close the file descriptor in case if the thread is interrupted by a signal and close(2) returns EINTR. 49 | // Other (most) systems do close the file descriptor even when when close(2) returns EINTR, and attempting to close it 50 | // again could close a different file descriptor that was opened by a different thread. 51 | // 52 | // Future POSIX standards will likely fix this by introducing posix_close (see https://www.austingroupbugs.net/view.php?id=529) 53 | // and prohibiting returning EINTR from close(2), but we still have to support older systems where this new behavior is not available and close(2) 54 | // behaves differently between systems. 55 | int res; 56 | while (true) 57 | { 58 | res = ::close(fd); 59 | if (BOOST_UNLIKELY(res < 0)) 60 | { 61 | int err = errno; 62 | if (err == EINTR) 63 | continue; 64 | } 65 | 66 | break; 67 | } 68 | #else 69 | ::close(fd); 70 | #endif 71 | #else // !defined(BOOST_WINDOWS) 72 | ::_close(fd); 73 | #endif // !defined(BOOST_WINDOWS) 74 | } 75 | }; 76 | 77 | } // namespace scope 78 | } // namespace boost 79 | 80 | #include 81 | 82 | #endif // BOOST_SCOPE_FD_DELETER_HPP_INCLUDED_ 83 | -------------------------------------------------------------------------------- /include/boost/scope/fd_resource_traits.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://www.boost.org/LICENSE_1_0.txt) 5 | * 6 | * Copyright (c) 2023 Andrey Semashev 7 | */ 8 | /*! 9 | * \file scope/fd_resource_traits.hpp 10 | * 11 | * This header contains definition of \c unique_resource traits 12 | * for compatibility with POSIX-like file descriptors. 13 | */ 14 | 15 | #ifndef BOOST_SCOPE_FD_RESOURCE_TRAITS_HPP_INCLUDED_ 16 | #define BOOST_SCOPE_FD_RESOURCE_TRAITS_HPP_INCLUDED_ 17 | 18 | #include 19 | #include 20 | 21 | #ifdef BOOST_HAS_PRAGMA_ONCE 22 | #pragma once 23 | #endif 24 | 25 | namespace boost { 26 | namespace scope { 27 | 28 | //! POSIX-like file descriptor resource traits 29 | struct fd_resource_traits 30 | { 31 | //! Creates a default fd value 32 | static int make_default() noexcept 33 | { 34 | return -1; 35 | } 36 | 37 | //! Tests if the fd is allocated (valid) 38 | static bool is_allocated(int fd) noexcept 39 | { 40 | return fd >= 0; 41 | } 42 | }; 43 | 44 | } // namespace scope 45 | } // namespace boost 46 | 47 | #include 48 | 49 | #endif // BOOST_SCOPE_FD_RESOURCE_TRAITS_HPP_INCLUDED_ 50 | -------------------------------------------------------------------------------- /include/boost/scope/scope_exit.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://www.boost.org/LICENSE_1_0.txt) 5 | * 6 | * Copyright (c) 2023 Andrey Semashev 7 | */ 8 | /*! 9 | * \file scope/scope_exit.hpp 10 | * 11 | * This header contains definition of \c scope_exit template. 12 | */ 13 | 14 | #ifndef BOOST_SCOPE_SCOPE_EXIT_HPP_INCLUDED_ 15 | #define BOOST_SCOPE_SCOPE_EXIT_HPP_INCLUDED_ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #ifdef BOOST_HAS_PRAGMA_ONCE 29 | #pragma once 30 | #endif 31 | 32 | namespace boost { 33 | namespace scope { 34 | 35 | template< typename Func, typename Cond > 36 | class scope_exit; 37 | 38 | namespace detail { 39 | 40 | // Workaround for clang < 5.0 which can't pass scope_exit as a template template parameter from within scope_exit definition 41 | template< typename T > 42 | using is_not_like_scope_exit = detail::is_not_like< T, scope_exit >; 43 | 44 | //! The scope guard used to invoke the condition and action functions in case of exception during scope guard construction 45 | template< typename Func, typename Cond > 46 | class init_guard 47 | { 48 | private: 49 | Func& m_func; 50 | Cond& m_cond; 51 | bool m_active; 52 | 53 | public: 54 | init_guard(Func& func, Cond& cond, bool active) noexcept : 55 | m_func(func), 56 | m_cond(cond), 57 | m_active(active) 58 | { 59 | } 60 | 61 | init_guard(init_guard const&) = delete; 62 | init_guard& operator= (init_guard const&) = delete; 63 | 64 | ~init_guard() 65 | noexcept(detail::conjunction< 66 | detail::is_nothrow_invocable< Func& >, 67 | detail::is_nothrow_invocable< Cond& > 68 | >::value) 69 | { 70 | if (m_active && m_cond()) 71 | m_func(); 72 | } 73 | 74 | Func&& get_func() noexcept 75 | { 76 | return static_cast< Func&& >(m_func); 77 | } 78 | 79 | Cond&& get_cond() noexcept 80 | { 81 | return static_cast< Cond&& >(m_cond); 82 | } 83 | 84 | void deactivate() noexcept 85 | { 86 | m_active = false; 87 | } 88 | }; 89 | 90 | } // namespace detail 91 | 92 | /*! 93 | * \brief A predicate that always returns \c true. 94 | * 95 | * This predicate can be used as the default condition function object for 96 | * \c scope_exit and similar scope guards. 97 | */ 98 | class always_true 99 | { 100 | public: 101 | //! Predicate result type 102 | using result_type = bool; 103 | 104 | /*! 105 | * **Throws:** Nothing. 106 | * 107 | * \returns \c true. 108 | */ 109 | result_type operator()() const noexcept 110 | { 111 | return true; 112 | } 113 | }; 114 | 115 | /*! 116 | * \brief Scope exit guard that conditionally invokes a function upon leaving the scope. 117 | * 118 | * The scope guard wraps two function objects: the scope guard action and 119 | * a condition for invoking the action. Both function objects must be 120 | * callable with no arguments and can be one of: 121 | * 122 | * \li A user-defined class with a public `operator()`. 123 | * \li An lvalue reference to such class. 124 | * \li An lvalue reference or pointer to function taking no arguments. 125 | * 126 | * The condition function object `operator()` must return a value 127 | * contextually convertible to \c true, if the action function object 128 | * is allowed to be executed, and \c false otherwise. Additionally, 129 | * the condition function object `operator()` must not throw, as 130 | * otherwise the action function object may not be called. 131 | * 132 | * The condition function object is optional, and if not specified in 133 | * template parameters, the scope guard will operate as if the condition 134 | * always returns \c true. 135 | * 136 | * The scope guard can be in either active or inactive state. By default, 137 | * the constructed scope guard is active. When active, and condition 138 | * function object returns \c true, the scope guard invokes the wrapped 139 | * action function object on destruction. Otherwise, the scope guard 140 | * does not call the wrapped action function object. 141 | * 142 | * The scope guard can be made inactive by moving-from the scope guard 143 | * or calling `set_active(false)`. An inactive scope guard can be made 144 | * active by calling `set_active(true)`. If a moved-from scope guard 145 | * is active on destruction, the behavior is undefined. 146 | * 147 | * \tparam Func Scope guard action function object type. 148 | * \tparam Cond Scope guard condition function object type. 149 | */ 150 | template< typename Func, typename Cond = always_true > 151 | class scope_exit 152 | { 153 | //! \cond 154 | private: 155 | struct func_holder : 156 | public detail::compact_storage< Func > 157 | { 158 | using func_base = detail::compact_storage< Func >; 159 | 160 | template< 161 | typename F, 162 | typename C, 163 | typename = typename std::enable_if< std::is_constructible< Func, F >::value >::type 164 | > 165 | explicit func_holder(F&& func, C&& cond, bool active, std::true_type) noexcept : 166 | func_base(static_cast< F&& >(func)) 167 | { 168 | } 169 | 170 | template< 171 | typename F, 172 | typename C, 173 | typename = typename std::enable_if< std::is_constructible< Func, F >::value >::type 174 | > 175 | explicit func_holder(F&& func, C&& cond, bool active, std::false_type) : 176 | func_holder(detail::init_guard< F, C >(func, cond, active)) 177 | { 178 | } 179 | 180 | private: 181 | template< typename F, typename C > 182 | explicit func_holder(detail::init_guard< F, C >&& init) : 183 | func_base(init.get_func()) 184 | { 185 | init.deactivate(); 186 | } 187 | }; 188 | 189 | struct cond_holder : 190 | public detail::compact_storage< Cond > 191 | { 192 | using cond_base = detail::compact_storage< Cond >; 193 | 194 | template< 195 | typename C, 196 | typename = typename std::enable_if< std::is_constructible< Cond, C >::value >::type 197 | > 198 | explicit cond_holder(C&& cond, Func& func, bool active, std::true_type) noexcept : 199 | cond_base(static_cast< C&& >(cond)) 200 | { 201 | } 202 | 203 | template< 204 | typename C, 205 | typename = typename std::enable_if< std::is_constructible< Cond, C >::value >::type 206 | > 207 | explicit cond_holder(C&& cond, Func& func, bool active, std::false_type) : 208 | cond_holder(detail::init_guard< Func&, C >(func, cond, active)) 209 | { 210 | } 211 | 212 | private: 213 | template< typename C > 214 | explicit cond_holder(detail::init_guard< Func&, C >&& init) : 215 | cond_base(init.get_cond()) 216 | { 217 | init.deactivate(); 218 | } 219 | }; 220 | 221 | struct data : 222 | public func_holder, 223 | public cond_holder 224 | { 225 | bool m_active; 226 | 227 | template< 228 | typename F, 229 | typename C, 230 | typename = typename std::enable_if< detail::conjunction< 231 | std::is_constructible< func_holder, F, C, bool, typename std::is_nothrow_constructible< Func, F >::type >, 232 | std::is_constructible< cond_holder, C, Func&, bool, typename std::is_nothrow_constructible< Cond, C >::type > 233 | >::value >::type 234 | > 235 | explicit data(F&& func, C&& cond, bool active) 236 | noexcept(detail::conjunction< std::is_nothrow_constructible< Func, F >, std::is_nothrow_constructible< Cond, C > >::value) : 237 | func_holder(static_cast< F&& >(func), static_cast< C&& >(cond), active, typename std::is_nothrow_constructible< Func, F >::type()), 238 | cond_holder(static_cast< C&& >(cond), func_holder::get(), active, typename std::is_nothrow_constructible< Cond, C >::type()), 239 | m_active(active) 240 | { 241 | } 242 | 243 | Func& get_func() noexcept 244 | { 245 | return func_holder::get(); 246 | } 247 | 248 | Func const& get_func() const noexcept 249 | { 250 | return func_holder::get(); 251 | } 252 | 253 | Cond& get_cond() noexcept 254 | { 255 | return cond_holder::get(); 256 | } 257 | 258 | Cond const& get_cond() const noexcept 259 | { 260 | return cond_holder::get(); 261 | } 262 | 263 | bool deactivate() noexcept 264 | { 265 | bool active = m_active; 266 | m_active = false; 267 | return active; 268 | } 269 | }; 270 | 271 | data m_data; 272 | 273 | //! \endcond 274 | public: 275 | /*! 276 | * \brief Constructs a scope guard with a given callable action function object. 277 | * 278 | * **Requires:** \c Func is constructible from \a func. \c Cond is nothrow default-constructible 279 | * and is not a pointer to function. 280 | * 281 | * \note The requirement for \c Cond default constructor to be non-throwing is to allow for 282 | * the condition function object to be called in case if constructing either function 283 | * object throws. 284 | * 285 | * **Effects:** Constructs the scope guard as if by calling 286 | * `scope_exit(std::forward< F >(func), Cond(), active)`. 287 | * 288 | * **Throws:** Nothing, unless construction of the function objects throw. 289 | * 290 | * \param func The callable action function object to invoke on destruction. 291 | * \param active Indicates whether the scope guard should be active upon construction. 292 | * 293 | * \post `this->active() == active` 294 | */ 295 | template< 296 | typename F 297 | //! \cond 298 | , typename = typename std::enable_if< detail::conjunction< 299 | detail::is_nothrow_nonnull_default_constructible< Cond >, 300 | std::is_constructible< 301 | data, 302 | typename detail::move_or_copy_construct_ref< F, Func >::type, 303 | typename detail::move_or_copy_construct_ref< Cond >::type, 304 | bool 305 | >, 306 | detail::is_not_like_scope_exit< F > 307 | >::value >::type 308 | //! \endcond 309 | > 310 | explicit scope_exit(F&& func, bool active = true) 311 | noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN( 312 | std::is_nothrow_constructible< 313 | data, 314 | typename detail::move_or_copy_construct_ref< F, Func >::type, 315 | typename detail::move_or_copy_construct_ref< Cond >::type, 316 | bool 317 | >::value 318 | )) : 319 | m_data 320 | ( 321 | static_cast< typename detail::move_or_copy_construct_ref< F, Func >::type >(func), 322 | static_cast< typename detail::move_or_copy_construct_ref< Cond >::type >(Cond()), 323 | active 324 | ) 325 | { 326 | } 327 | 328 | /*! 329 | * \brief Constructs a scope guard with a given callable action and condition function objects. 330 | * 331 | * **Requires:** \c Func is constructible from \a func. \c Cond is constructible from \a cond. 332 | * 333 | * **Effects:** If \c Func is nothrow constructible from `F&&` then constructs \c Func from 334 | * `std::forward< F >(func)`, otherwise constructs from `func`. If \c Cond is 335 | * nothrow constructible from `C&&` then constructs \c Cond from 336 | * `std::forward< C >(cond)`, otherwise constructs from `cond`. 337 | * 338 | * If \c Func or \c Cond construction throws and \a active is \c true, invokes 339 | * \a cond and, if it returns \c true, \a func before returning with the exception. 340 | * 341 | * **Throws:** Nothing, unless construction of the function objects throw. 342 | * 343 | * \param func The callable action function object to invoke on destruction. 344 | * \param cond The callable condition function object. 345 | * \param active Indicates whether the scope guard should be active upon construction. 346 | * 347 | * \post `this->active() == active` 348 | */ 349 | template< 350 | typename F, 351 | typename C 352 | //! \cond 353 | , typename = typename std::enable_if< detail::conjunction< 354 | detail::is_invocable< C const& >, 355 | std::is_constructible< 356 | data, 357 | typename detail::move_or_copy_construct_ref< F, Func >::type, 358 | typename detail::move_or_copy_construct_ref< C, Cond >::type, 359 | bool 360 | > 361 | >::value >::type 362 | //! \endcond 363 | > 364 | explicit scope_exit(F&& func, C&& cond, bool active = true) 365 | noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN( 366 | std::is_nothrow_constructible< 367 | data, 368 | typename detail::move_or_copy_construct_ref< F, Func >::type, 369 | typename detail::move_or_copy_construct_ref< C, Cond >::type, 370 | bool 371 | >::value 372 | )) : 373 | m_data 374 | ( 375 | static_cast< typename detail::move_or_copy_construct_ref< F, Func >::type >(func), 376 | static_cast< typename detail::move_or_copy_construct_ref< C, Cond >::type >(cond), 377 | active 378 | ) 379 | { 380 | } 381 | 382 | /*! 383 | * \brief Move-constructs a scope guard. 384 | * 385 | * **Requires:** \c Func and \c Cond are nothrow move-constructible or copy-constructible. 386 | * 387 | * **Effects:** If \c Func is nothrow move-constructible then move-constructs \c Func from 388 | * a member of \a that, otherwise copy-constructs \c Func. If \c Cond is nothrow 389 | * move-constructible then move-constructs \c Cond from a member of \a that, 390 | * otherwise copy-constructs \c Cond. 391 | * 392 | * If \c Func or \c Cond construction throws and `that.active() == true`, invokes 393 | * \c Cond object stored in \a that and, if it returns \c true, \a Func object 394 | * (either the newly constructed one, if its construction succeeded, or the original 395 | * one stored in \a that) before returning with the exception. 396 | * 397 | * If the construction succeeds, marks \a that as inactive. 398 | * 399 | * **Throws:** Nothing, unless move-construction of the function objects throw. 400 | * 401 | * \param that Move source. 402 | * 403 | * \post `that.active() == false` 404 | */ 405 | //! \cond 406 | template< 407 | bool Requires = std::is_constructible< 408 | data, 409 | typename detail::move_or_copy_construct_ref< Func >::type, 410 | typename detail::move_or_copy_construct_ref< Cond >::type, 411 | bool 412 | >::value, 413 | typename = typename std::enable_if< Requires >::type 414 | > 415 | //! \endcond 416 | scope_exit(scope_exit&& that) 417 | noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN( 418 | std::is_nothrow_constructible< 419 | data, 420 | typename detail::move_or_copy_construct_ref< Func >::type, 421 | typename detail::move_or_copy_construct_ref< Cond >::type, 422 | bool 423 | >::value 424 | )) : 425 | m_data 426 | ( 427 | static_cast< typename detail::move_or_copy_construct_ref< Func >::type >(that.m_data.get_func()), 428 | static_cast< typename detail::move_or_copy_construct_ref< Cond >::type >(that.m_data.get_cond()), 429 | that.m_data.deactivate() 430 | ) 431 | { 432 | } 433 | 434 | scope_exit& operator= (scope_exit&&) = delete; 435 | 436 | scope_exit(scope_exit const&) = delete; 437 | scope_exit& operator= (scope_exit const&) = delete; 438 | 439 | /*! 440 | * \brief If `active() == true`, and invoking the condition function object returns \c true, invokes 441 | * the wrapped callable action function object. Destroys the function objects. 442 | * 443 | * **Throws:** Nothing, unless invoking a function object throws. 444 | */ 445 | ~scope_exit() 446 | noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN( 447 | detail::conjunction< 448 | detail::is_nothrow_invocable< Func& >, 449 | detail::is_nothrow_invocable< Cond& > 450 | >::value 451 | )) 452 | { 453 | if (BOOST_LIKELY(m_data.m_active && m_data.get_cond()())) 454 | m_data.get_func()(); 455 | } 456 | 457 | /*! 458 | * \brief Returns \c true if the scope guard is active, otherwise \c false. 459 | * 460 | * \note This method does not call the condition function object specified on construction. 461 | * 462 | * **Throws:** Nothing. 463 | */ 464 | bool active() const noexcept 465 | { 466 | return m_data.m_active; 467 | } 468 | 469 | /*! 470 | * \brief Activates or deactivates the scope guard. 471 | * 472 | * **Throws:** Nothing. 473 | * 474 | * \param active The active status to set. 475 | * 476 | * \post `this->active() == active` 477 | */ 478 | void set_active(bool active) noexcept 479 | { 480 | m_data.m_active = active; 481 | } 482 | }; 483 | 484 | #if !defined(BOOST_NO_CXX17_DEDUCTION_GUIDES) 485 | template< typename Func > 486 | explicit scope_exit(Func) -> scope_exit< Func >; 487 | 488 | template< typename Func > 489 | explicit scope_exit(Func, bool) -> scope_exit< Func >; 490 | 491 | template< typename Func, typename Cond > 492 | explicit scope_exit(Func, Cond) -> scope_exit< Func, Cond >; 493 | 494 | template< typename Func, typename Cond > 495 | explicit scope_exit(Func, Cond, bool) -> scope_exit< Func, Cond >; 496 | #endif // !defined(BOOST_NO_CXX17_DEDUCTION_GUIDES) 497 | 498 | /*! 499 | * \brief Creates a scope guard with a given action function object. 500 | * 501 | * **Effects:** Constructs a scope guard as if by calling 502 | * `scope_exit< std::decay_t< F > >(std::forward< F >(func), active)`. 503 | * 504 | * \param func The callable action function object to invoke on destruction. 505 | * \param active Indicates whether the scope guard should be active upon construction. 506 | */ 507 | template< typename F > 508 | inline scope_exit< typename std::decay< F >::type > make_scope_exit(F&& func, bool active = true) 509 | noexcept(std::is_nothrow_constructible< 510 | scope_exit< typename std::decay< F >::type >, 511 | F, 512 | bool 513 | >::value) 514 | { 515 | return scope_exit< typename std::decay< F >::type >(static_cast< F&& >(func), active); 516 | } 517 | 518 | /*! 519 | * \brief Creates a conditional scope guard with given callable function objects. 520 | * 521 | * **Effects:** Constructs a scope guard as if by calling 522 | * `scope_exit< std::decay_t< F >, std::decay_t< C > >( 523 | * std::forward< F >(func), std::forward< C >(cond), active)`. 524 | * 525 | * \param func The callable action function object to invoke on destruction. 526 | * \param cond The callable condition function object. 527 | * \param active Indicates whether the scope guard should be active upon construction. 528 | */ 529 | template< typename F, typename C > 530 | inline 531 | #if !defined(BOOST_SCOPE_DOXYGEN) 532 | typename std::enable_if< 533 | std::is_constructible< 534 | scope_exit< typename std::decay< F >::type, typename std::decay< C >::type >, 535 | F, 536 | C, 537 | bool 538 | >::value, 539 | scope_exit< typename std::decay< F >::type, typename std::decay< C >::type > 540 | >::type 541 | #else 542 | scope_exit< typename std::decay< F >::type, typename std::decay< C >::type > 543 | #endif 544 | make_scope_exit(F&& func, C&& cond, bool active = true) 545 | noexcept(std::is_nothrow_constructible< 546 | scope_exit< typename std::decay< F >::type, typename std::decay< C >::type >, 547 | F, 548 | C, 549 | bool 550 | >::value) 551 | { 552 | return scope_exit< typename std::decay< F >::type, typename std::decay< C >::type >(static_cast< F&& >(func), static_cast< C&& >(cond), active); 553 | } 554 | 555 | } // namespace scope 556 | } // namespace boost 557 | 558 | #include 559 | 560 | #endif // BOOST_SCOPE_SCOPE_EXIT_HPP_INCLUDED_ 561 | -------------------------------------------------------------------------------- /include/boost/scope/scope_fail.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://www.boost.org/LICENSE_1_0.txt) 5 | * 6 | * Copyright (c) 2022 Andrey Semashev 7 | */ 8 | /*! 9 | * \file scope/scope_fail.hpp 10 | * 11 | * This header contains definition of \c scope_fail template. 12 | */ 13 | 14 | #ifndef BOOST_SCOPE_SCOPE_FAIL_HPP_INCLUDED_ 15 | #define BOOST_SCOPE_SCOPE_FAIL_HPP_INCLUDED_ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #ifdef BOOST_HAS_PRAGMA_ONCE 27 | #pragma once 28 | #endif 29 | 30 | namespace boost { 31 | namespace scope { 32 | 33 | template< typename Func, typename Cond > 34 | class scope_fail; 35 | 36 | namespace detail { 37 | 38 | // Workaround for clang < 5.0 which can't pass scope_fail as a template template parameter from within scope_fail definition 39 | template< typename T > 40 | using is_not_like_scope_fail = detail::is_not_like< T, scope_fail >; 41 | 42 | } // namespace detail 43 | 44 | /*! 45 | * \brief Scope exit guard that invokes a function upon leaving the scope, if 46 | * a failure condition is satisfied. 47 | * 48 | * The scope guard wraps two function objects: the scope guard action and 49 | * a failure condition for invoking the action. Both function objects must 50 | * be callable with no arguments and can be one of: 51 | * 52 | * \li A user-defined class with a public `operator()`. 53 | * \li An lvalue reference to such class. 54 | * \li An lvalue reference or pointer to function taking no arguments. 55 | * 56 | * The condition function object `operator()` must return a value 57 | * contextually convertible to \c true, if the failure is detected and the 58 | * action function object is allowed to be executed, and \c false otherwise. 59 | * Additionally, the failure condition function object `operator()` must not 60 | * throw, as otherwise the action function object may not be called. If not 61 | * specified, the default failure condition checks whether the scope is left 62 | * due to an exception - the action function object will not be called if 63 | * the scope is left normally. 64 | * 65 | * \sa scope_exit 66 | * \sa scope_success 67 | * 68 | * \tparam Func Scope guard action function object type. 69 | * \tparam Cond Scope guard failure condition function object type. 70 | */ 71 | template< typename Func, typename Cond = exception_checker > 72 | class scope_fail : 73 | public scope_exit< Func, Cond > 74 | { 75 | //! \cond 76 | private: 77 | using base_type = scope_exit< Func, Cond >; 78 | 79 | //! \endcond 80 | public: 81 | /*! 82 | * \brief Constructs a scope guard with a given callable function object. 83 | * 84 | * **Requires:** \c Func is constructible from \a func. \c Cond is nothrow default-constructible. 85 | * 86 | * **Effects:** Constructs the scope guard as if by calling 87 | * `scope_fail(std::forward< F >(func), Cond(), active)`. 88 | * 89 | * **Throws:** Nothing, unless construction of the function objects throw. 90 | * 91 | * \param func The callable action function object to invoke on destruction. 92 | * \param active Indicates whether the scope guard should be active upon construction. 93 | * 94 | * \post `this->active() == active` 95 | */ 96 | template< 97 | typename F 98 | //! \cond 99 | , typename = typename std::enable_if< detail::conjunction< 100 | std::is_constructible< base_type, F, bool >, 101 | detail::is_not_like_scope_fail< F > 102 | >::value >::type 103 | //! \endcond 104 | > 105 | explicit scope_fail(F&& func, bool active = true) 106 | noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(std::is_nothrow_constructible< base_type, F, bool >::value)) : 107 | base_type(static_cast< F&& >(func), active) 108 | { 109 | } 110 | 111 | /*! 112 | * \brief Constructs a scope guard with a given callable action and failure condition function objects. 113 | * 114 | * **Requires:** \c Func is constructible from \a func. \c Cond is constructible from \a cond. 115 | * 116 | * **Effects:** If \c Func is nothrow constructible from `F&&` then constructs \c Func from 117 | * `std::forward< F >(func)`, otherwise constructs from `func`. If \c Cond is 118 | * nothrow constructible from `C&&` then constructs \c Cond from 119 | * `std::forward< C >(cond)`, otherwise constructs from `cond`. 120 | * 121 | * If \c Func or \c Cond construction throws and \a active is \c true, invokes 122 | * \a cond and, if it returns \c true, \a func before returning with the exception. 123 | * 124 | * **Throws:** Nothing, unless construction of the function objects throw. 125 | * 126 | * \param func The callable action function object to invoke on destruction. 127 | * \param cond The callable failure condition function object. 128 | * \param active Indicates whether the scope guard should be active upon construction. 129 | * 130 | * \post `this->active() == active` 131 | */ 132 | template< 133 | typename F, 134 | typename C 135 | //! \cond 136 | , typename = typename std::enable_if< std::is_constructible< base_type, F, C, bool >::value >::type 137 | //! \endcond 138 | > 139 | explicit scope_fail(F&& func, C&& cond, bool active = true) 140 | noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(std::is_nothrow_constructible< base_type, F, C, bool >::value)) : 141 | base_type(static_cast< F&& >(func), static_cast< C&& >(cond), active) 142 | { 143 | } 144 | 145 | /*! 146 | * \brief Move-constructs a scope guard. 147 | * 148 | * **Requires:** \c Func and \c Cond are nothrow move-constructible or copy-constructible. 149 | * 150 | * **Effects:** If \c Func is nothrow move-constructible then move-constructs \c Func from 151 | * a member of \a that, otherwise copy-constructs \c Func. If \c Cond is nothrow 152 | * move-constructible then move-constructs \c Cond from a member of \a that, 153 | * otherwise copy-constructs \c Cond. 154 | * 155 | * If \c Func or \c Cond construction throws and `that.active() == true`, invokes 156 | * \c Cond object stored in \a that and, if it returns \c true, \a Func object 157 | * (either the newly constructed one, if its construction succeeded, or the original 158 | * one stored in \a that) before returning with the exception. 159 | * 160 | * If the construction succeeds, marks \a that as inactive. 161 | * 162 | * **Throws:** Nothing, unless move-construction of the function objects throw. 163 | * 164 | * \param that Move source. 165 | * 166 | * \post `that.active() == false` 167 | */ 168 | //! \cond 169 | template< 170 | bool Requires = std::is_move_constructible< base_type >::value, 171 | typename = typename std::enable_if< Requires >::type 172 | > 173 | //! \endcond 174 | scope_fail(scope_fail&& that) 175 | noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(std::is_nothrow_move_constructible< base_type >::value)) : 176 | base_type(static_cast< base_type&& >(that)) 177 | { 178 | } 179 | 180 | scope_fail& operator= (scope_fail&&) = delete; 181 | 182 | scope_fail(scope_fail const&) = delete; 183 | scope_fail& operator= (scope_fail const&) = delete; 184 | }; 185 | 186 | #if !defined(BOOST_NO_CXX17_DEDUCTION_GUIDES) 187 | template< typename Func > 188 | explicit scope_fail(Func) -> scope_fail< Func >; 189 | 190 | template< typename Func > 191 | explicit scope_fail(Func, bool) -> scope_fail< Func >; 192 | 193 | template< 194 | typename Func, 195 | typename Cond, 196 | typename = typename std::enable_if< detail::is_invocable< Cond const& >::value >::type 197 | > 198 | explicit scope_fail(Func, Cond) -> scope_fail< Func, Cond >; 199 | 200 | template< 201 | typename Func, 202 | typename Cond, 203 | typename = typename std::enable_if< detail::is_invocable< Cond const& >::value >::type 204 | > 205 | explicit scope_fail(Func, Cond, bool) -> scope_fail< Func, Cond >; 206 | #endif // !defined(BOOST_NO_CXX17_DEDUCTION_GUIDES) 207 | 208 | /*! 209 | * \brief Creates a scope fail guard with a given action function object. 210 | * 211 | * **Effects:** Constructs a scope guard as if by calling 212 | * `scope_fail< std::decay_t< F > >(std::forward< F >(func), active)`. 213 | * 214 | * \param func The callable function object to invoke on destruction. 215 | * \param active Indicates whether the scope guard should be active upon construction. 216 | */ 217 | template< typename F > 218 | inline scope_fail< typename std::decay< F >::type > make_scope_fail(F&& func, bool active = true) 219 | noexcept(std::is_nothrow_constructible< 220 | scope_fail< typename std::decay< F >::type >, 221 | F, 222 | bool 223 | >::value) 224 | { 225 | return scope_fail< typename std::decay< F >::type >(static_cast< F&& >(func), active); 226 | } 227 | 228 | /*! 229 | * \brief Creates a scope fail with given callable function objects. 230 | * 231 | * **Effects:** Constructs a scope guard as if by calling 232 | * `scope_fail< std::decay_t< F >, std::decay_t< C > >( 233 | * std::forward< F >(func), std::forward< C >(cond), active)`. 234 | * 235 | * \param func The callable action function object to invoke on destruction. 236 | * \param cond The callable failure condition function object. 237 | * \param active Indicates whether the scope guard should be active upon construction. 238 | */ 239 | template< typename F, typename C > 240 | inline 241 | #if !defined(BOOST_SCOPE_DOXYGEN) 242 | typename std::enable_if< 243 | detail::is_invocable< C const& >::value, 244 | scope_fail< typename std::decay< F >::type, typename std::decay< C >::type > 245 | >::type 246 | #else 247 | scope_fail< typename std::decay< F >::type, typename std::decay< C >::type > 248 | #endif 249 | make_scope_fail(F&& func, C&& cond, bool active = true) 250 | noexcept(std::is_nothrow_constructible< 251 | scope_fail< typename std::decay< F >::type, typename std::decay< C >::type >, 252 | F, 253 | C, 254 | bool 255 | >::value) 256 | { 257 | return scope_fail< typename std::decay< F >::type, typename std::decay< C >::type >(static_cast< F&& >(func), static_cast< C&& >(cond), active); 258 | } 259 | 260 | } // namespace scope 261 | } // namespace boost 262 | 263 | #include 264 | 265 | #endif // BOOST_SCOPE_SCOPE_FAIL_HPP_INCLUDED_ 266 | -------------------------------------------------------------------------------- /include/boost/scope/scope_success.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://www.boost.org/LICENSE_1_0.txt) 5 | * 6 | * Copyright (c) 2022 Andrey Semashev 7 | */ 8 | /*! 9 | * \file scope/scope_success.hpp 10 | * 11 | * This header contains definition of \c scope_success template. 12 | */ 13 | 14 | #ifndef BOOST_SCOPE_SCOPE_SUCCESS_HPP_INCLUDED_ 15 | #define BOOST_SCOPE_SCOPE_SUCCESS_HPP_INCLUDED_ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #ifdef BOOST_HAS_PRAGMA_ONCE 28 | #pragma once 29 | #endif 30 | 31 | namespace boost { 32 | namespace scope { 33 | 34 | template< typename Func, typename Cond > 35 | class scope_success; 36 | 37 | namespace detail { 38 | 39 | // Workaround for clang < 5.0 which can't pass scope_success as a template template parameter from within scope_success definition 40 | template< typename T > 41 | using is_not_like_scope_success = detail::is_not_like< T, scope_success >; 42 | 43 | template< typename Func > 44 | class logical_not; 45 | 46 | template< typename T > 47 | using is_not_like_logical_not = detail::is_not_like< T, logical_not >; 48 | 49 | template< typename Func > 50 | class logical_not 51 | { 52 | public: 53 | using result_type = bool; 54 | 55 | private: 56 | Func m_func; 57 | 58 | public: 59 | template< 60 | bool Requires = std::is_default_constructible< Func >::value, 61 | typename = typename std::enable_if< Requires >::type 62 | > 63 | logical_not() noexcept(std::is_nothrow_default_constructible< Func >::value) : 64 | m_func() 65 | { 66 | } 67 | 68 | template< 69 | typename F, 70 | typename = typename std::enable_if< detail::conjunction< 71 | std::is_constructible< Func, F >, 72 | detail::is_not_like_logical_not< F > 73 | >::value >::type 74 | > 75 | explicit logical_not(F&& func) noexcept(std::is_nothrow_constructible< Func, F >::value) : 76 | m_func(static_cast< F&& >(func)) 77 | { 78 | } 79 | 80 | result_type operator()() const noexcept(detail::is_nothrow_invocable< Func const& >::value) 81 | { 82 | return !m_func(); 83 | } 84 | }; 85 | 86 | } // namespace detail 87 | 88 | /*! 89 | * \brief Scope exit guard that invokes a function upon leaving the scope, if 90 | * a failure condition is not satisfied. 91 | * 92 | * The scope guard wraps two function objects: the scope guard action and 93 | * a failure condition for invoking the action. Both function objects must 94 | * be callable with no arguments and can be one of: 95 | * 96 | * \li A user-defined class with a public `operator()`. 97 | * \li An lvalue reference to such class. 98 | * \li An lvalue reference or pointer to function taking no arguments. 99 | * 100 | * The condition function object `operator()` must return a value 101 | * contextually convertible to \c true, if the failure is detected and the 102 | * action function object is not allowed to be executed, and \c false otherwise. 103 | * Additionally, the failure condition function object `operator()` must not 104 | * throw, as otherwise the action function object may not be called. If not 105 | * specified, the default failure condition checks whether the scope is left 106 | * due to an exception - the action function object will only be called if 107 | * the scope is left normally. 108 | * 109 | * \sa scope_exit 110 | * \sa scope_fail 111 | * 112 | * \tparam Func Scope guard action function object type. 113 | * \tparam Cond Scope guard failure condition function object type. 114 | */ 115 | template< typename Func, typename Cond = exception_checker > 116 | class scope_success : 117 | public scope_exit< Func, detail::logical_not< Cond > > 118 | { 119 | //! \cond 120 | private: 121 | using base_type = scope_exit< Func, detail::logical_not< Cond > >; 122 | 123 | //! \endcond 124 | public: 125 | /*! 126 | * \brief Constructs a scope guard with a given callable function object. 127 | * 128 | * **Requires:** \c Func is constructible from \a func. \c Cond is nothrow default-constructible. 129 | * 130 | * **Effects:** Constructs the scope guard as if by calling 131 | * `scope_success(std::forward< F >(func), Cond(), active)`. 132 | * 133 | * **Throws:** Nothing, unless construction of the function objects throw. 134 | * 135 | * \param func The callable action function object to invoke on destruction. 136 | * \param active Indicates whether the scope guard should be active upon construction. 137 | * 138 | * \post `this->active() == active` 139 | */ 140 | template< 141 | typename F 142 | //! \cond 143 | , typename = typename std::enable_if< detail::conjunction< 144 | std::is_constructible< base_type, F, bool >, 145 | detail::is_not_like_scope_success< F > 146 | >::value >::type 147 | //! \endcond 148 | > 149 | explicit scope_success(F&& func, bool active = true) 150 | noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(std::is_nothrow_constructible< base_type, F, bool >::value)) : 151 | base_type(static_cast< F&& >(func), active) 152 | { 153 | } 154 | 155 | /*! 156 | * \brief Constructs a scope guard with a given callable action and failure condition function objects. 157 | * 158 | * **Requires:** \c Func is constructible from \a func. \c Cond is constructible from \a cond. 159 | * 160 | * **Effects:** If \c Func is nothrow constructible from `F&&` then constructs \c Func from 161 | * `std::forward< F >(func)`, otherwise constructs from `func`. If \c Cond is 162 | * nothrow constructible from `C&&` then constructs \c Cond from 163 | * `std::forward< C >(cond)`, otherwise constructs from `cond`. 164 | * 165 | * If \c Func or \c Cond construction throws and \a active is \c true, invokes 166 | * \a cond and, if it returns \c true, \a func before returning with the exception. 167 | * 168 | * **Throws:** Nothing, unless construction of the function objects throw. 169 | * 170 | * \param func The callable action function object to invoke on destruction. 171 | * \param cond The callable failure condition function object. 172 | * \param active Indicates whether the scope guard should be active upon construction. 173 | * 174 | * \post `this->active() == active` 175 | */ 176 | template< 177 | typename F, 178 | typename C 179 | //! \cond 180 | , typename = typename std::enable_if< std::is_constructible< base_type, F, C, bool >::value >::type 181 | //! \endcond 182 | > 183 | explicit scope_success(F&& func, C&& cond, bool active = true) 184 | noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(std::is_nothrow_constructible< base_type, F, C, bool >::value)) : 185 | base_type(static_cast< F&& >(func), static_cast< C&& >(cond), active) 186 | { 187 | } 188 | 189 | /*! 190 | * \brief Move-constructs a scope guard. 191 | * 192 | * **Requires:** \c Func and \c Cond are nothrow move-constructible or copy-constructible. 193 | * 194 | * **Effects:** If \c Func is nothrow move-constructible then move-constructs \c Func from 195 | * a member of \a that, otherwise copy-constructs \c Func. If \c Cond is nothrow 196 | * move-constructible then move-constructs \c Cond from a member of \a that, 197 | * otherwise copy-constructs \c Cond. 198 | * 199 | * If \c Func or \c Cond construction throws and `that.active() == true`, invokes 200 | * \c Cond object stored in \a that and, if it returns \c true, \a Func object 201 | * (either the newly constructed one, if its construction succeeded, or the original 202 | * one stored in \a that) before returning with the exception. 203 | * 204 | * If the construction succeeds, marks \a that as inactive. 205 | * 206 | * **Throws:** Nothing, unless move-construction of the function objects throw. 207 | * 208 | * \param that Move source. 209 | * 210 | * \post `that.active() == false` 211 | */ 212 | //! \cond 213 | template< 214 | bool Requires = std::is_move_constructible< base_type >::value, 215 | typename = typename std::enable_if< Requires >::type 216 | > 217 | //! \endcond 218 | scope_success(scope_success&& that) 219 | noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(std::is_nothrow_move_constructible< base_type >::value)) : 220 | base_type(static_cast< base_type&& >(that)) 221 | { 222 | } 223 | 224 | scope_success& operator= (scope_success&&) = delete; 225 | 226 | scope_success(scope_success const&) = delete; 227 | scope_success& operator= (scope_success const&) = delete; 228 | }; 229 | 230 | #if !defined(BOOST_NO_CXX17_DEDUCTION_GUIDES) 231 | template< typename Func > 232 | explicit scope_success(Func) -> scope_success< Func >; 233 | 234 | template< typename Func > 235 | explicit scope_success(Func, bool) -> scope_success< Func >; 236 | 237 | template< 238 | typename Func, 239 | typename Cond, 240 | typename = typename std::enable_if< detail::is_invocable< Cond const& >::value >::type 241 | > 242 | explicit scope_success(Func, Cond) -> scope_success< Func, Cond >; 243 | 244 | template< 245 | typename Func, 246 | typename Cond, 247 | typename = typename std::enable_if< detail::is_invocable< Cond const& >::value >::type 248 | > 249 | explicit scope_success(Func, Cond, bool) -> scope_success< Func, Cond >; 250 | #endif // !defined(BOOST_NO_CXX17_DEDUCTION_GUIDES) 251 | 252 | /*! 253 | * \brief Creates a scope fail guard with a given action function object. 254 | * 255 | * **Effects:** Constructs a scope guard as if by calling 256 | * `scope_success< std::decay_t< F > >(std::forward< F >(func), active)`. 257 | * 258 | * \param func The callable function object to invoke on destruction. 259 | * \param active Indicates whether the scope guard should be active upon construction. 260 | */ 261 | template< typename F > 262 | inline scope_success< typename std::decay< F >::type > make_scope_success(F&& func, bool active = true) 263 | noexcept(std::is_nothrow_constructible< 264 | scope_success< typename std::decay< F >::type >, 265 | F, 266 | bool 267 | >::value) 268 | { 269 | return scope_success< typename std::decay< F >::type >(static_cast< F&& >(func), active); 270 | } 271 | 272 | /*! 273 | * \brief Creates a scope fail with given callable function objects. 274 | * 275 | * **Effects:** Constructs a scope guard as if by calling 276 | * `scope_success< std::decay_t< F >, std::decay_t< C > >( 277 | * std::forward< F >(func), std::forward< C >(cond), active)`. 278 | * 279 | * \param func The callable action function object to invoke on destruction. 280 | * \param cond The callable failure condition function object. 281 | * \param active Indicates whether the scope guard should be active upon construction. 282 | */ 283 | template< typename F, typename C > 284 | inline 285 | #if !defined(BOOST_SCOPE_DOXYGEN) 286 | typename std::enable_if< 287 | detail::is_invocable< C const& >::value, 288 | scope_success< typename std::decay< F >::type, typename std::decay< C >::type > 289 | >::type 290 | #else 291 | scope_success< typename std::decay< F >::type, typename std::decay< C >::type > 292 | #endif 293 | make_scope_success(F&& func, C&& cond, bool active = true) 294 | noexcept(std::is_nothrow_constructible< 295 | scope_success< typename std::decay< F >::type, typename std::decay< C >::type >, 296 | F, 297 | C, 298 | bool 299 | >::value) 300 | { 301 | return scope_success< typename std::decay< F >::type, typename std::decay< C >::type >(static_cast< F&& >(func), static_cast< C&& >(cond), active); 302 | } 303 | 304 | } // namespace scope 305 | } // namespace boost 306 | 307 | #include 308 | 309 | #endif // BOOST_SCOPE_SCOPE_SUCCESS_HPP_INCLUDED_ 310 | -------------------------------------------------------------------------------- /include/boost/scope/unique_fd.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://www.boost.org/LICENSE_1_0.txt) 5 | * 6 | * Copyright (c) 2023 Andrey Semashev 7 | */ 8 | /*! 9 | * \file scope/unique_fd.hpp 10 | * 11 | * This header contains definition of \c unique_fd type. 12 | */ 13 | 14 | #ifndef BOOST_SCOPE_UNIQUE_FD_HPP_INCLUDED_ 15 | #define BOOST_SCOPE_UNIQUE_FD_HPP_INCLUDED_ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #ifdef BOOST_HAS_PRAGMA_ONCE 24 | #pragma once 25 | #endif 26 | 27 | namespace boost { 28 | namespace scope { 29 | 30 | //! Unique POSIX-like file descriptor resource 31 | using unique_fd = unique_resource< int, fd_deleter, fd_resource_traits >; 32 | 33 | } // namespace scope 34 | } // namespace boost 35 | 36 | #include 37 | 38 | #endif // BOOST_SCOPE_UNIQUE_FD_HPP_INCLUDED_ 39 | -------------------------------------------------------------------------------- /include/boost/scope/unique_resource_fwd.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://www.boost.org/LICENSE_1_0.txt) 5 | * 6 | * Copyright (c) 2022 Andrey Semashev 7 | */ 8 | /*! 9 | * \file scope/unique_resource_fwd.hpp 10 | * 11 | * This header contains forward declaration of \c unique_resource template. 12 | */ 13 | 14 | #ifndef BOOST_SCOPE_UNIQUE_RESOURCE_FWD_HPP_INCLUDED_ 15 | #define BOOST_SCOPE_UNIQUE_RESOURCE_FWD_HPP_INCLUDED_ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #ifdef BOOST_HAS_PRAGMA_ONCE 24 | #pragma once 25 | #endif 26 | 27 | namespace boost { 28 | namespace scope { 29 | 30 | template< typename Resource, typename Deleter, typename Traits = void > 31 | class unique_resource; 32 | 33 | template< typename Resource, typename Deleter, typename Invalid = typename std::decay< Resource >::type > 34 | unique_resource< typename std::decay< Resource >::type, typename std::decay< Deleter >::type > 35 | make_unique_resource_checked(Resource&& res, Invalid const& invalid, Deleter&& del) 36 | noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(detail::conjunction< 37 | std::is_nothrow_constructible< typename std::decay< Resource >::type, typename detail::move_or_copy_construct_ref< Resource, typename std::decay< Resource >::type >::type >, 38 | std::is_nothrow_constructible< typename std::decay< Deleter >::type, typename detail::move_or_copy_construct_ref< Deleter, typename std::decay< Deleter >::type >::type > 39 | >::value)); 40 | 41 | } // namespace scope 42 | } // namespace boost 43 | 44 | #include 45 | 46 | #endif // BOOST_SCOPE_UNIQUE_RESOURCE_FWD_HPP_INCLUDED_ 47 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Automatic redirection failed, please go to 7 | doc/html/index.html  
8 |

© Copyright Andrey Semashev, 2023

9 |

Distributed under the Boost Software License, Version 1.0. (See accompanying 10 | file LICENSE_1_0.txt or copy 11 | at www.boost.org/LICENSE_1_0.txt)

12 | 13 | 14 | -------------------------------------------------------------------------------- /meta/libraries.json: -------------------------------------------------------------------------------- 1 | { 2 | "key": "scope", 3 | "name": "Scope", 4 | "authors": [ 5 | "Andrey Semashev" 6 | ], 7 | "description": "A collection of scope guards and a unique_resource wrapper.", 8 | "category": [ 9 | "Emulation", 10 | "Patterns" 11 | ], 12 | "maintainers": [ 13 | "Andrey Semashev " 14 | ], 15 | "cxxstd": "11" 16 | } 17 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Peter Dimov 2 | # Copyright 2023-2024 Andrey Semashev 3 | # Distributed under the Boost Software License, Version 1.0. 4 | # See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt 5 | 6 | include(BoostTest OPTIONAL RESULT_VARIABLE HAVE_BOOST_TEST) 7 | 8 | if (NOT HAVE_BOOST_TEST) 9 | return() 10 | endif() 11 | 12 | set(BOOST_TEST_LINK_LIBRARIES Boost::scope) 13 | include_directories(common) 14 | 15 | set(BOOST_TEST_COMPILE_FEATURES 16 | cxx_nullptr 17 | cxx_lambdas 18 | cxx_auto_type 19 | cxx_uniform_initialization 20 | ) 21 | 22 | if (WIN32) 23 | set(BOOST_TEST_COMPILE_DEFINITIONS "_CRT_SECURE_NO_WARNINGS" "_CRT_SECURE_NO_DEPRECATE") 24 | endif() 25 | 26 | if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang") 27 | set(BOOST_TEST_COMPILE_OPTIONS "-Wall" "-Wextra" "-Werror") 28 | elseif (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") 29 | set(BOOST_TEST_COMPILE_OPTIONS "/W4" "/WX") 30 | endif() 31 | 32 | file(GLOB RUN_TESTS LIST_DIRECTORIES OFF CONFIGURE_DEPENDS run/*.cpp) 33 | 34 | foreach(TEST IN LISTS RUN_TESTS) 35 | boost_test(TYPE run SOURCES ${TEST}) 36 | endforeach() 37 | 38 | unset(BOOST_TEST_COMPILE_OPTIONS) 39 | 40 | file(GLOB COMPILE_TESTS LIST_DIRECTORIES OFF CONFIGURE_DEPENDS compile/*.cpp) 41 | 42 | foreach(TEST IN LISTS COMPILE_TESTS) 43 | if("${TEST}" STREQUAL "${CMAKE_CURRENT_LIST_DIR}/compile/self_contained_header.cpp") 44 | continue() 45 | endif() 46 | 47 | boost_test(TYPE compile SOURCES ${TEST}) 48 | endforeach() 49 | 50 | file(GLOB COMPILE_FAIL_TESTS LIST_DIRECTORIES OFF CONFIGURE_DEPENDS compile_fail/*.cpp) 51 | 52 | foreach(TEST IN LISTS COMPILE_FAIL_TESTS) 53 | boost_test(TYPE compile-fail SOURCES ${TEST}) 54 | endforeach() 55 | -------------------------------------------------------------------------------- /test/Jamfile: -------------------------------------------------------------------------------- 1 | # Copyright 2023-2025 Andrey Semashev 2 | # 3 | # Distributed under the Boost Software License, Version 1.0. 4 | # (See accompanying file LICENSE_1_0.txt or copy at 5 | # https://www.boost.org/LICENSE_1_0.txt) 6 | 7 | require-b2 5.0.1 ; 8 | 9 | import testing ; 10 | import path ; 11 | import regex ; 12 | import os ; 13 | import-search /boost/config/checks ; 14 | import config : requires ; 15 | 16 | project 17 | : requirements 18 | /boost/scope//boost_scope 19 | common 20 | 21 | 1024 22 | 23 | [ requires 24 | exceptions 25 | cxx11_nullptr 26 | cxx11_lambdas 27 | cxx11_decltype 28 | cxx11_noexcept 29 | cxx11_constexpr 30 | cxx11_template_aliases 31 | cxx11_rvalue_references 32 | cxx11_auto_declarations 33 | cxx11_unified_initialization_syntax 34 | cxx11_defaulted_functions 35 | cxx11_deleted_functions 36 | cxx11_hdr_system_error 37 | ] 38 | 39 | windows:_CRT_SECURE_NO_WARNINGS 40 | windows:_CRT_SECURE_NO_DEPRECATE 41 | ; 42 | 43 | path-constant SCOPE_INCLUDE_DIR : ../include ; 44 | 45 | # this rule enumerates through all the sources and invokes 46 | # the run rule for each source, the result is a list of all 47 | # the run rules, which we can pass on to the test_suite rule: 48 | rule test_all 49 | { 50 | local all_rules ; 51 | local file ; 52 | 53 | if ! [ os.environ BOOST_SCOPE_TEST_WITHOUT_SELF_CONTAINED_HEADER_TESTS ] 54 | { 55 | local headers_path = [ path.make $(SCOPE_INCLUDE_DIR)/boost/scope ] ; 56 | for file in [ path.glob-tree $(headers_path) : *.hpp : detail ] 57 | { 58 | local rel_file = [ path.relative-to $(headers_path) $(file) ] ; 59 | # Note: The test name starts with '~' in order to group these tests in the test report table, preferably at the end. 60 | # All '/' are replaced with '-' because apparently test scripts have a problem with test names containing slashes. 61 | local test_name = [ regex.replace ~hdr/$(rel_file) "/" "-" ] ; 62 | #ECHO $(rel_file) ; 63 | all_rules += [ compile compile/self_contained_header.cpp : "BOOST_SCOPE_TEST_HEADER=$(rel_file)" $(file) : $(test_name) ] ; 64 | } 65 | } 66 | 67 | for file in [ glob compile/*.cpp ] 68 | { 69 | if [ path.basename $(file) ] != "self_contained_header.cpp" 70 | { 71 | all_rules += [ compile $(file) ] ; 72 | } 73 | } 74 | for file in [ glob compile_fail/*.cpp ] 75 | { 76 | all_rules += [ compile-fail $(file) ] ; 77 | } 78 | for file in [ glob run/*.cpp ] 79 | { 80 | all_rules += [ run $(file) : : : 81 | extra 82 | msvc:on 83 | clang:on 84 | gcc:on 85 | ] ; 86 | } 87 | 88 | #ECHO All rules: $(all_rules) ; 89 | return $(all_rules) ; 90 | } 91 | 92 | test-suite scope : [ test_all ] ; 93 | -------------------------------------------------------------------------------- /test/common/function_types.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://www.boost.org/LICENSE_1_0.txt) 5 | * 6 | * Copyright (c) 2023 Andrey Semashev 7 | */ 8 | /*! 9 | * \file function_types.hpp 10 | * \author Andrey Semashev 11 | * 12 | * \brief This file contains various function types for scope guard tests. 13 | */ 14 | 15 | #ifndef BOOST_SCOPE_TESTS_COMMON_FUNCTION_TYPES_H_INCLUDED_ 16 | #define BOOST_SCOPE_TESTS_COMMON_FUNCTION_TYPES_H_INCLUDED_ 17 | 18 | #include 19 | 20 | struct normal_func 21 | { 22 | int* m_n; 23 | 24 | explicit normal_func(int& n) noexcept : 25 | m_n(&n) 26 | { 27 | } 28 | 29 | void operator()() const noexcept 30 | { 31 | ++(*m_n); 32 | } 33 | }; 34 | 35 | struct moveable_only_func 36 | { 37 | int* m_n; 38 | 39 | explicit moveable_only_func(int& n) noexcept : 40 | m_n(&n) 41 | { 42 | } 43 | 44 | moveable_only_func(moveable_only_func const&) = delete; 45 | moveable_only_func& operator= (moveable_only_func const&) = delete; 46 | 47 | moveable_only_func(moveable_only_func&&) = default; 48 | moveable_only_func& operator= (moveable_only_func&&) = default; 49 | 50 | void operator()() const noexcept 51 | { 52 | ++(*m_n); 53 | } 54 | }; 55 | 56 | struct throw_on_copy_func 57 | { 58 | int* m_n; 59 | 60 | explicit throw_on_copy_func(int& n) noexcept : 61 | m_n(&n) 62 | { 63 | } 64 | 65 | throw_on_copy_func(throw_on_copy_func const&) 66 | { 67 | throw std::runtime_error("throw_on_copy_func copy ctor"); 68 | } 69 | 70 | throw_on_copy_func& operator= (throw_on_copy_func const&) = delete; 71 | 72 | void operator()() const noexcept 73 | { 74 | ++(*m_n); 75 | } 76 | }; 77 | 78 | struct throw_on_move_func 79 | { 80 | int* m_n; 81 | 82 | explicit throw_on_move_func(int& n) noexcept : 83 | m_n(&n) 84 | { 85 | } 86 | 87 | throw_on_move_func(throw_on_move_func const&) = default; 88 | throw_on_move_func& operator= (throw_on_move_func const&) = delete; 89 | 90 | throw_on_move_func(throw_on_move_func&&) 91 | { 92 | throw std::runtime_error("throw_on_move_func move ctor"); 93 | } 94 | 95 | throw_on_move_func& operator= (throw_on_move_func&&) = delete; 96 | 97 | void operator()() const noexcept 98 | { 99 | ++(*m_n); 100 | } 101 | }; 102 | 103 | struct throw_on_call_func 104 | { 105 | int* m_n; 106 | bool* m_destroyed; 107 | 108 | explicit throw_on_call_func(int& n, bool& destroyed) noexcept : 109 | m_n(&n), 110 | m_destroyed(&destroyed) 111 | { 112 | } 113 | 114 | ~throw_on_call_func() 115 | { 116 | *m_destroyed = true; 117 | } 118 | 119 | void operator()() const 120 | { 121 | ++(*m_n); 122 | throw std::runtime_error("throw_on_call_func call"); 123 | } 124 | }; 125 | 126 | #endif // BOOST_SCOPE_TESTS_COMMON_FUNCTION_TYPES_H_INCLUDED_ 127 | -------------------------------------------------------------------------------- /test/compile/self_contained_header.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://www.boost.org/LICENSE_1_0.txt) 5 | * 6 | * Copyright (c) 2023 Andrey Semashev 7 | */ 8 | /*! 9 | * \file self_contained_header.cpp 10 | * \author Andrey Semashev 11 | * 12 | * \brief This file contains a test boilerplate for checking that every public header is self-contained and does not have any missing #includes. 13 | */ 14 | 15 | #define BOOST_SCOPE_TEST_INCLUDE_HEADER() 16 | 17 | #include BOOST_SCOPE_TEST_INCLUDE_HEADER() 18 | 19 | int main(int, char*[]) 20 | { 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /test/compile/unallocated_resource_win_invalid_handle_value.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://www.boost.org/LICENSE_1_0.txt) 5 | * 6 | * Copyright (c) 2024 Andrey Semashev 7 | */ 8 | /*! 9 | * \file unallocated_resource_win_invalid_handle_value.cpp 10 | * \author Andrey Semashev 11 | * 12 | * \brief This file tests that \c unallocated_resource supports 13 | * \c INVALID_HANDLE_VALUE on Windows, as is described in the docs. 14 | * 15 | * This code relies on MSVC-specific behavior, which allows* \c INVALID_HANDLE_VALUE 16 | * to be specified in non-type template parameters. 17 | */ 18 | 19 | #include 20 | 21 | #if defined(BOOST_WINDOWS) && defined(BOOST_MSVC) && \ 22 | !defined(BOOST_NO_CXX17_FOLD_EXPRESSIONS) && !defined(BOOST_NO_CXX17_AUTO_NONTYPE_TEMPLATE_PARAMS) 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | int main() 30 | { 31 | boost::scope::unique_resource< 32 | HANDLE, 33 | boost::core::functor< CloseHandle >, 34 | boost::scope::unallocated_resource< INVALID_HANDLE_VALUE, (HANDLE)NULL > 35 | > ur; 36 | (void)ur; 37 | 38 | return 0; 39 | } 40 | 41 | #else // defined(BOOST_WINDOWS) ... 42 | 43 | #include 44 | 45 | BOOST_PRAGMA_MESSAGE("Skipping test because it is not supported on the platform/compiler/C++ version.") 46 | 47 | int main() 48 | { 49 | } 50 | 51 | #endif // defined(BOOST_WINDOWS) ... 52 | -------------------------------------------------------------------------------- /test/compile_fail/defer_guard_noncopyable.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://www.boost.org/LICENSE_1_0.txt) 5 | * 6 | * Copyright (c) 2023 Andrey Semashev 7 | */ 8 | /*! 9 | * \file defer_guard_noncopyable.cpp 10 | * \author Andrey Semashev 11 | * 12 | * \brief This file tests that \c defer_guard is noncopyable. 13 | */ 14 | 15 | #include 16 | #include "function_types.hpp" 17 | 18 | int main() 19 | { 20 | int n = 0; 21 | boost::scope::defer_guard< normal_func > guard1{ normal_func(n) }; 22 | boost::scope::defer_guard< normal_func > guard2 = guard1; 23 | 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /test/compile_fail/defer_guard_nonmoveable.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://www.boost.org/LICENSE_1_0.txt) 5 | * 6 | * Copyright (c) 2023 Andrey Semashev 7 | */ 8 | /*! 9 | * \file defer_guard_nonmoveable.cpp 10 | * \author Andrey Semashev 11 | * 12 | * \brief This file tests that \c defer_guard is nonmoveable. 13 | */ 14 | 15 | #include 16 | #include 17 | #include "function_types.hpp" 18 | 19 | int main() 20 | { 21 | int n = 0; 22 | boost::scope::defer_guard< normal_func > guard1{ normal_func(n) }; 23 | boost::scope::defer_guard< normal_func > guard2 = std::move(guard1); 24 | 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /test/compile_fail/scope_exit_cond_def_cted_fptr.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://www.boost.org/LICENSE_1_0.txt) 5 | * 6 | * Copyright (c) 2023 Andrey Semashev 7 | */ 8 | /*! 9 | * \file scope_exit_cond_def_cted_fptr.cpp 10 | * \author Andrey Semashev 11 | * 12 | * \brief This file tests that \c scope_exit with a function pointer 13 | * condition function object cannot be default-constructed. 14 | */ 15 | 16 | #include 17 | #include "function_types.hpp" 18 | 19 | int main() 20 | { 21 | int n = 0; 22 | boost::scope::scope_exit< normal_func, bool (*)() > guard{ normal_func(n) }; 23 | 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /test/compile_fail/scope_exit_noncopyable.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://www.boost.org/LICENSE_1_0.txt) 5 | * 6 | * Copyright (c) 2023 Andrey Semashev 7 | */ 8 | /*! 9 | * \file scope_exit_noncopyable.cpp 10 | * \author Andrey Semashev 11 | * 12 | * \brief This file tests that \c scope_exit is noncopyable. 13 | */ 14 | 15 | #include 16 | #include "function_types.hpp" 17 | 18 | int main() 19 | { 20 | int n = 0; 21 | boost::scope::scope_exit< normal_func > guard1{ normal_func(n) }; 22 | boost::scope::scope_exit< normal_func > guard2 = guard1; 23 | 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /test/compile_fail/scope_fail_noncopyable.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://www.boost.org/LICENSE_1_0.txt) 5 | * 6 | * Copyright (c) 2023 Andrey Semashev 7 | */ 8 | /*! 9 | * \file scope_fail_noncopyable.cpp 10 | * \author Andrey Semashev 11 | * 12 | * \brief This file tests that \c scope_fail is noncopyable. 13 | */ 14 | 15 | #include 16 | #include "function_types.hpp" 17 | 18 | int main() 19 | { 20 | int n = 0; 21 | boost::scope::scope_fail< normal_func > guard1{ normal_func(n) }; 22 | boost::scope::scope_fail< normal_func > guard2 = guard1; 23 | 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /test/compile_fail/scope_success_noncopyable.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://www.boost.org/LICENSE_1_0.txt) 5 | * 6 | * Copyright (c) 2023 Andrey Semashev 7 | */ 8 | /*! 9 | * \file scope_success_noncopyable.cpp 10 | * \author Andrey Semashev 11 | * 12 | * \brief This file tests that \c scope_exit is noncopyable. 13 | */ 14 | 15 | #include 16 | #include "function_types.hpp" 17 | 18 | int main() 19 | { 20 | int n = 0; 21 | boost::scope::scope_success< normal_func > guard1{ normal_func(n) }; 22 | boost::scope::scope_success< normal_func > guard2 = guard1; 23 | 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /test/compile_fail/unique_resource_bad_rtraits_isalloc_throwing.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://www.boost.org/LICENSE_1_0.txt) 5 | * 6 | * Copyright (c) 2024 Andrey Semashev 7 | */ 8 | /*! 9 | * \file unique_resource_bad_rtraits_isalloc_throwing.cpp 10 | * \author Andrey Semashev 11 | * 12 | * \brief This file tests that \c unique_resource rejects resource 13 | * traits where `is_allocated` is not `noexcept`. 14 | */ 15 | 16 | #include 17 | 18 | struct resource 19 | { 20 | resource(int) noexcept {} 21 | resource& operator= (int) noexcept { return *this; }; 22 | }; 23 | 24 | struct resource_deleter 25 | { 26 | using result_type = void; 27 | result_type operator() (resource const&) const noexcept {} 28 | }; 29 | 30 | struct bad_resource_traits 31 | { 32 | static int make_default() noexcept { return 10; } 33 | static bool is_allocated(resource const& res) { return false; } 34 | }; 35 | 36 | int main() 37 | { 38 | boost::scope::unique_resource< resource, resource_deleter, bad_resource_traits > ur; 39 | 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /test/compile_fail/unique_resource_bad_rtraits_mkdef_nonassignable.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://www.boost.org/LICENSE_1_0.txt) 5 | * 6 | * Copyright (c) 2024 Andrey Semashev 7 | */ 8 | /*! 9 | * \file unique_resource_bad_rtraits_mkdef_nonassignable.cpp 10 | * \author Andrey Semashev 11 | * 12 | * \brief This file tests that \c unique_resource rejects resource 13 | * traits where the resource cannot be assigned from the 14 | * result of `make_default`. 15 | */ 16 | 17 | #include 18 | 19 | struct resource 20 | { 21 | resource(int) noexcept {} 22 | resource& operator= (int) = delete; 23 | }; 24 | 25 | struct resource_deleter 26 | { 27 | using result_type = void; 28 | result_type operator() (resource const&) const noexcept {} 29 | }; 30 | 31 | struct bad_resource_traits 32 | { 33 | static int make_default() noexcept { return 10; } 34 | static bool is_allocated(resource const& res) noexcept { return false; } 35 | }; 36 | 37 | int main() 38 | { 39 | boost::scope::unique_resource< resource, resource_deleter, bad_resource_traits > ur; 40 | 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /test/compile_fail/unique_resource_bad_rtraits_mkdef_nonconstructible.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://www.boost.org/LICENSE_1_0.txt) 5 | * 6 | * Copyright (c) 2024 Andrey Semashev 7 | */ 8 | /*! 9 | * \file unique_resource_bad_rtraits_mkdef_nonconstructible.cpp 10 | * \author Andrey Semashev 11 | * 12 | * \brief This file tests that \c unique_resource rejects resource 13 | * traits where the resource cannot be constructed from the 14 | * result of `make_default`. 15 | */ 16 | 17 | #include 18 | 19 | struct resource 20 | { 21 | resource(int) = delete; 22 | resource& operator= (int) noexcept { return *this; } 23 | }; 24 | 25 | struct resource_deleter 26 | { 27 | using result_type = void; 28 | result_type operator() (resource const&) const noexcept {} 29 | }; 30 | 31 | struct bad_resource_traits 32 | { 33 | static int make_default() noexcept { return 10; } 34 | static bool is_allocated(resource const& res) noexcept { return false; } 35 | }; 36 | 37 | int main() 38 | { 39 | boost::scope::unique_resource< resource, resource_deleter, bad_resource_traits > ur; 40 | 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /test/compile_fail/unique_resource_bad_rtraits_mkdef_throwing.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://www.boost.org/LICENSE_1_0.txt) 5 | * 6 | * Copyright (c) 2024 Andrey Semashev 7 | */ 8 | /*! 9 | * \file unique_resource_bad_rtraits_mkdef_throwing.cpp 10 | * \author Andrey Semashev 11 | * 12 | * \brief This file tests that \c unique_resource rejects resource 13 | * traits where `make_default` is not `noexcept`. 14 | */ 15 | 16 | #include 17 | 18 | struct resource 19 | { 20 | resource(int) noexcept {} 21 | resource& operator= (int) noexcept { return *this; }; 22 | }; 23 | 24 | struct resource_deleter 25 | { 26 | using result_type = void; 27 | result_type operator() (resource const&) const noexcept {} 28 | }; 29 | 30 | struct bad_resource_traits 31 | { 32 | static int make_default() { return 10; } 33 | static bool is_allocated(resource const& res) noexcept { return false; } 34 | }; 35 | 36 | int main() 37 | { 38 | boost::scope::unique_resource< resource, resource_deleter, bad_resource_traits > ur; 39 | 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /test/compile_fail/unique_resource_bad_rtraits_reduced_mkdef_nonconstructible.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://www.boost.org/LICENSE_1_0.txt) 5 | * 6 | * Copyright (c) 2024 Andrey Semashev 7 | */ 8 | /*! 9 | * \file unique_resource_bad_rtraits_mkdef_nonconstructible.cpp 10 | * \author Andrey Semashev 11 | * 12 | * \brief This file tests that \c unique_resource rejects reduced 13 | * resource traits where the resource cannot be constructed 14 | * from the result of `make_default`. 15 | */ 16 | 17 | #include 18 | 19 | struct resource 20 | { 21 | resource(int) = delete; 22 | resource& operator= (int) noexcept { return *this; } 23 | }; 24 | 25 | struct resource_deleter 26 | { 27 | using result_type = void; 28 | result_type operator() (resource const&) const noexcept {} 29 | }; 30 | 31 | struct bad_resource_traits 32 | { 33 | static int make_default() noexcept { return 10; } 34 | }; 35 | 36 | int main() 37 | { 38 | boost::scope::unique_resource< resource, resource_deleter, bad_resource_traits > ur; 39 | 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /test/compile_fail/unique_resource_del_def_cted_fptr.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://www.boost.org/LICENSE_1_0.txt) 5 | * 6 | * Copyright (c) 2023 Andrey Semashev 7 | */ 8 | /*! 9 | * \file unique_resource_del_def_cted_fptr.cpp 10 | * \author Andrey Semashev 11 | * 12 | * \brief This file tests that \c unique_resource with a function pointer 13 | * deleter cannot be default-constructed. 14 | */ 15 | 16 | #include 17 | 18 | int main() 19 | { 20 | boost::scope::unique_resource< int, void (*)(int) > ur; 21 | 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /test/compile_fail/unique_resource_non_deducible_def_res.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://www.boost.org/LICENSE_1_0.txt) 5 | * 6 | * Copyright (c) 2023 Andrey Semashev 7 | */ 8 | /*! 9 | * \file unique_resource_non_deducible_def_res.cpp 10 | * \author Andrey Semashev 11 | * 12 | * \brief This file tests that \c unique_resource template parameters are not deducible from \c default_resource keyword. 13 | */ 14 | 15 | #include 16 | 17 | struct nop_resource_deleter 18 | { 19 | template< typename Resource > 20 | void operator() (Resource const& res) const noexcept 21 | { 22 | } 23 | }; 24 | 25 | int main() 26 | { 27 | boost::scope::unique_resource ur{ boost::scope::default_resource, nop_resource_deleter() }; 28 | 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /test/compile_fail/unique_resource_noncopyable.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://www.boost.org/LICENSE_1_0.txt) 5 | * 6 | * Copyright (c) 2023 Andrey Semashev 7 | */ 8 | /*! 9 | * \file unique_resource_noncopyable.cpp 10 | * \author Andrey Semashev 11 | * 12 | * \brief This file tests that \c unique_resource is noncopyable. 13 | */ 14 | 15 | #include 16 | 17 | template< typename Resource > 18 | struct empty_resource_deleter 19 | { 20 | void operator() (Resource const& res) const noexcept 21 | { 22 | } 23 | }; 24 | 25 | int main() 26 | { 27 | boost::scope::unique_resource< int, empty_resource_deleter< int > > ur1{ 10, empty_resource_deleter< int >() }; 28 | boost::scope::unique_resource< int, empty_resource_deleter< int > > ur2 = ur1; 29 | 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /test/compile_fail/unique_resource_ref_ctor_rv.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://www.boost.org/LICENSE_1_0.txt) 5 | * 6 | * Copyright (c) 2023 Andrey Semashev 7 | */ 8 | /*! 9 | * \file unique_resource_ref_ctor_rv.cpp 10 | * \author Andrey Semashev 11 | * 12 | * \brief This file tests that \c unique_resource for reference types is not constructible from rvalues. 13 | */ 14 | 15 | #include 16 | 17 | template< typename Resource > 18 | struct empty_resource_deleter 19 | { 20 | void operator() (Resource const& res) const noexcept 21 | { 22 | } 23 | }; 24 | 25 | int main() 26 | { 27 | boost::scope::unique_resource< int const&, empty_resource_deleter< int const& > > ur1{ 10, empty_resource_deleter< int const& >() }; 28 | 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /test/compile_fail/unique_resource_ref_reset_rv.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://www.boost.org/LICENSE_1_0.txt) 5 | * 6 | * Copyright (c) 2023 Andrey Semashev 7 | */ 8 | /*! 9 | * \file unique_resource_ref_reset_rv.cpp 10 | * \author Andrey Semashev 11 | * 12 | * \brief This file tests that \c unique_resource for reference types does not accept rvalues in \c reset(). 13 | */ 14 | 15 | #include 16 | 17 | template< typename Resource > 18 | struct empty_resource_deleter 19 | { 20 | void operator() (Resource const& res) const noexcept 21 | { 22 | } 23 | }; 24 | 25 | int main() 26 | { 27 | int res = 10; 28 | boost::scope::unique_resource< int const&, empty_resource_deleter< int const& > > ur1{ res, empty_resource_deleter< int const& >() }; 29 | ur1.reset(20); 30 | 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /test/run/defer_guard.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://www.boost.org/LICENSE_1_0.txt) 5 | * 6 | * Copyright (c) 2023-2024 Andrey Semashev 7 | */ 8 | /*! 9 | * \file defer_guard.cpp 10 | * \author Andrey Semashev 11 | * 12 | * \brief This file contains tests for \c defer_guard. 13 | */ 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include "function_types.hpp" 22 | 23 | #if defined(_MSC_VER) && !defined(__clang__) 24 | // warning C4702: unreachable code 25 | // This warning is triggered by tests that unconditionally throw exception at some point 26 | // and have code after that (e.g. parts of scope guard constructor and a check that verifies 27 | // that the following code is not reached). 28 | #pragma warning(disable: 4702) 29 | #endif 30 | 31 | int g_n = 0; 32 | 33 | void check_normal() 34 | { 35 | int n = 0; 36 | { 37 | boost::scope::defer_guard< normal_func > guard{ normal_func(n) }; 38 | } 39 | BOOST_TEST_EQ(n, 1); 40 | 41 | n = 0; 42 | { 43 | normal_func func(n); 44 | boost::scope::defer_guard< normal_func& > guard(func); 45 | } 46 | BOOST_TEST_EQ(n, 1); 47 | 48 | struct local 49 | { 50 | static void raw_func() 51 | { 52 | ++g_n; 53 | } 54 | }; 55 | 56 | g_n = 0; 57 | { 58 | boost::scope::defer_guard< void (&)() > guard(local::raw_func); 59 | } 60 | BOOST_TEST_EQ(g_n, 1); 61 | } 62 | 63 | void check_throw() 64 | { 65 | int n = 0; 66 | try 67 | { 68 | boost::scope::defer_guard< normal_func > guard{ normal_func(n) }; 69 | throw std::runtime_error("error"); 70 | } 71 | catch (...) {} 72 | BOOST_TEST_EQ(n, 1); 73 | 74 | n = 0; 75 | try 76 | { 77 | boost::scope::defer_guard< throw_on_copy_func > guard{ throw_on_copy_func(n) }; 78 | BOOST_ERROR("An exception is expected to be thrown by throw_on_copy_func"); 79 | } 80 | catch (...) {} 81 | BOOST_TEST_EQ(n, 1); 82 | 83 | n = 0; 84 | try 85 | { 86 | boost::scope::defer_guard< throw_on_move_func > guard{ throw_on_move_func(n) }; 87 | } 88 | catch (...) 89 | { 90 | BOOST_ERROR("An exception is not expected to be thrown by throw_on_move_func (copy ctor should be used)"); 91 | } 92 | BOOST_TEST_EQ(n, 1); 93 | 94 | n = 0; 95 | bool scope_ended = false, exception_thrown = false, func_destroyed = false; 96 | try 97 | { 98 | boost::scope::defer_guard< throw_on_call_func > guard{ throw_on_call_func(n, func_destroyed) }; 99 | func_destroyed = false; 100 | scope_ended = true; 101 | } 102 | catch (...) 103 | { 104 | exception_thrown = true; 105 | } 106 | BOOST_TEST_EQ(n, 1); 107 | BOOST_TEST(scope_ended); 108 | BOOST_TEST(exception_thrown); 109 | BOOST_TEST(func_destroyed); 110 | } 111 | 112 | void check_deduction() 113 | { 114 | #if !defined(BOOST_NO_CXX17_DEDUCTION_GUIDES) 115 | int n = 0; 116 | { 117 | boost::scope::defer_guard guard{ normal_func(n) }; 118 | BOOST_TEST_TRAIT_SAME(decltype(guard), boost::scope::defer_guard< normal_func >); 119 | } 120 | BOOST_TEST_EQ(n, 1); 121 | 122 | n = 0; 123 | { 124 | boost::scope::defer_guard guard([&n] { ++n; }); 125 | } 126 | BOOST_TEST_EQ(n, 1); 127 | 128 | struct local 129 | { 130 | static void raw_func() 131 | { 132 | ++g_n; 133 | } 134 | 135 | #if !defined(BOOST_SCOPE_NO_CXX17_NOEXCEPT_FUNCTION_TYPES) 136 | static void raw_func_noexcept() noexcept 137 | { 138 | ++g_n; 139 | } 140 | #endif 141 | }; 142 | 143 | g_n = 0; 144 | { 145 | boost::scope::defer_guard guard{ local::raw_func }; 146 | BOOST_TEST_TRAIT_SAME(decltype(guard), boost::scope::defer_guard< void (*)() >); 147 | } 148 | BOOST_TEST_EQ(g_n, 1); 149 | 150 | #if !defined(BOOST_SCOPE_NO_CXX17_NOEXCEPT_FUNCTION_TYPES) 151 | g_n = 0; 152 | { 153 | boost::scope::defer_guard guard{ local::raw_func_noexcept }; 154 | BOOST_TEST_TRAIT_SAME(decltype(guard), boost::scope::defer_guard< void (*)() noexcept >); 155 | } 156 | BOOST_TEST_EQ(g_n, 1); 157 | #endif 158 | 159 | n = 0; 160 | { 161 | BOOST_SCOPE_DEFER [&n] { ++n; }; 162 | BOOST_SCOPE_DEFER [&n] { ++n; }; 163 | } 164 | BOOST_TEST_EQ(n, 2); 165 | #endif // !defined(BOOST_NO_CXX17_DEDUCTION_GUIDES) 166 | } 167 | 168 | int main() 169 | { 170 | check_normal(); 171 | check_throw(); 172 | check_deduction(); 173 | 174 | return boost::report_errors(); 175 | } 176 | -------------------------------------------------------------------------------- /test/run/scope_exit.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://www.boost.org/LICENSE_1_0.txt) 5 | * 6 | * Copyright (c) 2023 Andrey Semashev 7 | */ 8 | /*! 9 | * \file scope_exit.cpp 10 | * \author Andrey Semashev 11 | * 12 | * \brief This file contains tests for \c scope_exit. 13 | */ 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include "function_types.hpp" 25 | 26 | #if defined(_MSC_VER) && !defined(__clang__) 27 | // warning C4702: unreachable code 28 | // This warning is triggered by tests that unconditionally throw exception at some point 29 | // and have code after that (e.g. parts of scope guard constructor and a check that verifies 30 | // that the following code is not reached). 31 | #pragma warning(disable: 4702) 32 | #endif 33 | 34 | int g_n = 0, g_c = 0; 35 | 36 | void check_normal_default_cond() 37 | { 38 | int n = 0; 39 | { 40 | boost::scope::scope_exit< normal_func > guard{ normal_func(n) }; 41 | BOOST_TEST(guard.active()); 42 | } 43 | BOOST_TEST_EQ(n, 1); 44 | 45 | n = 0; 46 | { 47 | boost::scope::scope_exit< moveable_only_func > guard{ moveable_only_func(n) }; 48 | BOOST_TEST(guard.active()); 49 | guard.set_active(false); 50 | BOOST_TEST(!guard.active()); 51 | guard.set_active(true); 52 | BOOST_TEST(guard.active()); 53 | } 54 | BOOST_TEST_EQ(n, 1); 55 | 56 | n = 0; 57 | { 58 | boost::scope::scope_exit< normal_func > guard(normal_func(n), false); 59 | BOOST_TEST(!guard.active()); 60 | } 61 | BOOST_TEST_EQ(n, 0); 62 | 63 | n = 0; 64 | { 65 | boost::scope::scope_exit< normal_func > guard(normal_func(n), false); 66 | BOOST_TEST(!guard.active()); 67 | guard.set_active(true); 68 | BOOST_TEST(guard.active()); 69 | } 70 | BOOST_TEST_EQ(n, 1); 71 | 72 | n = 0; 73 | { 74 | boost::scope::scope_exit< moveable_only_func > guard1{ moveable_only_func(n) }; 75 | BOOST_TEST(guard1.active()); 76 | boost::scope::scope_exit< moveable_only_func > guard2 = std::move(guard1); 77 | BOOST_TEST(!guard1.active()); 78 | BOOST_TEST(guard2.active()); 79 | boost::scope::scope_exit< moveable_only_func > guard3 = std::move(guard1); 80 | BOOST_TEST(!guard3.active()); 81 | } 82 | BOOST_TEST_EQ(n, 1); 83 | 84 | n = 0; 85 | { 86 | normal_func func(n); 87 | boost::scope::scope_exit< normal_func& > guard(func); 88 | BOOST_TEST(guard.active()); 89 | } 90 | BOOST_TEST_EQ(n, 1); 91 | 92 | n = 0; 93 | { 94 | normal_func func(n); 95 | boost::scope::scope_exit< normal_func& > guard1(func); 96 | BOOST_TEST(guard1.active()); 97 | boost::scope::scope_exit< normal_func& > guard2 = std::move(guard1); 98 | BOOST_TEST(!guard1.active()); 99 | BOOST_TEST(guard2.active()); 100 | boost::scope::scope_exit< normal_func& > guard3 = std::move(guard1); 101 | BOOST_TEST(!guard3.active()); 102 | } 103 | BOOST_TEST_EQ(n, 1); 104 | 105 | struct local 106 | { 107 | static void raw_func() 108 | { 109 | ++g_n; 110 | } 111 | }; 112 | 113 | g_n = 0; 114 | { 115 | boost::scope::scope_exit< void (&)() > guard(local::raw_func); 116 | BOOST_TEST(guard.active()); 117 | } 118 | BOOST_TEST_EQ(g_n, 1); 119 | 120 | g_n = 0; 121 | { 122 | boost::scope::scope_exit< void (&)() > guard1(local::raw_func); 123 | BOOST_TEST(guard1.active()); 124 | boost::scope::scope_exit< void (&)() > guard2 = std::move(guard1); 125 | BOOST_TEST(!guard1.active()); 126 | BOOST_TEST(guard2.active()); 127 | boost::scope::scope_exit< void (&)() > guard3 = std::move(guard1); 128 | BOOST_TEST(!guard3.active()); 129 | } 130 | BOOST_TEST_EQ(g_n, 1); 131 | } 132 | 133 | struct always_true 134 | { 135 | bool operator()() const noexcept 136 | { 137 | return true; 138 | } 139 | }; 140 | 141 | struct always_false 142 | { 143 | bool operator()() const noexcept 144 | { 145 | return false; 146 | } 147 | }; 148 | 149 | void check_normal() 150 | { 151 | int n = 0; 152 | { 153 | boost::scope::scope_exit< normal_func, always_true > guard{ normal_func(n), always_true() }; 154 | BOOST_TEST(guard.active()); 155 | } 156 | BOOST_TEST_EQ(n, 1); 157 | 158 | n = 0; 159 | { 160 | boost::scope::scope_exit< normal_func, always_false > guard{ normal_func(n), always_false() }; 161 | BOOST_TEST(guard.active()); 162 | } 163 | BOOST_TEST_EQ(n, 0); 164 | 165 | n = 0; 166 | { 167 | boost::scope::scope_exit< moveable_only_func, always_true > guard{ moveable_only_func(n) }; 168 | BOOST_TEST(guard.active()); 169 | guard.set_active(false); 170 | BOOST_TEST(!guard.active()); 171 | guard.set_active(true); 172 | BOOST_TEST(guard.active()); 173 | } 174 | BOOST_TEST_EQ(n, 1); 175 | 176 | n = 0; 177 | { 178 | boost::scope::scope_exit< normal_func, always_true > guard(normal_func(n), always_true(), false); 179 | BOOST_TEST(!guard.active()); 180 | } 181 | BOOST_TEST_EQ(n, 0); 182 | 183 | n = 0; 184 | { 185 | boost::scope::scope_exit< normal_func, always_true > guard(normal_func(n), false); 186 | BOOST_TEST(!guard.active()); 187 | } 188 | BOOST_TEST_EQ(n, 0); 189 | 190 | n = 0; 191 | { 192 | boost::scope::scope_exit< normal_func, always_true > guard(normal_func(n), false); 193 | BOOST_TEST(!guard.active()); 194 | guard.set_active(true); 195 | BOOST_TEST(guard.active()); 196 | } 197 | BOOST_TEST_EQ(n, 1); 198 | 199 | n = 0; 200 | { 201 | boost::scope::scope_exit< moveable_only_func, always_true > guard1{ moveable_only_func(n) }; 202 | BOOST_TEST(guard1.active()); 203 | boost::scope::scope_exit< moveable_only_func, always_true > guard2 = std::move(guard1); 204 | BOOST_TEST(!guard1.active()); 205 | BOOST_TEST(guard2.active()); 206 | boost::scope::scope_exit< moveable_only_func, always_true > guard3 = std::move(guard1); 207 | BOOST_TEST(!guard3.active()); 208 | } 209 | BOOST_TEST_EQ(n, 1); 210 | 211 | n = 0; 212 | { 213 | normal_func func(n); 214 | always_true cond; 215 | boost::scope::scope_exit< normal_func&, always_true& > guard(func, cond); 216 | BOOST_TEST(guard.active()); 217 | } 218 | BOOST_TEST_EQ(n, 1); 219 | 220 | n = 0; 221 | { 222 | normal_func func(n); 223 | always_true cond; 224 | boost::scope::scope_exit< normal_func&, always_true& > guard1(func, cond); 225 | BOOST_TEST(guard1.active()); 226 | boost::scope::scope_exit< normal_func&, always_true& > guard2 = std::move(guard1); 227 | BOOST_TEST(!guard1.active()); 228 | BOOST_TEST(guard2.active()); 229 | boost::scope::scope_exit< normal_func&, always_true& > guard3 = std::move(guard1); 230 | BOOST_TEST(!guard3.active()); 231 | } 232 | BOOST_TEST_EQ(n, 1); 233 | 234 | struct local 235 | { 236 | static void raw_func() 237 | { 238 | ++g_n; 239 | } 240 | 241 | static bool raw_cond() 242 | { 243 | ++g_c; 244 | return true; 245 | } 246 | }; 247 | 248 | g_n = 0; 249 | g_c = 0; 250 | { 251 | boost::scope::scope_exit< void (&)(), bool (&)() > guard(local::raw_func, local::raw_cond); 252 | BOOST_TEST(guard.active()); 253 | } 254 | BOOST_TEST_EQ(g_c, 1); 255 | BOOST_TEST_EQ(g_n, 1); 256 | 257 | g_n = 0; 258 | g_c = 0; 259 | { 260 | boost::scope::scope_exit< void (&)(), bool (&)() > guard1(local::raw_func, local::raw_cond); 261 | BOOST_TEST(guard1.active()); 262 | boost::scope::scope_exit< void (&)(), bool (&)() > guard2 = std::move(guard1); 263 | BOOST_TEST(!guard1.active()); 264 | BOOST_TEST(guard2.active()); 265 | boost::scope::scope_exit< void (&)(), bool (&)() > guard3 = std::move(guard1); 266 | BOOST_TEST(!guard3.active()); 267 | } 268 | BOOST_TEST_EQ(g_c, 1); 269 | BOOST_TEST_EQ(g_n, 1); 270 | } 271 | 272 | void check_throw_default_cond() 273 | { 274 | int n = 0; 275 | try 276 | { 277 | boost::scope::scope_exit< normal_func > guard{ normal_func(n) }; 278 | BOOST_TEST(guard.active()); 279 | throw std::runtime_error("error"); 280 | } 281 | catch (...) {} 282 | BOOST_TEST_EQ(n, 1); 283 | 284 | n = 0; 285 | try 286 | { 287 | boost::scope::scope_exit< throw_on_copy_func > guard{ throw_on_copy_func(n) }; 288 | BOOST_ERROR("An exception is expected to be thrown by throw_on_copy_func"); 289 | } 290 | catch (...) {} 291 | BOOST_TEST_EQ(n, 1); 292 | 293 | n = 0; 294 | try 295 | { 296 | boost::scope::scope_exit< throw_on_move_func > guard{ throw_on_move_func(n) }; 297 | } 298 | catch (...) 299 | { 300 | BOOST_ERROR("An exception is not expected to be thrown by throw_on_move_func (copy ctor should be used)"); 301 | } 302 | BOOST_TEST_EQ(n, 1); 303 | 304 | n = 0; 305 | bool scope_ended = false, exception_thrown = false, func_destroyed = false; 306 | try 307 | { 308 | boost::scope::scope_exit< throw_on_call_func > guard{ throw_on_call_func(n, func_destroyed) }; 309 | func_destroyed = false; 310 | scope_ended = true; 311 | } 312 | catch (...) 313 | { 314 | exception_thrown = true; 315 | } 316 | BOOST_TEST_EQ(n, 1); 317 | BOOST_TEST(scope_ended); 318 | BOOST_TEST(exception_thrown); 319 | BOOST_TEST(func_destroyed); 320 | } 321 | 322 | void check_throw() 323 | { 324 | int n = 0; 325 | try 326 | { 327 | boost::scope::scope_exit< throw_on_copy_func, boost::scope::exception_checker > guard{ throw_on_copy_func(n) }; 328 | BOOST_ERROR("An exception is expected to be thrown by throw_on_copy_func"); 329 | } 330 | catch (...) {} 331 | BOOST_TEST_EQ(n, 1); 332 | 333 | n = 0; 334 | try 335 | { 336 | boost::scope::scope_exit< throw_on_move_func, boost::scope::exception_checker > guard{ throw_on_move_func(n) }; 337 | } 338 | catch (...) 339 | { 340 | BOOST_ERROR("An exception is not expected to be thrown by throw_on_move_func (copy ctor should be used)"); 341 | } 342 | BOOST_TEST_EQ(n, 0); 343 | 344 | n = 0; 345 | bool scope_ended = false, exception_thrown = false, func_destroyed = false; 346 | try 347 | { 348 | boost::scope::scope_exit< throw_on_call_func, boost::scope::exception_checker > guard{ throw_on_call_func(n, func_destroyed) }; 349 | func_destroyed = false; 350 | scope_ended = true; 351 | } 352 | catch (...) 353 | { 354 | exception_thrown = true; 355 | } 356 | BOOST_TEST_EQ(n, 0); 357 | BOOST_TEST(scope_ended); 358 | BOOST_TEST(!exception_thrown); 359 | BOOST_TEST(func_destroyed); 360 | } 361 | 362 | void check_cond() 363 | { 364 | int n = 0; 365 | { 366 | int err = 0; 367 | boost::scope::scope_exit< normal_func, boost::scope::error_code_checker< int > > guard{ normal_func(n), boost::scope::check_error_code(err) }; 368 | BOOST_TEST(guard.active()); 369 | err = -1; 370 | } 371 | BOOST_TEST_EQ(n, 1); 372 | 373 | n = 0; 374 | { 375 | int err = 0; 376 | boost::scope::scope_exit< normal_func, boost::scope::error_code_checker< int > > guard{ normal_func(n), boost::scope::check_error_code(err) }; 377 | BOOST_TEST(guard.active()); 378 | } 379 | BOOST_TEST_EQ(n, 0); 380 | 381 | n = 0; 382 | { 383 | int err = 0; 384 | boost::scope::scope_exit< normal_func, boost::scope::error_code_checker< int > > guard{ normal_func(n), boost::scope::check_error_code(err), false }; 385 | BOOST_TEST(!guard.active()); 386 | err = -1; 387 | } 388 | BOOST_TEST_EQ(n, 0); 389 | 390 | n = 0; 391 | { 392 | std::error_code err{}; 393 | boost::scope::scope_exit< normal_func, boost::scope::error_code_checker< std::error_code > > guard{ normal_func(n), boost::scope::check_error_code(err) }; 394 | BOOST_TEST(guard.active()); 395 | err = std::make_error_code(std::errc::invalid_argument); 396 | } 397 | BOOST_TEST_EQ(n, 1); 398 | 399 | n = 0; 400 | { 401 | std::error_code err{}; 402 | boost::scope::scope_exit< normal_func, boost::scope::error_code_checker< std::error_code > > guard{ normal_func(n), boost::scope::check_error_code(err) }; 403 | BOOST_TEST(guard.active()); 404 | } 405 | BOOST_TEST_EQ(n, 0); 406 | 407 | n = 0; 408 | try 409 | { 410 | int err = 0; 411 | boost::scope::scope_exit< normal_func, boost::scope::error_code_checker< int > > guard{ normal_func(n), boost::scope::check_error_code(err) }; 412 | BOOST_TEST(guard.active()); 413 | throw std::runtime_error("error"); 414 | } 415 | catch (...) {} 416 | BOOST_TEST_EQ(n, 0); // exception is not the failure condition, err was still 0 when the scope guard was destroyed 417 | } 418 | 419 | void check_deduction() 420 | { 421 | int n = 0; 422 | { 423 | auto guard = boost::scope::make_scope_exit(normal_func(n)); 424 | BOOST_TEST(guard.active()); 425 | BOOST_TEST_TRAIT_SAME(decltype(guard), boost::scope::scope_exit< normal_func >); 426 | } 427 | BOOST_TEST_EQ(n, 1); 428 | 429 | n = 0; 430 | { 431 | auto guard = boost::scope::make_scope_exit(normal_func(n), false); 432 | BOOST_TEST(!guard.active()); 433 | BOOST_TEST_TRAIT_SAME(decltype(guard), boost::scope::scope_exit< normal_func >); 434 | } 435 | BOOST_TEST_EQ(n, 0); 436 | 437 | n = 0; 438 | { 439 | const normal_func func{ n }; 440 | auto guard = boost::scope::make_scope_exit(func, true); 441 | BOOST_TEST(guard.active()); 442 | BOOST_TEST_TRAIT_SAME(decltype(guard), boost::scope::scope_exit< normal_func >); 443 | } 444 | BOOST_TEST_EQ(n, 1); 445 | 446 | n = 0; 447 | { 448 | int err = 0; 449 | auto guard = boost::scope::make_scope_exit(normal_func(n), boost::scope::check_error_code(err)); 450 | BOOST_TEST(guard.active()); 451 | BOOST_TEST_TRAIT_SAME(decltype(guard), boost::scope::scope_exit< normal_func, boost::scope::error_code_checker< int > >); 452 | err = -1; 453 | } 454 | BOOST_TEST_EQ(n, 1); 455 | 456 | n = 0; 457 | { 458 | int err = 0; 459 | auto guard = boost::scope::make_scope_exit(normal_func(n), boost::scope::check_error_code(err), false); 460 | BOOST_TEST(!guard.active()); 461 | BOOST_TEST_TRAIT_SAME(decltype(guard), boost::scope::scope_exit< normal_func, boost::scope::error_code_checker< int > >); 462 | err = -1; 463 | } 464 | BOOST_TEST_EQ(n, 0); 465 | 466 | n = 0; 467 | { 468 | int err = 0; 469 | const normal_func func{ n }; 470 | const auto cond = boost::scope::check_error_code(err); 471 | auto guard = boost::scope::make_scope_exit(func, cond, true); 472 | BOOST_TEST(guard.active()); 473 | BOOST_TEST_TRAIT_SAME(decltype(guard), boost::scope::scope_exit< normal_func, boost::scope::error_code_checker< int > >); 474 | err = -1; 475 | } 476 | BOOST_TEST_EQ(n, 1); 477 | 478 | struct local 479 | { 480 | static void raw_func() 481 | { 482 | ++g_n; 483 | } 484 | 485 | static bool raw_cond() 486 | { 487 | ++g_c; 488 | return true; 489 | } 490 | 491 | #if !defined(BOOST_SCOPE_NO_CXX17_NOEXCEPT_FUNCTION_TYPES) 492 | static void raw_func_noexcept() noexcept 493 | { 494 | ++g_n; 495 | } 496 | 497 | static bool raw_cond_noexcept() noexcept 498 | { 499 | ++g_c; 500 | return true; 501 | } 502 | #endif 503 | }; 504 | 505 | g_n = 0; 506 | g_c = 0; 507 | { 508 | auto guard = boost::scope::make_scope_exit(local::raw_func, local::raw_cond); 509 | BOOST_TEST(guard.active()); 510 | BOOST_TEST_TRAIT_SAME(decltype(guard), boost::scope::scope_exit< void (*)(), bool (*)() >); 511 | } 512 | BOOST_TEST_EQ(g_n, 1); 513 | BOOST_TEST_EQ(g_c, 1); 514 | 515 | #if !defined(BOOST_SCOPE_NO_CXX17_NOEXCEPT_FUNCTION_TYPES) 516 | g_n = 0; 517 | g_c = 0; 518 | { 519 | auto guard = boost::scope::make_scope_exit(local::raw_func_noexcept, local::raw_cond_noexcept); 520 | BOOST_TEST(guard.active()); 521 | BOOST_TEST_TRAIT_SAME(decltype(guard), boost::scope::scope_exit< void (*)() noexcept, bool (*)() noexcept >); 522 | } 523 | BOOST_TEST_EQ(g_n, 1); 524 | BOOST_TEST_EQ(g_c, 1); 525 | #endif 526 | 527 | #if !defined(BOOST_NO_CXX17_DEDUCTION_GUIDES) 528 | n = 0; 529 | { 530 | boost::scope::scope_exit guard{ normal_func(n) }; 531 | BOOST_TEST(guard.active()); 532 | BOOST_TEST_TRAIT_SAME(decltype(guard), boost::scope::scope_exit< normal_func >); 533 | } 534 | BOOST_TEST_EQ(n, 1); 535 | 536 | n = 0; 537 | { 538 | boost::scope::scope_exit guard{ normal_func(n), true }; 539 | BOOST_TEST(guard.active()); 540 | BOOST_TEST_TRAIT_SAME(decltype(guard), boost::scope::scope_exit< normal_func >); 541 | } 542 | BOOST_TEST_EQ(n, 1); 543 | 544 | n = 0; 545 | { 546 | boost::scope::scope_exit guard([&n] { ++n; }); 547 | BOOST_TEST(guard.active()); 548 | } 549 | BOOST_TEST_EQ(n, 1); 550 | 551 | n = 0; 552 | { 553 | boost::scope::scope_exit guard1{ normal_func(n) }; 554 | boost::scope::scope_exit guard2 = std::move(guard1); 555 | BOOST_TEST(guard2.active()); 556 | BOOST_TEST_TRAIT_SAME(decltype(guard2), boost::scope::scope_exit< normal_func >); 557 | } 558 | BOOST_TEST_EQ(n, 1); 559 | 560 | n = 0; 561 | { 562 | int err = 0; 563 | boost::scope::scope_exit guard{ normal_func(n), boost::scope::check_error_code(err) }; 564 | BOOST_TEST(guard.active()); 565 | BOOST_TEST_TRAIT_SAME(decltype(guard), boost::scope::scope_exit< normal_func, boost::scope::error_code_checker< int > >); 566 | err = -1; 567 | } 568 | BOOST_TEST_EQ(n, 1); 569 | 570 | n = 0; 571 | { 572 | int err = 0; 573 | boost::scope::scope_exit guard{ normal_func(n), boost::scope::error_code_checker(err), false }; 574 | BOOST_TEST(!guard.active()); 575 | BOOST_TEST_TRAIT_SAME(decltype(guard), boost::scope::scope_exit< normal_func, boost::scope::error_code_checker< int > >); 576 | err = -1; 577 | } 578 | BOOST_TEST_EQ(n, 0); 579 | 580 | g_n = 0; 581 | g_c = 0; 582 | { 583 | boost::scope::scope_exit guard{ local::raw_func, local::raw_cond }; 584 | BOOST_TEST(guard.active()); 585 | BOOST_TEST_TRAIT_SAME(decltype(guard), boost::scope::scope_exit< void (*)(), bool (*)() >); 586 | } 587 | BOOST_TEST_EQ(g_n, 1); 588 | BOOST_TEST_EQ(g_c, 1); 589 | 590 | #if !defined(BOOST_SCOPE_NO_CXX17_NOEXCEPT_FUNCTION_TYPES) 591 | g_n = 0; 592 | g_c = 0; 593 | { 594 | boost::scope::scope_exit guard{ local::raw_func_noexcept, local::raw_cond_noexcept }; 595 | BOOST_TEST(guard.active()); 596 | BOOST_TEST_TRAIT_SAME(decltype(guard), boost::scope::scope_exit< void (*)() noexcept, bool (*)() noexcept >); 597 | } 598 | BOOST_TEST_EQ(g_n, 1); 599 | BOOST_TEST_EQ(g_c, 1); 600 | #endif 601 | 602 | n = 0; 603 | { 604 | int err = -1; 605 | boost::scope::scope_exit guard([&n] { ++n; }, [&err]() noexcept { return err < 0; }); 606 | BOOST_TEST(guard.active()); 607 | err = -1; 608 | } 609 | BOOST_TEST_EQ(n, 1); 610 | 611 | n = 0; 612 | { 613 | boost::scope::scope_exit guard1{ normal_func(n), always_true() }; 614 | boost::scope::scope_exit guard2 = std::move(guard1); 615 | BOOST_TEST(guard2.active()); 616 | BOOST_TEST_TRAIT_SAME(decltype(guard2), boost::scope::scope_exit< normal_func, always_true >); 617 | } 618 | BOOST_TEST_EQ(n, 1); 619 | #endif // !defined(BOOST_NO_CXX17_DEDUCTION_GUIDES) 620 | } 621 | 622 | int main() 623 | { 624 | check_normal_default_cond(); 625 | check_normal(); 626 | check_throw_default_cond(); 627 | check_throw(); 628 | check_deduction(); 629 | 630 | return boost::report_errors(); 631 | } 632 | -------------------------------------------------------------------------------- /test/run/scope_fail.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://www.boost.org/LICENSE_1_0.txt) 5 | * 6 | * Copyright (c) 2023 Andrey Semashev 7 | */ 8 | /*! 9 | * \file scope_fail.cpp 10 | * \author Andrey Semashev 11 | * 12 | * \brief This file contains tests for \c scope_fail. 13 | */ 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include "function_types.hpp" 24 | 25 | #if defined(_MSC_VER) && !defined(__clang__) 26 | // warning C4702: unreachable code 27 | // This warning is triggered by tests that unconditionally throw exception at some point 28 | // and have code after that (e.g. parts of scope guard constructor and a check that verifies 29 | // that the following code is not reached). 30 | #pragma warning(disable: 4702) 31 | #endif 32 | 33 | int g_n = 0, g_c = 0; 34 | 35 | void check_normal() 36 | { 37 | int n = 0; 38 | { 39 | boost::scope::scope_fail< normal_func > guard{ normal_func(n) }; 40 | BOOST_TEST(guard.active()); 41 | } 42 | BOOST_TEST_EQ(n, 0); 43 | 44 | n = 0; 45 | { 46 | boost::scope::scope_fail< moveable_only_func > guard{ moveable_only_func(n) }; 47 | BOOST_TEST(guard.active()); 48 | guard.set_active(false); 49 | BOOST_TEST(!guard.active()); 50 | guard.set_active(true); 51 | BOOST_TEST(guard.active()); 52 | } 53 | BOOST_TEST_EQ(n, 0); 54 | 55 | n = 0; 56 | { 57 | boost::scope::scope_fail< normal_func > guard(normal_func(n), false); 58 | BOOST_TEST(!guard.active()); 59 | } 60 | BOOST_TEST_EQ(n, 0); 61 | 62 | n = 0; 63 | { 64 | boost::scope::scope_fail< normal_func > guard(normal_func(n), false); 65 | BOOST_TEST(!guard.active()); 66 | guard.set_active(true); 67 | BOOST_TEST(guard.active()); 68 | } 69 | BOOST_TEST_EQ(n, 0); 70 | 71 | n = 0; 72 | { 73 | boost::scope::scope_fail< moveable_only_func > guard1{ moveable_only_func(n) }; 74 | BOOST_TEST(guard1.active()); 75 | boost::scope::scope_fail< moveable_only_func > guard2 = std::move(guard1); 76 | BOOST_TEST(!guard1.active()); 77 | BOOST_TEST(guard2.active()); 78 | boost::scope::scope_fail< moveable_only_func > guard3 = std::move(guard1); 79 | BOOST_TEST(!guard3.active()); 80 | } 81 | BOOST_TEST_EQ(n, 0); 82 | 83 | n = 0; 84 | { 85 | normal_func func(n); 86 | boost::scope::scope_fail< normal_func& > guard(func); 87 | BOOST_TEST(guard.active()); 88 | } 89 | BOOST_TEST_EQ(n, 0); 90 | 91 | n = 0; 92 | { 93 | normal_func func(n); 94 | boost::scope::scope_fail< normal_func& > guard1(func); 95 | BOOST_TEST(guard1.active()); 96 | boost::scope::scope_fail< normal_func& > guard2 = std::move(guard1); 97 | BOOST_TEST(!guard1.active()); 98 | BOOST_TEST(guard2.active()); 99 | boost::scope::scope_fail< normal_func& > guard3 = std::move(guard1); 100 | BOOST_TEST(!guard3.active()); 101 | } 102 | BOOST_TEST_EQ(n, 0); 103 | 104 | struct local 105 | { 106 | static void raw_func() 107 | { 108 | ++g_n; 109 | } 110 | }; 111 | 112 | g_n = 0; 113 | { 114 | boost::scope::scope_fail< void (&)() > guard(local::raw_func); 115 | BOOST_TEST(guard.active()); 116 | } 117 | BOOST_TEST_EQ(g_n, 0); 118 | 119 | g_n = 0; 120 | { 121 | boost::scope::scope_fail< void (&)() > guard1(local::raw_func); 122 | BOOST_TEST(guard1.active()); 123 | boost::scope::scope_fail< void (&)() > guard2 = std::move(guard1); 124 | BOOST_TEST(!guard1.active()); 125 | BOOST_TEST(guard2.active()); 126 | boost::scope::scope_fail< void (&)() > guard3 = std::move(guard1); 127 | BOOST_TEST(!guard3.active()); 128 | } 129 | BOOST_TEST_EQ(g_n, 0); 130 | } 131 | 132 | void check_throw() 133 | { 134 | int n = 0; 135 | try 136 | { 137 | boost::scope::scope_fail< normal_func > guard{ normal_func(n) }; 138 | BOOST_TEST(guard.active()); 139 | throw std::runtime_error("error"); 140 | } 141 | catch (...) {} 142 | BOOST_TEST_EQ(n, 1); 143 | 144 | n = 0; 145 | try 146 | { 147 | boost::scope::scope_fail< normal_func > guard1{ normal_func(n) }; 148 | BOOST_TEST(guard1.active()); 149 | throw std::runtime_error("error"); 150 | } 151 | catch (...) 152 | { 153 | BOOST_TEST_EQ(n, 1); 154 | 155 | boost::scope::scope_fail< normal_func > guard2{ normal_func(n) }; 156 | BOOST_TEST(guard2.active()); 157 | } 158 | BOOST_TEST_EQ(n, 1); 159 | 160 | #if !defined(BOOST_CORE_UNCAUGHT_EXCEPTIONS_EMULATED) 161 | n = 0; 162 | try 163 | { 164 | boost::scope::scope_fail< normal_func > guard1{ normal_func(n) }; 165 | BOOST_TEST(guard1.active()); 166 | throw std::runtime_error("error 1"); 167 | } 168 | catch (...) 169 | { 170 | BOOST_TEST_EQ(n, 1); 171 | 172 | try 173 | { 174 | boost::scope::scope_fail< normal_func > guard2{ normal_func(n) }; 175 | BOOST_TEST(guard2.active()); 176 | throw std::runtime_error("error 2"); 177 | } 178 | catch (...) {} 179 | } 180 | BOOST_TEST_EQ(n, 2); 181 | #endif // !defined(BOOST_CORE_UNCAUGHT_EXCEPTIONS_EMULATED) 182 | 183 | n = 0; 184 | try 185 | { 186 | boost::scope::scope_fail< throw_on_copy_func > guard{ throw_on_copy_func(n) }; 187 | BOOST_ERROR("An exception is expected to be thrown by throw_on_copy_func"); 188 | } 189 | catch (...) {} 190 | BOOST_TEST_EQ(n, 1); 191 | 192 | n = 0; 193 | try 194 | { 195 | boost::scope::scope_fail< throw_on_move_func > guard{ throw_on_move_func(n) }; 196 | } 197 | catch (...) 198 | { 199 | BOOST_ERROR("An exception is not expected to be thrown by throw_on_move_func (copy ctor should be used)"); 200 | } 201 | BOOST_TEST_EQ(n, 0); 202 | 203 | n = 0; 204 | bool scope_ended = false, exception_thrown = false, func_destroyed = false; 205 | try 206 | { 207 | boost::scope::scope_fail< throw_on_call_func > guard{ throw_on_call_func(n, func_destroyed) }; 208 | func_destroyed = false; 209 | scope_ended = true; 210 | } 211 | catch (...) 212 | { 213 | exception_thrown = true; 214 | } 215 | BOOST_TEST_EQ(n, 0); 216 | BOOST_TEST(scope_ended); 217 | BOOST_TEST(!exception_thrown); 218 | BOOST_TEST(func_destroyed); 219 | } 220 | 221 | void check_cond() 222 | { 223 | int n = 0; 224 | { 225 | int err = 0; 226 | boost::scope::scope_fail< normal_func, boost::scope::error_code_checker< int > > guard{ normal_func(n), boost::scope::check_error_code(err) }; 227 | BOOST_TEST(guard.active()); 228 | err = -1; 229 | } 230 | BOOST_TEST_EQ(n, 1); 231 | 232 | n = 0; 233 | { 234 | int err = 0; 235 | boost::scope::scope_fail< normal_func, boost::scope::error_code_checker< int > > guard{ normal_func(n), boost::scope::check_error_code(err) }; 236 | BOOST_TEST(guard.active()); 237 | } 238 | BOOST_TEST_EQ(n, 0); 239 | 240 | n = 0; 241 | { 242 | int err = 0; 243 | boost::scope::scope_fail< normal_func, boost::scope::error_code_checker< int > > guard{ normal_func(n), boost::scope::check_error_code(err), false }; 244 | BOOST_TEST(!guard.active()); 245 | err = -1; 246 | } 247 | BOOST_TEST_EQ(n, 0); 248 | 249 | n = 0; 250 | { 251 | std::error_code err{}; 252 | boost::scope::scope_fail< normal_func, boost::scope::error_code_checker< std::error_code > > guard{ normal_func(n), boost::scope::check_error_code(err) }; 253 | BOOST_TEST(guard.active()); 254 | err = std::make_error_code(std::errc::invalid_argument); 255 | } 256 | BOOST_TEST_EQ(n, 1); 257 | 258 | n = 0; 259 | { 260 | std::error_code err{}; 261 | boost::scope::scope_fail< normal_func, boost::scope::error_code_checker< std::error_code > > guard{ normal_func(n), boost::scope::check_error_code(err) }; 262 | BOOST_TEST(guard.active()); 263 | } 264 | BOOST_TEST_EQ(n, 0); 265 | 266 | n = 0; 267 | try 268 | { 269 | int err = 0; 270 | boost::scope::scope_fail< normal_func, boost::scope::error_code_checker< int > > guard{ normal_func(n), boost::scope::check_error_code(err) }; 271 | BOOST_TEST(guard.active()); 272 | throw std::runtime_error("error"); 273 | } 274 | catch (...) {} 275 | BOOST_TEST_EQ(n, 0); // exception is not the failure condition, err was still 0 when the scope guard was destroyed 276 | } 277 | 278 | void check_deduction() 279 | { 280 | int n = 0; 281 | try 282 | { 283 | auto guard = boost::scope::make_scope_fail(normal_func(n)); 284 | BOOST_TEST(guard.active()); 285 | BOOST_TEST_TRAIT_SAME(decltype(guard), boost::scope::scope_fail< normal_func >); 286 | throw std::runtime_error("error"); 287 | } 288 | catch (...) {} 289 | BOOST_TEST_EQ(n, 1); 290 | 291 | n = 0; 292 | try 293 | { 294 | auto guard = boost::scope::make_scope_fail(normal_func(n), false); 295 | BOOST_TEST(!guard.active()); 296 | BOOST_TEST_TRAIT_SAME(decltype(guard), boost::scope::scope_fail< normal_func >); 297 | throw std::runtime_error("error"); 298 | } 299 | catch (...) {} 300 | BOOST_TEST_EQ(n, 0); 301 | 302 | n = 0; 303 | try 304 | { 305 | const normal_func func{ n }; 306 | auto guard = boost::scope::make_scope_fail(func, true); 307 | BOOST_TEST(guard.active()); 308 | BOOST_TEST_TRAIT_SAME(decltype(guard), boost::scope::scope_fail< normal_func >); 309 | throw std::runtime_error("error"); 310 | } 311 | catch (...) {} 312 | BOOST_TEST_EQ(n, 1); 313 | 314 | n = 0; 315 | { 316 | int err = 0; 317 | auto guard = boost::scope::make_scope_fail(normal_func(n), boost::scope::check_error_code(err)); 318 | BOOST_TEST(guard.active()); 319 | BOOST_TEST_TRAIT_SAME(decltype(guard), boost::scope::scope_fail< normal_func, boost::scope::error_code_checker< int > >); 320 | err = -1; 321 | } 322 | BOOST_TEST_EQ(n, 1); 323 | 324 | struct local 325 | { 326 | static void raw_func() 327 | { 328 | ++g_n; 329 | } 330 | 331 | static bool raw_cond() 332 | { 333 | ++g_c; 334 | return true; 335 | } 336 | 337 | #if !defined(BOOST_SCOPE_NO_CXX17_NOEXCEPT_FUNCTION_TYPES) 338 | static void raw_func_noexcept() noexcept 339 | { 340 | ++g_n; 341 | } 342 | 343 | static bool raw_cond_noexcept() noexcept 344 | { 345 | ++g_c; 346 | return true; 347 | } 348 | #endif 349 | }; 350 | 351 | g_n = 0; 352 | g_c = 0; 353 | { 354 | auto guard = boost::scope::make_scope_fail(local::raw_func, local::raw_cond); 355 | BOOST_TEST(guard.active()); 356 | BOOST_TEST_TRAIT_SAME(decltype(guard), boost::scope::scope_fail< void (*)(), bool (*)() >); 357 | } 358 | BOOST_TEST_EQ(g_n, 1); 359 | BOOST_TEST_EQ(g_c, 1); 360 | 361 | #if !defined(BOOST_SCOPE_NO_CXX17_NOEXCEPT_FUNCTION_TYPES) 362 | g_n = 0; 363 | g_c = 0; 364 | { 365 | auto guard = boost::scope::make_scope_fail(local::raw_func_noexcept, local::raw_cond_noexcept); 366 | BOOST_TEST(guard.active()); 367 | BOOST_TEST_TRAIT_SAME(decltype(guard), boost::scope::scope_fail< void (*)() noexcept, bool (*)() noexcept >); 368 | } 369 | BOOST_TEST_EQ(g_n, 1); 370 | BOOST_TEST_EQ(g_c, 1); 371 | #endif 372 | 373 | #if !defined(BOOST_NO_CXX17_DEDUCTION_GUIDES) 374 | n = 0; 375 | try 376 | { 377 | boost::scope::scope_fail guard{ normal_func(n) }; 378 | BOOST_TEST(guard.active()); 379 | BOOST_TEST_TRAIT_SAME(decltype(guard), boost::scope::scope_fail< normal_func >); 380 | throw std::runtime_error("error"); 381 | } 382 | catch (...) {} 383 | BOOST_TEST_EQ(n, 1); 384 | 385 | n = 0; 386 | try 387 | { 388 | boost::scope::scope_fail guard{ normal_func(n), false }; 389 | BOOST_TEST(!guard.active()); 390 | BOOST_TEST_TRAIT_SAME(decltype(guard), boost::scope::scope_fail< normal_func >); 391 | throw std::runtime_error("error"); 392 | } 393 | catch (...) {} 394 | BOOST_TEST_EQ(n, 0); 395 | 396 | n = 0; 397 | { 398 | int err = 0; 399 | boost::scope::scope_fail guard{ normal_func(n), boost::scope::check_error_code(err) }; 400 | BOOST_TEST(guard.active()); 401 | BOOST_TEST_TRAIT_SAME(decltype(guard), boost::scope::scope_fail< normal_func, boost::scope::error_code_checker< int > >); 402 | err = -1; 403 | } 404 | BOOST_TEST_EQ(n, 1); 405 | 406 | n = 0; 407 | { 408 | int err = 0; 409 | boost::scope::scope_fail guard{ normal_func(n), boost::scope::error_code_checker(err), true }; 410 | BOOST_TEST(guard.active()); 411 | BOOST_TEST_TRAIT_SAME(decltype(guard), boost::scope::scope_fail< normal_func, boost::scope::error_code_checker< int > >); 412 | err = -1; 413 | } 414 | BOOST_TEST_EQ(n, 1); 415 | 416 | g_n = 0; 417 | g_c = 0; 418 | { 419 | boost::scope::scope_fail guard{ local::raw_func, local::raw_cond }; 420 | BOOST_TEST(guard.active()); 421 | BOOST_TEST_TRAIT_SAME(decltype(guard), boost::scope::scope_fail< void (*)(), bool (*)() >); 422 | } 423 | BOOST_TEST_EQ(g_n, 1); 424 | BOOST_TEST_EQ(g_c, 1); 425 | 426 | #if !defined(BOOST_SCOPE_NO_CXX17_NOEXCEPT_FUNCTION_TYPES) 427 | g_n = 0; 428 | g_c = 0; 429 | { 430 | boost::scope::scope_fail guard{ local::raw_func_noexcept, local::raw_cond_noexcept }; 431 | BOOST_TEST(guard.active()); 432 | BOOST_TEST_TRAIT_SAME(decltype(guard), boost::scope::scope_fail< void (*)() noexcept, bool (*)() noexcept >); 433 | } 434 | BOOST_TEST_EQ(g_n, 1); 435 | BOOST_TEST_EQ(g_c, 1); 436 | #endif 437 | 438 | n = 0; 439 | try 440 | { 441 | boost::scope::scope_fail guard([&n] { ++n; }); 442 | BOOST_TEST(guard.active()); 443 | throw std::runtime_error("error"); 444 | } 445 | catch (...) {} 446 | BOOST_TEST_EQ(n, 1); 447 | 448 | n = 0; 449 | { 450 | int err = -1; 451 | boost::scope::scope_fail guard([&n] { ++n; }, [&err]() noexcept { return err < 0; }); 452 | BOOST_TEST(guard.active()); 453 | } 454 | BOOST_TEST_EQ(n, 1); 455 | 456 | n = 0; 457 | try 458 | { 459 | boost::scope::scope_fail guard1{ normal_func(n) }; 460 | boost::scope::scope_fail guard2 = std::move(guard1); 461 | BOOST_TEST(guard2.active()); 462 | BOOST_TEST_TRAIT_SAME(decltype(guard2), boost::scope::scope_fail< normal_func >); 463 | throw std::runtime_error("error"); 464 | } 465 | catch (...) {} 466 | BOOST_TEST_EQ(n, 1); 467 | #endif // !defined(BOOST_NO_CXX17_DEDUCTION_GUIDES) 468 | } 469 | 470 | int main() 471 | { 472 | check_normal(); 473 | check_throw(); 474 | check_cond(); 475 | check_deduction(); 476 | 477 | return boost::report_errors(); 478 | } 479 | -------------------------------------------------------------------------------- /test/run/scope_success.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://www.boost.org/LICENSE_1_0.txt) 5 | * 6 | * Copyright (c) 2023 Andrey Semashev 7 | */ 8 | /*! 9 | * \file scope_success.cpp 10 | * \author Andrey Semashev 11 | * 12 | * \brief This file contains tests for \c scope_success. 13 | */ 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include "function_types.hpp" 24 | 25 | #if defined(_MSC_VER) && !defined(__clang__) 26 | // warning C4702: unreachable code 27 | // This warning is triggered by tests that unconditionally throw exception at some point 28 | // and have code after that (e.g. parts of scope guard constructor and a check that verifies 29 | // that the following code is not reached). 30 | #pragma warning(disable: 4702) 31 | #endif 32 | 33 | int g_n = 0, g_c = 0; 34 | 35 | void check_normal() 36 | { 37 | int n = 0; 38 | { 39 | boost::scope::scope_success< normal_func > guard{ normal_func(n) }; 40 | BOOST_TEST(guard.active()); 41 | } 42 | BOOST_TEST_EQ(n, 1); 43 | 44 | n = 0; 45 | { 46 | boost::scope::scope_success< moveable_only_func > guard{ moveable_only_func(n) }; 47 | BOOST_TEST(guard.active()); 48 | guard.set_active(false); 49 | BOOST_TEST(!guard.active()); 50 | guard.set_active(true); 51 | BOOST_TEST(guard.active()); 52 | } 53 | BOOST_TEST_EQ(n, 1); 54 | 55 | n = 0; 56 | { 57 | boost::scope::scope_success< normal_func > guard(normal_func(n), false); 58 | BOOST_TEST(!guard.active()); 59 | } 60 | BOOST_TEST_EQ(n, 0); 61 | 62 | n = 0; 63 | { 64 | boost::scope::scope_success< normal_func > guard(normal_func(n), false); 65 | BOOST_TEST(!guard.active()); 66 | guard.set_active(true); 67 | BOOST_TEST(guard.active()); 68 | } 69 | BOOST_TEST_EQ(n, 1); 70 | 71 | n = 0; 72 | { 73 | boost::scope::scope_success< moveable_only_func > guard1{ moveable_only_func(n) }; 74 | BOOST_TEST(guard1.active()); 75 | boost::scope::scope_success< moveable_only_func > guard2 = std::move(guard1); 76 | BOOST_TEST(!guard1.active()); 77 | BOOST_TEST(guard2.active()); 78 | boost::scope::scope_success< moveable_only_func > guard3 = std::move(guard1); 79 | BOOST_TEST(!guard3.active()); 80 | } 81 | BOOST_TEST_EQ(n, 1); 82 | 83 | n = 0; 84 | { 85 | normal_func func(n); 86 | boost::scope::scope_success< normal_func& > guard(func); 87 | BOOST_TEST(guard.active()); 88 | } 89 | BOOST_TEST_EQ(n, 1); 90 | 91 | n = 0; 92 | { 93 | normal_func func(n); 94 | boost::scope::scope_success< normal_func& > guard1(func); 95 | BOOST_TEST(guard1.active()); 96 | boost::scope::scope_success< normal_func& > guard2 = std::move(guard1); 97 | BOOST_TEST(!guard1.active()); 98 | BOOST_TEST(guard2.active()); 99 | boost::scope::scope_success< normal_func& > guard3 = std::move(guard1); 100 | BOOST_TEST(!guard3.active()); 101 | } 102 | BOOST_TEST_EQ(n, 1); 103 | 104 | struct local 105 | { 106 | static void raw_func() 107 | { 108 | ++g_n; 109 | } 110 | }; 111 | 112 | g_n = 0; 113 | { 114 | boost::scope::scope_success< void (&)() > guard(local::raw_func); 115 | BOOST_TEST(guard.active()); 116 | } 117 | BOOST_TEST_EQ(g_n, 1); 118 | 119 | g_n = 0; 120 | { 121 | boost::scope::scope_success< void (&)() > guard1(local::raw_func); 122 | BOOST_TEST(guard1.active()); 123 | boost::scope::scope_success< void (&)() > guard2 = std::move(guard1); 124 | BOOST_TEST(!guard1.active()); 125 | BOOST_TEST(guard2.active()); 126 | boost::scope::scope_success< void (&)() > guard3 = std::move(guard1); 127 | BOOST_TEST(!guard3.active()); 128 | } 129 | BOOST_TEST_EQ(g_n, 1); 130 | } 131 | 132 | void check_throw() 133 | { 134 | int n = 0; 135 | try 136 | { 137 | boost::scope::scope_success< normal_func > guard{ normal_func(n) }; 138 | BOOST_TEST(guard.active()); 139 | throw std::runtime_error("error"); 140 | } 141 | catch (...) {} 142 | BOOST_TEST_EQ(n, 0); 143 | 144 | n = 0; 145 | try 146 | { 147 | boost::scope::scope_success< normal_func > guard1{ normal_func(n) }; 148 | BOOST_TEST(guard1.active()); 149 | throw std::runtime_error("error"); 150 | } 151 | catch (...) 152 | { 153 | BOOST_TEST_EQ(n, 0); 154 | 155 | boost::scope::scope_success< normal_func > guard2{ normal_func(n) }; 156 | BOOST_TEST(guard2.active()); 157 | } 158 | BOOST_TEST_EQ(n, 1); 159 | 160 | #if !defined(BOOST_CORE_UNCAUGHT_EXCEPTIONS_EMULATED) 161 | n = 0; 162 | try 163 | { 164 | boost::scope::scope_success< normal_func > guard1{ normal_func(n) }; 165 | BOOST_TEST(guard1.active()); 166 | throw std::runtime_error("error 1"); 167 | } 168 | catch (...) 169 | { 170 | BOOST_TEST_EQ(n, 0); 171 | 172 | try 173 | { 174 | boost::scope::scope_success< normal_func > guard2{ normal_func(n) }; 175 | BOOST_TEST(guard2.active()); 176 | throw std::runtime_error("error 2"); 177 | } 178 | catch (...) {} 179 | } 180 | BOOST_TEST_EQ(n, 0); 181 | #endif // !defined(BOOST_CORE_UNCAUGHT_EXCEPTIONS_EMULATED) 182 | 183 | n = 0; 184 | try 185 | { 186 | boost::scope::scope_success< throw_on_copy_func > guard{ throw_on_copy_func(n) }; 187 | BOOST_ERROR("An exception is expected to be thrown by throw_on_copy_func"); 188 | } 189 | catch (...) {} 190 | BOOST_TEST_EQ(n, 0); 191 | 192 | n = 0; 193 | try 194 | { 195 | boost::scope::scope_success< throw_on_move_func > guard{ throw_on_move_func(n) }; 196 | } 197 | catch (...) 198 | { 199 | BOOST_ERROR("An exception is not expected to be thrown by throw_on_move_func (copy ctor should be used)"); 200 | } 201 | BOOST_TEST_EQ(n, 1); 202 | 203 | n = 0; 204 | bool scope_ended = false, exception_thrown = false, func_destroyed = false; 205 | try 206 | { 207 | boost::scope::scope_success< throw_on_call_func > guard{ throw_on_call_func(n, func_destroyed) }; 208 | func_destroyed = false; 209 | scope_ended = true; 210 | } 211 | catch (...) 212 | { 213 | exception_thrown = true; 214 | } 215 | BOOST_TEST_EQ(n, 1); 216 | BOOST_TEST(scope_ended); 217 | BOOST_TEST(exception_thrown); 218 | BOOST_TEST(func_destroyed); 219 | } 220 | 221 | void check_cond() 222 | { 223 | int n = 0; 224 | { 225 | int err = 0; 226 | boost::scope::scope_success< normal_func, boost::scope::error_code_checker< int > > guard{ normal_func(n), boost::scope::check_error_code(err) }; 227 | BOOST_TEST(guard.active()); 228 | } 229 | BOOST_TEST_EQ(n, 1); 230 | 231 | n = 0; 232 | { 233 | int err = 0; 234 | boost::scope::scope_success< normal_func, boost::scope::error_code_checker< int > > guard{ normal_func(n), boost::scope::check_error_code(err) }; 235 | BOOST_TEST(guard.active()); 236 | err = -1; 237 | } 238 | BOOST_TEST_EQ(n, 0); 239 | 240 | n = 0; 241 | { 242 | int err = 0; 243 | boost::scope::scope_success< normal_func, boost::scope::error_code_checker< int > > guard{ normal_func(n), boost::scope::check_error_code(err), false }; 244 | BOOST_TEST(!guard.active()); 245 | } 246 | BOOST_TEST_EQ(n, 0); 247 | 248 | n = 0; 249 | { 250 | std::error_code err{}; 251 | boost::scope::scope_success< normal_func, boost::scope::error_code_checker< std::error_code > > guard{ normal_func(n), boost::scope::check_error_code(err) }; 252 | BOOST_TEST(guard.active()); 253 | } 254 | BOOST_TEST_EQ(n, 1); 255 | 256 | n = 0; 257 | { 258 | std::error_code err{}; 259 | boost::scope::scope_success< normal_func, boost::scope::error_code_checker< std::error_code > > guard{ normal_func(n), boost::scope::check_error_code(err) }; 260 | BOOST_TEST(guard.active()); 261 | err = std::make_error_code(std::errc::invalid_argument); 262 | } 263 | BOOST_TEST_EQ(n, 0); 264 | 265 | n = 0; 266 | try 267 | { 268 | int err = 0; 269 | boost::scope::scope_success< normal_func, boost::scope::error_code_checker< int > > guard{ normal_func(n), boost::scope::check_error_code(err) }; 270 | BOOST_TEST(guard.active()); 271 | throw std::runtime_error("error"); 272 | } 273 | catch (...) {} 274 | BOOST_TEST_EQ(n, 1); // exception is not the failure condition, err was still 0 when the scope guard was destroyed 275 | } 276 | 277 | void check_deduction() 278 | { 279 | int n = 0; 280 | { 281 | auto guard = boost::scope::make_scope_success(normal_func(n)); 282 | BOOST_TEST(guard.active()); 283 | BOOST_TEST_TRAIT_SAME(decltype(guard), boost::scope::scope_success< normal_func >); 284 | } 285 | BOOST_TEST_EQ(n, 1); 286 | 287 | n = 0; 288 | { 289 | auto guard = boost::scope::make_scope_success(normal_func(n), false); 290 | BOOST_TEST(!guard.active()); 291 | BOOST_TEST_TRAIT_SAME(decltype(guard), boost::scope::scope_success< normal_func >); 292 | } 293 | BOOST_TEST_EQ(n, 0); 294 | 295 | n = 0; 296 | { 297 | const normal_func func{ n }; 298 | auto guard = boost::scope::make_scope_success(func, true); 299 | BOOST_TEST(guard.active()); 300 | BOOST_TEST_TRAIT_SAME(decltype(guard), boost::scope::scope_success< normal_func >); 301 | } 302 | BOOST_TEST_EQ(n, 1); 303 | 304 | n = 0; 305 | { 306 | int err = 0; 307 | auto guard = boost::scope::make_scope_success(normal_func(n), boost::scope::check_error_code(err)); 308 | BOOST_TEST(guard.active()); 309 | BOOST_TEST_TRAIT_SAME(decltype(guard), boost::scope::scope_success< normal_func, boost::scope::error_code_checker< int > >); 310 | } 311 | BOOST_TEST_EQ(n, 1); 312 | 313 | struct local 314 | { 315 | static void raw_func() 316 | { 317 | ++g_n; 318 | } 319 | 320 | static bool raw_cond() 321 | { 322 | ++g_c; 323 | return false; 324 | } 325 | 326 | #if !defined(BOOST_SCOPE_NO_CXX17_NOEXCEPT_FUNCTION_TYPES) 327 | static void raw_func_noexcept() noexcept 328 | { 329 | ++g_n; 330 | } 331 | 332 | static bool raw_cond_noexcept() noexcept 333 | { 334 | ++g_c; 335 | return false; 336 | } 337 | #endif 338 | }; 339 | 340 | g_n = 0; 341 | g_c = 0; 342 | { 343 | auto guard = boost::scope::make_scope_success(local::raw_func, local::raw_cond); 344 | BOOST_TEST(guard.active()); 345 | BOOST_TEST_TRAIT_SAME(decltype(guard), boost::scope::scope_success< void (*)(), bool (*)() >); 346 | } 347 | BOOST_TEST_EQ(g_n, 1); 348 | BOOST_TEST_EQ(g_c, 1); 349 | 350 | #if !defined(BOOST_SCOPE_NO_CXX17_NOEXCEPT_FUNCTION_TYPES) 351 | g_n = 0; 352 | g_c = 0; 353 | { 354 | auto guard = boost::scope::make_scope_success(local::raw_func_noexcept, local::raw_cond_noexcept); 355 | BOOST_TEST(guard.active()); 356 | BOOST_TEST_TRAIT_SAME(decltype(guard), boost::scope::scope_success< void (*)() noexcept, bool (*)() noexcept >); 357 | } 358 | BOOST_TEST_EQ(g_n, 1); 359 | BOOST_TEST_EQ(g_c, 1); 360 | #endif 361 | 362 | #if !defined(BOOST_NO_CXX17_DEDUCTION_GUIDES) 363 | n = 0; 364 | { 365 | boost::scope::scope_success guard{ normal_func(n) }; 366 | BOOST_TEST(guard.active()); 367 | BOOST_TEST_TRAIT_SAME(decltype(guard), boost::scope::scope_success< normal_func >); 368 | } 369 | BOOST_TEST_EQ(n, 1); 370 | 371 | n = 0; 372 | { 373 | boost::scope::scope_success guard{ normal_func(n), false }; 374 | BOOST_TEST(!guard.active()); 375 | BOOST_TEST_TRAIT_SAME(decltype(guard), boost::scope::scope_success< normal_func >); 376 | } 377 | BOOST_TEST_EQ(n, 0); 378 | 379 | n = 0; 380 | { 381 | int err = 0; 382 | boost::scope::scope_success guard{ normal_func(n), boost::scope::check_error_code(err) }; 383 | BOOST_TEST(guard.active()); 384 | BOOST_TEST_TRAIT_SAME(decltype(guard), boost::scope::scope_success< normal_func, boost::scope::error_code_checker< int > >); 385 | } 386 | BOOST_TEST_EQ(n, 1); 387 | 388 | n = 0; 389 | { 390 | int err = 0; 391 | boost::scope::scope_success guard{ normal_func(n), boost::scope::error_code_checker(err), true }; 392 | BOOST_TEST(guard.active()); 393 | BOOST_TEST_TRAIT_SAME(decltype(guard), boost::scope::scope_success< normal_func, boost::scope::error_code_checker< int > >); 394 | } 395 | BOOST_TEST_EQ(n, 1); 396 | 397 | g_n = 0; 398 | g_c = 0; 399 | { 400 | boost::scope::scope_success guard{ local::raw_func, local::raw_cond }; 401 | BOOST_TEST(guard.active()); 402 | BOOST_TEST_TRAIT_SAME(decltype(guard), boost::scope::scope_success< void (*)(), bool (*)() >); 403 | } 404 | BOOST_TEST_EQ(g_n, 1); 405 | BOOST_TEST_EQ(g_c, 1); 406 | 407 | #if !defined(BOOST_SCOPE_NO_CXX17_NOEXCEPT_FUNCTION_TYPES) 408 | g_n = 0; 409 | g_c = 0; 410 | { 411 | boost::scope::scope_success guard{ local::raw_func_noexcept, local::raw_cond_noexcept }; 412 | BOOST_TEST(guard.active()); 413 | BOOST_TEST_TRAIT_SAME(decltype(guard), boost::scope::scope_success< void (*)() noexcept, bool (*)() noexcept >); 414 | } 415 | BOOST_TEST_EQ(g_n, 1); 416 | BOOST_TEST_EQ(g_c, 1); 417 | #endif 418 | 419 | n = 0; 420 | { 421 | boost::scope::scope_success guard([&n] { ++n; }); 422 | BOOST_TEST(guard.active()); 423 | } 424 | BOOST_TEST_EQ(n, 1); 425 | 426 | n = 0; 427 | { 428 | int err = 10; 429 | boost::scope::scope_success guard([&n] { ++n; }, [&err]() noexcept { return err < 0; }); 430 | BOOST_TEST(guard.active()); 431 | } 432 | BOOST_TEST_EQ(n, 1); 433 | 434 | n = 0; 435 | { 436 | boost::scope::scope_success guard1{ normal_func(n) }; 437 | boost::scope::scope_success guard2 = std::move(guard1); 438 | BOOST_TEST(guard2.active()); 439 | BOOST_TEST_TRAIT_SAME(decltype(guard2), boost::scope::scope_success< normal_func >); 440 | } 441 | BOOST_TEST_EQ(n, 1); 442 | #endif // !defined(BOOST_NO_CXX17_DEDUCTION_GUIDES) 443 | } 444 | 445 | int main() 446 | { 447 | check_normal(); 448 | check_throw(); 449 | check_cond(); 450 | check_deduction(); 451 | 452 | return boost::report_errors(); 453 | } 454 | -------------------------------------------------------------------------------- /test/run/unique_fd.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://www.boost.org/LICENSE_1_0.txt) 5 | * 6 | * Copyright (c) 2023 Andrey Semashev 7 | */ 8 | /*! 9 | * \file unique_fd.cpp 10 | * \author Andrey Semashev 11 | * 12 | * \brief This file contains tests for \c unique_fd. 13 | */ 14 | 15 | #include 16 | 17 | #include 18 | #include 19 | 20 | #if defined(BOOST_WINDOWS) 21 | #include 22 | #endif 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #if defined(_MSC_VER) && defined(_CPPLIB_VER) 30 | #include 31 | #include 32 | #include 33 | 34 | void noop_invalid_parameter(const wchar_t* expression, const wchar_t* function, const wchar_t* file, unsigned int line, uintptr_t pReserved) 35 | { 36 | } 37 | 38 | #include 39 | #endif // defined(_MSC_VER) && defined(_CPPLIB_VER) 40 | 41 | #if defined(BOOST_WINDOWS) 42 | #define open _open 43 | #define O_RDONLY _O_RDONLY 44 | #define stat _stat 45 | #define fstat _fstat 46 | #endif // defined(BOOST_WINDOWS) 47 | 48 | #if defined(__GNUC__) 49 | // missing initializer for member 'stat::...' 50 | #pragma GCC diagnostic ignored "-Wmissing-field-initializers" 51 | #endif 52 | 53 | int main(int argc, char* args[]) 54 | { 55 | #if defined(_MSC_VER) && defined(_CPPLIB_VER) 56 | // Disable assertion failure message boxes and aborts on invalid parameters 57 | _set_invalid_parameter_handler(&noop_invalid_parameter); 58 | _CrtSetReportMode(_CRT_ASSERT, 0); 59 | #endif 60 | 61 | { 62 | boost::scope::unique_fd ur; 63 | BOOST_TEST_LT(ur.get(), 0); 64 | BOOST_TEST(!ur.allocated()); 65 | } 66 | 67 | if (argc > 0) 68 | { 69 | int fd = 0; 70 | { 71 | boost::scope::unique_fd ur(::open(args[0], O_RDONLY)); 72 | BOOST_TEST_GE(ur.get(), 0); 73 | BOOST_TEST(ur.allocated()); 74 | fd = ur.get(); 75 | } 76 | 77 | struct stat st = {}; 78 | int res = ::fstat(fd, &st); 79 | BOOST_TEST_LT(res, 0); 80 | int err = errno; 81 | BOOST_TEST_EQ(err, EBADF); 82 | } 83 | else 84 | { 85 | std::puts("Test executable file name not provided in process args"); 86 | } 87 | 88 | return boost::report_errors(); 89 | } 90 | --------------------------------------------------------------------------------