473 lines
13 KiB
C++
473 lines
13 KiB
C++
// Copyright 2009 Howard Hinnant, Ion Gaztañaga.
|
|
// Distributed under the Boost Software License, Version 1.0. (See
|
|
// accompanying file LICENSE_1_0.txt or copy at
|
|
// http://www.boost.org/LICENSE_1_0.txt)
|
|
// See http://www.boost.org/libs/foreach for documentation
|
|
|
|
// This is a C++03 emulation of std::unique_ptr placed in namespace boost.
|
|
// Reference http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2800.pdf
|
|
// for the latest unique_ptr specification, and
|
|
// reference http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html
|
|
// for any pending issues against this specification.
|
|
|
|
#ifndef BUTIL_UNIQUE_PTR_H
|
|
#define BUTIL_UNIQUE_PTR_H
|
|
|
|
#include "butil/build_config.h"
|
|
|
|
#if defined(BUTIL_CXX11_ENABLED)
|
|
|
|
#include <memory> // std::unique_ptr
|
|
|
|
#elif !defined(BAIDU_NO_EMULATED_UNIQUE_PTR)
|
|
|
|
#include <algorithm> // std::swap until C++11
|
|
#include "butil/type_traits.h"
|
|
#include "butil/macros.h" // BAIDU_CASSERT
|
|
|
|
namespace std {
|
|
|
|
namespace up_detail {
|
|
|
|
typedef char one;
|
|
struct two {one _[2];};
|
|
|
|
// An is_convertible<From, To> that considers From an rvalue (consistent with C++0X).
|
|
// This is a simplified version neglecting the types function, array, void and abstract types
|
|
// I had to make a special case out of is_convertible<T,T> to make move-only
|
|
// types happy.
|
|
|
|
namespace is_conv_imp {
|
|
template <class T> one test1(const T&);
|
|
template <class T> two test1(...);
|
|
template <class T> one test2(T);
|
|
template <class T> two test2(...);
|
|
template <class T> T source();
|
|
}
|
|
|
|
template <class T1, class T2>
|
|
struct is_convertible {
|
|
static const bool value = sizeof(is_conv_imp::test1<T2>(is_conv_imp::source<T1>())) == 1;
|
|
};
|
|
|
|
template <class T>
|
|
struct is_convertible<T, T> {
|
|
static const bool value = sizeof(is_conv_imp::test2<T>(is_conv_imp::source<T>())) == 1;
|
|
};
|
|
|
|
template <class T>
|
|
class rv {
|
|
T& r_;
|
|
|
|
public:
|
|
explicit rv(T& r) : r_(r) {}
|
|
T* operator->() {return &r_;}
|
|
T& operator*() {return r_;}
|
|
};
|
|
|
|
template <class T>
|
|
struct identity {
|
|
typedef T type;
|
|
};
|
|
|
|
} // up_detail
|
|
|
|
template <class T>
|
|
inline
|
|
typename butil::enable_if<
|
|
!up_detail::is_convertible<T, up_detail::rv<T> >::value,
|
|
T&
|
|
>::type
|
|
move(T& t) {
|
|
return t;
|
|
}
|
|
|
|
template <class T>
|
|
inline
|
|
typename butil::enable_if <
|
|
!up_detail::is_convertible<T, up_detail::rv<T> >::value,
|
|
const T&
|
|
>::type
|
|
move(const T& t) {
|
|
return t;
|
|
}
|
|
|
|
template <class T>
|
|
inline
|
|
typename butil::enable_if <
|
|
up_detail::is_convertible<T, up_detail::rv<T> >::value,
|
|
T
|
|
>::type
|
|
move(T& t) {
|
|
return T(up_detail::rv<T>(t));
|
|
}
|
|
|
|
template <class T>
|
|
inline
|
|
typename butil::enable_if <
|
|
butil::is_reference<T>::value,
|
|
T
|
|
>::type
|
|
forward(typename up_detail::identity<T>::type t) {
|
|
return t;
|
|
}
|
|
|
|
template <class T>
|
|
inline
|
|
typename butil::enable_if <
|
|
!butil::is_reference<T>::value,
|
|
T
|
|
>::type
|
|
forward(typename up_detail::identity<T>::type& t) {
|
|
return move(t);
|
|
}
|
|
|
|
template <class T>
|
|
inline
|
|
typename butil::enable_if <
|
|
!butil::is_reference<T>::value,
|
|
T
|
|
>::type
|
|
forward(const typename up_detail::identity<T>::type& t) {
|
|
return move(const_cast<T&>(t));
|
|
}
|
|
|
|
namespace up_detail {
|
|
|
|
// A move-aware but stripped-down compressed_pair which only optimizes storage for T2
|
|
template <class T1, class T2, bool = butil::is_empty<T2>::value>
|
|
class UniquePtrStorage {
|
|
T1 t1_;
|
|
T2 t2_;
|
|
|
|
typedef typename butil::add_reference<T2>::type T2_reference;
|
|
typedef typename butil::add_reference<const T2>::type T2_const_reference;
|
|
|
|
UniquePtrStorage(const UniquePtrStorage&);
|
|
UniquePtrStorage& operator=(const UniquePtrStorage&);
|
|
public:
|
|
operator rv<UniquePtrStorage>() {return rv<UniquePtrStorage>(*this);}
|
|
|
|
UniquePtrStorage() : t1_(), t2_() {}
|
|
explicit UniquePtrStorage(T1 t1) : t1_(move(t1)), t2_() {}
|
|
UniquePtrStorage(T1 t1, T2 t2) : t1_(move(t1)), t2_(forward<T2>(t2)) {}
|
|
|
|
T1& first() {return t1_;}
|
|
const T1& first() const {return t1_;}
|
|
|
|
T2_reference second() {return t2_;}
|
|
T2_const_reference second() const {return t2_;}
|
|
};
|
|
|
|
template <class T1, class T2>
|
|
class UniquePtrStorage<T1, T2, true> : private T2 {
|
|
T1 t1_;
|
|
typedef T2 t2_;
|
|
|
|
UniquePtrStorage(const UniquePtrStorage&);
|
|
UniquePtrStorage& operator=(const UniquePtrStorage&);
|
|
public:
|
|
operator rv<UniquePtrStorage>() {return rv<UniquePtrStorage>(*this);}
|
|
|
|
UniquePtrStorage() : t1_() {}
|
|
explicit UniquePtrStorage(T1 t1) : t1_(move(t1)) {}
|
|
UniquePtrStorage(T1 t1, T2 t2) : t2_(move(t2)), t1_(move(t1)) {}
|
|
|
|
T1& first() {return t1_;}
|
|
const T1& first() const {return t1_;}
|
|
|
|
T2& second() {return *this;}
|
|
const T2& second() const {return *this;}
|
|
};
|
|
|
|
template <class T1, class T2, bool b>
|
|
inline
|
|
void
|
|
swap(UniquePtrStorage<T1, T2, b>& x, UniquePtrStorage<T1, T2, b>& y) {
|
|
using std::swap;
|
|
swap(x.first(), y.first());
|
|
swap(x.second(), y.second());
|
|
}
|
|
|
|
} // up_detail
|
|
|
|
template <class T>
|
|
struct default_delete {
|
|
default_delete() {}
|
|
template <class U>
|
|
default_delete(const default_delete<U>&,
|
|
typename butil::enable_if<up_detail::is_convertible<U*, T*>::value>::type* = 0) {}
|
|
|
|
void operator()(T* ptr) const {
|
|
BAIDU_CASSERT(sizeof(T) > 0, T_is_empty);
|
|
delete ptr;
|
|
}
|
|
};
|
|
|
|
template <class T>
|
|
struct default_delete<T[]> {
|
|
void operator()(T* ptr) const {
|
|
BAIDU_CASSERT(sizeof(T) > 0, T_is_empty);
|
|
delete [] ptr;
|
|
}
|
|
|
|
private:
|
|
|
|
template <class U> void operator()(U*) const;
|
|
};
|
|
|
|
namespace up_detail {
|
|
|
|
namespace pointer_type_imp {
|
|
|
|
template <class U> static two test(...);
|
|
template <class U> static one test(typename U::pointer* = 0);
|
|
|
|
} // pointer_type_imp
|
|
|
|
template <class T>
|
|
struct has_pointer_type {
|
|
static const bool value = sizeof(pointer_type_imp::test<T>(0)) == 1;
|
|
};
|
|
|
|
namespace pointer_type_imp {
|
|
|
|
template <class T, class D, bool = has_pointer_type<D>::value>
|
|
struct pointer_type {
|
|
typedef typename D::pointer type;
|
|
};
|
|
|
|
template <class T, class D>
|
|
struct pointer_type<T, D, false> {
|
|
typedef T* type;
|
|
};
|
|
|
|
} // pointer_type_imp
|
|
|
|
template <class T, class D>
|
|
struct pointer_type {
|
|
typedef typename pointer_type_imp::pointer_type<T,
|
|
typename butil::remove_reference<D>::type>::type type;
|
|
};
|
|
|
|
} // up_detail
|
|
|
|
template <class T, class D = default_delete<T> >
|
|
class unique_ptr {
|
|
public:
|
|
typedef T element_type;
|
|
typedef D deleter_type;
|
|
typedef typename up_detail::pointer_type<element_type, deleter_type>::type pointer;
|
|
|
|
private:
|
|
up_detail::UniquePtrStorage<pointer, deleter_type> ptr_;
|
|
|
|
typedef typename butil::add_reference<deleter_type>::type deleter_reference;
|
|
typedef typename butil::add_reference<const deleter_type>::type deleter_const_reference;
|
|
|
|
struct nat {int for_bool_;};
|
|
|
|
unique_ptr(unique_ptr&);
|
|
unique_ptr& operator=(unique_ptr&);
|
|
|
|
public:
|
|
operator up_detail::rv<unique_ptr>() {
|
|
return up_detail::rv<unique_ptr>(*this);
|
|
}
|
|
unique_ptr(up_detail::rv<unique_ptr> r)
|
|
: ptr_(r->release(), forward<deleter_type>(r->get_deleter())) {}
|
|
unique_ptr& operator=(up_detail::rv<unique_ptr> r) {
|
|
reset(r->release());
|
|
ptr_.second() = move(r->get_deleter());
|
|
return *this;
|
|
}
|
|
|
|
unique_ptr() {}
|
|
|
|
explicit unique_ptr(pointer p) : ptr_(p) {}
|
|
|
|
unique_ptr(pointer p, typename butil::conditional<butil::is_reference<D>::value,
|
|
volatile typename butil::remove_reference<D>::type&, D>::type d)
|
|
: ptr_(move(p), forward<D>(const_cast<typename butil::add_reference<D>::type>(d))) {}
|
|
|
|
template <class U, class E>
|
|
unique_ptr(unique_ptr<U, E> u,
|
|
typename butil::enable_if <
|
|
!butil::is_array<U>::value &&
|
|
up_detail::is_convertible<typename unique_ptr<U>::pointer, pointer>::value
|
|
&&
|
|
up_detail::is_convertible<E, deleter_type>::value &&
|
|
(
|
|
!butil::is_reference<deleter_type>::value ||
|
|
butil::is_same<deleter_type, E>::value)
|
|
>::type* = 0)
|
|
: ptr_(u.release(), forward<D>(forward<E>(u.get_deleter()))) {}
|
|
|
|
~unique_ptr() {
|
|
BAIDU_CASSERT(!butil::is_reference<deleter_type>::value, deleter_is_ref);
|
|
BAIDU_CASSERT(!butil::is_pointer<deleter_type>::value, deleter_is_pointer);
|
|
reset();
|
|
}
|
|
|
|
unique_ptr& operator=(int nat::*) {
|
|
reset();
|
|
return *this;
|
|
}
|
|
|
|
template <class U, class E>
|
|
unique_ptr& operator=(unique_ptr<U, E> u) {
|
|
reset(u.release());
|
|
ptr_.second() = move(u.get_deleter());
|
|
return *this;
|
|
}
|
|
|
|
typename butil::add_reference<T>::type operator*() const {return *get();}
|
|
pointer operator->() const {return get();}
|
|
pointer get() const {return ptr_.first();}
|
|
deleter_reference get_deleter() {return ptr_.second();}
|
|
deleter_const_reference get_deleter() const {return ptr_.second();}
|
|
operator int nat::*() const {return get() ? &nat::for_bool_ : 0;}
|
|
|
|
void reset(pointer p = pointer()) {
|
|
pointer t = get();
|
|
if (t != pointer())
|
|
get_deleter()(t);
|
|
ptr_.first() = p;
|
|
}
|
|
|
|
pointer release() {
|
|
pointer tmp = get();
|
|
ptr_.first() = pointer();
|
|
return tmp;
|
|
}
|
|
|
|
void swap(unique_ptr& u) {up_detail::swap(ptr_, u.ptr_);}
|
|
};
|
|
|
|
template <class T, class D>
|
|
class unique_ptr<T[], D> {
|
|
public:
|
|
typedef T element_type;
|
|
typedef D deleter_type;
|
|
typedef typename up_detail::pointer_type<element_type, deleter_type>::type pointer;
|
|
|
|
private:
|
|
up_detail::UniquePtrStorage<pointer, deleter_type> ptr_;
|
|
|
|
typedef typename butil::add_reference<deleter_type>::type deleter_reference;
|
|
typedef typename butil::add_reference<const deleter_type>::type deleter_const_reference;
|
|
|
|
struct nat {int for_bool_;};
|
|
|
|
unique_ptr(unique_ptr&);
|
|
unique_ptr& operator=(unique_ptr&);
|
|
|
|
public:
|
|
operator up_detail::rv<unique_ptr>() {return up_detail::rv<unique_ptr>(*this);}
|
|
unique_ptr(up_detail::rv<unique_ptr> r)
|
|
: ptr_(r->release(), forward<deleter_type>(r->get_deleter())) {}
|
|
unique_ptr& operator=(up_detail::rv<unique_ptr> r) {
|
|
reset(r->release());
|
|
ptr_.second() = move(r->get_deleter());
|
|
return *this;
|
|
}
|
|
|
|
unique_ptr() {}
|
|
|
|
explicit unique_ptr(pointer p) : ptr_(p) {}
|
|
|
|
unique_ptr(pointer p, typename butil::conditional<butil::is_reference<D>::value,
|
|
volatile typename butil::remove_reference<D>::type&, D>::type d)
|
|
: ptr_(move(p), forward<D>(const_cast<typename butil::add_reference<D>::type>(d))) {}
|
|
|
|
~unique_ptr() {
|
|
BAIDU_CASSERT(!butil::is_reference<deleter_type>::value, deleter_is_ref);
|
|
BAIDU_CASSERT(!butil::is_pointer<deleter_type>::value, deleter_is_pointer);
|
|
reset();
|
|
}
|
|
|
|
T& operator[](size_t i) const {return get()[i];}
|
|
pointer get() const {return ptr_.first();}
|
|
deleter_reference get_deleter() {return ptr_.second();}
|
|
deleter_const_reference get_deleter() const {return ptr_.second();}
|
|
operator int nat::*() const {return get() ? &nat::for_bool_ : 0;}
|
|
|
|
void reset(pointer p = pointer()) {
|
|
pointer t = get();
|
|
if (t != pointer())
|
|
get_deleter()(t);
|
|
ptr_.first() = p;
|
|
}
|
|
|
|
pointer release() {
|
|
pointer tmp = get();
|
|
ptr_.first() = pointer();
|
|
return tmp;
|
|
}
|
|
|
|
void swap(unique_ptr& u) {up_detail::swap(ptr_, u.ptr_);}
|
|
private:
|
|
template <class U>
|
|
explicit unique_ptr(
|
|
U, typename butil::enable_if<up_detail::is_convertible<U, pointer>::value>::type* = 0);
|
|
|
|
template <class U>
|
|
unique_ptr(U, typename butil::conditional<butil::is_reference<D>::value,
|
|
volatile typename butil::remove_reference<D>::type&, D>::type,
|
|
typename butil::enable_if<up_detail::is_convertible<U, pointer>::value>::type* = 0);
|
|
};
|
|
|
|
template<class T, class D>
|
|
inline
|
|
void
|
|
swap(unique_ptr<T, D>& x, unique_ptr<T, D>& y) {
|
|
x.swap(y);
|
|
}
|
|
|
|
template<class T1, class D1, class T2, class D2>
|
|
inline
|
|
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>
|
|
inline
|
|
bool
|
|
operator!=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y) {
|
|
return !(x == y);
|
|
}
|
|
|
|
template<class T1, class D1, class T2, class D2>
|
|
inline
|
|
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>
|
|
inline
|
|
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>
|
|
inline
|
|
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>
|
|
inline
|
|
bool
|
|
operator>=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y) {
|
|
return !(x < y);
|
|
}
|
|
|
|
} // namespace std
|
|
|
|
#endif // BUTIL_CXX11_ENABLED
|
|
#endif // BUTIL_UNIQUE_PTR_H
|