Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-04-19 08:44:21

0001 /*
0002  * Distributed under the Boost Software License, Version 1.0.
0003  * (See accompanying file LICENSE_1_0.txt or copy at
0004  * https://www.boost.org/LICENSE_1_0.txt)
0005  *
0006  * Copyright (c) 2022-2024 Andrey Semashev
0007  */
0008 /*!
0009  * \file scope/defer.hpp
0010  *
0011  * This header contains definition of \c defer_guard template.
0012  */
0013 
0014 #ifndef BOOST_SCOPE_DEFER_HPP_INCLUDED_
0015 #define BOOST_SCOPE_DEFER_HPP_INCLUDED_
0016 
0017 #include <type_traits>
0018 #include <boost/scope/detail/config.hpp>
0019 #include <boost/scope/detail/is_not_like.hpp>
0020 #include <boost/scope/detail/move_or_copy_construct_ref.hpp>
0021 #include <boost/scope/detail/type_traits/conjunction.hpp>
0022 #include <boost/scope/detail/type_traits/is_nothrow_invocable.hpp>
0023 #include <boost/scope/detail/header.hpp>
0024 
0025 #ifdef BOOST_HAS_PRAGMA_ONCE
0026 #pragma once
0027 #endif
0028 
0029 namespace boost {
0030 namespace scope {
0031 
0032 template< typename Func >
0033 class defer_guard;
0034 
0035 namespace detail {
0036 
0037 // Workaround for clang < 5.0 which can't pass defer_guard as a template template parameter from within defer_guard definition
0038 template< typename T >
0039 using is_not_like_defer_guard = detail::is_not_like< T, defer_guard >;
0040 
0041 } // namespace detail
0042 
0043 /*!
0044  * \brief Defer guard that invokes a function upon leaving the scope.
0045  *
0046  * The scope guard wraps a function object callable with no arguments
0047  * that can be one of:
0048  *
0049  * \li A user-defined class with a public `operator()`.
0050  * \li An lvalue reference to such class.
0051  * \li An lvalue reference or pointer to function taking no arguments.
0052  *
0053  * The defer guard unconditionally invokes the wrapped function object
0054  * on destruction.
0055  */
0056 template< typename Func >
0057 class defer_guard
0058 {
0059 //! \cond
0060 private:
0061     struct data
0062     {
0063         Func m_func;
0064 
0065         template< typename F, typename = typename std::enable_if< std::is_constructible< Func, F >::value >::type >
0066         explicit data(F&& func, std::true_type) noexcept :
0067             m_func(static_cast< F&& >(func))
0068         {
0069         }
0070 
0071         template< typename F, typename = typename std::enable_if< std::is_constructible< Func, F >::value >::type >
0072         explicit data(F&& func, std::false_type) try :
0073             m_func(static_cast< F&& >(func))
0074         {
0075         }
0076         catch (...)
0077         {
0078             func();
0079         }
0080     };
0081 
0082     data m_data;
0083 
0084 //! \endcond
0085 public:
0086     /*!
0087      * \brief Constructs a defer guard with a given callable function object.
0088      *
0089      * **Requires:** \c Func is constructible from \a func.
0090      *
0091      * **Effects:** If \c Func is nothrow constructible from `F&&` then constructs \c Func from
0092      *              `std::forward< F >(func)`, otherwise constructs from `func`.
0093      *
0094      *              If \c Func construction throws, invokes \a func before returning with the exception.
0095      *
0096      * **Throws:** Nothing, unless construction of the function object throws.
0097      *
0098      * \param func The callable function object to invoke on destruction.
0099      */
0100     template<
0101         typename F
0102         //! \cond
0103         , typename = typename std::enable_if< detail::conjunction<
0104             std::is_constructible<
0105                 data,
0106                 typename detail::move_or_copy_construct_ref< F, Func >::type,
0107                 typename std::is_nothrow_constructible< Func, typename detail::move_or_copy_construct_ref< F, Func >::type >::type
0108             >,
0109             detail::is_not_like_defer_guard< F >
0110         >::value >::type
0111         //! \endcond
0112     >
0113     defer_guard(F&& func)
0114         noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(
0115             std::is_nothrow_constructible<
0116                 data,
0117                 typename detail::move_or_copy_construct_ref< F, Func >::type,
0118                 typename std::is_nothrow_constructible< Func, typename detail::move_or_copy_construct_ref< F, Func >::type >::type
0119             >::value
0120         )) :
0121         m_data
0122         (
0123             static_cast< typename detail::move_or_copy_construct_ref< F, Func >::type >(func),
0124             typename std::is_nothrow_constructible< Func, typename detail::move_or_copy_construct_ref< F, Func >::type >::type()
0125         )
0126     {
0127     }
0128 
0129     defer_guard(defer_guard const&) = delete;
0130     defer_guard& operator= (defer_guard const&) = delete;
0131 
0132     /*!
0133      * \brief Invokes the wrapped callable function object and destroys the callable.
0134      *
0135      * **Throws:** Nothing, unless invoking the callable throws.
0136      */
0137     ~defer_guard() noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(detail::is_nothrow_invocable< Func& >::value))
0138     {
0139         m_data.m_func();
0140     }
0141 };
0142 
0143 #if !defined(BOOST_NO_CXX17_DEDUCTION_GUIDES)
0144 template< typename Func >
0145 defer_guard(Func) -> defer_guard< Func >;
0146 #endif // !defined(BOOST_NO_CXX17_DEDUCTION_GUIDES)
0147 
0148 } // namespace scope
0149 
0150 //! \cond
0151 #if defined(BOOST_MSVC)
0152 #define BOOST_SCOPE_DETAIL_UNIQUE_VAR_TAG __COUNTER__
0153 #else
0154 #define BOOST_SCOPE_DETAIL_UNIQUE_VAR_TAG __LINE__
0155 #endif
0156 //! \endcond
0157 
0158 /*!
0159  * \brief The macro creates a uniquely named defer guard.
0160  *
0161  * The macro should be followed by a function object that should be called
0162  * on leaving the current scope. Usage example:
0163  *
0164  * ```
0165  * BOOST_SCOPE_DEFER []
0166  * {
0167  *     std::cout << "Hello world!" << std::endl;
0168  * };
0169  * ```
0170  *
0171  * \note Using this macro requires C++17.
0172  */
0173 #define BOOST_SCOPE_DEFER \
0174     boost::scope::defer_guard BOOST_JOIN(_boost_defer_guard_, BOOST_SCOPE_DETAIL_UNIQUE_VAR_TAG) =
0175 
0176 } // namespace boost
0177 
0178 #include <boost/scope/detail/footer.hpp>
0179 
0180 #endif // BOOST_SCOPE_DEFER_HPP_INCLUDED_