/************************************************************************* * * Copyright 2016 Realm Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * **************************************************************************/ #ifndef REALM_UTIL_BIND_PTR_HPP #define REALM_UTIL_BIND_PTR_HPP #include <algorithm> #include <memory> #include <atomic> #include <ostream> #include <utility> #include <realm/util/features.h> #include <realm/util/assert.hpp> namespace realm { namespace util { class bind_ptr_base { public: struct adopt_tag { }; }; /// A generic intrusive smart pointer that binds itself explicitely to /// the target object. /// /// This class is agnostic towards what 'binding' means for the target /// object, but a common use is 'reference counting'. See RefCountBase /// for an example of that. /// /// This smart pointer implementation assumes that the target object /// destructor never throws. template <class T> class bind_ptr : public bind_ptr_base { public: constexpr bind_ptr() noexcept : m_ptr(nullptr) { } ~bind_ptr() noexcept { unbind(); } explicit bind_ptr(T* p) noexcept { bind(p); } template <class U> explicit bind_ptr(U* p) noexcept { bind(p); } bind_ptr(T* p, adopt_tag) noexcept { m_ptr = p; } template <class U> bind_ptr(U* p, adopt_tag) noexcept { m_ptr = p; } // Copy construct bind_ptr(const bind_ptr& p) noexcept { bind(p.m_ptr); } template <class U> bind_ptr(const bind_ptr<U>& p) noexcept { bind(p.m_ptr); } // Copy assign bind_ptr& operator=(const bind_ptr& p) noexcept { bind_ptr(p).swap(*this); return *this; } template <class U> bind_ptr& operator=(const bind_ptr<U>& p) noexcept { bind_ptr(p).swap(*this); return *this; } // Move construct bind_ptr(bind_ptr&& p) noexcept : m_ptr(p.release()) { } template <class U> bind_ptr(bind_ptr<U>&& p) noexcept : m_ptr(p.release()) { } // Move from std::unique_ptr bind_ptr(std::unique_ptr<T>&& p) noexcept { bind(p.release()); } // Move assign bind_ptr& operator=(bind_ptr&& p) noexcept { bind_ptr(std::move(p)).swap(*this); return *this; } template <class U> bind_ptr& operator=(bind_ptr<U>&& p) noexcept { bind_ptr(std::move(p)).swap(*this); return *this; } //@{ // Comparison template <class U> bool operator==(const bind_ptr<U>&) const noexcept; template <class U> bool operator==(U*) const noexcept; template <class U> bool operator!=(const bind_ptr<U>&) const noexcept; template <class U> bool operator!=(U*) const noexcept; template <class U> bool operator<(const bind_ptr<U>&) const noexcept; template <class U> bool operator<(U*) const noexcept; template <class U> bool operator>(const bind_ptr<U>&) const noexcept; template <class U> bool operator>(U*) const noexcept; template <class U> bool operator<=(const bind_ptr<U>&) const noexcept; template <class U> bool operator<=(U*) const noexcept; template <class U> bool operator>=(const bind_ptr<U>&) const noexcept; template <class U> bool operator>=(U*) const noexcept; //@} // Dereference T& operator*() const noexcept { return *m_ptr; } T* operator->() const noexcept { return m_ptr; } explicit operator bool() const noexcept { return m_ptr != 0; } T* get() const noexcept { return m_ptr; } void reset() noexcept { bind_ptr().swap(*this); } void reset(T* p) noexcept { bind_ptr(p).swap(*this); } template <class U> void reset(U* p) noexcept { bind_ptr(p).swap(*this); } void reset(T* p, adopt_tag) noexcept { bind_ptr(p, adopt_tag{}).swap(*this); } template <class U> void reset(U* p, adopt_tag) noexcept { bind_ptr(p, adopt_tag{}).swap(*this); } T* release() noexcept { T* const p = m_ptr; m_ptr = nullptr; return p; } void swap(bind_ptr& p) noexcept { std::swap(m_ptr, p.m_ptr); } friend void swap(bind_ptr& a, bind_ptr& b) noexcept { a.swap(b); } protected: struct casting_move_tag { }; template <class U> bind_ptr(bind_ptr<U>* p, casting_move_tag) noexcept : m_ptr(static_cast<T*>(p->release())) { } private: T* m_ptr; void bind(T* p) noexcept { if (p) p->bind_ptr(); m_ptr = p; } void unbind() noexcept { if (m_ptr) m_ptr->unbind_ptr(); } template <class> friend class bind_ptr; }; // Deduction guides template <class T> bind_ptr(T*) -> bind_ptr<T>; template <class T> bind_ptr(T*, bind_ptr_base::adopt_tag) -> bind_ptr<T>; template <class T, typename... Args> bind_ptr<T> make_bind(Args&&... __args) { return bind_ptr<T>(new T(std::forward<Args>(__args)...)); } template <class C, class T, class U> inline std::basic_ostream<C, T>& operator<<(std::basic_ostream<C, T>& out, const bind_ptr<U>& p) { out << static_cast<const void*>(p.get()); return out; } //@{ // Comparison template <class T, class U> bool operator==(T*, const bind_ptr<U>&) noexcept; template <class T, class U> bool operator!=(T*, const bind_ptr<U>&) noexcept; template <class T, class U> bool operator<(T*, const bind_ptr<U>&) noexcept; template <class T, class U> bool operator>(T*, const bind_ptr<U>&) noexcept; template <class T, class U> bool operator<=(T*, const bind_ptr<U>&) noexcept; template <class T, class U> bool operator>=(T*, const bind_ptr<U>&) noexcept; //@} /// Polymorphic convenience base class for reference counting objects. /// /// Together with bind_ptr, this class delivers simple instrusive /// reference counting. /// /// \sa bind_ptr class RefCountBase { public: RefCountBase() noexcept : m_ref_count(0) { } virtual ~RefCountBase() noexcept { REALM_ASSERT(m_ref_count == 0); } RefCountBase(const RefCountBase&) : m_ref_count(0) { } void operator=(const RefCountBase&) {} protected: void bind_ptr() const noexcept { ++m_ref_count; } void unbind_ptr() const noexcept { if (--m_ref_count == 0) delete this; } private: mutable unsigned long m_ref_count; template <class> friend class bind_ptr; }; /// Same as RefCountBase, but this one makes the copying of, and the /// destruction of counted references thread-safe. /// /// \sa RefCountBase /// \sa bind_ptr class AtomicRefCountBase { public: AtomicRefCountBase() noexcept : m_ref_count(0) { } virtual ~AtomicRefCountBase() noexcept { REALM_ASSERT(m_ref_count == 0); } AtomicRefCountBase(const AtomicRefCountBase&) : m_ref_count(0) { } void operator=(const AtomicRefCountBase&) {} protected: // FIXME: Operators ++ and -- as used below use // std::memory_order_seq_cst. This can be optimized. void bind_ptr() const noexcept { ++m_ref_count; } void unbind_ptr() const noexcept { if (--m_ref_count == 0) { delete this; } } private: mutable std::atomic<unsigned long> m_ref_count; template <class> friend class bind_ptr; }; // Implementation: template <class T> template <class U> bool bind_ptr<T>::operator==(const bind_ptr<U>& p) const noexcept { return m_ptr == p.m_ptr; } template <class T> template <class U> bool bind_ptr<T>::operator==(U* p) const noexcept { return m_ptr == p; } template <class T> template <class U> bool bind_ptr<T>::operator!=(const bind_ptr<U>& p) const noexcept { return m_ptr != p.m_ptr; } template <class T> template <class U> bool bind_ptr<T>::operator!=(U* p) const noexcept { return m_ptr != p; } template <class T> template <class U> bool bind_ptr<T>::operator<(const bind_ptr<U>& p) const noexcept { return m_ptr < p.m_ptr; } template <class T> template <class U> bool bind_ptr<T>::operator<(U* p) const noexcept { return m_ptr < p; } template <class T> template <class U> bool bind_ptr<T>::operator>(const bind_ptr<U>& p) const noexcept { return m_ptr > p.m_ptr; } template <class T> template <class U> bool bind_ptr<T>::operator>(U* p) const noexcept { return m_ptr > p; } template <class T> template <class U> bool bind_ptr<T>::operator<=(const bind_ptr<U>& p) const noexcept { return m_ptr <= p.m_ptr; } template <class T> template <class U> bool bind_ptr<T>::operator<=(U* p) const noexcept { return m_ptr <= p; } template <class T> template <class U> bool bind_ptr<T>::operator>=(const bind_ptr<U>& p) const noexcept { return m_ptr >= p.m_ptr; } template <class T> template <class U> bool bind_ptr<T>::operator>=(U* p) const noexcept { return m_ptr >= p; } template <class T, class U> bool operator==(T* a, const bind_ptr<U>& b) noexcept { return b == a; } template <class T, class U> bool operator!=(T* a, const bind_ptr<U>& b) noexcept { return b != a; } template <class T, class U> bool operator<(T* a, const bind_ptr<U>& b) noexcept { return b > a; } template <class T, class U> bool operator>(T* a, const bind_ptr<U>& b) noexcept { return b < a; } template <class T, class U> bool operator<=(T* a, const bind_ptr<U>& b) noexcept { return b >= a; } template <class T, class U> bool operator>=(T* a, const bind_ptr<U>& b) noexcept { return b <= a; } } // namespace util } // namespace realm #endif // REALM_UTIL_BIND_PTR_HPP