blob: 67d7f27baf454f096e76f714075099f246c37a94 [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FBL_UNIQUE_PTR_H_
#define FBL_UNIQUE_PTR_H_
#include <stdlib.h>
#include <fbl/alloc_checker.h>
#include <fbl/macros.h>
#include <fbl/recycler.h>
#include <zircon/compiler.h>
#include <type_traits>
#include <utility>
namespace fbl {
// This is a simplified version of std::unique_ptr<> that can automatically
// dispose a pointer when it goes out of scope.
//
// Compared to std::unique_ptr, it does not support custom deleters and has
// restrictive type conversion semantics.
template <typename T>
class unique_ptr {
public:
constexpr unique_ptr() : ptr_(nullptr) {}
constexpr unique_ptr(decltype(nullptr)) : unique_ptr() {}
explicit unique_ptr(T* t) : ptr_(t) { }
~unique_ptr() {
recycle(ptr_);
}
unique_ptr(unique_ptr&& o) : ptr_(o.release()) {}
unique_ptr& operator=(unique_ptr&& o) {
reset(o.release());
return *this;
}
unique_ptr& operator=(decltype(nullptr)) {
reset();
return *this;
}
// Comparison against nullptr operators (of the form, myptr == nullptr).
bool operator==(decltype(nullptr)) const { return (ptr_ == nullptr); }
bool operator!=(decltype(nullptr)) const { return (ptr_ != nullptr); }
// Comparison against other unique_ptr<>'s.
bool operator==(const unique_ptr& o) const { return ptr_ == o.ptr_; }
bool operator!=(const unique_ptr& o) const { return ptr_ != o.ptr_; }
bool operator< (const unique_ptr& o) const { return ptr_ < o.ptr_; }
bool operator<=(const unique_ptr& o) const { return ptr_ <= o.ptr_; }
bool operator> (const unique_ptr& o) const { return ptr_ > o.ptr_; }
bool operator>=(const unique_ptr& o) const { return ptr_ >= o.ptr_; }
// move semantics only
DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(unique_ptr);
T* release() __WARN_UNUSED_RESULT {
T* t = ptr_;
ptr_ = nullptr;
return t;
}
void reset(T* t = nullptr) {
recycle(ptr_);
ptr_ = t;
}
void swap(unique_ptr& other) {
T* t = ptr_;
ptr_ = other.ptr_;
other.ptr_ = t;
}
T* get() const {
return ptr_;
}
explicit operator bool() const {
return static_cast<bool>(ptr_);
}
T& operator*() const {
return *ptr_;
}
T* operator->() const {
return ptr_;
}
// Implicit upcasting via construction.
//
// We permit implicit casting of a unique_ptr<U> to a unique_ptr<T> as long
// as the following conditions both hold:
//
// 1) U* is implicitly convertible to a T*
// 2) T is the same as const U, neither T nor U are a class/struct type, or
// both T and U are class/struct types and T has a virtual destructor.
//
// Note: we do this via an implicit converting constructor (instead of a
// user-defined conversion operator) so that we can demand that we are
// converting from a properly moved rvalue reference.
//
// Also Note: This behavior is *not* the same as std::unique_ptr.
// std::unique_ptr only cares about point #1. Its behavior emulates raw
// pointers and will gladly let you implicitly convert a class U to a class
// T as an implicit upcast regardless of whether or not T has a virtual
// destructor.
template <typename U,
typename = std::enable_if_t<std::is_convertible_v<U*, T*>>>
unique_ptr(unique_ptr<U>&& o) : ptr_(o.release()) {
static_assert(std::is_same_v<T, const U> ||
(std::is_class_v<T> == std::is_class_v<U> &&
(!std::is_class_v<T> || std::has_virtual_destructor_v<T>)),
"Cannot convert unique_ptr<U> to unique_ptr<T> unless T is the same "
"as const U, neither T nor U are class/struct types, or T has a "
"virtual destructor");
}
private:
static void recycle(T* ptr) {
enum { type_must_be_complete = sizeof(T) };
if (ptr) {
if constexpr (::fbl::internal::has_fbl_recycle_v<T>) {
::fbl::internal::recycler<T>::recycle(ptr);
} else {
delete ptr;
}
}
}
T* ptr_;
};
template <typename T>
class unique_ptr<T[]> {
public:
constexpr unique_ptr() : ptr_(nullptr) {}
constexpr unique_ptr(decltype(nullptr)) : unique_ptr() {}
explicit unique_ptr(T* array) : ptr_(array) {}
unique_ptr(unique_ptr&& other) : ptr_(other.release()) {}
~unique_ptr() {
enum { type_must_be_complete = sizeof(T) };
if (ptr_) delete[] ptr_;
}
unique_ptr& operator=(unique_ptr&& o) {
reset(o.release());
return *this;
}
// Comparison against nullptr operators (of the form, myptr == nullptr).
bool operator==(decltype(nullptr)) const { return (ptr_ == nullptr); }
bool operator!=(decltype(nullptr)) const { return (ptr_ != nullptr); }
// Comparison against other unique_ptr<>'s.
bool operator==(const unique_ptr& o) const { return ptr_ == o.ptr_; }
bool operator!=(const unique_ptr& o) const { return ptr_ != o.ptr_; }
bool operator< (const unique_ptr& o) const { return ptr_ < o.ptr_; }
bool operator<=(const unique_ptr& o) const { return ptr_ <= o.ptr_; }
bool operator> (const unique_ptr& o) const { return ptr_ > o.ptr_; }
bool operator>=(const unique_ptr& o) const { return ptr_ >= o.ptr_; }
unique_ptr(const unique_ptr& o) = delete;
unique_ptr& operator=(const unique_ptr& o) = delete;
T* release() __WARN_UNUSED_RESULT {
T* t = ptr_;
ptr_ = nullptr;
return t;
}
void reset(T* t = nullptr) {
enum { type_must_be_complete = sizeof(T) };
if (ptr_) delete[] ptr_;
ptr_ = t;
}
void swap(unique_ptr& other) {
T* t = ptr_;
ptr_ = other.ptr_;
other.ptr_ = t;
}
T* get() const {
return ptr_;
}
explicit operator bool() const {
return static_cast<bool>(ptr_);
}
T& operator[](size_t i) const {
return ptr_[i];
}
private:
T* ptr_;
};
// Comparison against nullptr operators (of the form, nullptr == myptr) for T and T[]
template <typename T>
static inline bool operator==(decltype(nullptr), const unique_ptr<T>& ptr) {
return (ptr.get() == nullptr);
}
template <typename T>
static inline bool operator!=(decltype(nullptr), const unique_ptr<T>& ptr) {
return (ptr.get() != nullptr);
}
namespace internal {
template <typename T>
struct unique_type {
using single = unique_ptr<T>;
};
template <typename T>
struct unique_type<T[]> {
using incomplete_array = unique_ptr<T[]>;
};
} // namespace internal
// Constructs a new object and assigns it to a unique_ptr.
template <typename T, typename... Args>
typename internal::unique_type<T>::single
make_unique(Args&&... args) {
return unique_ptr<T>(new T(std::forward<Args>(args)...));
}
template <typename T, typename... Args>
typename internal::unique_type<T>::incomplete_array
make_unique(size_t size) {
using single_type = std::remove_extent_t<T>;
return unique_ptr<single_type[]>(new single_type[size]());
}
template <typename T, typename... Args>
typename internal::unique_type<T>::single
make_unique_checked(AllocChecker* ac, Args&&... args) {
return unique_ptr<T>(new (ac) T(std::forward<Args>(args)...));
}
} // namespace fbl
#endif // FBL_UNIQUE_PTR_H_