|
|
@@ -23,6 +23,7 @@ |
|
|
|
#include "scope_exit.h" |
|
|
|
#include <utility> |
|
|
|
#include <type_traits> |
|
|
|
#include <functional> |
|
|
|
|
|
|
|
namespace sr |
|
|
|
{ |
|
|
@@ -36,50 +37,99 @@ namespace sr |
|
|
|
constexpr auto is_nothrow_move_or_copy_constructible_from_v = is_ntmocp_constructible<T, TT>::value; |
|
|
|
|
|
|
|
|
|
|
|
template<class T, |
|
|
|
class U = std::conditional_t<(!std::is_nothrow_move_assignable<T>::value |
|
|
|
&& std::is_copy_assignable<T>::value), |
|
|
|
const T&, |
|
|
|
T &&>> |
|
|
|
constexpr U move_assign_if_noexcept(T& value) noexcept |
|
|
|
template<class T, class U = std::conditional_t<std::is_nothrow_move_constructible<T>::value, T&&, const T&>> |
|
|
|
constexpr U forward_if_nothrow_move_constructible(T&& value) noexcept |
|
|
|
{ |
|
|
|
return std::move(value); |
|
|
|
return std::forward<T>(value); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
template<class T, class U = std::conditional_t<std::is_nothrow_move_constructible<T>::value, T&&, const T&>> |
|
|
|
constexpr U forward_if_nothrow_move_constructible(T&& value) |
|
|
|
|
|
|
|
template<class T> |
|
|
|
struct Wrapper |
|
|
|
{ |
|
|
|
return std::forward<T>(value); |
|
|
|
} |
|
|
|
template<class TT, class G, std::enable_if_t<std::is_constructible<T, TT>::value, int> = 0> |
|
|
|
explicit Wrapper(TT&& value, G&& g) noexcept(noexcept(Wrapper{value})) : Wrapper(value) |
|
|
|
{ |
|
|
|
g.release(); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
T& get() noexcept |
|
|
|
{ |
|
|
|
return m_value; |
|
|
|
} |
|
|
|
|
|
|
|
template<class R, class D> |
|
|
|
class unique_resource |
|
|
|
const T& get() const noexcept |
|
|
|
{ |
|
|
|
return m_value; |
|
|
|
} |
|
|
|
|
|
|
|
void reset(T&& newValue) noexcept(std::is_nothrow_assignable<T, decltype(std::move_if_noexcept(newValue))>::value) |
|
|
|
{ |
|
|
|
m_value = std::move_if_noexcept(newValue); |
|
|
|
} |
|
|
|
|
|
|
|
void reset(const T& newValue) noexcept(std::is_nothrow_assignable<T, const T&>::value) |
|
|
|
{ |
|
|
|
m_value = newValue; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
|
|
|
Wrapper(const T& value) noexcept(noexcept(T{value})) : m_value(value) |
|
|
|
{ |
|
|
|
} |
|
|
|
|
|
|
|
Wrapper(T&& value) noexcept(noexcept(T{std::move_if_noexcept(value)})) : m_value(std::move_if_noexcept(value)) |
|
|
|
{ |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
T m_value; |
|
|
|
}; |
|
|
|
|
|
|
|
template<class T> |
|
|
|
struct Wrapper<T&> |
|
|
|
{ |
|
|
|
public: |
|
|
|
template<class TT, class G, std::enable_if_t<std::is_convertible<TT, T&>::value, int> = 0> |
|
|
|
explicit Wrapper(TT&& value, G&& g) noexcept(noexcept(static_cast<T&>(value))) : m_value(static_cast<T&>(value)) |
|
|
|
{ |
|
|
|
g.release(); |
|
|
|
} |
|
|
|
|
|
|
|
template<class RR, class DD, |
|
|
|
std::enable_if_t<(!std::is_lvalue_reference<RR>::value) |
|
|
|
&& std::is_nothrow_constructible<R, RR>::value, int> = 0, |
|
|
|
std::enable_if_t<(!std::is_lvalue_reference<DD>::value) |
|
|
|
&& std::is_nothrow_constructible<D, DD>::value, int> = 0, |
|
|
|
std::enable_if_t<(std::is_copy_constructible<R>::value || std::is_nothrow_move_constructible<R>::value) |
|
|
|
&& (std::is_copy_constructible<D>::value || std::is_nothrow_move_constructible<D>::value), int> = 0, |
|
|
|
std::enable_if_t<is_nothrow_move_or_copy_constructible_from_v<R, RR>, int> = 0, |
|
|
|
std::enable_if_t<is_nothrow_move_or_copy_constructible_from_v<D, DD>, int> = 0 |
|
|
|
> |
|
|
|
explicit unique_resource(RR&& r, DD&& d) noexcept(std::is_nothrow_constructible<R,RR>::value |
|
|
|
&& std::is_nothrow_constructible<D, DD>::value) |
|
|
|
: m_resource(std::move(r)), |
|
|
|
m_deleter(std::move(d)), |
|
|
|
m_execute_on_destruction(true) |
|
|
|
|
|
|
|
T& get() noexcept |
|
|
|
{ |
|
|
|
return m_value.get(); |
|
|
|
} |
|
|
|
|
|
|
|
const T& get() const noexcept |
|
|
|
{ |
|
|
|
return m_value.get(); |
|
|
|
} |
|
|
|
|
|
|
|
void reset(T& newValue) noexcept |
|
|
|
{ |
|
|
|
m_value = std::ref(newValue); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
|
|
|
std::reference_wrapper<T> m_value; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template<class R, class D> |
|
|
|
class unique_resource |
|
|
|
{ |
|
|
|
public: |
|
|
|
|
|
|
|
template<class RR, class DD, |
|
|
|
std::enable_if_t<std::is_lvalue_reference<RR>::value || std::is_lvalue_reference<DD>::value, int> = 0, |
|
|
|
std::enable_if_t<(std::is_copy_constructible<R>::value || std::is_nothrow_move_constructible<R>::value) |
|
|
|
&& (std::is_copy_constructible<D>::value || std::is_nothrow_move_constructible<D>::value), int> = 0, |
|
|
|
std::enable_if_t<is_nothrow_move_or_copy_constructible_from_v<R, RR>, int> = 0, |
|
|
@@ -87,39 +137,21 @@ namespace sr |
|
|
|
> |
|
|
|
explicit unique_resource(RR&& r, DD&& d) noexcept(std::is_nothrow_constructible<R, RR>::value |
|
|
|
&& std::is_nothrow_constructible<D, DD>::value) |
|
|
|
try : m_resource(r), |
|
|
|
m_deleter(d), |
|
|
|
m_execute_on_destruction(true) |
|
|
|
{ |
|
|
|
} |
|
|
|
catch( ... ) |
|
|
|
{ |
|
|
|
d(r); |
|
|
|
} |
|
|
|
|
|
|
|
template<class TR = R, std::enable_if_t<std::is_nothrow_move_constructible<TR>::value, int> = 0> |
|
|
|
unique_resource(unique_resource&& other) noexcept(std::is_nothrow_move_constructible<R>::value |
|
|
|
&& std::is_nothrow_move_constructible<D>::value) |
|
|
|
: m_resource(forward_if_nothrow_move_constructible<R>(std::forward<R>(other.m_resource))), |
|
|
|
m_deleter(forward_if_nothrow_move_constructible<D>(std::forward<D>(other.m_deleter))), |
|
|
|
m_execute_on_destruction(std::exchange(other.m_execute_on_destruction, false)) |
|
|
|
: m_resource(std::forward<RR>(r), make_scope_exit([&r, &d] { d(r); })), |
|
|
|
m_deleter(std::forward<DD>(d), make_scope_exit([this, &d] { d(get()); })), |
|
|
|
m_execute_on_destruction(true) |
|
|
|
{ |
|
|
|
} |
|
|
|
|
|
|
|
template<class TR = R, std::enable_if_t<!std::is_nothrow_move_constructible<TR>::value, int> = 0> |
|
|
|
unique_resource(unique_resource&& other) noexcept(std::is_nothrow_move_constructible<R>::value |
|
|
|
&& std::is_nothrow_move_constructible<D>::value) |
|
|
|
try : m_resource(forward_if_nothrow_move_constructible<R>(std::forward<R>(other.m_resource))), |
|
|
|
m_deleter(forward_if_nothrow_move_constructible<D>(std::forward<D>(other.m_deleter))), |
|
|
|
&& std::is_nothrow_move_constructible<D>::value) |
|
|
|
: m_resource(forward_if_nothrow_move_constructible(other.m_resource.get()), make_scope_exit([] { })), |
|
|
|
m_deleter(forward_if_nothrow_move_constructible(other.m_deleter.get()), make_scope_exit([&other] { |
|
|
|
other.get_deleter()(other.m_resource.get()); |
|
|
|
other.release(); })), |
|
|
|
m_execute_on_destruction(std::exchange(other.m_execute_on_destruction, false)) |
|
|
|
{ |
|
|
|
} |
|
|
|
catch( ... ) |
|
|
|
{ |
|
|
|
other.get_deleter()(other.m_resource); |
|
|
|
other.release(); |
|
|
|
throw; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
unique_resource(const unique_resource&) = delete; |
|
|
@@ -135,7 +167,7 @@ namespace sr |
|
|
|
if( m_execute_on_destruction == true ) |
|
|
|
{ |
|
|
|
m_execute_on_destruction = false; |
|
|
|
get_deleter()(m_resource); |
|
|
|
get_deleter()(m_resource.get()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@@ -144,7 +176,7 @@ namespace sr |
|
|
|
{ |
|
|
|
auto se = make_scope_exit([this, &r] { get_deleter()(r); }); |
|
|
|
reset(); |
|
|
|
m_resource = move_assign_if_noexcept(r); |
|
|
|
m_resource.reset(std::forward<RR>(r)); |
|
|
|
m_execute_on_destruction = true; |
|
|
|
se.release(); |
|
|
|
} |
|
|
@@ -154,9 +186,9 @@ namespace sr |
|
|
|
m_execute_on_destruction = false; |
|
|
|
} |
|
|
|
|
|
|
|
const R& get() const noexcept |
|
|
|
decltype(auto) get() const noexcept |
|
|
|
{ |
|
|
|
return m_resource; |
|
|
|
return m_resource.get(); |
|
|
|
} |
|
|
|
|
|
|
|
template<class RR = R, |
|
|
@@ -166,7 +198,7 @@ namespace sr |
|
|
|
> |
|
|
|
RR operator->() const noexcept |
|
|
|
{ |
|
|
|
return m_resource; |
|
|
|
return m_resource.get(); |
|
|
|
} |
|
|
|
|
|
|
|
template<class RR = R, |
|
|
@@ -178,7 +210,7 @@ namespace sr |
|
|
|
|
|
|
|
const D& get_deleter() const noexcept |
|
|
|
{ |
|
|
|
return m_deleter; |
|
|
|
return m_deleter.get(); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@@ -191,8 +223,23 @@ namespace sr |
|
|
|
if( this != &other ) |
|
|
|
{ |
|
|
|
reset(); |
|
|
|
m_resource = std::forward<RR>(other.m_resource); |
|
|
|
m_deleter = std::forward<DD>(other.m_deleter); |
|
|
|
|
|
|
|
if( std::is_nothrow_move_assignable<R>::value == true ) |
|
|
|
{ |
|
|
|
m_deleter.reset(forward_if_nothrow_move_constructible(other.m_deleter.get())); |
|
|
|
m_resource.reset(std::forward<RR>(other.m_resource.get())); |
|
|
|
} |
|
|
|
else if( std::is_nothrow_move_assignable<D>::value == true ) |
|
|
|
{ |
|
|
|
m_resource.reset(forward_if_nothrow_move_constructible(other.m_resource.get())); |
|
|
|
m_deleter.reset(std::forward<DD>(other.m_deleter.get())); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
m_resource = other.m_resource; |
|
|
|
m_deleter = other.m_deleter; |
|
|
|
} |
|
|
|
|
|
|
|
m_execute_on_destruction = std::exchange(other.m_execute_on_destruction, false); |
|
|
|
} |
|
|
|
return *this; |
|
|
@@ -203,8 +250,8 @@ namespace sr |
|
|
|
|
|
|
|
private: |
|
|
|
|
|
|
|
R m_resource; |
|
|
|
D m_deleter; |
|
|
|
Wrapper<R> m_resource; |
|
|
|
Wrapper<D> m_deleter; |
|
|
|
bool m_execute_on_destruction; |
|
|
|
}; |
|
|
|
|