Created
January 17, 2017 22:41
-
-
Save HowardHinnant/f31426dfe7e4062611b319733fcffb73 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef SCOPE | |
#define SCOPE | |
#include <exception> | |
#include <type_traits> | |
namespace xstd | |
{ | |
// scope_exit | |
template <class EF> | |
class scope_exit | |
{ | |
EF ef_; | |
bool execute_ = true; | |
public: | |
~scope_exit(); | |
scope_exit(scope_exit&& rhs) noexcept; | |
explicit scope_exit(EF f) noexcept; | |
void release() noexcept; | |
}; | |
template <class EF> | |
inline | |
scope_exit<EF>::~scope_exit() | |
{ | |
if (execute_) | |
ef_(); | |
} | |
template <class EF> | |
inline | |
scope_exit<EF>::scope_exit(scope_exit&& rhs) noexcept | |
: ef_(std::forward<EF>(rhs.ef_)) | |
, execute_(rhs.execute_) | |
{ | |
rhs.release(); | |
} | |
template <class EF> | |
inline | |
scope_exit<EF>::scope_exit(EF f) noexcept | |
: ef_(std::forward<EF>(f)) | |
{ | |
} | |
template <class EF> | |
inline | |
void | |
scope_exit<EF>::release() noexcept | |
{ | |
execute_ = false; | |
} | |
// make_scope_xxx | |
template <class EF> | |
inline | |
scope_exit<EF> | |
make_scope_exit(EF ef) noexcept | |
{ | |
return scope_exit<EF>{std::move(ef)}; | |
} | |
template <class EF> | |
auto | |
make_scope_fail(EF ef) noexcept | |
{ | |
return make_scope_exit([ef = std::move(ef), ec = std::uncaught_exceptions()] | |
{ | |
if (ec < std::uncaught_exceptions()) | |
ef(); | |
}); | |
} | |
template <class EF> | |
auto | |
make_scope_success(EF ef) noexcept | |
{ | |
return make_scope_exit([ef = std::move(ef), ec = std::uncaught_exceptions()] | |
{ | |
if (!(ec < std::uncaught_exceptions())) | |
ef(); | |
}); | |
} | |
// unique_resource | |
template<class R, class D> | |
class unique_resource | |
{ | |
R r_; | |
D d_; | |
bool execute_; | |
public: | |
~unique_resource(); | |
unique_resource(unique_resource&& rhs) noexcept; | |
unique_resource& operator=(unique_resource&& rhs) noexcept; | |
unique_resource(R r, D d) noexcept; | |
void reset(); | |
void reset(R r); | |
R release() noexcept; | |
R const& get() const noexcept; | |
operator R const& () const noexcept; | |
template <class Constraint = std::integral_constant<bool, std::is_pointer<R>::value && | |
(std::is_class<std::remove_pointer_t<R>>::value || | |
std::is_union<std::remove_pointer_t<R>>::value)>> | |
std::enable_if_t<Constraint::value, R> | |
operator->() const noexcept; | |
template <class T = void, class Constraint = std::enable_if_t<std::is_void<T>::value && | |
std::is_pointer<R>::value>> | |
decltype(auto) | |
operator* () const noexcept; | |
const D& get_deleter() const noexcept; | |
}; | |
template<class R, class D> | |
inline | |
unique_resource<R, D>::~unique_resource() | |
{ | |
reset(); | |
} | |
template<class R, class D> | |
inline | |
unique_resource<R, D>::unique_resource(unique_resource&& rhs) noexcept | |
: r_(std::move(rhs.r_)) | |
, d_(std::move(rhs.d_)) | |
, execute_(std::move(rhs.execute_)) | |
{ | |
rhs.release(); | |
} | |
template<class R, class D> | |
unique_resource<R, D>& | |
unique_resource<R, D>::operator=(unique_resource&& rhs) noexcept | |
{ | |
reset(); | |
r_ = std::move(rhs.r_); | |
d_ = std::move(rhs.d_); | |
execute_ = std::move(rhs.execute_); | |
rhs.release(); | |
return *this; | |
} | |
template<class R, class D> | |
inline | |
unique_resource<R, D>::unique_resource(R r, D d) noexcept | |
: r_(std::move(r)) | |
, d_(std::move(d)) | |
, execute_(true) | |
{ | |
} | |
template<class R, class D> | |
inline | |
void | |
unique_resource<R, D>::reset() | |
{ | |
if (execute_) | |
{ | |
execute_ = false; | |
d_(r_); | |
} | |
} | |
template<class R, class D> | |
inline | |
void | |
unique_resource<R, D>::reset(R r) | |
{ | |
reset(); | |
r_ = std::move(r); | |
execute_ = true; | |
} | |
template<class R, class D> | |
inline | |
R | |
unique_resource<R, D>::release() noexcept | |
{ | |
execute_ = false; | |
return std::move(r_); | |
} | |
template<class R, class D> | |
inline | |
R const& | |
unique_resource<R, D>::get() const noexcept | |
{ | |
return r_; | |
} | |
template<class R, class D> | |
inline | |
unique_resource<R, D>::operator R const& () const noexcept | |
{ | |
return r_; | |
} | |
template<class R, class D> | |
template <class Constraint> | |
inline | |
std::enable_if_t<Constraint::value, R> | |
unique_resource<R, D>::operator->() const noexcept | |
{ | |
return r_; | |
} | |
template<class R, class D> | |
template <class T, class Constraint> | |
inline | |
decltype(auto) | |
unique_resource<R, D>::operator* () const noexcept | |
{ | |
return *r_; | |
} | |
template<class R, class D> | |
inline | |
const D& | |
unique_resource<R, D>::get_deleter() const noexcept | |
{ | |
return d_; | |
} | |
template<class R,class D> | |
inline | |
unique_resource<R, D> | |
make_unique_resource(R r, D d) noexcept | |
{ | |
return unique_resource<R, D>{std::move(r), std::move(d)}; | |
} | |
template<class R, class D, class RI = R> | |
inline | |
unique_resource<R, D> | |
make_unique_resource_checked(R r, RI invalid, D d) noexcept | |
{ | |
auto ur = unique_resource<R,D>(std::move(r), std::move(d)); | |
if (static_cast<bool>(r == invalid)) | |
ur.release(); | |
return ur; | |
} | |
} // namespace xstd | |
#endif // SCOPE |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment