Browse Source

Merge branch 'unique_resource_move_fixes' into development

Fixes #71, fixes #67, fixes #66, fixes #63, fixes #58, fixes #51,
fixes #65.
main
offa 7 years ago
parent
commit
c02a811f7d
2 changed files with 120 additions and 73 deletions
  1. +7
    -7
      .travis.yml
  2. +113
    -66
      include/unique_resource.h

+ 7
- 7
.travis.yml View File

@@ -28,13 +28,13 @@ matrix:
packages:
- g++-5
sources: *sources
- env: CXX=clang++-5.0 CC=clang-5.0
addons:
apt:
packages:
- clang-5.0
- libc++-dev
sources: *sources
#- env: CXX=clang++-5.0 CC=clang-5.0
#addons:
#apt:
#packages:
#- clang-5.0
#- libc++-dev
#sources: *sources
- env: CXX=clang++-4.0 CC=clang-4.0
addons:
apt:

+ 113
- 66
include/unique_resource.h View File

@@ -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;
};


Loading…
Cancel
Save