1// Copyright 2016 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#pragma once 6 7#include <stdlib.h> 8#include <fbl/alloc_checker.h> 9#include <fbl/macros.h> 10#include <fbl/recycler.h> 11#include <fbl/type_support.h> 12#include <zircon/compiler.h> 13 14namespace fbl { 15 16// This is a simplified version of std::unique_ptr<> that can automatically 17// dispose a pointer when it goes out of scope. 18// 19// Compared to std::unique_ptr, it does not support custom deleters and has 20// restrictive type conversion semantics. 21template <typename T> 22class unique_ptr { 23public: 24 constexpr unique_ptr() : ptr_(nullptr) {} 25 constexpr unique_ptr(decltype(nullptr)) : unique_ptr() {} 26 27 explicit unique_ptr(T* t) : ptr_(t) { } 28 29 ~unique_ptr() { 30 recycle(ptr_); 31 } 32 33 unique_ptr(unique_ptr&& o) : ptr_(o.release()) {} 34 unique_ptr& operator=(unique_ptr&& o) { 35 reset(o.release()); 36 return *this; 37 } 38 39 unique_ptr& operator=(decltype(nullptr)) { 40 reset(); 41 return *this; 42 } 43 44 // Comparison against nullptr operators (of the form, myptr == nullptr). 45 bool operator==(decltype(nullptr)) const { return (ptr_ == nullptr); } 46 bool operator!=(decltype(nullptr)) const { return (ptr_ != nullptr); } 47 48 // Comparison against other unique_ptr<>'s. 49 bool operator==(const unique_ptr& o) const { return ptr_ == o.ptr_; } 50 bool operator!=(const unique_ptr& o) const { return ptr_ != o.ptr_; } 51 bool operator< (const unique_ptr& o) const { return ptr_ < o.ptr_; } 52 bool operator<=(const unique_ptr& o) const { return ptr_ <= o.ptr_; } 53 bool operator> (const unique_ptr& o) const { return ptr_ > o.ptr_; } 54 bool operator>=(const unique_ptr& o) const { return ptr_ >= o.ptr_; } 55 56 // move semantics only 57 DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(unique_ptr); 58 59 T* release() __WARN_UNUSED_RESULT { 60 T* t = ptr_; 61 ptr_ = nullptr; 62 return t; 63 } 64 void reset(T* t = nullptr) { 65 recycle(ptr_); 66 ptr_ = t; 67 } 68 void swap(unique_ptr& other) { 69 T* t = ptr_; 70 ptr_ = other.ptr_; 71 other.ptr_ = t; 72 } 73 74 T* get() const { 75 return ptr_; 76 } 77 78 explicit operator bool() const { 79 return static_cast<bool>(ptr_); 80 } 81 82 T& operator*() const { 83 return *ptr_; 84 } 85 T* operator->() const { 86 return ptr_; 87 } 88 89 // Implicit upcasting via construction. 90 // 91 // We permit implicit casting of a unique_ptr<U> to a unique_ptr<T> as long 92 // as the following conditions both hold: 93 // 94 // 1) U* is implicitly convertible to a T* 95 // 2) T is the same as const U, neither T nor U are a class/struct type, or 96 // both T and U are class/struct types and T has a virtual destructor. 97 // 98 // Note: we do this via an implicit converting constructor (instead of a 99 // user-defined conversion operator) so that we can demand that we are 100 // converting from a properly moved rvalue reference. 101 // 102 // Also Note: This behavior is *not* the same as std::unique_ptr. 103 // std::unique_ptr only cares about point #1. Its behavior emulates raw 104 // pointers and will gladly let you implicitly convert a class U to a class 105 // T as an implicit upcast regardless of whether or not T has a virtual 106 // destructor. 107 template <typename U, 108 typename = typename enable_if<is_convertible_pointer<U*, T*>::value>::type> 109 unique_ptr(unique_ptr<U>&& o) : ptr_(o.release()) { 110 static_assert(is_same<T, const U>::value || 111 (is_class<T>::value == is_class<U>::value && 112 (!is_class<T>::value || has_virtual_destructor<T>::value)), 113 "Cannot convert unique_ptr<U> to unique_ptr<T> unless T is the same " 114 "as const U, neither T nor U are class/struct types, or T has a " 115 "virtual destructor"); 116 } 117 118private: 119 static void recycle(T* ptr) { 120 enum { type_must_be_complete = sizeof(T) }; 121 if (ptr) { 122 if (::fbl::internal::has_fbl_recycle<T>::value) { 123 ::fbl::internal::recycler<T>::recycle(ptr); 124 } else { 125 delete ptr; 126 } 127 } 128 } 129 130 T* ptr_; 131}; 132 133template <typename T> 134class unique_ptr<T[]> { 135public: 136 constexpr unique_ptr() : ptr_(nullptr) {} 137 constexpr unique_ptr(decltype(nullptr)) : unique_ptr() {} 138 139 explicit unique_ptr(T* array) : ptr_(array) {} 140 141 unique_ptr(unique_ptr&& other) : ptr_(other.release()) {} 142 143 ~unique_ptr() { 144 enum { type_must_be_complete = sizeof(T) }; 145 if (ptr_) delete[] ptr_; 146 } 147 148 unique_ptr& operator=(unique_ptr&& o) { 149 reset(o.release()); 150 return *this; 151 } 152 153 // Comparison against nullptr operators (of the form, myptr == nullptr). 154 bool operator==(decltype(nullptr)) const { return (ptr_ == nullptr); } 155 bool operator!=(decltype(nullptr)) const { return (ptr_ != nullptr); } 156 157 // Comparison against other unique_ptr<>'s. 158 bool operator==(const unique_ptr& o) const { return ptr_ == o.ptr_; } 159 bool operator!=(const unique_ptr& o) const { return ptr_ != o.ptr_; } 160 bool operator< (const unique_ptr& o) const { return ptr_ < o.ptr_; } 161 bool operator<=(const unique_ptr& o) const { return ptr_ <= o.ptr_; } 162 bool operator> (const unique_ptr& o) const { return ptr_ > o.ptr_; } 163 bool operator>=(const unique_ptr& o) const { return ptr_ >= o.ptr_; } 164 165 unique_ptr(const unique_ptr& o) = delete; 166 unique_ptr& operator=(const unique_ptr& o) = delete; 167 168 T* release() __WARN_UNUSED_RESULT { 169 T* t = ptr_; 170 ptr_ = nullptr; 171 return t; 172 } 173 void reset(T* t = nullptr) { 174 enum { type_must_be_complete = sizeof(T) }; 175 if (ptr_) delete[] ptr_; 176 ptr_ = t; 177 } 178 void swap(unique_ptr& other) { 179 T* t = ptr_; 180 ptr_ = other.ptr_; 181 other.ptr_ = t; 182 } 183 184 T* get() const { 185 return ptr_; 186 } 187 188 explicit operator bool() const { 189 return static_cast<bool>(ptr_); 190 } 191 T& operator[](size_t i) const { 192 return ptr_[i]; 193 } 194 195private: 196 T* ptr_; 197}; 198 199// Comparison against nullptr operators (of the form, nullptr == myptr) for T and T[] 200template <typename T> 201static inline bool operator==(decltype(nullptr), const unique_ptr<T>& ptr) { 202 return (ptr.get() == nullptr); 203} 204 205template <typename T> 206static inline bool operator!=(decltype(nullptr), const unique_ptr<T>& ptr) { 207 return (ptr.get() != nullptr); 208} 209 210// Constructs a new object and assigns it to a unique_ptr. 211template <typename T, typename... Args> 212unique_ptr<T> make_unique(Args&&... args) { 213 return unique_ptr<T>(new T(fbl::forward<Args>(args)...)); 214} 215template <typename T, typename... Args> 216unique_ptr<T> make_unique_checked(AllocChecker* ac, Args&&... args) { 217 return unique_ptr<T>(new (ac) T(fbl::forward<Args>(args)...)); 218} 219 220} // namespace fbl 221