From 9194f7182e1544c6fc81abf3a5cbecb3cace9317 Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Wed, 1 Mar 2023 16:54:49 +0700 Subject: [PATCH] add embedded defer.hpp --- develop/singles/headers/meta.hpp/meta_all.hpp | 154 ++++++++++++++++-- headers/meta.hpp/meta_base.hpp | 1 + headers/meta.hpp/meta_base/base.hpp | 19 +-- headers/meta.hpp/meta_base/defer.hpp | 144 ++++++++++++++++ 4 files changed, 298 insertions(+), 20 deletions(-) create mode 100644 headers/meta.hpp/meta_base/defer.hpp diff --git a/develop/singles/headers/meta.hpp/meta_all.hpp b/develop/singles/headers/meta.hpp/meta_all.hpp index a9765e0..2f113e0 100644 --- a/develop/singles/headers/meta.hpp/meta_all.hpp +++ b/develop/singles/headers/meta.hpp/meta_all.hpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -17,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -28,6 +30,8 @@ #include #include #include +#include +#include #include #include #include @@ -40,24 +44,19 @@ # define META_HPP_NO_RTTI #endif -#if !defined(META_HPP_NO_EXCEPTIONS) -# include -#endif - -#if !defined(META_HPP_NO_RTTI) -# include -# include -#endif - #if !defined(META_HPP_FWD) # define META_HPP_FWD(v) std::forward(v) #endif #if !defined(META_HPP_ASSERT) -# include # define META_HPP_ASSERT(...) assert(__VA_ARGS__) // NOLINT #endif +#if !defined(META_HPP_PP_CAT) +# define META_HPP_PP_CAT(x, y) META_HPP_PP_CAT_I(x, y) +# define META_HPP_PP_CAT_I(x, y) x##y +#endif + namespace meta_hpp::detail { template < typename Enum > @@ -303,6 +302,141 @@ namespace meta_hpp::detail using copy_cvref_t = typename copy_cvref::type; } +namespace meta_hpp::detail::impl +{ + template < typename F, typename... Args > + class defer_impl { + public: + defer_impl() = delete; + defer_impl(defer_impl&&) = delete; + defer_impl(const defer_impl&) = delete; + defer_impl& operator=(defer_impl&&) = delete; + defer_impl& operator=(const defer_impl&) = delete; + + template < typename UF > + explicit defer_impl(UF&& f, std::tuple&& args) + : f_{std::forward(f)} + , args_{std::move(args)} {} + + void dismiss() noexcept { + dismissed_ = true; + } + + protected: + ~defer_impl() noexcept { + if ( !dismissed_ ) { + std::apply(std::move(f_), std::move(args_)); + } + } + + private: + F f_; + std::tuple args_; + bool dismissed_{}; + }; +} + +namespace meta_hpp::detail +{ + template < typename F, typename... Args > + class defer final : public impl::defer_impl { + public: + defer() = delete; + defer(defer&&) = delete; + defer(const defer&) = delete; + defer& operator=(defer&&) = delete; + defer& operator=(const defer&) = delete; + + template < typename UF > + explicit defer(UF&& f, std::tuple&& args) + : impl::defer_impl{std::forward(f), std::move(args)} {} + + ~defer() noexcept = default; + }; + + template < typename F, typename... Args > + class error_defer final : public impl::defer_impl { + public: + error_defer() = delete; + error_defer(error_defer&&) = delete; + error_defer(const error_defer&) = delete; + error_defer& operator=(error_defer&&) = delete; + error_defer& operator=(const error_defer&) = delete; + + template < typename UF > + explicit error_defer(UF&& f, std::tuple&& args) + : impl::defer_impl{std::forward(f), std::move(args)} + , exceptions_{std::uncaught_exceptions()} {} + + ~error_defer() noexcept { + if ( exceptions_ == std::uncaught_exceptions() ) { + this->dismiss(); + } + } + + private: + int exceptions_{}; + }; + + template < typename F, typename... Args > + class return_defer final : public impl::defer_impl { + public: + return_defer() = delete; + return_defer(return_defer&&) = delete; + return_defer(const return_defer&) = delete; + return_defer& operator=(return_defer&&) = delete; + return_defer& operator=(const return_defer&) = delete; + + template < typename UF > + explicit return_defer(UF&& f, std::tuple&& args) + : impl::defer_impl{std::forward(f), std::move(args)} + , exceptions_{std::uncaught_exceptions()} {} + + ~return_defer() noexcept { + if ( exceptions_ != std::uncaught_exceptions() ) { + this->dismiss(); + } + } + + private: + int exceptions_{}; + }; + + template < typename F, typename... Args > + auto make_defer(F&& f, Args&&... args) { + using defer_t = defer, std::decay_t...>; + return defer_t{std::forward(f), std::make_tuple(std::forward(args)...)}; + } + + template < typename F, typename... Args > + auto make_error_defer(F&& f, Args&&... args) { + using defer_t = error_defer, std::decay_t...>; + return defer_t{std::forward(f), std::make_tuple(std::forward(args)...)}; + } + + template < typename F, typename... Args > + auto make_return_defer(F&& f, Args&&... args) { + using defer_t = return_defer, std::decay_t...>; + return defer_t{std::forward(f), std::make_tuple(std::forward(args)...)}; + } +} + +#ifdef __COUNTER__ +# define META_HPP_DEFER(...) \ + auto META_HPP_PP_CAT(meta_hpp_generated_defer_, __COUNTER__) { ::meta_hpp::detail::make_defer(__VA_ARGS__) } +# define META_HPP_ERROR_DEFER(...) \ + auto META_HPP_PP_CAT(meta_hpp_generated_error_defer_, __COUNTER__) { ::meta_hpp::detail::make_error_defer(__VA_ARGS__) } +# define META_HPP_RETURN_DEFER(...) \ + auto META_HPP_PP_CAT(meta_hpp_generated_return_defer_, __COUNTER__) { ::meta_hpp::detail::make_return_defer(__VA_ARGS__) } +#else +# define META_HPP_DEFER(...) \ + auto META_HPP_PP_CAT(meta_hpp_generated_defer_, __LINE__) { ::meta_hpp::detail::make_defer(__VA_ARGS__) } +# define META_HPP_ERROR_DEFER(...) \ + auto META_HPP_PP_CAT(meta_hpp_generated_error_defer_, __LINE__) { ::meta_hpp::detail::make_error_defer(__VA_ARGS__) } +# define META_HPP_RETURN_DEFER(...) \ + auto META_HPP_PP_CAT(meta_hpp_generated_return_defer_, __LINE__) { ::meta_hpp::detail::make_return_defer(__VA_ARGS__) } +#endif + #if !defined(META_HPP_NO_EXCEPTIONS) # define META_HPP_TRY try # define META_HPP_CATCH(...) catch ( __VA_ARGS__ ) diff --git a/headers/meta.hpp/meta_base.hpp b/headers/meta.hpp/meta_base.hpp index db7104e..8aceaf6 100644 --- a/headers/meta.hpp/meta_base.hpp +++ b/headers/meta.hpp/meta_base.hpp @@ -10,6 +10,7 @@ #include "meta_base/bitflags.hpp" #include "meta_base/cv_traits.hpp" #include "meta_base/cvref_traits.hpp" +#include "meta_base/defer.hpp" #include "meta_base/exceptions.hpp" #include "meta_base/fixed_function.hpp" #include "meta_base/fnv1a_hash.hpp" diff --git a/headers/meta.hpp/meta_base/base.hpp b/headers/meta.hpp/meta_base/base.hpp index 07c9f06..5cae5f2 100644 --- a/headers/meta.hpp/meta_base/base.hpp +++ b/headers/meta.hpp/meta_base/base.hpp @@ -6,6 +6,7 @@ #pragma once +#include #include #include #include @@ -18,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -29,6 +31,8 @@ #include #include #include +#include +#include #include #include #include @@ -41,20 +45,15 @@ # define META_HPP_NO_RTTI #endif -#if !defined(META_HPP_NO_EXCEPTIONS) -# include -#endif - -#if !defined(META_HPP_NO_RTTI) -# include -# include -#endif - #if !defined(META_HPP_FWD) # define META_HPP_FWD(v) std::forward(v) #endif #if !defined(META_HPP_ASSERT) -# include # define META_HPP_ASSERT(...) assert(__VA_ARGS__) // NOLINT #endif + +#if !defined(META_HPP_PP_CAT) +# define META_HPP_PP_CAT(x, y) META_HPP_PP_CAT_I(x, y) +# define META_HPP_PP_CAT_I(x, y) x##y +#endif diff --git a/headers/meta.hpp/meta_base/defer.hpp b/headers/meta.hpp/meta_base/defer.hpp new file mode 100644 index 0000000..7764070 --- /dev/null +++ b/headers/meta.hpp/meta_base/defer.hpp @@ -0,0 +1,144 @@ +/******************************************************************************* + * This file is part of the "https://github.com/blackmatov/meta.hpp" + * For conditions of distribution and use, see copyright notice in LICENSE.md + * Copyright (C) 2021-2023, by Matvey Cherevko (blackmatov@gmail.com) + ******************************************************************************/ + +#pragma once + +#include "base.hpp" + +namespace meta_hpp::detail::impl +{ + template < typename F, typename... Args > + class defer_impl { + public: + defer_impl() = delete; + defer_impl(defer_impl&&) = delete; + defer_impl(const defer_impl&) = delete; + defer_impl& operator=(defer_impl&&) = delete; + defer_impl& operator=(const defer_impl&) = delete; + + template < typename UF > + explicit defer_impl(UF&& f, std::tuple&& args) + : f_{std::forward(f)} + , args_{std::move(args)} {} + + void dismiss() noexcept { + dismissed_ = true; + } + + protected: + ~defer_impl() noexcept { + if ( !dismissed_ ) { + std::apply(std::move(f_), std::move(args_)); + } + } + + private: + F f_; + std::tuple args_; + bool dismissed_{}; + }; +} + +namespace meta_hpp::detail +{ + template < typename F, typename... Args > + class defer final : public impl::defer_impl { + public: + defer() = delete; + defer(defer&&) = delete; + defer(const defer&) = delete; + defer& operator=(defer&&) = delete; + defer& operator=(const defer&) = delete; + + template < typename UF > + explicit defer(UF&& f, std::tuple&& args) + : impl::defer_impl{std::forward(f), std::move(args)} {} + + ~defer() noexcept = default; + }; + + template < typename F, typename... Args > + class error_defer final : public impl::defer_impl { + public: + error_defer() = delete; + error_defer(error_defer&&) = delete; + error_defer(const error_defer&) = delete; + error_defer& operator=(error_defer&&) = delete; + error_defer& operator=(const error_defer&) = delete; + + template < typename UF > + explicit error_defer(UF&& f, std::tuple&& args) + : impl::defer_impl{std::forward(f), std::move(args)} + , exceptions_{std::uncaught_exceptions()} {} + + ~error_defer() noexcept { + if ( exceptions_ == std::uncaught_exceptions() ) { + this->dismiss(); + } + } + + private: + int exceptions_{}; + }; + + template < typename F, typename... Args > + class return_defer final : public impl::defer_impl { + public: + return_defer() = delete; + return_defer(return_defer&&) = delete; + return_defer(const return_defer&) = delete; + return_defer& operator=(return_defer&&) = delete; + return_defer& operator=(const return_defer&) = delete; + + template < typename UF > + explicit return_defer(UF&& f, std::tuple&& args) + : impl::defer_impl{std::forward(f), std::move(args)} + , exceptions_{std::uncaught_exceptions()} {} + + ~return_defer() noexcept { + if ( exceptions_ != std::uncaught_exceptions() ) { + this->dismiss(); + } + } + + private: + int exceptions_{}; + }; + + template < typename F, typename... Args > + auto make_defer(F&& f, Args&&... args) { + using defer_t = defer, std::decay_t...>; + return defer_t{std::forward(f), std::make_tuple(std::forward(args)...)}; + } + + template < typename F, typename... Args > + auto make_error_defer(F&& f, Args&&... args) { + using defer_t = error_defer, std::decay_t...>; + return defer_t{std::forward(f), std::make_tuple(std::forward(args)...)}; + } + + template < typename F, typename... Args > + auto make_return_defer(F&& f, Args&&... args) { + using defer_t = return_defer, std::decay_t...>; + return defer_t{std::forward(f), std::make_tuple(std::forward(args)...)}; + } +} + +#ifdef __COUNTER__ +# define META_HPP_DEFER(...) \ + auto META_HPP_PP_CAT(meta_hpp_generated_defer_, __COUNTER__) { ::meta_hpp::detail::make_defer(__VA_ARGS__) } +# define META_HPP_ERROR_DEFER(...) \ + auto META_HPP_PP_CAT(meta_hpp_generated_error_defer_, __COUNTER__) { ::meta_hpp::detail::make_error_defer(__VA_ARGS__) } +# define META_HPP_RETURN_DEFER(...) \ + auto META_HPP_PP_CAT(meta_hpp_generated_return_defer_, __COUNTER__) { ::meta_hpp::detail::make_return_defer(__VA_ARGS__) } +#else +# define META_HPP_DEFER(...) \ + auto META_HPP_PP_CAT(meta_hpp_generated_defer_, __LINE__) { ::meta_hpp::detail::make_defer(__VA_ARGS__) } +# define META_HPP_ERROR_DEFER(...) \ + auto META_HPP_PP_CAT(meta_hpp_generated_error_defer_, __LINE__) { ::meta_hpp::detail::make_error_defer(__VA_ARGS__) } +# define META_HPP_RETURN_DEFER(...) \ + auto META_HPP_PP_CAT(meta_hpp_generated_return_defer_, __LINE__) { ::meta_hpp::detail::make_return_defer(__VA_ARGS__) } +#endif