jpayne@69: // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors jpayne@69: // Licensed under the MIT License: jpayne@69: // jpayne@69: // Permission is hereby granted, free of charge, to any person obtaining a copy jpayne@69: // of this software and associated documentation files (the "Software"), to deal jpayne@69: // in the Software without restriction, including without limitation the rights jpayne@69: // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell jpayne@69: // copies of the Software, and to permit persons to whom the Software is jpayne@69: // furnished to do so, subject to the following conditions: jpayne@69: // jpayne@69: // The above copyright notice and this permission notice shall be included in jpayne@69: // all copies or substantial portions of the Software. jpayne@69: // jpayne@69: // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR jpayne@69: // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, jpayne@69: // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE jpayne@69: // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER jpayne@69: // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, jpayne@69: // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN jpayne@69: // THE SOFTWARE. jpayne@69: jpayne@69: #pragma once jpayne@69: jpayne@69: #include "common.h" jpayne@69: jpayne@69: KJ_BEGIN_HEADER jpayne@69: jpayne@69: namespace kj { jpayne@69: jpayne@69: template jpayne@69: inline constexpr bool _kj_internal_isPolymorphic(T*) { jpayne@69: // If you get a compiler error here complaining that T is incomplete, it's because you are trying jpayne@69: // to use kj::Own with a type that has only been forward-declared. Since KJ doesn't know if jpayne@69: // the type might be involved in inheritance (especially multiple inheritance), it doesn't know jpayne@69: // how to correctly call the disposer to destroy the type, since the object's true memory address jpayne@69: // may differ from the address used to point to a superclass. jpayne@69: // jpayne@69: // However, if you know for sure that T is NOT polymorphic (i.e. it doesn't have a vtable and jpayne@69: // isn't involved in inheritance), then you can use KJ_DECLARE_NON_POLYMORPHIC(T) to declare this jpayne@69: // to KJ without actually completing the type. Place this macro invocation either in the global jpayne@69: // scope, or in the same namespace as T is defined. jpayne@69: return __is_polymorphic(T); jpayne@69: } jpayne@69: jpayne@69: #define KJ_DECLARE_NON_POLYMORPHIC(...) \ jpayne@69: inline constexpr bool _kj_internal_isPolymorphic(__VA_ARGS__*) { \ jpayne@69: return false; \ jpayne@69: } jpayne@69: // If you want to use kj::Own for an incomplete type T that you know is not polymorphic, then jpayne@69: // write `KJ_DECLARE_NON_POLYMORPHIC(T)` either at the global scope or in the same namespace as jpayne@69: // T is declared. jpayne@69: // jpayne@69: // This also works for templates, e.g.: jpayne@69: // jpayne@69: // template jpayne@69: // struct MyType; jpayne@69: // template jpayne@69: // KJ_DECLARE_NON_POLYMORPHIC(MyType) jpayne@69: jpayne@69: namespace _ { // private jpayne@69: jpayne@69: template struct RefOrVoid_ { typedef T& Type; }; jpayne@69: template <> struct RefOrVoid_ { typedef void Type; }; jpayne@69: template <> struct RefOrVoid_ { typedef void Type; }; jpayne@69: jpayne@69: template jpayne@69: using RefOrVoid = typename RefOrVoid_::Type; jpayne@69: // Evaluates to T&, unless T is `void`, in which case evaluates to `void`. jpayne@69: // jpayne@69: // This is a hack needed to avoid defining Own as a totally separate class. jpayne@69: jpayne@69: template jpayne@69: struct CastToVoid_; jpayne@69: jpayne@69: template jpayne@69: struct CastToVoid_ { jpayne@69: static void* apply(T* ptr) { jpayne@69: return static_cast(ptr); jpayne@69: } jpayne@69: static const void* applyConst(T* ptr) { jpayne@69: const T* cptr = ptr; jpayne@69: return static_cast(cptr); jpayne@69: } jpayne@69: }; jpayne@69: jpayne@69: template jpayne@69: struct CastToVoid_ { jpayne@69: static void* apply(T* ptr) { jpayne@69: return dynamic_cast(ptr); jpayne@69: } jpayne@69: static const void* applyConst(T* ptr) { jpayne@69: const T* cptr = ptr; jpayne@69: return dynamic_cast(cptr); jpayne@69: } jpayne@69: }; jpayne@69: jpayne@69: template jpayne@69: void* castToVoid(T* ptr) { jpayne@69: return CastToVoid_::apply(ptr); jpayne@69: } jpayne@69: jpayne@69: template jpayne@69: const void* castToConstVoid(T* ptr) { jpayne@69: return CastToVoid_::applyConst(ptr); jpayne@69: } jpayne@69: jpayne@69: } // namespace _ (private) jpayne@69: jpayne@69: // ======================================================================================= jpayne@69: // Disposer -- Implementation details. jpayne@69: jpayne@69: class Disposer { jpayne@69: // Abstract interface for a thing that "disposes" of objects, where "disposing" usually means jpayne@69: // calling the destructor followed by freeing the underlying memory. `Own` encapsulates an jpayne@69: // object pointer with corresponding Disposer. jpayne@69: // jpayne@69: // Few developers will ever touch this interface. It is primarily useful for those implementing jpayne@69: // custom memory allocators. jpayne@69: jpayne@69: protected: jpayne@69: // Do not declare a destructor, as doing so will force a global initializer for each HeapDisposer jpayne@69: // instance. Eww! jpayne@69: jpayne@69: virtual void disposeImpl(void* pointer) const = 0; jpayne@69: // Disposes of the object, given a pointer to the beginning of the object. If the object is jpayne@69: // polymorphic, this pointer is determined by dynamic_cast(). For non-polymorphic types, jpayne@69: // Own does not allow any casting, so the pointer exactly matches the original one given to jpayne@69: // Own. jpayne@69: jpayne@69: public: jpayne@69: jpayne@69: template jpayne@69: void dispose(T* object) const; jpayne@69: // Helper wrapper around disposeImpl(). jpayne@69: // jpayne@69: // If T is polymorphic, calls `disposeImpl(dynamic_cast(object))`, otherwise calls jpayne@69: // `disposeImpl(implicitCast(object))`. jpayne@69: // jpayne@69: // Callers must not call dispose() on the same pointer twice, even if the first call throws jpayne@69: // an exception. jpayne@69: jpayne@69: private: jpayne@69: template jpayne@69: struct Dispose_; jpayne@69: }; jpayne@69: jpayne@69: template jpayne@69: class DestructorOnlyDisposer: public Disposer { jpayne@69: // A disposer that merely calls the type's destructor and nothing else. jpayne@69: jpayne@69: public: jpayne@69: static const DestructorOnlyDisposer instance; jpayne@69: jpayne@69: void disposeImpl(void* pointer) const override { jpayne@69: reinterpret_cast(pointer)->~T(); jpayne@69: } jpayne@69: }; jpayne@69: jpayne@69: template jpayne@69: const DestructorOnlyDisposer DestructorOnlyDisposer::instance = DestructorOnlyDisposer(); jpayne@69: jpayne@69: class NullDisposer: public Disposer { jpayne@69: // A disposer that does nothing. jpayne@69: jpayne@69: public: jpayne@69: static const NullDisposer instance; jpayne@69: jpayne@69: void disposeImpl(void* pointer) const override {} jpayne@69: }; jpayne@69: jpayne@69: // ======================================================================================= jpayne@69: // Own -- An owned pointer. jpayne@69: jpayne@69: template jpayne@69: class Own; jpayne@69: jpayne@69: template jpayne@69: class Own { jpayne@69: // A transferrable title to a T. When an Own goes out of scope, the object's Disposer is jpayne@69: // called to dispose of it. An Own can be efficiently passed by move, without relocating the jpayne@69: // underlying object; this transfers ownership. jpayne@69: // jpayne@69: // This is much like std::unique_ptr, except: jpayne@69: // - You cannot release(). An owned object is not necessarily allocated with new (see next jpayne@69: // point), so it would be hard to use release() correctly. jpayne@69: // - The deleter is made polymorphic by virtual call rather than by template. This is much jpayne@69: // more powerful -- it allows the use of custom allocators, freelists, etc. This could jpayne@69: // _almost_ be accomplished with unique_ptr by forcing everyone to use something like jpayne@69: // std::unique_ptr, except that things get hairy in the presence of multiple jpayne@69: // inheritance and upcasting, and anyway if you force everyone to use a custom deleter jpayne@69: // then you've lost any benefit to interoperating with the "standard" unique_ptr. jpayne@69: jpayne@69: public: jpayne@69: KJ_DISALLOW_COPY(Own); jpayne@69: inline Own(): disposer(nullptr), ptr(nullptr) {} jpayne@69: inline Own(Own&& other) noexcept jpayne@69: : disposer(other.disposer), ptr(other.ptr) { other.ptr = nullptr; } jpayne@69: inline Own(Own>&& other) noexcept jpayne@69: : disposer(other.disposer), ptr(other.ptr) { other.ptr = nullptr; } jpayne@69: template ()>> jpayne@69: inline Own(Own&& other) noexcept jpayne@69: : disposer(other.disposer), ptr(cast(other.ptr)) { jpayne@69: other.ptr = nullptr; jpayne@69: } jpayne@69: template ()>> jpayne@69: inline Own(Own&& other) noexcept; jpayne@69: // Convert statically-disposed Own to dynamically-disposed Own. jpayne@69: inline Own(T* ptr, const Disposer& disposer) noexcept: disposer(&disposer), ptr(ptr) {} jpayne@69: jpayne@69: ~Own() noexcept(false) { dispose(); } jpayne@69: jpayne@69: inline Own& operator=(Own&& other) { jpayne@69: // Move-assignnment operator. jpayne@69: jpayne@69: // Careful, this might own `other`. Therefore we have to transfer the pointers first, then jpayne@69: // dispose. jpayne@69: const Disposer* disposerCopy = disposer; jpayne@69: T* ptrCopy = ptr; jpayne@69: disposer = other.disposer; jpayne@69: ptr = other.ptr; jpayne@69: other.ptr = nullptr; jpayne@69: if (ptrCopy != nullptr) { jpayne@69: disposerCopy->dispose(const_cast*>(ptrCopy)); jpayne@69: } jpayne@69: return *this; jpayne@69: } jpayne@69: jpayne@69: inline Own& operator=(decltype(nullptr)) { jpayne@69: dispose(); jpayne@69: return *this; jpayne@69: } jpayne@69: jpayne@69: template jpayne@69: Own attach(Attachments&&... attachments) KJ_WARN_UNUSED_RESULT; jpayne@69: // Returns an Own which points to the same object but which also ensures that all values jpayne@69: // passed to `attachments` remain alive until after this object is destroyed. Normally jpayne@69: // `attachments` are other Owns pointing to objects that this one depends on. jpayne@69: // jpayne@69: // Note that attachments will eventually be destroyed in the order they are listed. Hence, jpayne@69: // foo.attach(bar, baz) is equivalent to (but more efficient than) foo.attach(bar).attach(baz). jpayne@69: jpayne@69: template jpayne@69: Own downcast() { jpayne@69: // Downcast the pointer to Own, destroying the original pointer. If this pointer does not jpayne@69: // actually point at an instance of U, the results are undefined (throws an exception in debug jpayne@69: // mode if RTTI is enabled, otherwise you're on your own). jpayne@69: jpayne@69: Own result; jpayne@69: if (ptr != nullptr) { jpayne@69: result.ptr = &kj::downcast(*ptr); jpayne@69: result.disposer = disposer; jpayne@69: ptr = nullptr; jpayne@69: } jpayne@69: return result; jpayne@69: } jpayne@69: jpayne@69: #define NULLCHECK KJ_IREQUIRE(ptr != nullptr, "null Own<> dereference") jpayne@69: inline T* operator->() { NULLCHECK; return ptr; } jpayne@69: inline const T* operator->() const { NULLCHECK; return ptr; } jpayne@69: inline _::RefOrVoid operator*() { NULLCHECK; return *ptr; } jpayne@69: inline _::RefOrVoid operator*() const { NULLCHECK; return *ptr; } jpayne@69: #undef NULLCHECK jpayne@69: inline T* get() { return ptr; } jpayne@69: inline const T* get() const { return ptr; } jpayne@69: inline operator T*() { return ptr; } jpayne@69: inline operator const T*() const { return ptr; } jpayne@69: jpayne@69: private: jpayne@69: const Disposer* disposer; // Only valid if ptr != nullptr. jpayne@69: T* ptr; jpayne@69: jpayne@69: inline explicit Own(decltype(nullptr)): disposer(nullptr), ptr(nullptr) {} jpayne@69: jpayne@69: inline bool operator==(decltype(nullptr)) { return ptr == nullptr; } jpayne@69: inline bool operator!=(decltype(nullptr)) { return ptr != nullptr; } jpayne@69: // Only called by Maybe>. jpayne@69: jpayne@69: inline void dispose() { jpayne@69: // Make sure that if an exception is thrown, we are left with a null ptr, so we won't possibly jpayne@69: // dispose again. jpayne@69: T* ptrCopy = ptr; jpayne@69: if (ptrCopy != nullptr) { jpayne@69: ptr = nullptr; jpayne@69: disposer->dispose(const_cast*>(ptrCopy)); jpayne@69: } jpayne@69: } jpayne@69: jpayne@69: template jpayne@69: static inline T* cast(U* ptr) { jpayne@69: static_assert(_kj_internal_isPolymorphic((T*)nullptr), jpayne@69: "Casting owned pointers requires that the target type is polymorphic."); jpayne@69: return ptr; jpayne@69: } jpayne@69: jpayne@69: template jpayne@69: friend class Own; jpayne@69: friend class Maybe>; jpayne@69: }; jpayne@69: jpayne@69: template <> jpayne@69: template jpayne@69: inline void* Own::cast(U* ptr) { jpayne@69: return _::castToVoid(ptr); jpayne@69: } jpayne@69: jpayne@69: template <> jpayne@69: template jpayne@69: inline const void* Own::cast(U* ptr) { jpayne@69: return _::castToConstVoid(ptr); jpayne@69: } jpayne@69: jpayne@69: template jpayne@69: class Own { jpayne@69: // If a `StaticDisposer` is specified (which is not the norm), then the object will be deleted jpayne@69: // by calling StaticDisposer::dispose(pointer). The pointer passed to `dispose()` could be a jpayne@69: // superclass of `T`, if the pointer has been upcast. jpayne@69: // jpayne@69: // This type can be useful for micro-optimization, if you've found that you are doing excessive jpayne@69: // heap allocations to the point where the virtual call on destruction is costing non-negligible jpayne@69: // resources. You should avoid this unless you have a specific need, because it precludes a lot jpayne@69: // of power. jpayne@69: jpayne@69: public: jpayne@69: KJ_DISALLOW_COPY(Own); jpayne@69: inline Own(): ptr(nullptr) {} jpayne@69: inline Own(Own&& other) noexcept jpayne@69: : ptr(other.ptr) { other.ptr = nullptr; } jpayne@69: inline Own(Own, StaticDisposer>&& other) noexcept jpayne@69: : ptr(other.ptr) { other.ptr = nullptr; } jpayne@69: template ()>> jpayne@69: inline Own(Own&& other) noexcept jpayne@69: : ptr(cast(other.ptr)) { jpayne@69: other.ptr = nullptr; jpayne@69: } jpayne@69: inline explicit Own(T* ptr) noexcept: ptr(ptr) {} jpayne@69: jpayne@69: ~Own() noexcept(false) { dispose(); } jpayne@69: jpayne@69: inline Own& operator=(Own&& other) { jpayne@69: // Move-assignnment operator. jpayne@69: jpayne@69: // Careful, this might own `other`. Therefore we have to transfer the pointers first, then jpayne@69: // dispose. jpayne@69: T* ptrCopy = ptr; jpayne@69: ptr = other.ptr; jpayne@69: other.ptr = nullptr; jpayne@69: if (ptrCopy != nullptr) { jpayne@69: StaticDisposer::dispose(ptrCopy); jpayne@69: } jpayne@69: return *this; jpayne@69: } jpayne@69: jpayne@69: inline Own& operator=(decltype(nullptr)) { jpayne@69: dispose(); jpayne@69: return *this; jpayne@69: } jpayne@69: jpayne@69: template jpayne@69: Own downcast() { jpayne@69: // Downcast the pointer to Own, destroying the original pointer. If this pointer does not jpayne@69: // actually point at an instance of U, the results are undefined (throws an exception in debug jpayne@69: // mode if RTTI is enabled, otherwise you're on your own). jpayne@69: jpayne@69: Own result; jpayne@69: if (ptr != nullptr) { jpayne@69: result.ptr = &kj::downcast(*ptr); jpayne@69: ptr = nullptr; jpayne@69: } jpayne@69: return result; jpayne@69: } jpayne@69: jpayne@69: #define NULLCHECK KJ_IREQUIRE(ptr != nullptr, "null Own<> dereference") jpayne@69: inline T* operator->() { NULLCHECK; return ptr; } jpayne@69: inline const T* operator->() const { NULLCHECK; return ptr; } jpayne@69: inline _::RefOrVoid operator*() { NULLCHECK; return *ptr; } jpayne@69: inline _::RefOrVoid operator*() const { NULLCHECK; return *ptr; } jpayne@69: #undef NULLCHECK jpayne@69: inline T* get() { return ptr; } jpayne@69: inline const T* get() const { return ptr; } jpayne@69: inline operator T*() { return ptr; } jpayne@69: inline operator const T*() const { return ptr; } jpayne@69: jpayne@69: private: jpayne@69: T* ptr; jpayne@69: jpayne@69: inline explicit Own(decltype(nullptr)): ptr(nullptr) {} jpayne@69: jpayne@69: inline bool operator==(decltype(nullptr)) { return ptr == nullptr; } jpayne@69: inline bool operator!=(decltype(nullptr)) { return ptr != nullptr; } jpayne@69: // Only called by Maybe>. jpayne@69: jpayne@69: inline void dispose() { jpayne@69: // Make sure that if an exception is thrown, we are left with a null ptr, so we won't possibly jpayne@69: // dispose again. jpayne@69: T* ptrCopy = ptr; jpayne@69: if (ptrCopy != nullptr) { jpayne@69: ptr = nullptr; jpayne@69: StaticDisposer::dispose(ptrCopy); jpayne@69: } jpayne@69: } jpayne@69: jpayne@69: template jpayne@69: static inline T* cast(U* ptr) { jpayne@69: return ptr; jpayne@69: } jpayne@69: jpayne@69: template jpayne@69: friend class Own; jpayne@69: friend class Maybe>; jpayne@69: }; jpayne@69: jpayne@69: namespace _ { // private jpayne@69: jpayne@69: template jpayne@69: class OwnOwn { jpayne@69: public: jpayne@69: inline OwnOwn(Own&& value) noexcept: value(kj::mv(value)) {} jpayne@69: jpayne@69: inline Own& operator*() & { return value; } jpayne@69: inline const Own& operator*() const & { return value; } jpayne@69: inline Own&& operator*() && { return kj::mv(value); } jpayne@69: inline const Own&& operator*() const && { return kj::mv(value); } jpayne@69: inline Own* operator->() { return &value; } jpayne@69: inline const Own* operator->() const { return &value; } jpayne@69: inline operator Own*() { return value ? &value : nullptr; } jpayne@69: inline operator const Own*() const { return value ? &value : nullptr; } jpayne@69: jpayne@69: private: jpayne@69: Own value; jpayne@69: }; jpayne@69: jpayne@69: template jpayne@69: OwnOwn readMaybe(Maybe>&& maybe) { return OwnOwn(kj::mv(maybe.ptr)); } jpayne@69: template jpayne@69: Own* readMaybe(Maybe>& maybe) { return maybe.ptr ? &maybe.ptr : nullptr; } jpayne@69: template jpayne@69: const Own* readMaybe(const Maybe>& maybe) { jpayne@69: return maybe.ptr ? &maybe.ptr : nullptr; jpayne@69: } jpayne@69: jpayne@69: } // namespace _ (private) jpayne@69: jpayne@69: template jpayne@69: class Maybe> { jpayne@69: public: jpayne@69: inline Maybe(): ptr(nullptr) {} jpayne@69: inline Maybe(Own&& t) noexcept: ptr(kj::mv(t)) {} jpayne@69: inline Maybe(Maybe&& other) noexcept: ptr(kj::mv(other.ptr)) {} jpayne@69: jpayne@69: template jpayne@69: inline Maybe(Maybe>&& other): ptr(mv(other.ptr)) {} jpayne@69: template jpayne@69: inline Maybe(Own&& other): ptr(mv(other)) {} jpayne@69: jpayne@69: inline Maybe(decltype(nullptr)) noexcept: ptr(nullptr) {} jpayne@69: jpayne@69: inline Own& emplace(Own value) { jpayne@69: // Assign the Maybe to the given value and return the content. This avoids the need to do a jpayne@69: // KJ_ASSERT_NONNULL() immediately after setting the Maybe just to read it back again. jpayne@69: ptr = kj::mv(value); jpayne@69: return ptr; jpayne@69: } jpayne@69: jpayne@69: template jpayne@69: inline operator NoInfer>() { return ptr.get(); } jpayne@69: template jpayne@69: inline operator NoInfer>() const { return ptr.get(); } jpayne@69: // Implicit conversion to `Maybe`. The weird templating is to make sure that jpayne@69: // `Maybe>` can be instantiated with the compiler complaining about forming references jpayne@69: // to void -- the use of templates here will cause SFINAE to kick in and hide these, whereas if jpayne@69: // they are not templates then SFINAE isn't applied and so they are considered errors. jpayne@69: jpayne@69: inline Maybe& operator=(Maybe&& other) { ptr = kj::mv(other.ptr); return *this; } jpayne@69: jpayne@69: inline bool operator==(decltype(nullptr)) const { return ptr == nullptr; } jpayne@69: inline bool operator!=(decltype(nullptr)) const { return ptr != nullptr; } jpayne@69: jpayne@69: Own& orDefault(Own& defaultValue) { jpayne@69: if (ptr == nullptr) { jpayne@69: return defaultValue; jpayne@69: } else { jpayne@69: return ptr; jpayne@69: } jpayne@69: } jpayne@69: const Own& orDefault(const Own& defaultValue) const { jpayne@69: if (ptr == nullptr) { jpayne@69: return defaultValue; jpayne@69: } else { jpayne@69: return ptr; jpayne@69: } jpayne@69: } jpayne@69: jpayne@69: template () ? instance>() : instance()())> jpayne@69: Result orDefault(F&& lazyDefaultValue) && { jpayne@69: if (ptr == nullptr) { jpayne@69: return lazyDefaultValue(); jpayne@69: } else { jpayne@69: return kj::mv(ptr); jpayne@69: } jpayne@69: } jpayne@69: jpayne@69: template jpayne@69: auto map(Func&& f) & -> Maybe&>()))> { jpayne@69: if (ptr == nullptr) { jpayne@69: return nullptr; jpayne@69: } else { jpayne@69: return f(ptr); jpayne@69: } jpayne@69: } jpayne@69: jpayne@69: template jpayne@69: auto map(Func&& f) const & -> Maybe&>()))> { jpayne@69: if (ptr == nullptr) { jpayne@69: return nullptr; jpayne@69: } else { jpayne@69: return f(ptr); jpayne@69: } jpayne@69: } jpayne@69: jpayne@69: template jpayne@69: auto map(Func&& f) && -> Maybe&&>()))> { jpayne@69: if (ptr == nullptr) { jpayne@69: return nullptr; jpayne@69: } else { jpayne@69: return f(kj::mv(ptr)); jpayne@69: } jpayne@69: } jpayne@69: jpayne@69: template jpayne@69: auto map(Func&& f) const && -> Maybe&&>()))> { jpayne@69: if (ptr == nullptr) { jpayne@69: return nullptr; jpayne@69: } else { jpayne@69: return f(kj::mv(ptr)); jpayne@69: } jpayne@69: } jpayne@69: jpayne@69: private: jpayne@69: Own ptr; jpayne@69: jpayne@69: template jpayne@69: friend class Maybe; jpayne@69: template jpayne@69: friend _::OwnOwn _::readMaybe(Maybe>&& maybe); jpayne@69: template jpayne@69: friend Own* _::readMaybe(Maybe>& maybe); jpayne@69: template jpayne@69: friend const Own* _::readMaybe(const Maybe>& maybe); jpayne@69: }; jpayne@69: jpayne@69: namespace _ { // private jpayne@69: jpayne@69: template jpayne@69: class HeapDisposer final: public Disposer { jpayne@69: public: jpayne@69: virtual void disposeImpl(void* pointer) const override { delete reinterpret_cast(pointer); } jpayne@69: jpayne@69: static const HeapDisposer instance; jpayne@69: }; jpayne@69: jpayne@69: #if _MSC_VER && _MSC_VER < 1920 && !defined(__clang__) jpayne@69: template jpayne@69: __declspec(selectany) const HeapDisposer HeapDisposer::instance = HeapDisposer(); jpayne@69: // On MSVC 2017 we suddenly started seeing a linker error on one specific specialization of jpayne@69: // `HeapDisposer::instance` when seemingly-unrelated code was modified. Explicitly specifying jpayne@69: // `__declspec(selectany)` seems to fix it. But why? Shouldn't template members have `selectany` jpayne@69: // behavior by default? We don't know. It works and we're moving on. jpayne@69: #else jpayne@69: template jpayne@69: const HeapDisposer HeapDisposer::instance = HeapDisposer(); jpayne@69: #endif jpayne@69: jpayne@69: #if KJ_CPP_STD >= 202002L jpayne@69: template jpayne@69: class CustomDisposer: public Disposer { jpayne@69: public: jpayne@69: void disposeImpl(void* pointer) const override { jpayne@69: (*F)(reinterpret_cast(pointer)); jpayne@69: } jpayne@69: }; jpayne@69: jpayne@69: template jpayne@69: static constexpr CustomDisposer CUSTOM_DISPOSER_INSTANCE {}; jpayne@69: #else jpayne@69: template jpayne@69: class CustomDisposer: public Disposer { jpayne@69: public: jpayne@69: static const CustomDisposer instance; jpayne@69: jpayne@69: void disposeImpl(void* pointer) const override { jpayne@69: (*F)(reinterpret_cast(pointer)); jpayne@69: } jpayne@69: }; jpayne@69: jpayne@69: template jpayne@69: const CustomDisposer CustomDisposer::instance = CustomDisposer(); jpayne@69: #endif jpayne@69: jpayne@69: } // namespace _ (private) jpayne@69: jpayne@69: template jpayne@69: Own heap(Params&&... params) { jpayne@69: // heap(...) allocates a T on the heap, forwarding the parameters to its constructor. The jpayne@69: // exact heap implementation is unspecified -- for now it is operator new, but you should not jpayne@69: // assume this. (Since we know the object size at delete time, we could actually implement an jpayne@69: // allocator that is more efficient than operator new.) jpayne@69: jpayne@69: return Own(new T(kj::fwd(params)...), _::HeapDisposer::instance); jpayne@69: } jpayne@69: jpayne@69: template jpayne@69: Own> heap(T&& orig) { jpayne@69: // Allocate a copy (or move) of the argument on the heap. jpayne@69: // jpayne@69: // The purpose of this overload is to allow you to omit the template parameter as there is only jpayne@69: // one argument and the purpose is to copy it. jpayne@69: jpayne@69: typedef Decay T2; jpayne@69: return Own(new T2(kj::fwd(orig)), _::HeapDisposer::instance); jpayne@69: } jpayne@69: jpayne@69: #if KJ_CPP_STD > 201402L jpayne@69: #if KJ_CPP_STD < 202002L jpayne@69: template jpayne@69: Own disposeWith(T* ptr) { jpayne@69: // Associate a pre-allocated raw pointer with a corresponding disposal function. jpayne@69: // The first template parameter should be a function pointer e.g. disposeWith(new int(0)). jpayne@69: jpayne@69: return Own(ptr, _::CustomDisposer::instance); jpayne@69: } jpayne@69: #else jpayne@69: template jpayne@69: Own disposeWith(T* ptr) { jpayne@69: // Associate a pre-allocated raw pointer with a corresponding disposal function. jpayne@69: // The first template parameter should be a function pointer e.g. disposeWith(new int(0)). jpayne@69: jpayne@69: return Own(ptr, _::CUSTOM_DISPOSER_INSTANCE); jpayne@69: } jpayne@69: #endif jpayne@69: #endif jpayne@69: jpayne@69: template jpayne@69: Own> attachVal(T&& value, Attachments&&... attachments); jpayne@69: // Returns an Own that takes ownership of `value` and `attachments`, and points to `value`. jpayne@69: // jpayne@69: // This is equivalent to heap(value).attach(attachments), but only does one allocation rather than jpayne@69: // two. jpayne@69: jpayne@69: template jpayne@69: Own attachRef(T& value, Attachments&&... attachments); jpayne@69: // Like attach() but `value` is not moved; the resulting Own points to its existing location. jpayne@69: // This is preferred if `value` is already owned by one of `attachments`. jpayne@69: // jpayne@69: // This is equivalent to Own(&value, kj::NullDisposer::instance).attach(attachments), but jpayne@69: // is easier to write and allocates slightly less memory. jpayne@69: jpayne@69: // ======================================================================================= jpayne@69: // SpaceFor -- assists in manual allocation jpayne@69: jpayne@69: template jpayne@69: class SpaceFor { jpayne@69: // A class which has the same size and alignment as T but does not call its constructor or jpayne@69: // destructor automatically. Instead, call construct() to construct a T in the space, which jpayne@69: // returns an Own which will take care of calling T's destructor later. jpayne@69: jpayne@69: public: jpayne@69: inline SpaceFor() {} jpayne@69: inline ~SpaceFor() {} jpayne@69: jpayne@69: template jpayne@69: Own construct(Params&&... params) { jpayne@69: ctor(value, kj::fwd(params)...); jpayne@69: return Own(&value, DestructorOnlyDisposer::instance); jpayne@69: } jpayne@69: jpayne@69: private: jpayne@69: union { jpayne@69: T value; jpayne@69: }; jpayne@69: }; jpayne@69: jpayne@69: // ======================================================================================= jpayne@69: // Inline implementation details jpayne@69: jpayne@69: template jpayne@69: struct Disposer::Dispose_ { jpayne@69: static void dispose(T* object, const Disposer& disposer) { jpayne@69: // Note that dynamic_cast does not require RTTI to be enabled, because the offset to jpayne@69: // the top of the object is in the vtable -- as it obviously needs to be to correctly implement jpayne@69: // operator delete. jpayne@69: disposer.disposeImpl(dynamic_cast(object)); jpayne@69: } jpayne@69: }; jpayne@69: template jpayne@69: struct Disposer::Dispose_ { jpayne@69: static void dispose(T* object, const Disposer& disposer) { jpayne@69: disposer.disposeImpl(static_cast(object)); jpayne@69: } jpayne@69: }; jpayne@69: jpayne@69: template jpayne@69: void Disposer::dispose(T* object) const { jpayne@69: Dispose_::dispose(object, *this); jpayne@69: } jpayne@69: jpayne@69: namespace _ { // private jpayne@69: jpayne@69: template jpayne@69: struct OwnedBundle; jpayne@69: jpayne@69: template <> jpayne@69: struct OwnedBundle<> {}; jpayne@69: jpayne@69: template jpayne@69: struct OwnedBundle: public OwnedBundle { jpayne@69: OwnedBundle(First&& first, Rest&&... rest) jpayne@69: : OwnedBundle(kj::fwd(rest)...), first(kj::fwd(first)) {} jpayne@69: jpayne@69: // Note that it's intentional that `first` is destroyed before `rest`. This way, doing jpayne@69: // ptr.attach(foo, bar, baz) is equivalent to ptr.attach(foo).attach(bar).attach(baz) in terms jpayne@69: // of destruction order (although the former does fewer allocations). jpayne@69: Decay first; jpayne@69: }; jpayne@69: jpayne@69: template jpayne@69: struct DisposableOwnedBundle final: public Disposer, public OwnedBundle { jpayne@69: DisposableOwnedBundle(T&&... values): OwnedBundle(kj::fwd(values)...) {} jpayne@69: void disposeImpl(void* pointer) const override { delete this; } jpayne@69: }; jpayne@69: jpayne@69: template jpayne@69: class StaticDisposerAdapter final: public Disposer { jpayne@69: // Adapts a static disposer to be called dynamically. jpayne@69: public: jpayne@69: virtual void disposeImpl(void* pointer) const override { jpayne@69: StaticDisposer::dispose(reinterpret_cast(pointer)); jpayne@69: } jpayne@69: jpayne@69: static const StaticDisposerAdapter instance; jpayne@69: }; jpayne@69: jpayne@69: template jpayne@69: const StaticDisposerAdapter StaticDisposerAdapter::instance = jpayne@69: StaticDisposerAdapter(); jpayne@69: jpayne@69: } // namespace _ (private) jpayne@69: jpayne@69: template jpayne@69: template jpayne@69: Own Own::attach(Attachments&&... attachments) { jpayne@69: T* ptrCopy = ptr; jpayne@69: jpayne@69: KJ_IREQUIRE(ptrCopy != nullptr, "cannot attach to null pointer"); jpayne@69: jpayne@69: // HACK: If someone accidentally calls .attach() on a null pointer in opt mode, try our best to jpayne@69: // accomplish reasonable behavior: We turn the pointer non-null but still invalid, so that the jpayne@69: // disposer will still be called when the pointer goes out of scope. jpayne@69: if (ptrCopy == nullptr) ptrCopy = reinterpret_cast(1); jpayne@69: jpayne@69: auto bundle = new _::DisposableOwnedBundle, Attachments...>( jpayne@69: kj::mv(*this), kj::fwd(attachments)...); jpayne@69: return Own(ptrCopy, *bundle); jpayne@69: } jpayne@69: jpayne@69: template jpayne@69: Own attachRef(T& value, Attachments&&... attachments) { jpayne@69: auto bundle = new _::DisposableOwnedBundle(kj::fwd(attachments)...); jpayne@69: return Own(&value, *bundle); jpayne@69: } jpayne@69: jpayne@69: template jpayne@69: Own> attachVal(T&& value, Attachments&&... attachments) { jpayne@69: auto bundle = new _::DisposableOwnedBundle( jpayne@69: kj::fwd(value), kj::fwd(attachments)...); jpayne@69: return Own>(&bundle->first, *bundle); jpayne@69: } jpayne@69: jpayne@69: template jpayne@69: template jpayne@69: inline Own::Own(Own&& other) noexcept jpayne@69: : ptr(cast(other.ptr)) { jpayne@69: if (_::castToVoid(other.ptr) != reinterpret_cast(other.ptr)) { jpayne@69: // Oh dangit, there's some sort of multiple inheritance going on and `StaticDisposerAdapter` jpayne@69: // won't actually work because it'll receive a pointer pointing to the top of the object, which jpayne@69: // isn't exactly the same as the `U*` pointer it wants. We have no choice but to allocate jpayne@69: // a dynamic disposer here. jpayne@69: disposer = new _::DisposableOwnedBundle>(kj::mv(other)); jpayne@69: } else { jpayne@69: disposer = &_::StaticDisposerAdapter::instance; jpayne@69: other.ptr = nullptr; jpayne@69: } jpayne@69: } jpayne@69: jpayne@69: } // namespace kj jpayne@69: jpayne@69: KJ_END_HEADER