Mercurial > repos > rliterman > csp2
comparison CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/include/kj/memory.h @ 69:33d812a61356
planemo upload commit 2e9511a184a1ca667c7be0c6321a36dc4e3d116d
author | jpayne |
---|---|
date | Tue, 18 Mar 2025 17:55:14 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
67:0e9998148a16 | 69:33d812a61356 |
---|---|
1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors | |
2 // Licensed under the MIT License: | |
3 // | |
4 // Permission is hereby granted, free of charge, to any person obtaining a copy | |
5 // of this software and associated documentation files (the "Software"), to deal | |
6 // in the Software without restriction, including without limitation the rights | |
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
8 // copies of the Software, and to permit persons to whom the Software is | |
9 // furnished to do so, subject to the following conditions: | |
10 // | |
11 // The above copyright notice and this permission notice shall be included in | |
12 // all copies or substantial portions of the Software. | |
13 // | |
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
20 // THE SOFTWARE. | |
21 | |
22 #pragma once | |
23 | |
24 #include "common.h" | |
25 | |
26 KJ_BEGIN_HEADER | |
27 | |
28 namespace kj { | |
29 | |
30 template <typename T> | |
31 inline constexpr bool _kj_internal_isPolymorphic(T*) { | |
32 // If you get a compiler error here complaining that T is incomplete, it's because you are trying | |
33 // to use kj::Own<T> with a type that has only been forward-declared. Since KJ doesn't know if | |
34 // the type might be involved in inheritance (especially multiple inheritance), it doesn't know | |
35 // how to correctly call the disposer to destroy the type, since the object's true memory address | |
36 // may differ from the address used to point to a superclass. | |
37 // | |
38 // However, if you know for sure that T is NOT polymorphic (i.e. it doesn't have a vtable and | |
39 // isn't involved in inheritance), then you can use KJ_DECLARE_NON_POLYMORPHIC(T) to declare this | |
40 // to KJ without actually completing the type. Place this macro invocation either in the global | |
41 // scope, or in the same namespace as T is defined. | |
42 return __is_polymorphic(T); | |
43 } | |
44 | |
45 #define KJ_DECLARE_NON_POLYMORPHIC(...) \ | |
46 inline constexpr bool _kj_internal_isPolymorphic(__VA_ARGS__*) { \ | |
47 return false; \ | |
48 } | |
49 // If you want to use kj::Own<T> for an incomplete type T that you know is not polymorphic, then | |
50 // write `KJ_DECLARE_NON_POLYMORPHIC(T)` either at the global scope or in the same namespace as | |
51 // T is declared. | |
52 // | |
53 // This also works for templates, e.g.: | |
54 // | |
55 // template <typename X, typename Y> | |
56 // struct MyType; | |
57 // template <typename X, typename Y> | |
58 // KJ_DECLARE_NON_POLYMORPHIC(MyType<X, Y>) | |
59 | |
60 namespace _ { // private | |
61 | |
62 template <typename T> struct RefOrVoid_ { typedef T& Type; }; | |
63 template <> struct RefOrVoid_<void> { typedef void Type; }; | |
64 template <> struct RefOrVoid_<const void> { typedef void Type; }; | |
65 | |
66 template <typename T> | |
67 using RefOrVoid = typename RefOrVoid_<T>::Type; | |
68 // Evaluates to T&, unless T is `void`, in which case evaluates to `void`. | |
69 // | |
70 // This is a hack needed to avoid defining Own<void> as a totally separate class. | |
71 | |
72 template <typename T, bool isPolymorphic = _kj_internal_isPolymorphic((T*)nullptr)> | |
73 struct CastToVoid_; | |
74 | |
75 template <typename T> | |
76 struct CastToVoid_<T, false> { | |
77 static void* apply(T* ptr) { | |
78 return static_cast<void*>(ptr); | |
79 } | |
80 static const void* applyConst(T* ptr) { | |
81 const T* cptr = ptr; | |
82 return static_cast<const void*>(cptr); | |
83 } | |
84 }; | |
85 | |
86 template <typename T> | |
87 struct CastToVoid_<T, true> { | |
88 static void* apply(T* ptr) { | |
89 return dynamic_cast<void*>(ptr); | |
90 } | |
91 static const void* applyConst(T* ptr) { | |
92 const T* cptr = ptr; | |
93 return dynamic_cast<const void*>(cptr); | |
94 } | |
95 }; | |
96 | |
97 template <typename T> | |
98 void* castToVoid(T* ptr) { | |
99 return CastToVoid_<T>::apply(ptr); | |
100 } | |
101 | |
102 template <typename T> | |
103 const void* castToConstVoid(T* ptr) { | |
104 return CastToVoid_<T>::applyConst(ptr); | |
105 } | |
106 | |
107 } // namespace _ (private) | |
108 | |
109 // ======================================================================================= | |
110 // Disposer -- Implementation details. | |
111 | |
112 class Disposer { | |
113 // Abstract interface for a thing that "disposes" of objects, where "disposing" usually means | |
114 // calling the destructor followed by freeing the underlying memory. `Own<T>` encapsulates an | |
115 // object pointer with corresponding Disposer. | |
116 // | |
117 // Few developers will ever touch this interface. It is primarily useful for those implementing | |
118 // custom memory allocators. | |
119 | |
120 protected: | |
121 // Do not declare a destructor, as doing so will force a global initializer for each HeapDisposer | |
122 // instance. Eww! | |
123 | |
124 virtual void disposeImpl(void* pointer) const = 0; | |
125 // Disposes of the object, given a pointer to the beginning of the object. If the object is | |
126 // polymorphic, this pointer is determined by dynamic_cast<void*>(). For non-polymorphic types, | |
127 // Own<T> does not allow any casting, so the pointer exactly matches the original one given to | |
128 // Own<T>. | |
129 | |
130 public: | |
131 | |
132 template <typename T> | |
133 void dispose(T* object) const; | |
134 // Helper wrapper around disposeImpl(). | |
135 // | |
136 // If T is polymorphic, calls `disposeImpl(dynamic_cast<void*>(object))`, otherwise calls | |
137 // `disposeImpl(implicitCast<void*>(object))`. | |
138 // | |
139 // Callers must not call dispose() on the same pointer twice, even if the first call throws | |
140 // an exception. | |
141 | |
142 private: | |
143 template <typename T, bool polymorphic = _kj_internal_isPolymorphic((T*)nullptr)> | |
144 struct Dispose_; | |
145 }; | |
146 | |
147 template <typename T> | |
148 class DestructorOnlyDisposer: public Disposer { | |
149 // A disposer that merely calls the type's destructor and nothing else. | |
150 | |
151 public: | |
152 static const DestructorOnlyDisposer instance; | |
153 | |
154 void disposeImpl(void* pointer) const override { | |
155 reinterpret_cast<T*>(pointer)->~T(); | |
156 } | |
157 }; | |
158 | |
159 template <typename T> | |
160 const DestructorOnlyDisposer<T> DestructorOnlyDisposer<T>::instance = DestructorOnlyDisposer<T>(); | |
161 | |
162 class NullDisposer: public Disposer { | |
163 // A disposer that does nothing. | |
164 | |
165 public: | |
166 static const NullDisposer instance; | |
167 | |
168 void disposeImpl(void* pointer) const override {} | |
169 }; | |
170 | |
171 // ======================================================================================= | |
172 // Own<T> -- An owned pointer. | |
173 | |
174 template <typename T, typename StaticDisposer = decltype(nullptr)> | |
175 class Own; | |
176 | |
177 template <typename T> | |
178 class Own<T, decltype(nullptr)> { | |
179 // A transferrable title to a T. When an Own<T> goes out of scope, the object's Disposer is | |
180 // called to dispose of it. An Own<T> can be efficiently passed by move, without relocating the | |
181 // underlying object; this transfers ownership. | |
182 // | |
183 // This is much like std::unique_ptr, except: | |
184 // - You cannot release(). An owned object is not necessarily allocated with new (see next | |
185 // point), so it would be hard to use release() correctly. | |
186 // - The deleter is made polymorphic by virtual call rather than by template. This is much | |
187 // more powerful -- it allows the use of custom allocators, freelists, etc. This could | |
188 // _almost_ be accomplished with unique_ptr by forcing everyone to use something like | |
189 // std::unique_ptr<T, kj::Deleter>, except that things get hairy in the presence of multiple | |
190 // inheritance and upcasting, and anyway if you force everyone to use a custom deleter | |
191 // then you've lost any benefit to interoperating with the "standard" unique_ptr. | |
192 | |
193 public: | |
194 KJ_DISALLOW_COPY(Own); | |
195 inline Own(): disposer(nullptr), ptr(nullptr) {} | |
196 inline Own(Own&& other) noexcept | |
197 : disposer(other.disposer), ptr(other.ptr) { other.ptr = nullptr; } | |
198 inline Own(Own<RemoveConstOrDisable<T>>&& other) noexcept | |
199 : disposer(other.disposer), ptr(other.ptr) { other.ptr = nullptr; } | |
200 template <typename U, typename = EnableIf<canConvert<U*, T*>()>> | |
201 inline Own(Own<U>&& other) noexcept | |
202 : disposer(other.disposer), ptr(cast(other.ptr)) { | |
203 other.ptr = nullptr; | |
204 } | |
205 template <typename U, typename StaticDisposer, typename = EnableIf<canConvert<U*, T*>()>> | |
206 inline Own(Own<U, StaticDisposer>&& other) noexcept; | |
207 // Convert statically-disposed Own to dynamically-disposed Own. | |
208 inline Own(T* ptr, const Disposer& disposer) noexcept: disposer(&disposer), ptr(ptr) {} | |
209 | |
210 ~Own() noexcept(false) { dispose(); } | |
211 | |
212 inline Own& operator=(Own&& other) { | |
213 // Move-assignnment operator. | |
214 | |
215 // Careful, this might own `other`. Therefore we have to transfer the pointers first, then | |
216 // dispose. | |
217 const Disposer* disposerCopy = disposer; | |
218 T* ptrCopy = ptr; | |
219 disposer = other.disposer; | |
220 ptr = other.ptr; | |
221 other.ptr = nullptr; | |
222 if (ptrCopy != nullptr) { | |
223 disposerCopy->dispose(const_cast<RemoveConst<T>*>(ptrCopy)); | |
224 } | |
225 return *this; | |
226 } | |
227 | |
228 inline Own& operator=(decltype(nullptr)) { | |
229 dispose(); | |
230 return *this; | |
231 } | |
232 | |
233 template <typename... Attachments> | |
234 Own<T> attach(Attachments&&... attachments) KJ_WARN_UNUSED_RESULT; | |
235 // Returns an Own<T> which points to the same object but which also ensures that all values | |
236 // passed to `attachments` remain alive until after this object is destroyed. Normally | |
237 // `attachments` are other Own<?>s pointing to objects that this one depends on. | |
238 // | |
239 // Note that attachments will eventually be destroyed in the order they are listed. Hence, | |
240 // foo.attach(bar, baz) is equivalent to (but more efficient than) foo.attach(bar).attach(baz). | |
241 | |
242 template <typename U> | |
243 Own<U> downcast() { | |
244 // Downcast the pointer to Own<U>, destroying the original pointer. If this pointer does not | |
245 // actually point at an instance of U, the results are undefined (throws an exception in debug | |
246 // mode if RTTI is enabled, otherwise you're on your own). | |
247 | |
248 Own<U> result; | |
249 if (ptr != nullptr) { | |
250 result.ptr = &kj::downcast<U>(*ptr); | |
251 result.disposer = disposer; | |
252 ptr = nullptr; | |
253 } | |
254 return result; | |
255 } | |
256 | |
257 #define NULLCHECK KJ_IREQUIRE(ptr != nullptr, "null Own<> dereference") | |
258 inline T* operator->() { NULLCHECK; return ptr; } | |
259 inline const T* operator->() const { NULLCHECK; return ptr; } | |
260 inline _::RefOrVoid<T> operator*() { NULLCHECK; return *ptr; } | |
261 inline _::RefOrVoid<const T> operator*() const { NULLCHECK; return *ptr; } | |
262 #undef NULLCHECK | |
263 inline T* get() { return ptr; } | |
264 inline const T* get() const { return ptr; } | |
265 inline operator T*() { return ptr; } | |
266 inline operator const T*() const { return ptr; } | |
267 | |
268 private: | |
269 const Disposer* disposer; // Only valid if ptr != nullptr. | |
270 T* ptr; | |
271 | |
272 inline explicit Own(decltype(nullptr)): disposer(nullptr), ptr(nullptr) {} | |
273 | |
274 inline bool operator==(decltype(nullptr)) { return ptr == nullptr; } | |
275 inline bool operator!=(decltype(nullptr)) { return ptr != nullptr; } | |
276 // Only called by Maybe<Own<T>>. | |
277 | |
278 inline void dispose() { | |
279 // Make sure that if an exception is thrown, we are left with a null ptr, so we won't possibly | |
280 // dispose again. | |
281 T* ptrCopy = ptr; | |
282 if (ptrCopy != nullptr) { | |
283 ptr = nullptr; | |
284 disposer->dispose(const_cast<RemoveConst<T>*>(ptrCopy)); | |
285 } | |
286 } | |
287 | |
288 template <typename U> | |
289 static inline T* cast(U* ptr) { | |
290 static_assert(_kj_internal_isPolymorphic((T*)nullptr), | |
291 "Casting owned pointers requires that the target type is polymorphic."); | |
292 return ptr; | |
293 } | |
294 | |
295 template <typename, typename> | |
296 friend class Own; | |
297 friend class Maybe<Own<T>>; | |
298 }; | |
299 | |
300 template <> | |
301 template <typename U> | |
302 inline void* Own<void>::cast(U* ptr) { | |
303 return _::castToVoid(ptr); | |
304 } | |
305 | |
306 template <> | |
307 template <typename U> | |
308 inline const void* Own<const void>::cast(U* ptr) { | |
309 return _::castToConstVoid(ptr); | |
310 } | |
311 | |
312 template <typename T, typename StaticDisposer> | |
313 class Own { | |
314 // If a `StaticDisposer` is specified (which is not the norm), then the object will be deleted | |
315 // by calling StaticDisposer::dispose(pointer). The pointer passed to `dispose()` could be a | |
316 // superclass of `T`, if the pointer has been upcast. | |
317 // | |
318 // This type can be useful for micro-optimization, if you've found that you are doing excessive | |
319 // heap allocations to the point where the virtual call on destruction is costing non-negligible | |
320 // resources. You should avoid this unless you have a specific need, because it precludes a lot | |
321 // of power. | |
322 | |
323 public: | |
324 KJ_DISALLOW_COPY(Own); | |
325 inline Own(): ptr(nullptr) {} | |
326 inline Own(Own&& other) noexcept | |
327 : ptr(other.ptr) { other.ptr = nullptr; } | |
328 inline Own(Own<RemoveConstOrDisable<T>, StaticDisposer>&& other) noexcept | |
329 : ptr(other.ptr) { other.ptr = nullptr; } | |
330 template <typename U, typename = EnableIf<canConvert<U*, T*>()>> | |
331 inline Own(Own<U, StaticDisposer>&& other) noexcept | |
332 : ptr(cast(other.ptr)) { | |
333 other.ptr = nullptr; | |
334 } | |
335 inline explicit Own(T* ptr) noexcept: ptr(ptr) {} | |
336 | |
337 ~Own() noexcept(false) { dispose(); } | |
338 | |
339 inline Own& operator=(Own&& other) { | |
340 // Move-assignnment operator. | |
341 | |
342 // Careful, this might own `other`. Therefore we have to transfer the pointers first, then | |
343 // dispose. | |
344 T* ptrCopy = ptr; | |
345 ptr = other.ptr; | |
346 other.ptr = nullptr; | |
347 if (ptrCopy != nullptr) { | |
348 StaticDisposer::dispose(ptrCopy); | |
349 } | |
350 return *this; | |
351 } | |
352 | |
353 inline Own& operator=(decltype(nullptr)) { | |
354 dispose(); | |
355 return *this; | |
356 } | |
357 | |
358 template <typename U> | |
359 Own<U, StaticDisposer> downcast() { | |
360 // Downcast the pointer to Own<U>, destroying the original pointer. If this pointer does not | |
361 // actually point at an instance of U, the results are undefined (throws an exception in debug | |
362 // mode if RTTI is enabled, otherwise you're on your own). | |
363 | |
364 Own<U, StaticDisposer> result; | |
365 if (ptr != nullptr) { | |
366 result.ptr = &kj::downcast<U>(*ptr); | |
367 ptr = nullptr; | |
368 } | |
369 return result; | |
370 } | |
371 | |
372 #define NULLCHECK KJ_IREQUIRE(ptr != nullptr, "null Own<> dereference") | |
373 inline T* operator->() { NULLCHECK; return ptr; } | |
374 inline const T* operator->() const { NULLCHECK; return ptr; } | |
375 inline _::RefOrVoid<T> operator*() { NULLCHECK; return *ptr; } | |
376 inline _::RefOrVoid<const T> operator*() const { NULLCHECK; return *ptr; } | |
377 #undef NULLCHECK | |
378 inline T* get() { return ptr; } | |
379 inline const T* get() const { return ptr; } | |
380 inline operator T*() { return ptr; } | |
381 inline operator const T*() const { return ptr; } | |
382 | |
383 private: | |
384 T* ptr; | |
385 | |
386 inline explicit Own(decltype(nullptr)): ptr(nullptr) {} | |
387 | |
388 inline bool operator==(decltype(nullptr)) { return ptr == nullptr; } | |
389 inline bool operator!=(decltype(nullptr)) { return ptr != nullptr; } | |
390 // Only called by Maybe<Own<T>>. | |
391 | |
392 inline void dispose() { | |
393 // Make sure that if an exception is thrown, we are left with a null ptr, so we won't possibly | |
394 // dispose again. | |
395 T* ptrCopy = ptr; | |
396 if (ptrCopy != nullptr) { | |
397 ptr = nullptr; | |
398 StaticDisposer::dispose(ptrCopy); | |
399 } | |
400 } | |
401 | |
402 template <typename U> | |
403 static inline T* cast(U* ptr) { | |
404 return ptr; | |
405 } | |
406 | |
407 template <typename, typename> | |
408 friend class Own; | |
409 friend class Maybe<Own<T, StaticDisposer>>; | |
410 }; | |
411 | |
412 namespace _ { // private | |
413 | |
414 template <typename T, typename D> | |
415 class OwnOwn { | |
416 public: | |
417 inline OwnOwn(Own<T, D>&& value) noexcept: value(kj::mv(value)) {} | |
418 | |
419 inline Own<T, D>& operator*() & { return value; } | |
420 inline const Own<T, D>& operator*() const & { return value; } | |
421 inline Own<T, D>&& operator*() && { return kj::mv(value); } | |
422 inline const Own<T, D>&& operator*() const && { return kj::mv(value); } | |
423 inline Own<T, D>* operator->() { return &value; } | |
424 inline const Own<T, D>* operator->() const { return &value; } | |
425 inline operator Own<T, D>*() { return value ? &value : nullptr; } | |
426 inline operator const Own<T, D>*() const { return value ? &value : nullptr; } | |
427 | |
428 private: | |
429 Own<T, D> value; | |
430 }; | |
431 | |
432 template <typename T, typename D> | |
433 OwnOwn<T, D> readMaybe(Maybe<Own<T, D>>&& maybe) { return OwnOwn<T, D>(kj::mv(maybe.ptr)); } | |
434 template <typename T, typename D> | |
435 Own<T, D>* readMaybe(Maybe<Own<T, D>>& maybe) { return maybe.ptr ? &maybe.ptr : nullptr; } | |
436 template <typename T, typename D> | |
437 const Own<T, D>* readMaybe(const Maybe<Own<T, D>>& maybe) { | |
438 return maybe.ptr ? &maybe.ptr : nullptr; | |
439 } | |
440 | |
441 } // namespace _ (private) | |
442 | |
443 template <typename T, typename D> | |
444 class Maybe<Own<T, D>> { | |
445 public: | |
446 inline Maybe(): ptr(nullptr) {} | |
447 inline Maybe(Own<T, D>&& t) noexcept: ptr(kj::mv(t)) {} | |
448 inline Maybe(Maybe&& other) noexcept: ptr(kj::mv(other.ptr)) {} | |
449 | |
450 template <typename U> | |
451 inline Maybe(Maybe<Own<U, D>>&& other): ptr(mv(other.ptr)) {} | |
452 template <typename U> | |
453 inline Maybe(Own<U, D>&& other): ptr(mv(other)) {} | |
454 | |
455 inline Maybe(decltype(nullptr)) noexcept: ptr(nullptr) {} | |
456 | |
457 inline Own<T, D>& emplace(Own<T, D> value) { | |
458 // Assign the Maybe to the given value and return the content. This avoids the need to do a | |
459 // KJ_ASSERT_NONNULL() immediately after setting the Maybe just to read it back again. | |
460 ptr = kj::mv(value); | |
461 return ptr; | |
462 } | |
463 | |
464 template <typename U = T> | |
465 inline operator NoInfer<Maybe<U&>>() { return ptr.get(); } | |
466 template <typename U = T> | |
467 inline operator NoInfer<Maybe<const U&>>() const { return ptr.get(); } | |
468 // Implicit conversion to `Maybe<U&>`. The weird templating is to make sure that | |
469 // `Maybe<Own<void>>` can be instantiated with the compiler complaining about forming references | |
470 // to void -- the use of templates here will cause SFINAE to kick in and hide these, whereas if | |
471 // they are not templates then SFINAE isn't applied and so they are considered errors. | |
472 | |
473 inline Maybe& operator=(Maybe&& other) { ptr = kj::mv(other.ptr); return *this; } | |
474 | |
475 inline bool operator==(decltype(nullptr)) const { return ptr == nullptr; } | |
476 inline bool operator!=(decltype(nullptr)) const { return ptr != nullptr; } | |
477 | |
478 Own<T, D>& orDefault(Own<T, D>& defaultValue) { | |
479 if (ptr == nullptr) { | |
480 return defaultValue; | |
481 } else { | |
482 return ptr; | |
483 } | |
484 } | |
485 const Own<T, D>& orDefault(const Own<T, D>& defaultValue) const { | |
486 if (ptr == nullptr) { | |
487 return defaultValue; | |
488 } else { | |
489 return ptr; | |
490 } | |
491 } | |
492 | |
493 template <typename F, | |
494 typename Result = decltype(instance<bool>() ? instance<Own<T, D>>() : instance<F>()())> | |
495 Result orDefault(F&& lazyDefaultValue) && { | |
496 if (ptr == nullptr) { | |
497 return lazyDefaultValue(); | |
498 } else { | |
499 return kj::mv(ptr); | |
500 } | |
501 } | |
502 | |
503 template <typename Func> | |
504 auto map(Func&& f) & -> Maybe<decltype(f(instance<Own<T, D>&>()))> { | |
505 if (ptr == nullptr) { | |
506 return nullptr; | |
507 } else { | |
508 return f(ptr); | |
509 } | |
510 } | |
511 | |
512 template <typename Func> | |
513 auto map(Func&& f) const & -> Maybe<decltype(f(instance<const Own<T, D>&>()))> { | |
514 if (ptr == nullptr) { | |
515 return nullptr; | |
516 } else { | |
517 return f(ptr); | |
518 } | |
519 } | |
520 | |
521 template <typename Func> | |
522 auto map(Func&& f) && -> Maybe<decltype(f(instance<Own<T, D>&&>()))> { | |
523 if (ptr == nullptr) { | |
524 return nullptr; | |
525 } else { | |
526 return f(kj::mv(ptr)); | |
527 } | |
528 } | |
529 | |
530 template <typename Func> | |
531 auto map(Func&& f) const && -> Maybe<decltype(f(instance<const Own<T, D>&&>()))> { | |
532 if (ptr == nullptr) { | |
533 return nullptr; | |
534 } else { | |
535 return f(kj::mv(ptr)); | |
536 } | |
537 } | |
538 | |
539 private: | |
540 Own<T, D> ptr; | |
541 | |
542 template <typename U> | |
543 friend class Maybe; | |
544 template <typename U, typename D2> | |
545 friend _::OwnOwn<U, D2> _::readMaybe(Maybe<Own<U, D2>>&& maybe); | |
546 template <typename U, typename D2> | |
547 friend Own<U, D2>* _::readMaybe(Maybe<Own<U, D2>>& maybe); | |
548 template <typename U, typename D2> | |
549 friend const Own<U, D2>* _::readMaybe(const Maybe<Own<U, D2>>& maybe); | |
550 }; | |
551 | |
552 namespace _ { // private | |
553 | |
554 template <typename T> | |
555 class HeapDisposer final: public Disposer { | |
556 public: | |
557 virtual void disposeImpl(void* pointer) const override { delete reinterpret_cast<T*>(pointer); } | |
558 | |
559 static const HeapDisposer instance; | |
560 }; | |
561 | |
562 #if _MSC_VER && _MSC_VER < 1920 && !defined(__clang__) | |
563 template <typename T> | |
564 __declspec(selectany) const HeapDisposer<T> HeapDisposer<T>::instance = HeapDisposer<T>(); | |
565 // On MSVC 2017 we suddenly started seeing a linker error on one specific specialization of | |
566 // `HeapDisposer::instance` when seemingly-unrelated code was modified. Explicitly specifying | |
567 // `__declspec(selectany)` seems to fix it. But why? Shouldn't template members have `selectany` | |
568 // behavior by default? We don't know. It works and we're moving on. | |
569 #else | |
570 template <typename T> | |
571 const HeapDisposer<T> HeapDisposer<T>::instance = HeapDisposer<T>(); | |
572 #endif | |
573 | |
574 #if KJ_CPP_STD >= 202002L | |
575 template <typename T, void(*F)(T*)> | |
576 class CustomDisposer: public Disposer { | |
577 public: | |
578 void disposeImpl(void* pointer) const override { | |
579 (*F)(reinterpret_cast<T*>(pointer)); | |
580 } | |
581 }; | |
582 | |
583 template <typename T, void(*F)(T*)> | |
584 static constexpr CustomDisposer<T, F> CUSTOM_DISPOSER_INSTANCE {}; | |
585 #else | |
586 template <typename T, void(*F)(T*)> | |
587 class CustomDisposer: public Disposer { | |
588 public: | |
589 static const CustomDisposer instance; | |
590 | |
591 void disposeImpl(void* pointer) const override { | |
592 (*F)(reinterpret_cast<T*>(pointer)); | |
593 } | |
594 }; | |
595 | |
596 template <typename T, void(*F)(T*)> | |
597 const CustomDisposer<T, F> CustomDisposer<T, F>::instance = CustomDisposer<T, F>(); | |
598 #endif | |
599 | |
600 } // namespace _ (private) | |
601 | |
602 template <typename T, typename... Params> | |
603 Own<T> heap(Params&&... params) { | |
604 // heap<T>(...) allocates a T on the heap, forwarding the parameters to its constructor. The | |
605 // exact heap implementation is unspecified -- for now it is operator new, but you should not | |
606 // assume this. (Since we know the object size at delete time, we could actually implement an | |
607 // allocator that is more efficient than operator new.) | |
608 | |
609 return Own<T>(new T(kj::fwd<Params>(params)...), _::HeapDisposer<T>::instance); | |
610 } | |
611 | |
612 template <typename T> | |
613 Own<Decay<T>> heap(T&& orig) { | |
614 // Allocate a copy (or move) of the argument on the heap. | |
615 // | |
616 // The purpose of this overload is to allow you to omit the template parameter as there is only | |
617 // one argument and the purpose is to copy it. | |
618 | |
619 typedef Decay<T> T2; | |
620 return Own<T2>(new T2(kj::fwd<T>(orig)), _::HeapDisposer<T2>::instance); | |
621 } | |
622 | |
623 #if KJ_CPP_STD > 201402L | |
624 #if KJ_CPP_STD < 202002L | |
625 template <auto F, typename T> | |
626 Own<T> disposeWith(T* ptr) { | |
627 // Associate a pre-allocated raw pointer with a corresponding disposal function. | |
628 // The first template parameter should be a function pointer e.g. disposeWith<freeInt>(new int(0)). | |
629 | |
630 return Own<T>(ptr, _::CustomDisposer<T, F>::instance); | |
631 } | |
632 #else | |
633 template <auto F, typename T> | |
634 Own<T> disposeWith(T* ptr) { | |
635 // Associate a pre-allocated raw pointer with a corresponding disposal function. | |
636 // The first template parameter should be a function pointer e.g. disposeWith<freeInt>(new int(0)). | |
637 | |
638 return Own<T>(ptr, _::CUSTOM_DISPOSER_INSTANCE<T, F>); | |
639 } | |
640 #endif | |
641 #endif | |
642 | |
643 template <typename T, typename... Attachments> | |
644 Own<Decay<T>> attachVal(T&& value, Attachments&&... attachments); | |
645 // Returns an Own<T> that takes ownership of `value` and `attachments`, and points to `value`. | |
646 // | |
647 // This is equivalent to heap(value).attach(attachments), but only does one allocation rather than | |
648 // two. | |
649 | |
650 template <typename T, typename... Attachments> | |
651 Own<T> attachRef(T& value, Attachments&&... attachments); | |
652 // Like attach() but `value` is not moved; the resulting Own<T> points to its existing location. | |
653 // This is preferred if `value` is already owned by one of `attachments`. | |
654 // | |
655 // This is equivalent to Own<T>(&value, kj::NullDisposer::instance).attach(attachments), but | |
656 // is easier to write and allocates slightly less memory. | |
657 | |
658 // ======================================================================================= | |
659 // SpaceFor<T> -- assists in manual allocation | |
660 | |
661 template <typename T> | |
662 class SpaceFor { | |
663 // A class which has the same size and alignment as T but does not call its constructor or | |
664 // destructor automatically. Instead, call construct() to construct a T in the space, which | |
665 // returns an Own<T> which will take care of calling T's destructor later. | |
666 | |
667 public: | |
668 inline SpaceFor() {} | |
669 inline ~SpaceFor() {} | |
670 | |
671 template <typename... Params> | |
672 Own<T> construct(Params&&... params) { | |
673 ctor(value, kj::fwd<Params>(params)...); | |
674 return Own<T>(&value, DestructorOnlyDisposer<T>::instance); | |
675 } | |
676 | |
677 private: | |
678 union { | |
679 T value; | |
680 }; | |
681 }; | |
682 | |
683 // ======================================================================================= | |
684 // Inline implementation details | |
685 | |
686 template <typename T> | |
687 struct Disposer::Dispose_<T, true> { | |
688 static void dispose(T* object, const Disposer& disposer) { | |
689 // Note that dynamic_cast<void*> does not require RTTI to be enabled, because the offset to | |
690 // the top of the object is in the vtable -- as it obviously needs to be to correctly implement | |
691 // operator delete. | |
692 disposer.disposeImpl(dynamic_cast<void*>(object)); | |
693 } | |
694 }; | |
695 template <typename T> | |
696 struct Disposer::Dispose_<T, false> { | |
697 static void dispose(T* object, const Disposer& disposer) { | |
698 disposer.disposeImpl(static_cast<void*>(object)); | |
699 } | |
700 }; | |
701 | |
702 template <typename T> | |
703 void Disposer::dispose(T* object) const { | |
704 Dispose_<T>::dispose(object, *this); | |
705 } | |
706 | |
707 namespace _ { // private | |
708 | |
709 template <typename... T> | |
710 struct OwnedBundle; | |
711 | |
712 template <> | |
713 struct OwnedBundle<> {}; | |
714 | |
715 template <typename First, typename... Rest> | |
716 struct OwnedBundle<First, Rest...>: public OwnedBundle<Rest...> { | |
717 OwnedBundle(First&& first, Rest&&... rest) | |
718 : OwnedBundle<Rest...>(kj::fwd<Rest>(rest)...), first(kj::fwd<First>(first)) {} | |
719 | |
720 // Note that it's intentional that `first` is destroyed before `rest`. This way, doing | |
721 // ptr.attach(foo, bar, baz) is equivalent to ptr.attach(foo).attach(bar).attach(baz) in terms | |
722 // of destruction order (although the former does fewer allocations). | |
723 Decay<First> first; | |
724 }; | |
725 | |
726 template <typename... T> | |
727 struct DisposableOwnedBundle final: public Disposer, public OwnedBundle<T...> { | |
728 DisposableOwnedBundle(T&&... values): OwnedBundle<T...>(kj::fwd<T>(values)...) {} | |
729 void disposeImpl(void* pointer) const override { delete this; } | |
730 }; | |
731 | |
732 template <typename T, typename StaticDisposer> | |
733 class StaticDisposerAdapter final: public Disposer { | |
734 // Adapts a static disposer to be called dynamically. | |
735 public: | |
736 virtual void disposeImpl(void* pointer) const override { | |
737 StaticDisposer::dispose(reinterpret_cast<T*>(pointer)); | |
738 } | |
739 | |
740 static const StaticDisposerAdapter instance; | |
741 }; | |
742 | |
743 template <typename T, typename D> | |
744 const StaticDisposerAdapter<T, D> StaticDisposerAdapter<T, D>::instance = | |
745 StaticDisposerAdapter<T, D>(); | |
746 | |
747 } // namespace _ (private) | |
748 | |
749 template <typename T> | |
750 template <typename... Attachments> | |
751 Own<T> Own<T>::attach(Attachments&&... attachments) { | |
752 T* ptrCopy = ptr; | |
753 | |
754 KJ_IREQUIRE(ptrCopy != nullptr, "cannot attach to null pointer"); | |
755 | |
756 // HACK: If someone accidentally calls .attach() on a null pointer in opt mode, try our best to | |
757 // accomplish reasonable behavior: We turn the pointer non-null but still invalid, so that the | |
758 // disposer will still be called when the pointer goes out of scope. | |
759 if (ptrCopy == nullptr) ptrCopy = reinterpret_cast<T*>(1); | |
760 | |
761 auto bundle = new _::DisposableOwnedBundle<Own<T>, Attachments...>( | |
762 kj::mv(*this), kj::fwd<Attachments>(attachments)...); | |
763 return Own<T>(ptrCopy, *bundle); | |
764 } | |
765 | |
766 template <typename T, typename... Attachments> | |
767 Own<T> attachRef(T& value, Attachments&&... attachments) { | |
768 auto bundle = new _::DisposableOwnedBundle<Attachments...>(kj::fwd<Attachments>(attachments)...); | |
769 return Own<T>(&value, *bundle); | |
770 } | |
771 | |
772 template <typename T, typename... Attachments> | |
773 Own<Decay<T>> attachVal(T&& value, Attachments&&... attachments) { | |
774 auto bundle = new _::DisposableOwnedBundle<T, Attachments...>( | |
775 kj::fwd<T>(value), kj::fwd<Attachments>(attachments)...); | |
776 return Own<Decay<T>>(&bundle->first, *bundle); | |
777 } | |
778 | |
779 template <typename T> | |
780 template <typename U, typename StaticDisposer, typename> | |
781 inline Own<T>::Own(Own<U, StaticDisposer>&& other) noexcept | |
782 : ptr(cast(other.ptr)) { | |
783 if (_::castToVoid(other.ptr) != reinterpret_cast<void*>(other.ptr)) { | |
784 // Oh dangit, there's some sort of multiple inheritance going on and `StaticDisposerAdapter` | |
785 // won't actually work because it'll receive a pointer pointing to the top of the object, which | |
786 // isn't exactly the same as the `U*` pointer it wants. We have no choice but to allocate | |
787 // a dynamic disposer here. | |
788 disposer = new _::DisposableOwnedBundle<Own<U, StaticDisposer>>(kj::mv(other)); | |
789 } else { | |
790 disposer = &_::StaticDisposerAdapter<U, StaticDisposer>::instance; | |
791 other.ptr = nullptr; | |
792 } | |
793 } | |
794 | |
795 } // namespace kj | |
796 | |
797 KJ_END_HEADER |