]> git.saurik.com Git - apple/xnu.git/blobdiff - libkern/os/smart_ptr.h
xnu-6153.11.26.tar.gz
[apple/xnu.git] / libkern / os / smart_ptr.h
diff --git a/libkern/os/smart_ptr.h b/libkern/os/smart_ptr.h
new file mode 100644 (file)
index 0000000..5f89c7f
--- /dev/null
@@ -0,0 +1,523 @@
+#ifndef _OS_SMART_POINTER_H
+#define _OS_SMART_POINTER_H
+
+#include <sys/cdefs.h>
+#include <os/cpp_util.h>
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wc++11-extensions"
+
+#if __has_attribute(trivial_abi)
+# define OS_TRIVIAL_ABI __attribute__((trivial_abi))
+#else
+# error Smart pointers depend on trivial_abi attribute
+#endif
+
+#if !OS_HAS_RVALUE_REFERENCES
+# error Smart pointers depend on rvalue references
+#endif
+
+/* C++98 compatibility */
+#if !OS_HAS_NULLPTR && !defined(nullptr)
+# define nullptr NULL
+#endif
+
+#ifndef OSPTR_LOG
+# define OSPTR_LOG(x, ...) do {} while(0)
+#endif
+
+namespace os {
+static struct no_retain_t {} no_retain;
+
+template<class T, class Policy>
+class OS_TRIVIAL_ABI smart_ptr
+{
+       template<class U, class OtherPolicy> friend class smart_ptr;
+
+public:
+
+/*
+ * Default constructor, creates a null pointer
+ */
+       smart_ptr() : pointer(nullptr)
+       {
+               OSPTR_LOG("Default construct smart_ptr\n");
+       }
+
+#if OS_HAS_NULLPTR
+/*
+ * Construction from a nullptr
+ */
+       smart_ptr(os::nullptr_t) : pointer(nullptr)
+       {
+               OSPTR_LOG("Construct smart_ptr from null\n");
+       }
+#endif
+
+/*
+ * Construct from a raw pointer, taking a reference to the object
+ */
+       explicit smart_ptr(T *&p) : pointer(p)
+       {
+               OSPTR_LOG("Construct smart_ptr from raw %p\n", pointer);
+               if (pointer != nullptr) {
+                       _retain(pointer);
+               }
+       }
+
+/*
+ * Construct from a raw pointer, without bumping the refcount
+ */
+       explicit smart_ptr(T *&p, no_retain_t) : pointer(p)
+       {
+               OSPTR_LOG("Construct smart_ptr from raw %p no retain\n", pointer);
+       }
+
+/*
+ * Copy constructor from the same smart_ptr type
+ */
+       smart_ptr(smart_ptr const &rhs) : pointer(rhs.pointer)
+       {
+               OSPTR_LOG("Copy construct smart_ptr with %p\n", rhs.pointer);
+               if (pointer != nullptr) {
+                       _retain(pointer);
+               }
+       }
+
+#if !LIBKERN_NO_MEMBER_TEMPLATES
+/*
+ * Allows copy of a smart_ptr<T> from a smart_ptr<U>
+ * if U is convertible to T. For example, if T is a base class of U
+ */
+       template<class U>
+       smart_ptr(smart_ptr<U, Policy> const &rhs) : pointer(rhs.get())
+       {
+               OSPTR_LOG("Copy construct smart_ptr with compatible %p\n", rhs.pointer);
+               if (pointer != nullptr) {
+                       _retain(pointer);
+               }
+       }
+#endif
+
+/*
+ * Assign to an OSPointer from a raw pointer
+ */
+       smart_ptr &
+       operator=(T *&rhs)
+       {
+               OSPTR_LOG("Assign smart_ptr with replacing %p with raw %p\n", pointer, rhs);
+               smart_ptr(rhs).swap(*this);
+               return *this;
+       }
+
+#if OS_HAS_NULLPTR
+/*
+ * Assign to an OSPointer from a null pointer
+ */
+       smart_ptr &
+       operator=(os::nullptr_t)
+       {
+               OSPTR_LOG("Assign smart_ptr to null replacing %p\n", pointer);
+               smart_ptr().swap(*this);
+               return *this;
+       }
+#endif
+
+/*
+ * Assign to a smart_ptr from a smart_ptr of the same type
+ */
+       smart_ptr &
+       operator=(smart_ptr &rhs)
+       {
+               OSPTR_LOG("Assign smart_ptr replacing %p with %p\n", pointer, rhs.pointer);
+               smart_ptr(rhs).swap(*this);
+               return *this;
+       }
+
+#if !LIBKERN_NO_MEMBER_TEMPLATES
+/*
+ * Allows assignment of a smart_ptr<T> from a smart_ptr<U>
+ * if U is convertible to T. For example, if T is a base class of U.
+ */
+       template <class U>
+       smart_ptr &
+       operator=(smart_ptr<U, Policy> const &rhs)
+       {
+               OSPTR_LOG("Assign smart_ptr to compatible replacing %p with %p\n", pointer, rhs.pointer);
+               smart_ptr(rhs.get()).swap(*this);
+               return *this;
+       }
+#endif
+
+/*
+ * Move support
+ */
+
+#if OS_HAS_RVALUE_REFERENCES
+/*
+ * Move-construct from a different smart_ptr of the same pointer type
+ */
+       smart_ptr(smart_ptr &&rhs) : pointer(rhs.pointer)
+       {
+               OSPTR_LOG("Move construct smart_ptr with %p\n", rhs.pointer);
+               rhs.pointer = nullptr;
+       }
+
+/*
+ * Move-construct from a raw pointer
+ */
+       smart_ptr(T *&&p) : pointer(p)
+       {
+               OSPTR_LOG("Move construct smart_ptr with %p\n", pointer);
+               if (pointer != nullptr) {
+                       _retain(pointer);
+               }
+               p = nullptr;
+       }
+
+/*
+ * Move-construct from a raw pointer without bumping the refcount
+ */
+       smart_ptr(T *&&p, no_retain_t) : pointer(p)
+       {
+               OSPTR_LOG("Move construct smart_ptr with %p no retain\n", pointer);
+               p = nullptr;
+       }
+
+/*
+ * Move-assign to a smart_ptr from a raw pointer
+ */
+       smart_ptr &
+       operator=(T *&&rhs)
+       {
+               OSPTR_LOG("Move assign smart_ptr replacing %p with raw %p\n", pointer, rhs);
+               smart_ptr(os::move(rhs)).swap(*this);
+               rhs = nullptr;
+               return *this;
+       }
+
+/*
+ * Move-assign from a different smart_ptr of the same type
+ */
+       smart_ptr &
+       operator=(smart_ptr &&rhs)
+       {
+               OSPTR_LOG("Move assign smart_ptr replacing %p with %p\n", pointer, rhs.pointer);
+               smart_ptr(os::move(rhs)).swap(*this);
+               return *this;
+       }
+
+/*
+ * Move from a different smart_ptr with a compatible pointer type
+ */
+       template<class U>
+       smart_ptr(smart_ptr<U, Policy> &&rhs) : pointer(rhs.pointer)
+       {
+               OSPTR_LOG("Move construct smart_ptr with compatible %p\n", rhs.pointer);
+               rhs.pointer = nullptr;
+       }
+
+       template<class U>
+       smart_ptr &
+       operator=(smart_ptr<U, Policy> &&rhs)
+       {
+               OSPTR_LOG("Move assign smart_ptr replacing %p with compatible %p\n", pointer, rhs.pointer);
+               smart_ptr(os::move(rhs)).swap(*this);
+               return *this;
+       }
+#endif
+
+/*
+ * Destructor - decreases the object's reference count
+ */
+       ~smart_ptr()
+       {
+               OSPTR_LOG("Destroy smart_ptr with %p\n", pointer);
+               if (pointer) {
+                       _release(pointer);
+               }
+       }
+
+/*
+ * Create a new object of type T and wrap it in a smart_ptr. The object will have
+ * a reference count of 1, so destruction of the smart_ptr will result in the
+ * object being freed if the smart_ptr wasn't copied first.
+ */
+       static inline smart_ptr
+       alloc()
+       {
+               return smart_ptr(_alloc(), no_retain);
+       }
+
+       void
+       reset()
+       {
+               smart_ptr().swap(*this);
+       }
+
+       T *
+       get() const
+       {
+               return pointer;
+       }
+
+       T **
+       get_for_out_param()
+       {
+               reset();
+               return &pointer;
+       }
+
+/*
+ * Take ownership of object from raw pointer
+ */
+       void
+       attach(T *&p)
+       {
+               OSPTR_LOG("Attach smart_ptr with %p\n", p);
+               smart_ptr(p, no_retain).swap(*this);
+       }
+
+       void
+       attach(T *&&p)
+       {
+               OSPTR_LOG("Move attach smart_ptr with %p\n", p);
+               smart_ptr(os::move(p), no_retain).swap(*this);
+       }
+
+/* Return and drop ownership of pointer with NO release() */
+       T *
+       detach()
+       {
+               OSPTR_LOG("Detach smart_ptr with %p\n", pointer);
+               T *ret = pointer;
+               pointer = nullptr;
+               return ret;
+       }
+
+       T *
+       operator->() const
+       {
+               OSPTR_LOG("Dereference smart_ptr with %p\n", pointer);
+               return pointer;
+       }
+
+       explicit
+       operator bool() const
+       {
+               return pointer != nullptr;
+       }
+
+       inline void
+       swap(smart_ptr &p)
+       {
+               T *temp = pointer;
+               pointer = p.pointer;
+               p.pointer = temp;
+       }
+
+/* swap pointers to the same type but with different policies */
+       template<class OtherPolicy>
+       void
+       swap(smart_ptr<T, OtherPolicy> &p)
+       {
+               if (p.pointer) {
+                       _retain(p.pointer);
+               }
+               if (pointer) {
+                       smart_ptr<T, OtherPolicy>::_retain(pointer);
+               }
+
+               T *temp = pointer;
+               pointer = p.pointer;
+               p.pointer = temp;
+
+               if (p.pointer) {
+                       _release(p.pointer);
+               }
+               if (pointer) {
+                       smart_ptr<T, OtherPolicy>::_release(pointer);
+               }
+       }
+
+       template<class U>
+       smart_ptr<U, Policy>
+       const_pointer_cast() const &
+       {
+               OSPTR_LOG("const_pointer_cast smart_ptr with %p\n", pointer);
+               return smart_ptr<U, Policy>(const_cast<U *>(pointer));
+       }
+
+       template <class U>
+       smart_ptr<U, Policy>
+       const_pointer_cast() &&
+       {
+               OSPTR_LOG("const_pointer_cast move smart_ptr with %p\n", pointer);
+               U *newPointer = const_cast<U *>(detach());
+               return smart_ptr<U, Policy>(os::move(newPointer), no_retain);
+       }
+
+       template <class U>
+       smart_ptr<U, Policy>
+       static_pointer_cast() const &
+       {
+               OSPTR_LOG("static_pointer_cast smart_ptr with %p\n", pointer);
+               return smart_ptr<U, Policy>(static_cast<U *>(pointer));
+       }
+
+       template <class U>
+       smart_ptr<U, Policy>
+       static_pointer_cast() &&
+       {
+               OSPTR_LOG("static_pointer_cast move smart_ptr with %p\n", pointer);
+               return smart_ptr<U, Policy>(static_cast<U *>(detach()), no_retain);
+       }
+
+       template <class U>
+       smart_ptr<U, Policy>
+       dynamic_pointer_cast() const &
+       {
+               OSPTR_LOG("dynamic_pointer_cast smart_ptr with %p\n", pointer);
+               return smart_ptr<U, Policy>(Policy::template dyn_cast<T, U>(pointer));
+       }
+
+       template <class U>
+       smart_ptr<U, Policy>
+       dynamic_pointer_cast() &&
+       {
+               OSPTR_LOG("dynamic_pointer_cast move smart_ptr with %p\n", pointer);
+               U *newPointer = Policy::template dyn_cast<T, U>(pointer);
+
+               if (newPointer != nullptr) {
+                       detach();
+               } else {
+                       reset();
+               }
+               return smart_ptr<U, Policy>(os::move(newPointer), no_retain);
+       }
+
+private:
+       static inline void
+       _retain(T *obj)
+       {
+               OSPTR_LOG("    %s with %p\n", __FUNCTION__, obj);
+               Policy::retain(obj);
+       }
+
+       static inline void
+       _release(T *obj)
+       {
+               OSPTR_LOG("    %s with %p\n", __FUNCTION__, obj);
+               Policy::release(obj);
+       }
+
+       static inline T *
+       _alloc()
+       {
+               OSPTR_LOG("    %s\n", __FUNCTION__);
+               return Policy::template alloc<T>();
+       }
+
+       T *pointer;
+};
+
+/*
+ * Comparison
+ */
+
+template<class T, class Policy>
+inline bool
+operator==(smart_ptr<T, Policy> const &a, smart_ptr<T, Policy> const &b)
+{
+       return a.get() == b.get();
+}
+
+template<class T, class Policy>
+inline bool
+operator!=(smart_ptr<T, Policy> const &a, smart_ptr<T, Policy> const &b)
+{
+       return a.get() != b.get();
+}
+
+template<class A, class A_policy, class B, class B_policy>
+inline bool
+operator==(smart_ptr<A, A_policy> const &a, smart_ptr<B, B_policy> const &b)
+{
+       return a.get() == b.get();
+}
+
+template<class A, class A_policy, class B, class B_policy>
+inline bool
+operator!=(smart_ptr<A, A_policy> const &a, smart_ptr<B, B_policy> const &b)
+{
+       return a.get() != b.get();
+}
+
+/*
+ * Comparison with nullptr
+ */
+
+#if OS_HAS_NULLPTR
+template<class T, class Policy>
+inline bool
+operator==(smart_ptr<T, Policy> const &p, os::nullptr_t)
+{
+       return p.get() == nullptr;
+}
+
+template<class T, class Policy> inline bool
+operator==(os::nullptr_t, smart_ptr<T, Policy> const &p)
+{
+       return p.get() == nullptr;
+}
+
+template<class T, class Policy>
+inline bool
+operator!=(smart_ptr<T, Policy> const &p, os::nullptr_t)
+{
+       return p.get() != nullptr;
+}
+
+template<class T, class Policy>
+inline bool
+operator!=(os::nullptr_t, smart_ptr<T, Policy> const &p)
+{
+       return p.get() != nullptr;
+}
+#endif
+
+/*
+ * Comparison with raw pointer
+ */
+
+template<class T, class Policy>
+inline bool
+operator==(smart_ptr<T, Policy> const &p, const os::remove_const_t<T> *other)
+{
+       return p.get() == other;
+}
+
+template<class T, class Policy>
+inline bool
+operator==(const os::remove_const_t<T> *other, smart_ptr<T, Policy> const &p)
+{
+       return other == p.get();
+}
+
+template<class T, class Policy>
+inline bool
+operator!=(smart_ptr<T, Policy> const &p, const os::remove_const_t<T> *other)
+{
+       return p.get() != other;
+}
+
+template<class T, class Policy>
+inline bool
+operator!=(const os::remove_const_t<T> *other, smart_ptr<T, Policy> const &p)
+{
+       return other != p.get();
+}
+};
+
+#pragma clang diagnostic pop
+#endif /* _OS_SMART_POINTER_H */