Skip to content

Instantly share code, notes, and snippets.

@HowardHinnant
Created January 17, 2017 22:41
Show Gist options
  • Save HowardHinnant/f31426dfe7e4062611b319733fcffb73 to your computer and use it in GitHub Desktop.
Save HowardHinnant/f31426dfe7e4062611b319733fcffb73 to your computer and use it in GitHub Desktop.
#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