1/*
2 * Copyright (C) 2017 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#pragma once
27
28#include <wtf/CagedPtr.h>
29
30namespace WTF {
31
32template<Gigacage::Kind kind, typename T, typename Enable = void>
33class CagedUniquePtr : public CagedPtr<kind, T> {
34public:
35 CagedUniquePtr(T* ptr = nullptr)
36 : CagedPtr<kind, T>(ptr)
37 {
38 }
39
40 CagedUniquePtr(CagedUniquePtr&& ptr)
41 : CagedPtr<kind, T>(ptr.m_ptr)
42 {
43 ptr.m_ptr = nullptr;
44 }
45
46 CagedUniquePtr(const CagedUniquePtr&) = delete;
47
48 template<typename... Arguments>
49 static CagedUniquePtr create(Arguments&&... arguments)
50 {
51 T* result = static_cast<T*>(Gigacage::malloc(kind, sizeof(T)));
52 new (result) T(std::forward<Arguments>(arguments)...);
53 return CagedUniquePtr(result);
54 }
55
56 CagedUniquePtr& operator=(CagedUniquePtr&& ptr)
57 {
58 destroy();
59 this->m_ptr = ptr.m_ptr;
60 ptr.m_ptr = nullptr;
61 return *this;
62 }
63
64 CagedUniquePtr& operator=(const CagedUniquePtr&) = delete;
65
66 ~CagedUniquePtr()
67 {
68 destroy();
69 }
70
71private:
72 void destroy()
73 {
74 if (!this->m_ptr)
75 return;
76 this->m_ptr->~T();
77 Gigacage::free(kind, this->m_ptr);
78 }
79};
80
81template<Gigacage::Kind kind, typename T>
82class CagedUniquePtr<kind, T[], typename std::enable_if<std::is_trivially_destructible<T>::value>::type> : public CagedPtr<kind, T> {
83public:
84 CagedUniquePtr() : CagedPtr<kind, T>() { }
85
86 CagedUniquePtr(T* ptr)
87 : CagedPtr<kind, T>(ptr)
88 {
89 }
90
91 CagedUniquePtr(CagedUniquePtr&& ptr)
92 : CagedPtr<kind, T>(ptr.m_ptr)
93 {
94 ptr.m_ptr = nullptr;
95 }
96
97 CagedUniquePtr(const CagedUniquePtr&) = delete;
98
99 template<typename... Arguments>
100 static CagedUniquePtr create(size_t count, Arguments&&... arguments)
101 {
102 T* result = static_cast<T*>(Gigacage::mallocArray(kind, count, sizeof(T)));
103 while (count--)
104 new (result + count) T(std::forward<Arguments>(arguments)...);
105 return CagedUniquePtr(result);
106 }
107
108 CagedUniquePtr& operator=(CagedUniquePtr&& ptr)
109 {
110 destroy();
111 this->m_ptr = ptr.m_ptr;
112 ptr.m_ptr = nullptr;
113 return *this;
114 }
115
116 CagedUniquePtr& operator=(const CagedUniquePtr&) = delete;
117
118 ~CagedUniquePtr()
119 {
120 destroy();
121 }
122
123private:
124 void destroy()
125 {
126 if (!this->m_ptr)
127 return;
128 Gigacage::free(kind, this->m_ptr);
129 }
130};
131
132template<Gigacage::Kind kind, typename T>
133class CagedUniquePtr<kind, T[], typename std::enable_if<!std::is_trivially_destructible<T>::value>::type> : public CagedPtr<kind, T> {
134public:
135 CagedUniquePtr() : CagedPtr<kind, T>() { }
136
137 CagedUniquePtr(T* ptr, size_t count)
138 : CagedPtr<kind, T>(ptr)
139 , m_count(count)
140 {
141 }
142
143 CagedUniquePtr(CagedUniquePtr&& ptr)
144 : CagedPtr<kind, T>(ptr.m_ptr)
145 , m_count(ptr.m_count)
146 {
147 ptr.clear();
148 }
149
150 CagedUniquePtr(const CagedUniquePtr&) = delete;
151
152 template<typename... Arguments>
153 static CagedUniquePtr create(size_t count, Arguments&&... arguments)
154 {
155 T* result = static_cast<T*>(Gigacage::mallocArray(kind, count, sizeof(T)));
156 while (count--)
157 new (result + count) T(std::forward<Arguments>(arguments)...);
158 return CagedUniquePtr(result, count);
159 }
160
161 CagedUniquePtr& operator=(CagedUniquePtr&& ptr)
162 {
163 destroy();
164 this->m_ptr = ptr.m_ptr;
165 m_count = ptr.m_count;
166 ptr.clear();
167 return *this;
168 }
169
170 CagedUniquePtr& operator=(const CagedUniquePtr&) = delete;
171
172 ~CagedUniquePtr()
173 {
174 destroy();
175 }
176
177 // FIXME: It's weird that we inherit CagedPtr::operator== and friends, which don't do anything
178 // about m_count. It "works" because pointer equality is enough so long as everything is sane, but
179 // it seems like a missed opportunity to assert things.
180 // https://bugs.webkit.org/show_bug.cgi?id=175541
181
182private:
183 void destroy()
184 {
185 if (!this->m_ptr)
186 return;
187 while (m_count--)
188 this->m_ptr[m_count].~T();
189 Gigacage::free(kind, this->m_ptr);
190 }
191
192 void clear()
193 {
194 this->m_ptr = nullptr;
195 m_count = 0;
196 }
197
198 size_t m_count { 0 };
199};
200
201} // namespace WTF
202
203using WTF::CagedUniquePtr;
204
205