thor-os/tstl/include/unique_ptr.hpp
Baptiste Wicht e3c66b0faa Cleanup
2016-09-25 21:04:42 +02:00

209 lines
4.8 KiB
C++

//=======================================================================
// Copyright Baptiste Wicht 2013-2016.
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
// http://www.opensource.org/licenses/MIT)
//=======================================================================
#ifndef UNIQUE_PTR_H
#define UNIQUE_PTR_H
#include <tuple.hpp>
#include <algorithms.hpp>
namespace std {
template<typename T>
struct default_delete {
constexpr default_delete() = default;
constexpr default_delete(const default_delete&) {}
void operator()(T* ptr) const {
static_assert(sizeof(T) > 0, "Type must be complete");
delete ptr;
}
};
//Partial specialization for arrays
template<typename T>
struct default_delete<T[]> {
constexpr default_delete() = default;
constexpr default_delete(const default_delete&) {}
void operator()(T* ptr) const {
static_assert(sizeof(T) > 0, "Type must be complete");
delete[] ptr;
}
};
template <typename T, typename D = default_delete<T>>
class unique_ptr {
public:
using pointer_type = T*;
using element_type = T;
using deleter_type = D;
private:
using data_impl = tuple<pointer_type, deleter_type>;
data_impl _data;
public:
unique_ptr() : _data() {}
unique_ptr(decltype(nullptr)) : unique_ptr() {}
explicit unique_ptr(pointer_type p) : _data(make_tuple(p, deleter_type())) {}
unique_ptr(unique_ptr&& u) : _data(make_tuple(u.unlock(), u.get_deleter())) {}
unique_ptr& operator=(unique_ptr&& u){
reset(u.unlock());
get_deleter() = std::forward<deleter_type>(u.get_deleter());
return *this;
}
~unique_ptr(){
reset();
}
// Disable copy
unique_ptr(const unique_ptr& rhs) = delete;
unique_ptr& operator=(const unique_ptr& rhs) = delete;
unique_ptr& operator=(decltype(nullptr)){
reset();
return *this;
}
//Access
element_type& operator*() const {
return *get();
}
pointer_type operator->() const {
return get();
}
pointer_type get() const {
return std::get<0>(_data);
}
deleter_type& get_deleter(){
return std::get<1>(_data);
}
const deleter_type& get_deleter() const {
return std::get<1>(_data);
}
explicit operator bool() const {
return get() == pointer_type() ? false : true;
}
pointer_type unlock(){
pointer_type p = get();
std::get<0>(_data) = pointer_type();
return p;
}
void reset(pointer_type p = pointer_type()){
if(get() != pointer_type()){
get_deleter()(get());
}
std::get<0>(_data) = p;
}
};
//Partial specialization for array
template <typename T, typename D>
class unique_ptr<T[], D> {
public:
using pointer_type = T*;
using element_type = T;
using deleter_type = D;
private:
using data_impl = tuple<pointer_type, deleter_type>;
data_impl _data;
public:
unique_ptr() : _data() {}
unique_ptr(decltype(nullptr)) : unique_ptr() {}
explicit unique_ptr(pointer_type p) : _data(make_tuple(p, deleter_type())) {}
unique_ptr(unique_ptr&& u) : _data(make_tuple(u.unlock(), u.get_deleter())) {}
unique_ptr& operator=(unique_ptr&& u){
reset(u.unlock());
get_deleter() = std::forward<deleter_type>(u.get_deleter());
return *this;
}
~unique_ptr(){
reset();
}
// Disable copy
unique_ptr(const unique_ptr& rhs) = delete;
unique_ptr& operator=(const unique_ptr& rhs) = delete;
unique_ptr& operator=(decltype(nullptr)){
reset();
return *this;
}
pointer_type get() const {
return std::get<0>(_data);
}
deleter_type& get_deleter(){
return std::get<1>(_data);
}
const deleter_type& get_deleter() const {
return std::get<1>(_data);
}
element_type& operator[](size_t i) const {
return get()[i];
}
explicit operator bool() const {
return get() == pointer_type() ? false : true;
}
pointer_type unlock(){
pointer_type p = get();
std::get<0>(_data) = pointer_type();
return p;
}
void reset(){
reset(pointer_type());
}
void reset(pointer_type p){
auto tmp = get();
std::get<0>(_data) = p;
if(tmp){
get_deleter()(tmp);
}
}
};
static_assert(sizeof(unique_ptr<long>) == sizeof(long), "unique_ptr must have zero overhead with default deleter");
static_assert(sizeof(unique_ptr<long[]>) == sizeof(long), "unique_ptr must have zero overhead with default deleter");
template <typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args){
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
} //end of namespace std
#endif