mirror of
https://github.com/BlackMATov/defer.hpp.git
synced 2025-12-16 22:19:19 +07:00
initial commit
This commit is contained in:
150
headers/defer.hpp/defer.hpp
Normal file
150
headers/defer.hpp/defer.hpp
Normal file
@@ -0,0 +1,150 @@
|
||||
/*******************************************************************************
|
||||
* This file is part of the "https://github.com/blackmatov/defer.hpp"
|
||||
* For conditions of distribution and use, see copyright notice in LICENSE.md
|
||||
* Copyright (C) 2020, by Matvey Cherevko (blackmatov@gmail.com)
|
||||
******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <exception>
|
||||
#include <functional>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace defer_hpp
|
||||
{
|
||||
namespace impl
|
||||
{
|
||||
class noncopyable {
|
||||
public:
|
||||
noncopyable(const noncopyable&) = delete;
|
||||
noncopyable& operator=(const noncopyable&) = delete;
|
||||
protected:
|
||||
noncopyable() = default;
|
||||
~noncopyable() = default;
|
||||
};
|
||||
|
||||
template < typename F, typename... Args >
|
||||
class defer_impl : noncopyable {
|
||||
public:
|
||||
template < typename UF >
|
||||
explicit defer_impl(
|
||||
UF&& f,
|
||||
std::tuple<Args...>&& args)
|
||||
: f_(std::forward<UF>(f))
|
||||
, args_(std::move(args)) {}
|
||||
|
||||
virtual ~defer_impl() noexcept {
|
||||
if ( !dismissed_ ) {
|
||||
std::apply(std::move(f_), std::move(args_));
|
||||
}
|
||||
}
|
||||
|
||||
void dismiss() noexcept {
|
||||
dismissed_ = true;
|
||||
}
|
||||
private:
|
||||
F f_;
|
||||
std::tuple<Args...> args_;
|
||||
bool dismissed_{};
|
||||
};
|
||||
|
||||
template < typename F, typename... Args >
|
||||
class error_defer_impl final : public defer_impl<F, Args...> {
|
||||
public:
|
||||
template < typename UF >
|
||||
explicit error_defer_impl(
|
||||
UF&& f,
|
||||
std::tuple<Args...>&& args)
|
||||
: defer_impl<F>(std::forward<UF>(f), std::move(args))
|
||||
, exceptions_(std::uncaught_exceptions()) {}
|
||||
|
||||
~error_defer_impl() noexcept final {
|
||||
if ( exceptions_ == std::uncaught_exceptions() ) {
|
||||
this->dismiss();
|
||||
}
|
||||
}
|
||||
private:
|
||||
int exceptions_{};
|
||||
};
|
||||
|
||||
template < typename F, typename... Args >
|
||||
class return_defer_impl final : public defer_impl<F, Args...> {
|
||||
public:
|
||||
template < typename UF >
|
||||
explicit return_defer_impl(
|
||||
UF&& f,
|
||||
std::tuple<Args...>&& args)
|
||||
: defer_impl<F>(std::forward<UF>(f), std::move(args))
|
||||
, exceptions_(std::uncaught_exceptions()) {}
|
||||
|
||||
~return_defer_impl() noexcept final {
|
||||
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 = impl::defer_impl<
|
||||
std::decay_t<F>,
|
||||
std::decay_t<Args>...>;
|
||||
return defer_t(
|
||||
std::forward<F>(f),
|
||||
std::make_tuple(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
template < typename F, typename... Args >
|
||||
auto make_error_defer(F&& f, Args&&... args) {
|
||||
using defer_t = impl::error_defer_impl<
|
||||
std::decay_t<F>,
|
||||
std::decay_t<Args>...>;
|
||||
return defer_t(
|
||||
std::forward<F>(f),
|
||||
std::make_tuple(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
template < typename F, typename... Args >
|
||||
auto make_return_defer(F&& f, Args&&... args) {
|
||||
using defer_t = impl::return_defer_impl<
|
||||
std::decay_t<F>,
|
||||
std::decay_t<Args>...>;
|
||||
return defer_t(
|
||||
std::forward<F>(f),
|
||||
std::make_tuple(std::forward<Args>(args)...));
|
||||
}
|
||||
}
|
||||
|
||||
#define DEFER_IMPL_PP_CAT(x, y) DEFER_IMPL_PP_CAT_I(x, y)
|
||||
#define DEFER_IMPL_PP_CAT_I(x, y) x ## y
|
||||
|
||||
#ifdef __COUNTER__
|
||||
#define DEFER(...)\
|
||||
auto DEFER_IMPL_PP_CAT(generated_defer_, __COUNTER__) =\
|
||||
::defer_hpp::make_defer(__VA_ARGS__)
|
||||
|
||||
#define ERROR_DEFER(...)\
|
||||
auto DEFER_IMPL_PP_CAT(generated_error_defer_, __COUNTER__) =\
|
||||
::defer_hpp::make_error_defer(__VA_ARGS__)
|
||||
|
||||
#define RETURN_DEFER(...)\
|
||||
auto DEFER_IMPL_PP_CAT(generated_return_defer_, __COUNTER__) =\
|
||||
::defer_hpp::make_return_defer(__VA_ARGS__)
|
||||
#else
|
||||
#define DEFER(...)\
|
||||
auto DEFER_IMPL_PP_CAT(generated_defer_, __LINE__) =\
|
||||
::defer_hpp::make_defer(__VA_ARGS__)
|
||||
|
||||
#define ERROR_DEFER(...)\
|
||||
auto DEFER_IMPL_PP_CAT(generated_error_defer_, __LINE__) =\
|
||||
::defer_hpp::make_error_defer(__VA_ARGS__)
|
||||
|
||||
#define RETURN_DEFER(...)\
|
||||
auto DEFER_IMPL_PP_CAT(generated_return_defer_, __LINE__) =\
|
||||
::defer_hpp::make_return_defer(__VA_ARGS__)
|
||||
#endif
|
||||
Reference in New Issue
Block a user