#pragma once #include "drape/drape_diagnostics.hpp" #include "base/assert.hpp" #include "base/mutex.hpp" #include #include #include #include #include #include #include // This class tracks usage of drape_ptr's and ref_ptr's class DpPointerTracker { public: typedef std::map> TAlivePointers; static DpPointerTracker & Instance(); template void RefPtr(T * refPtr) { RefPtrNamed(static_cast(refPtr), typeid(refPtr).name()); } void DerefPtr(void * p); void DestroyPtr(void * p); TAlivePointers const & GetAlivePointers() const; private: DpPointerTracker() = default; ~DpPointerTracker(); void RefPtrNamed(void * refPtr, std::string const & name); TAlivePointers m_alivePointers; std::mutex m_mutex; }; // Custom deleter for unique_ptr class DpPointerDeleter { public: template void operator()(T * p) { DpPointerTracker::Instance().DestroyPtr(p); delete p; } }; #if defined(TRACK_POINTERS) template using drape_ptr = std::unique_ptr; #else template using drape_ptr = std::unique_ptr; #endif template drape_ptr make_unique_dp(Args &&... args) { return drape_ptr(new T(std::forward(args)...)); } template class ref_ptr { public: ref_ptr() noexcept : m_ptr(nullptr) { #if defined(TRACK_POINTERS) m_isOwnerUnique = false; #endif } #if defined(TRACK_POINTERS) ref_ptr(T * ptr, bool isOwnerUnique = false) noexcept #else ref_ptr(T * ptr) noexcept #endif : m_ptr(ptr) { #if defined(TRACK_POINTERS) m_isOwnerUnique = isOwnerUnique; if (m_isOwnerUnique) DpPointerTracker::Instance().RefPtr(m_ptr); #endif } ref_ptr(ref_ptr const & rhs) noexcept : m_ptr(rhs.m_ptr) { #if defined(TRACK_POINTERS) m_isOwnerUnique = rhs.m_isOwnerUnique; if (m_isOwnerUnique) DpPointerTracker::Instance().RefPtr(m_ptr); #endif } ref_ptr(ref_ptr && rhs) noexcept { m_ptr = rhs.m_ptr; rhs.m_ptr = nullptr; #if defined(TRACK_POINTERS) m_isOwnerUnique = rhs.m_isOwnerUnique; rhs.m_isOwnerUnique = false; #endif } ~ref_ptr() { #if defined(TRACK_POINTERS) if (m_isOwnerUnique) DpPointerTracker::Instance().DerefPtr(m_ptr); #endif m_ptr = nullptr; } T * operator->() const { return m_ptr; } template operator ref_ptr() const { static_assert(std::is_base_of::value || std::is_base_of::value || std::is_void::value || std::is_void::value, ""); #if defined(TRACK_POINTERS) return ref_ptr(static_cast(m_ptr), m_isOwnerUnique); #else return ref_ptr(static_cast(m_ptr)); #endif } template ref_ptr downcast() const { ASSERT(dynamic_cast(m_ptr) != nullptr, ()); #if defined(TRACK_POINTERS) return ref_ptr(static_cast(m_ptr), m_isOwnerUnique); #else return ref_ptr(static_cast(m_ptr)); #endif } explicit operator bool() const { return m_ptr != nullptr; } bool operator==(ref_ptr const & rhs) const { return m_ptr == rhs.m_ptr; } bool operator==(T * rhs) const { return m_ptr == rhs; } bool operator!=(ref_ptr const & rhs) const { return !operator==(rhs); } bool operator!=(T * rhs) const { return !operator==(rhs); } bool operator<(ref_ptr const & rhs) const { return m_ptr < rhs.m_ptr; } template ::value>> TResult & operator*() const { return *m_ptr; } ref_ptr & operator=(ref_ptr const & rhs) noexcept { if (this == &rhs) return *this; #if defined(TRACK_POINTERS) if (m_isOwnerUnique) DpPointerTracker::Instance().DerefPtr(m_ptr); #endif m_ptr = rhs.m_ptr; #if defined(TRACK_POINTERS) m_isOwnerUnique = rhs.m_isOwnerUnique; if (m_isOwnerUnique) DpPointerTracker::Instance().RefPtr(m_ptr); #endif return *this; } ref_ptr & operator=(ref_ptr && rhs) noexcept { if (this == &rhs) return *this; #if defined(TRACK_POINTERS) if (m_isOwnerUnique) DpPointerTracker::Instance().DerefPtr(m_ptr); #endif m_ptr = rhs.m_ptr; rhs.m_ptr = nullptr; #if defined(TRACK_POINTERS) m_isOwnerUnique = rhs.m_isOwnerUnique; rhs.m_isOwnerUnique = false; #endif return *this; } T * get() const { return m_ptr; } private: T* m_ptr; #if defined(TRACK_POINTERS) bool m_isOwnerUnique; #endif template friend inline std::string DebugPrint(ref_ptr const & v); }; template inline std::string DebugPrint(ref_ptr const & v) { return DebugPrint(v.m_ptr); } template ref_ptr make_ref(drape_ptr const & drapePtr) { #if defined(TRACK_POINTERS) return ref_ptr(drapePtr.get(), true /* isOwnerUnique */); #else return ref_ptr(drapePtr.get()); #endif } template ref_ptr make_ref(T* ptr) { #if defined(TRACK_POINTERS) return ref_ptr(ptr, false /* isOwnerUnique */); #else return ref_ptr(ptr); #endif }