You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
353 lines
8.0 KiB
353 lines
8.0 KiB
// -*- c++ -*-
|
|
|
|
#pragma once
|
|
|
|
#include <type_traits>
|
|
#include <utility>
|
|
|
|
namespace std {
|
|
// [C++11 20.6.12.1]
|
|
template <class T>
|
|
T*
|
|
addressof(T& r) noexcept
|
|
{
|
|
return reinterpret_cast<T*>(&(char&)r);
|
|
}
|
|
|
|
// [C++11 20.7.1.1] Default deleters
|
|
template <class T>
|
|
struct default_delete {
|
|
constexpr default_delete() noexcept = default;
|
|
template <class U, typename = typename
|
|
std::enable_if<std::is_convertible<U*, T*>::value>::type>
|
|
default_delete(const default_delete<U>&) noexcept { }
|
|
void operator()(T* ptr) const
|
|
{
|
|
delete ptr;
|
|
}
|
|
};
|
|
|
|
template <class T>
|
|
struct default_delete<T[]> {
|
|
constexpr default_delete() noexcept = default;
|
|
void operator()(T* ptr) const
|
|
{
|
|
delete[] ptr;
|
|
}
|
|
template <class U> void operator()(U*) const = delete;
|
|
};
|
|
|
|
// Use empty base optimization if D is an empty class. However, D
|
|
// might also be a function type, in which case we can't subclass.
|
|
template<class P, class D, bool empty> struct __uptr_impl;
|
|
template<class P, class D>
|
|
struct __uptr_impl<P, D, true> : private D
|
|
{
|
|
P ptr_;
|
|
__uptr_impl(P ptr, const D &d) noexcept : D(d), ptr_(ptr) { }
|
|
__uptr_impl(P ptr, D &&d) noexcept : D(std::move(d)), ptr_(ptr) { }
|
|
D &get_deleter() { return *this; }
|
|
};
|
|
template<class P, class D>
|
|
struct __uptr_impl<P, D, false>
|
|
{
|
|
D d_;
|
|
P ptr_;
|
|
__uptr_impl(P ptr, const D &d) noexcept : d_(d), ptr_(ptr) { }
|
|
__uptr_impl(P ptr, D &&d) noexcept : d_(std::move(d)), ptr_(ptr) { }
|
|
D &get_deleter() { return d_; }
|
|
};
|
|
|
|
// [C++11 20.7.1.2]
|
|
template <class T, class D = default_delete<T>>
|
|
class unique_ptr
|
|
{
|
|
public:
|
|
typedef T* pointer; // XXX Violates standard
|
|
typedef T element_type;
|
|
typedef D deleter_type;
|
|
|
|
private:
|
|
__uptr_impl<pointer, D, std::is_empty<D>::value> impl_;
|
|
|
|
public:
|
|
constexpr unique_ptr() noexcept : impl_(nullptr, D()) { }
|
|
|
|
explicit unique_ptr(pointer p) noexcept : impl_(p, D()) { }
|
|
|
|
unique_ptr(pointer p,
|
|
typename conditional<is_reference<D>::value, D, const D&>::type
|
|
d) noexcept
|
|
: impl_(p, d) { }
|
|
|
|
unique_ptr(pointer p, typename remove_reference<D>::type&& d) noexcept
|
|
: impl_(std::move(p), std::move(d))
|
|
{
|
|
static_assert(!is_reference<D>::value,
|
|
"rvalue deleter bound to reference");
|
|
}
|
|
|
|
unique_ptr(unique_ptr&& u) noexcept
|
|
: impl_(u.release(), std::forward<D>(u.get_deleter())) { }
|
|
|
|
constexpr unique_ptr(nullptr_t) noexcept : unique_ptr() { }
|
|
|
|
template <class U, class E, typename = typename
|
|
enable_if
|
|
<is_convertible<typename unique_ptr<U, E>::pointer, pointer>::value &&
|
|
!is_array<U>::value &&
|
|
conditional<is_reference<D>::value,
|
|
is_same<E, D>,
|
|
is_convertible<E, D> >::type::value>::type>
|
|
unique_ptr(unique_ptr<U, E>&& u) noexcept
|
|
: impl_(u.release(), std::forward<E>(u.get_deleter())) { }
|
|
|
|
~unique_ptr()
|
|
{
|
|
if (get() != nullptr)
|
|
get_deleter()(get());
|
|
}
|
|
|
|
unique_ptr&
|
|
operator=(unique_ptr&& u) noexcept
|
|
{
|
|
reset(u.release());
|
|
get_deleter() = std::forward<D>(u.get_deleter());
|
|
return *this;
|
|
}
|
|
|
|
template <class U, class E, typename = typename
|
|
enable_if
|
|
<is_convertible<typename unique_ptr<U, E>::pointer, pointer>::value &&
|
|
!is_array<U>::value>::type>
|
|
unique_ptr&
|
|
operator=(unique_ptr<U, E>&& u) noexcept
|
|
{
|
|
reset(u.release());
|
|
get_deleter() = std::forward<E>(u.get_deleter());
|
|
return *this;
|
|
}
|
|
|
|
unique_ptr&
|
|
operator=(nullptr_t) noexcept
|
|
{
|
|
reset();
|
|
return *this;
|
|
}
|
|
|
|
typename add_lvalue_reference<T>::type
|
|
operator*() const
|
|
{
|
|
return *get();
|
|
}
|
|
|
|
pointer
|
|
operator->() const noexcept
|
|
{
|
|
return get();
|
|
}
|
|
|
|
pointer
|
|
get() const noexcept
|
|
{
|
|
return impl_.ptr_;
|
|
}
|
|
|
|
deleter_type&
|
|
get_deleter() noexcept
|
|
{
|
|
return impl_.get_deleter();
|
|
}
|
|
|
|
const deleter_type&
|
|
get_deleter() const noexcept
|
|
{
|
|
return impl_.get_deleter();
|
|
}
|
|
|
|
explicit
|
|
operator bool() const noexcept
|
|
{
|
|
return get() != nullptr;
|
|
}
|
|
|
|
pointer
|
|
release() noexcept
|
|
{
|
|
pointer p = get();
|
|
impl_.ptr_ = pointer();
|
|
return p;
|
|
}
|
|
|
|
void
|
|
reset(pointer p = pointer()) noexcept
|
|
{
|
|
pointer o = get();
|
|
impl_.ptr_ = p;
|
|
if (o != pointer())
|
|
get_deleter()(o);
|
|
}
|
|
|
|
void
|
|
swap(unique_ptr& u) noexcept
|
|
{
|
|
std::swap(impl_.ptr_, u.impl_.ptr_);
|
|
std::swap(get_deleter(), u.get_deleter());
|
|
}
|
|
|
|
// Disable copy from lvalue
|
|
unique_ptr(const unique_ptr&) = delete;
|
|
unique_ptr& operator=(const unique_ptr&) = delete;
|
|
};
|
|
|
|
// [C++11 20.7.1.3]
|
|
template <class T, class D>
|
|
class unique_ptr<T[], D>
|
|
{
|
|
public:
|
|
typedef T* pointer; // XXX Violates standard
|
|
typedef T element_type;
|
|
typedef D deleter_type;
|
|
|
|
private:
|
|
__uptr_impl<pointer, D, std::is_empty<D>::value> impl_;
|
|
|
|
public:
|
|
constexpr unique_ptr() noexcept : impl_(nullptr, D()) { }
|
|
|
|
explicit unique_ptr(pointer p) noexcept : impl_(p, D()) { }
|
|
|
|
unique_ptr(pointer p,
|
|
typename conditional<is_reference<D>::value, D, const D&>::type
|
|
d) noexcept
|
|
: impl_(p, d) { }
|
|
|
|
unique_ptr(pointer p, typename remove_reference<D>::type&& d) noexcept
|
|
: impl_(std::move(p), std::move(d))
|
|
{
|
|
static_assert(!is_reference<D>::value,
|
|
"rvalue deleter bound to reference");
|
|
}
|
|
|
|
unique_ptr(unique_ptr&& u) noexcept
|
|
: impl_(u.release(), std::forward<D>(u.get_deleter())) { }
|
|
|
|
constexpr unique_ptr(nullptr_t) noexcept : unique_ptr() { }
|
|
|
|
~unique_ptr()
|
|
{
|
|
if (get() != nullptr)
|
|
get_deleter()(get());
|
|
}
|
|
|
|
unique_ptr&
|
|
operator=(unique_ptr&& u) noexcept
|
|
{
|
|
reset(u.release());
|
|
get_deleter() = std::forward<D>(u.get_deleter());
|
|
return *this;
|
|
}
|
|
|
|
unique_ptr&
|
|
operator=(nullptr_t) noexcept
|
|
{
|
|
reset();
|
|
return *this;
|
|
}
|
|
|
|
T&
|
|
operator[](size_t i) const
|
|
{
|
|
return get()[i];
|
|
}
|
|
|
|
pointer
|
|
get() const noexcept
|
|
{
|
|
return impl_.ptr_;
|
|
}
|
|
|
|
deleter_type&
|
|
get_deleter() noexcept
|
|
{
|
|
return impl_.get_deleter();
|
|
}
|
|
|
|
explicit
|
|
operator bool() const noexcept
|
|
{
|
|
return get() != nullptr;
|
|
}
|
|
|
|
pointer
|
|
release() noexcept
|
|
{
|
|
pointer p = get();
|
|
impl_.ptr_ = pointer();
|
|
return p;
|
|
}
|
|
|
|
void
|
|
reset(pointer p = pointer()) noexcept
|
|
{
|
|
pointer o = get();
|
|
impl_.ptr_ = p;
|
|
if (o != pointer())
|
|
get_deleter()(o);
|
|
}
|
|
|
|
// Disallow resetting to convertible pointer types
|
|
template<typename U, typename = typename enable_if
|
|
<is_pointer<pointer>::value &&
|
|
is_convertible<U*, pointer>::value &&
|
|
is_base_of<T, U>::value &&
|
|
!is_same<typename remove_cv<T>::type,
|
|
typename remove_cv<U>::type>::value>::type>
|
|
void reset(U*) = delete;
|
|
|
|
void
|
|
swap(unique_ptr& u) noexcept
|
|
{
|
|
std::swap(impl_.ptr_, u.impl_.ptr_);
|
|
std::swap(get_deleter(), u.get_deleter());
|
|
}
|
|
};
|
|
|
|
// [C++14 20.8.1.4]
|
|
template<class T>
|
|
struct __make_unique_result
|
|
{
|
|
typedef unique_ptr<T> single;
|
|
};
|
|
|
|
template<class T>
|
|
struct __make_unique_result<T[]>
|
|
{
|
|
typedef unique_ptr<T[]> array;
|
|
};
|
|
|
|
template<class T, size_t Bound>
|
|
struct __make_unique_result<T[Bound]>
|
|
{
|
|
struct invalid { };
|
|
};
|
|
|
|
template<class T, class ...Args>
|
|
typename __make_unique_result<T>::single
|
|
make_unique(Args&& ...args)
|
|
{
|
|
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
|
|
}
|
|
|
|
template<class T>
|
|
typename __make_unique_result<T>::array
|
|
make_unique(size_t bound)
|
|
{
|
|
return unique_ptr<T>(new typename remove_extent<T>::type[bound]());
|
|
}
|
|
|
|
template<class T, class... Args>
|
|
typename __make_unique_result<T>::invalid
|
|
make_unique(Args&&...) = delete;
|
|
}
|