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