Assert that unique_ref is always defined and not nullptr
This commit is contained in:
parent
317088e449
commit
ec3bec07ff
@ -28,37 +28,42 @@ namespace cpputils {
|
|||||||
template<class T, class D = std::default_delete<T>>
|
template<class T, class D = std::default_delete<T>>
|
||||||
class unique_ref final {
|
class unique_ref final {
|
||||||
public:
|
public:
|
||||||
// TODO Add assert != nullptr to all calls (also move constructors, ...) and test performance impact (maybe disable assertions in prod?)
|
|
||||||
using element_type = typename std::unique_ptr<T, D>::element_type;
|
using element_type = typename std::unique_ptr<T, D>::element_type;
|
||||||
using deleter_type = typename std::unique_ptr<T, D>::deleter_type;
|
using deleter_type = typename std::unique_ptr<T, D>::deleter_type;
|
||||||
using pointer = typename std::unique_ptr<T, D>::pointer;
|
using pointer = typename std::unique_ptr<T, D>::pointer;
|
||||||
|
|
||||||
unique_ref(unique_ref&& from) noexcept: _target(std::move(from._target)) {
|
unique_ref(unique_ref&& from) noexcept
|
||||||
|
: _target(std::move(from._target)) {
|
||||||
from._target = nullptr;
|
from._target = nullptr;
|
||||||
|
_invariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class U> unique_ref(unique_ref<U>&& from) noexcept: _target(std::move(from._target)) {
|
template<class U> unique_ref(unique_ref<U>&& from) noexcept
|
||||||
|
: _target(std::move(from._target)) {
|
||||||
from._target = nullptr;
|
from._target = nullptr;
|
||||||
|
_invariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
unique_ref& operator=(unique_ref&& from) noexcept {
|
unique_ref& operator=(unique_ref&& from) noexcept {
|
||||||
_target = std::move(from._target);
|
_target = std::move(from._target);
|
||||||
from._target = nullptr;
|
from._target = nullptr;
|
||||||
|
_invariant();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class U> unique_ref& operator=(unique_ref<U>&& from) noexcept {
|
template<class U> unique_ref& operator=(unique_ref<U>&& from) noexcept {
|
||||||
_target = std::move(from._target);
|
_target = std::move(from._target);
|
||||||
from._target = nullptr;
|
from._target = nullptr;
|
||||||
|
_invariant();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
typename std::add_lvalue_reference<element_type>::type operator*() const& noexcept {
|
typename std::add_lvalue_reference<element_type>::type operator*() const& noexcept {
|
||||||
ASSERT(_target.get() != nullptr, "Member was moved out to another unique_ref. This instance is invalid.");
|
_invariant();
|
||||||
return *_target;
|
return *_target;
|
||||||
}
|
}
|
||||||
typename std::add_rvalue_reference<element_type>::type operator*() && noexcept {
|
typename std::add_rvalue_reference<element_type>::type operator*() && noexcept {
|
||||||
ASSERT(_target.get() != nullptr, "Member was moved out to another unique_ref. This instance is invalid.");
|
_invariant();
|
||||||
return std::move(*_target);
|
return std::move(*_target);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,18 +72,20 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
pointer get() const noexcept {
|
pointer get() const noexcept {
|
||||||
ASSERT(_target.get() != nullptr, "Member was moved out to another unique_ref. This instance is invalid.");
|
_invariant();
|
||||||
return _target.get();
|
return _target.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T2>
|
template<class T2>
|
||||||
operator std::unique_ptr<T2>() && noexcept {
|
operator std::unique_ptr<T2>() && noexcept {
|
||||||
return std::move(_target);
|
_invariant();
|
||||||
|
return std::move(_target);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T2>
|
template<class T2>
|
||||||
operator std::shared_ptr<T2>() && noexcept {
|
operator std::shared_ptr<T2>() && noexcept {
|
||||||
return std::move(_target);
|
_invariant();
|
||||||
|
return std::move(_target);
|
||||||
}
|
}
|
||||||
|
|
||||||
void swap(unique_ref& rhs) noexcept {
|
void swap(unique_ref& rhs) noexcept {
|
||||||
@ -90,20 +97,29 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
deleter_type& get_deleter() noexcept {
|
deleter_type& get_deleter() noexcept {
|
||||||
return _target.get_deleter();
|
return _target.get_deleter();
|
||||||
}
|
}
|
||||||
|
|
||||||
const deleter_type& get_deleter() const noexcept {
|
const deleter_type& get_deleter() const noexcept {
|
||||||
return _target.get_deleter();
|
return _target.get_deleter();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit unique_ref(std::unique_ptr<T, D> target) noexcept: _target(std::move(target)) {}
|
explicit unique_ref(std::unique_ptr<T, D> target) noexcept
|
||||||
|
: _target(std::move(target)) {}
|
||||||
|
|
||||||
|
void _invariant() const {
|
||||||
|
// TODO Test performance impact of this
|
||||||
|
ASSERT(_target.get() != nullptr, "Member was moved out to another unique_ref. This instance is invalid.");
|
||||||
|
}
|
||||||
|
|
||||||
template<class U, class... Args> friend unique_ref<U> make_unique_ref(Args&&... args);
|
template<class U, class... Args> friend unique_ref<U> make_unique_ref(Args&&... args);
|
||||||
template<class T2, class D2> friend boost::optional<unique_ref<T2, D2>> nullcheck(std::unique_ptr<T2, D2> ptr) noexcept;
|
template<class T2, class D2> friend boost::optional<unique_ref<T2, D2>> nullcheck(std::unique_ptr<T2, D2> ptr) noexcept;
|
||||||
template<class T2, class D2> friend class unique_ref;
|
template<class T2, class D2> friend class unique_ref;
|
||||||
template<class DST, class SRC> friend boost::optional<unique_ref<DST>> dynamic_pointer_move(unique_ref<SRC> &source) noexcept;
|
template<class DST, class SRC> friend boost::optional<unique_ref<DST>> dynamic_pointer_move(unique_ref<SRC> &source) noexcept;
|
||||||
template<class T2, class D2> friend const typename unique_ref<T2, D2>::pointer _extract_ptr(const unique_ref<T2, D2> &obj) noexcept;
|
template<class T2, class D2> friend bool operator==(const unique_ref<T2, D2>& lhs, const unique_ref<T2, D2>& rhs) noexcept;
|
||||||
|
friend struct std::hash<unique_ref<T, D>>;
|
||||||
|
friend struct std::less<unique_ref<T, D>>;
|
||||||
|
|
||||||
std::unique_ptr<T, D> _target;
|
std::unique_ptr<T, D> _target;
|
||||||
|
|
||||||
@ -127,10 +143,6 @@ template<class T, class D> inline void destruct(unique_ref<T, D> /*ptr*/) {
|
|||||||
// ptr will be moved in to this function and destructed on return
|
// ptr will be moved in to this function and destructed on return
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T, class D> const typename unique_ref<T, D>::pointer _extract_ptr(const unique_ref<T, D> &obj) noexcept {
|
|
||||||
return obj._target.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO Also allow passing a rvalue reference, otherwise dynamic_pointer_move(func()) won't work
|
//TODO Also allow passing a rvalue reference, otherwise dynamic_pointer_move(func()) won't work
|
||||||
template<class DST, class SRC>
|
template<class DST, class SRC>
|
||||||
inline boost::optional<unique_ref<DST>> dynamic_pointer_move(unique_ref<SRC> &source) noexcept {
|
inline boost::optional<unique_ref<DST>> dynamic_pointer_move(unique_ref<SRC> &source) noexcept {
|
||||||
@ -139,7 +151,7 @@ inline boost::optional<unique_ref<DST>> dynamic_pointer_move(unique_ref<SRC> &so
|
|||||||
|
|
||||||
template<class T, class D>
|
template<class T, class D>
|
||||||
inline bool operator==(const unique_ref<T, D> &lhs, const unique_ref<T, D> &rhs) noexcept {
|
inline bool operator==(const unique_ref<T, D> &lhs, const unique_ref<T, D> &rhs) noexcept {
|
||||||
return _extract_ptr(lhs) == _extract_ptr(rhs);
|
return lhs._target == rhs._target;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T, class D>
|
template<class T, class D>
|
||||||
@ -168,14 +180,14 @@ namespace std {
|
|||||||
// Allow using it in std::unordered_set / std::unordered_map
|
// Allow using it in std::unordered_set / std::unordered_map
|
||||||
template<class T, class D> struct hash<cpputils::unique_ref<T, D>> {
|
template<class T, class D> struct hash<cpputils::unique_ref<T, D>> {
|
||||||
size_t operator()(const cpputils::unique_ref<T, D> &ref) const noexcept {
|
size_t operator()(const cpputils::unique_ref<T, D> &ref) const noexcept {
|
||||||
return std::hash<typename cpputils::unique_ref<T, D>::pointer>()(_extract_ptr(ref));
|
return std::hash<unique_ptr<T, D>>()(ref._target);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Allow using it in std::map / std::set
|
// Allow using it in std::map / std::set
|
||||||
template <class T, class D> struct less<cpputils::unique_ref<T, D>> {
|
template <class T, class D> struct less<cpputils::unique_ref<T, D>> {
|
||||||
bool operator()(const cpputils::unique_ref<T, D> &lhs, const cpputils::unique_ref<T, D> &rhs) const noexcept {
|
bool operator()(const cpputils::unique_ref<T, D> &lhs, const cpputils::unique_ref<T, D> &rhs) const noexcept {
|
||||||
return _extract_ptr(lhs) < _extract_ptr(rhs);
|
return lhs._target < rhs._target;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user