mirror of https://github.com/ARMmbed/mbed-os.git
Add ARMC5 unique_ptr
Standard library implementation should be fine for other toolchains.pull/11039/head
parent
b1c35b7a86
commit
f27c7ecb64
|
@ -23,13 +23,17 @@
|
|||
* - For ARM C 5, C++11/14 features:
|
||||
* - std::align
|
||||
* - std::addressof
|
||||
* - std::unique_ptr, std::make_unique, std::default_delete
|
||||
*/
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <mstd_type_traits>
|
||||
|
||||
#ifdef __CC_ARM
|
||||
|
||||
#include <cstddef> // size_t, ptrdiff_t
|
||||
#include <_move.h> // exchange
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
@ -56,6 +60,437 @@ T *addressof(T &arg) noexcept
|
|||
return reinterpret_cast<T *>(const_cast<char *>(&reinterpret_cast<const volatile char &>(arg)));
|
||||
}
|
||||
|
||||
// [unique.ptr]
|
||||
namespace impl
|
||||
{
|
||||
/* Base version - use T * */
|
||||
template <typename T, typename D, typename = void>
|
||||
struct unique_ptr_type_helper {
|
||||
typedef T *type;
|
||||
};
|
||||
|
||||
/* if "remove_reference_t<D>::pointer" is a type, specialise to use it */
|
||||
template <typename T, typename D>
|
||||
struct unique_ptr_type_helper<T, D, mstd::void_t<typename remove_reference_t<D>::pointer>> {
|
||||
typedef typename remove_reference_t<D>::pointer type;
|
||||
};
|
||||
|
||||
template <class T, class D>
|
||||
using unique_ptr_type_helper_t = typename unique_ptr_type_helper<T, D>::type;
|
||||
|
||||
// Want to eliminate storage for the deleter - could just use it as a base
|
||||
// class, for empty base optimisation, if we knew it was a class. But it could be
|
||||
// a pointer or reference. Here's a version that uses deleter as base,
|
||||
template<class D, typename = void>
|
||||
class deleter_store : private D {
|
||||
public:
|
||||
constexpr deleter_store() noexcept = default;
|
||||
template <typename _D>
|
||||
constexpr deleter_store(_D &&d) noexcept : D(std::forward<_D>(d)) { }
|
||||
|
||||
D &get_deleter() noexcept { return static_cast<D &>(*this); }
|
||||
const D &get_deleter() const noexcept { return static_cast<const D &>(*this); }
|
||||
};
|
||||
|
||||
//Here's a version that stores (for pointer/reference)
|
||||
template<class D>
|
||||
class deleter_store<D, enable_if_t<!is_class<D>::value>> {
|
||||
D d;
|
||||
public:
|
||||
constexpr deleter_store() noexcept : d() { }
|
||||
template <typename _D>
|
||||
constexpr deleter_store(_D &&d) noexcept : d(std::forward<_D>(d)) { }
|
||||
|
||||
D &get_deleter() noexcept { return d; }
|
||||
const D &get_deleter() const noexcept { return d; }
|
||||
};
|
||||
}
|
||||
|
||||
// [unique.ptr.dltr.dflt]
|
||||
template<class T>
|
||||
struct default_delete {
|
||||
constexpr default_delete() noexcept = default;
|
||||
|
||||
template <class U, class = enable_if_t<is_convertible<U *, T *>::value>>
|
||||
default_delete(const default_delete<U> &d) noexcept { }
|
||||
|
||||
void operator()(T *ptr) const
|
||||
{
|
||||
// Program is ill-formed if T is incomplete - generate diagnostic by breaking compilation
|
||||
// (Behaviour of raw delete of incomplete class is undefined if complete class is non-trivial, else permitted)
|
||||
static_assert(sizeof(T) == sizeof(T), "Cannot delete incomplete type");
|
||||
delete ptr;
|
||||
}
|
||||
};
|
||||
|
||||
// [unique.ptr.dltr.dflt1]
|
||||
template<class T>
|
||||
struct default_delete<T[]> {
|
||||
constexpr default_delete() noexcept = default;
|
||||
|
||||
template <class U, class = enable_if_t<is_convertible<U (*)[], T (*)[]>::value>>
|
||||
default_delete(const default_delete<U> &d) noexcept { }
|
||||
|
||||
template <class U, class = enable_if_t<is_convertible<U (*)[], T (*)[]>::value>>
|
||||
void operator()(U *ptr) const
|
||||
{
|
||||
delete[] ptr;
|
||||
}
|
||||
};
|
||||
|
||||
// [unique.ptr.single]
|
||||
template<
|
||||
class T,
|
||||
class D = default_delete<T>
|
||||
> class unique_ptr : public impl::deleter_store<D>
|
||||
{
|
||||
template <class U, class E>
|
||||
static constexpr bool is_compatible_unique_ptr()
|
||||
{
|
||||
return is_convertible<typename unique_ptr<U,E>::pointer, pointer>::value &&
|
||||
!is_array<U>::value;
|
||||
}
|
||||
public:
|
||||
typedef impl::unique_ptr_type_helper_t<T, D> pointer;
|
||||
typedef T element_type;
|
||||
typedef D deleter_type;
|
||||
// [unique.ptr.single.ctor]
|
||||
template <class _D = D, typename = enable_if_t<!is_pointer<_D>::value && is_default_constructible<_D>::value>>
|
||||
constexpr unique_ptr() noexcept : impl::deleter_store<D>(), ptr_() { }
|
||||
template <class _D = D, typename = enable_if_t<!is_pointer<_D>::value && is_default_constructible<_D>::value>>
|
||||
constexpr unique_ptr(nullptr_t) noexcept : unique_ptr() { }
|
||||
template <class _D = D, typename = enable_if_t<!is_pointer<_D>::value && is_default_constructible<_D>::value>>
|
||||
explicit unique_ptr(pointer ptr) noexcept : impl::deleter_store<D>(), ptr_(ptr) { }
|
||||
template <class _D = D, typename = enable_if_t<is_copy_constructible<_D>::value>>
|
||||
unique_ptr(pointer ptr, const D &d) noexcept : impl::deleter_store<D>(d), ptr_(ptr) { }
|
||||
template <class _D = D, typename = enable_if_t<is_move_constructible<_D>::value>>
|
||||
unique_ptr(pointer ptr, enable_if_t<!is_lvalue_reference<_D>::value, _D &&> d) noexcept : impl::deleter_store<D>(move(d)), ptr_(ptr) { }
|
||||
template <class _D = D, typename _A = remove_reference_t<_D>>
|
||||
unique_ptr(pointer ptr, enable_if_t<is_lvalue_reference<_D>::value, _A &&> d) = delete;
|
||||
unique_ptr(const unique_ptr &) = delete;
|
||||
unique_ptr(unique_ptr &&u) noexcept : impl::deleter_store<D>(forward<D>(u.get_deleter())), ptr_(u.ptr_) { u.ptr_ = nullptr; }
|
||||
template <class U, class E, class = enable_if_t<
|
||||
is_compatible_unique_ptr<U, E>() &&
|
||||
(is_reference<D>::value ? is_same<E, D>::value : is_convertible<E,D>::value)>>
|
||||
unique_ptr(unique_ptr<U, E>&& u) noexcept : impl::deleter_store<D>(std::forward<E>(u.get_deleter())), ptr_(u.release()) { }
|
||||
|
||||
// [unique.ptr.single.dtor]
|
||||
~unique_ptr()
|
||||
{
|
||||
if (ptr_) {
|
||||
this->get_deleter()(ptr_);
|
||||
}
|
||||
}
|
||||
|
||||
// [unique.ptr.single.modifiers]
|
||||
pointer release() noexcept
|
||||
{
|
||||
return std::exchange(ptr_, nullptr);
|
||||
}
|
||||
|
||||
void reset(pointer ptr = pointer()) noexcept
|
||||
{
|
||||
pointer old = std::exchange(ptr_, ptr);
|
||||
if (old) {
|
||||
this->get_deleter()(old);
|
||||
}
|
||||
}
|
||||
|
||||
void swap(unique_ptr &other) noexcept
|
||||
{
|
||||
using std::swap;
|
||||
swap(this->get_deleter(), other.get_deleter());
|
||||
swap(ptr_, other.ptr_);
|
||||
}
|
||||
|
||||
// [unique.ptr.single.asgn]
|
||||
unique_ptr &operator=(const unique_ptr &r) = delete;
|
||||
unique_ptr &operator=(unique_ptr &&r) noexcept
|
||||
{
|
||||
reset(r.release());
|
||||
this->get_deleter() = std::forward<D>(r.get_deleter());
|
||||
return *this;
|
||||
}
|
||||
unique_ptr &operator=(nullptr_t) noexcept
|
||||
{
|
||||
reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class U, class E>
|
||||
enable_if_t<is_compatible_unique_ptr<U, E>() &&
|
||||
is_assignable<D &, E &&>::value,
|
||||
unique_ptr> &operator=(unique_ptr<U, E> &&u) noexcept
|
||||
{
|
||||
reset(u.release());
|
||||
this->get_deleter() = std::forward<E>(u.get_deleter());
|
||||
return *this;
|
||||
}
|
||||
|
||||
// [unique.ptr.single.observers]
|
||||
pointer get() const noexcept { return ptr_; }
|
||||
pointer operator->() const noexcept { return ptr_; }
|
||||
add_lvalue_reference_t<T> operator*() const noexcept { return *ptr_; }
|
||||
explicit operator bool() const noexcept { return ptr_; }
|
||||
private:
|
||||
pointer ptr_;
|
||||
};
|
||||
|
||||
// [unique.ptr.runtime]
|
||||
template<class T, class D>
|
||||
class unique_ptr<T[], D> : public impl::deleter_store<D>
|
||||
{
|
||||
template <class U>
|
||||
static constexpr bool is_compatible_pointer()
|
||||
{
|
||||
return is_same<U, pointer>::value ||
|
||||
is_same<U, nullptr_t>::value ||
|
||||
(is_same<pointer, element_type *>::value && is_pointer<U>::value &&
|
||||
is_convertible<remove_pointer_t<U> (*)[], element_type (*)[]>::value);
|
||||
}
|
||||
|
||||
template <class U, class E, class UP = unique_ptr<U,E>>
|
||||
static constexpr bool is_compatible_unique_ptr()
|
||||
{
|
||||
return is_array<U>::value &&
|
||||
is_same<pointer, element_type *>::value &&
|
||||
is_same<typename UP::pointer, typename UP::element_type *>::value &&
|
||||
is_convertible<typename UP::element_type(*)[], element_type(*)[]>::value;
|
||||
}
|
||||
public:
|
||||
typedef impl::unique_ptr_type_helper_t<T, D> pointer;
|
||||
typedef T element_type;
|
||||
typedef D deleter_type;
|
||||
|
||||
// [unique.ptr.runtime.ctor] / [unique.ptr.single.ctor]
|
||||
template <class _D = D, typename = enable_if_t<!is_pointer<_D>::value && is_default_constructible<_D>::value>>
|
||||
constexpr unique_ptr() noexcept : impl::deleter_store<D>(), ptr_() { }
|
||||
|
||||
template <class _D = D, typename = enable_if_t<!is_pointer<_D>::value && is_default_constructible<_D>::value>>
|
||||
constexpr unique_ptr(nullptr_t) noexcept : unique_ptr() { }
|
||||
|
||||
template <class _D = D, typename = enable_if_t<!is_pointer<_D>::value && is_default_constructible<_D>::value>,
|
||||
class U, typename = enable_if_t<is_compatible_pointer<U>()>>
|
||||
explicit unique_ptr(U ptr) noexcept : impl::deleter_store<D>(), ptr_(ptr) { }
|
||||
|
||||
template <class _D = D, typename = enable_if_t<is_copy_constructible<_D>::value>,
|
||||
class U, typename = enable_if_t<is_compatible_pointer<U>()>>
|
||||
unique_ptr(U ptr, const D &d) noexcept : impl::deleter_store<D>(d), ptr_(ptr) { }
|
||||
|
||||
template <class _D = D, typename = enable_if_t<is_move_constructible<_D>::value>,
|
||||
class U, typename = enable_if_t<is_compatible_pointer<U>()>>
|
||||
unique_ptr(U ptr, enable_if_t<!is_lvalue_reference<_D>::value, _D &&> d) noexcept : impl::deleter_store<D>(std::move(d)), ptr_(ptr) { }
|
||||
|
||||
template <class _D = D, typename _A = remove_reference_t<_D>,
|
||||
class U, typename = enable_if_t<is_compatible_pointer<U>()>>
|
||||
unique_ptr(U ptr, enable_if_t<is_lvalue_reference<_D>::value, _A &&> d) = delete;
|
||||
|
||||
unique_ptr(const unique_ptr &) = delete;
|
||||
unique_ptr(unique_ptr &&u) noexcept : impl::deleter_store<D>(std::forward<D>(u.get_deleter())), ptr_(u.ptr_) { u.ptr_ = nullptr; }
|
||||
|
||||
template <class U, class E,
|
||||
typename = enable_if_t<is_compatible_unique_ptr<U, E>() &&
|
||||
(is_reference<D>::value ? is_same<E,D>::value : is_convertible<E,D>::value)>>
|
||||
unique_ptr(unique_ptr<U, E>&& u) noexcept : impl::deleter_store<D>(std::forward<E>(u.get_deleter())), ptr_(u.release()) { }
|
||||
|
||||
// [unique.ptr.single.dtor]
|
||||
~unique_ptr()
|
||||
{
|
||||
if (ptr_) {
|
||||
this->get_deleter()(ptr_);
|
||||
}
|
||||
}
|
||||
|
||||
// [unique.ptr.runtime.modifiers] / [unique.ptr.single.modifiers]
|
||||
pointer release() noexcept
|
||||
{
|
||||
return std::exchange(ptr_, nullptr);
|
||||
}
|
||||
|
||||
void reset(pointer ptr = pointer()) noexcept
|
||||
{
|
||||
pointer old = std::exchange(ptr_, ptr);
|
||||
if (old) {
|
||||
this->get_deleter()(old);
|
||||
}
|
||||
}
|
||||
|
||||
template <class U>
|
||||
void reset(U) = delete;
|
||||
|
||||
void swap(unique_ptr &other) noexcept
|
||||
{
|
||||
using std::swap;
|
||||
swap(this->get_deleter(), other.get_deleter());
|
||||
swap(ptr_, other.ptr_);
|
||||
}
|
||||
|
||||
// [unique.ptr.runtime.asgn] / [unique.ptr.single.asgn]
|
||||
unique_ptr &operator=(const unique_ptr &r) = delete;
|
||||
unique_ptr &operator=(unique_ptr &&r) noexcept
|
||||
{
|
||||
reset(r.release());
|
||||
this->get_deleter() = std::forward<D>(r.get_deleter());
|
||||
return *this;
|
||||
}
|
||||
unique_ptr &operator=(nullptr_t) noexcept
|
||||
{
|
||||
reset();
|
||||
return *this;
|
||||
}
|
||||
template <class U, class E>
|
||||
enable_if_t<is_compatible_unique_ptr<U, E>() &&
|
||||
is_assignable<D &, E &&>::value,
|
||||
unique_ptr> &operator=(unique_ptr<U, E> &&u) noexcept
|
||||
{
|
||||
reset(u.release());
|
||||
this->get_deleter() = std::forward<E>(u.get_deleter());
|
||||
return *this;
|
||||
}
|
||||
|
||||
// [unique.ptr.runtime.observers] / [unique.ptr.single.observers]
|
||||
pointer get() const noexcept { return ptr_; }
|
||||
T &operator[](size_t index) const { return ptr_[index]; }
|
||||
explicit operator bool() const noexcept { return ptr_; }
|
||||
private:
|
||||
pointer ptr_;
|
||||
};
|
||||
|
||||
// [unique.ptr.create]
|
||||
template <typename T, typename... Args>
|
||||
enable_if_t<!is_array<T>::value,
|
||||
unique_ptr<T>> make_unique(Args &&... args)
|
||||
{
|
||||
return unique_ptr<T>(new T(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
enable_if_t<is_array<T>::value && extent<T>::value == 0,
|
||||
unique_ptr<T>> make_unique(size_t size)
|
||||
{
|
||||
return unique_ptr<T>(new remove_extent_t<T>[size]());
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
enable_if_t<extent<T>::value != 0,
|
||||
void> make_unique(Args &&... args) = delete;
|
||||
|
||||
// [unique.ptr.special]
|
||||
template< class T, class D>
|
||||
void swap(unique_ptr<T,D> &lhs, unique_ptr<T,D> &rhs) noexcept
|
||||
{
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
template<class T1, class D1, class T2, class D2>
|
||||
bool operator==(const unique_ptr<T1, D1> &x, const unique_ptr<T2, D2> &y)
|
||||
{
|
||||
return x.get() == y.get();
|
||||
}
|
||||
|
||||
template<class T1, class D1, class T2, class D2>
|
||||
bool operator!=(const unique_ptr<T1, D1> &x, const unique_ptr<T2, D2> &y)
|
||||
{
|
||||
return x.get() != y.get();
|
||||
}
|
||||
|
||||
template<class T1, class D1, class T2, class D2>
|
||||
bool operator<(const unique_ptr<T1, D1> &x, const unique_ptr<T2, D2> &y)
|
||||
{
|
||||
using CT = common_type_t<typename unique_ptr<T1, D1>::pointer, typename unique_ptr<T2, D2>::pointer>;
|
||||
return less<CT>()(x.get(), y.get());
|
||||
}
|
||||
|
||||
template<class T1, class D1, class T2, class D2>
|
||||
bool operator<=(const unique_ptr<T1, D1> &x, const unique_ptr<T2, D2> &y)
|
||||
{
|
||||
return !(y < x);
|
||||
}
|
||||
|
||||
template<class T1, class D1, class T2, class D2>
|
||||
bool operator>(const unique_ptr<T1, D1> &x, const unique_ptr<T2, D2> &y)
|
||||
{
|
||||
return y < x;
|
||||
}
|
||||
|
||||
template<class T1, class D1, class T2, class D2>
|
||||
bool operator>=(const unique_ptr<T1, D1> &x, const unique_ptr<T2, D2> &y)
|
||||
{
|
||||
return !(x < y);
|
||||
}
|
||||
|
||||
template <class T, class D>
|
||||
bool operator==(const unique_ptr<T, D> &x, nullptr_t) noexcept
|
||||
{
|
||||
return !x;
|
||||
}
|
||||
|
||||
template <class T, class D>
|
||||
bool operator==(nullptr_t, const unique_ptr<T, D> &x) noexcept
|
||||
{
|
||||
return !x;
|
||||
}
|
||||
|
||||
template <class T, class D>
|
||||
bool operator!=(const unique_ptr<T, D> &x, nullptr_t) noexcept
|
||||
{
|
||||
return bool(x);
|
||||
}
|
||||
|
||||
template <class T, class D>
|
||||
bool operator!=(nullptr_t, const unique_ptr<T, D> &x) noexcept
|
||||
{
|
||||
return bool(x);
|
||||
}
|
||||
|
||||
template <class T, class D>
|
||||
bool operator<(const unique_ptr<T, D> &x, nullptr_t) noexcept
|
||||
{
|
||||
return less<typename unique_ptr<T, D>::pointer>()(x.get(), nullptr);
|
||||
}
|
||||
|
||||
template <class T, class D>
|
||||
bool operator<(nullptr_t, const unique_ptr<T, D> &x) noexcept
|
||||
{
|
||||
return less<typename unique_ptr<T, D>::pointer>()(nullptr, x.get());
|
||||
}
|
||||
|
||||
template <class T, class D>
|
||||
bool operator>(const unique_ptr<T, D> &x, nullptr_t) noexcept
|
||||
{
|
||||
return nullptr < x;
|
||||
}
|
||||
|
||||
template <class T, class D>
|
||||
bool operator>(nullptr_t, const unique_ptr<T, D> &x) noexcept
|
||||
{
|
||||
return x < nullptr;
|
||||
}
|
||||
|
||||
template <class T, class D>
|
||||
bool operator<=(const unique_ptr<T, D> &x, nullptr_t) noexcept
|
||||
{
|
||||
return !(nullptr < x);
|
||||
}
|
||||
|
||||
template <class T, class D>
|
||||
bool operator<=(nullptr_t, const unique_ptr<T, D> &x) noexcept
|
||||
{
|
||||
return !(x < nullptr);
|
||||
}
|
||||
|
||||
template <class T, class D>
|
||||
bool operator>=(const unique_ptr<T, D> &x, nullptr_t) noexcept
|
||||
{
|
||||
return !(x < nullptr);
|
||||
}
|
||||
|
||||
template <class T, class D>
|
||||
bool operator>=(nullptr_t, const unique_ptr<T, D> &x) noexcept
|
||||
{
|
||||
return !(nullptr < x);
|
||||
}
|
||||
|
||||
} // namespace std
|
||||
|
||||
#endif // __CC_ARM
|
||||
|
@ -67,6 +502,10 @@ namespace mstd {
|
|||
using std::uninitialized_fill_n;
|
||||
using std::addressof;
|
||||
using std::align;
|
||||
|
||||
using std::default_delete;
|
||||
using std::unique_ptr;
|
||||
using std::make_unique;
|
||||
}
|
||||
|
||||
#endif // MSTD_MEMORY_
|
||||
|
|
Loading…
Reference in New Issue