From c452e74e0c1c54e93e4bffa2ef288f3a4a4273f1 Mon Sep 17 00:00:00 2001 From: Eduardo Bart Date: Mon, 4 Mar 2013 13:14:35 -0300 Subject: [PATCH] Implement stdext::shared_ptr It's an alternative to stdext::shared_object_ptr with weak pointers support and some other functionallity, however it's heavier, uses more memory, more allocation and slower, this class should be used when really needed, prefer stdext::shared_object_ptr --- src/framework/CMakeLists.txt | 1 + src/framework/stdext/shared_object.h | 17 +- src/framework/stdext/shared_ptr.h | 232 +++++++++++++++++++++++++++ src/framework/stdext/types.h | 1 + 4 files changed, 242 insertions(+), 9 deletions(-) create mode 100644 src/framework/stdext/shared_ptr.h diff --git a/src/framework/CMakeLists.txt b/src/framework/CMakeLists.txt index 310e30e6..b96b7044 100644 --- a/src/framework/CMakeLists.txt +++ b/src/framework/CMakeLists.txt @@ -50,6 +50,7 @@ set(framework_SOURCES ${framework_SOURCES} ${CMAKE_CURRENT_LIST_DIR}/stdext/packed_storage.h ${CMAKE_CURRENT_LIST_DIR}/stdext/packed_vector.h ${CMAKE_CURRENT_LIST_DIR}/stdext/shared_object.h + ${CMAKE_CURRENT_LIST_DIR}/stdext/shared_ptr.h ${CMAKE_CURRENT_LIST_DIR}/stdext/stdext.h ${CMAKE_CURRENT_LIST_DIR}/stdext/string.cpp ${CMAKE_CURRENT_LIST_DIR}/stdext/string.h diff --git a/src/framework/stdext/shared_object.h b/src/framework/stdext/shared_object.h index 016a512c..7b62a75b 100644 --- a/src/framework/stdext/shared_object.h +++ b/src/framework/stdext/shared_object.h @@ -23,6 +23,7 @@ #ifndef STDEXT_SHARED_OBJECT_H #define STDEXT_SHARED_OBJECT_H +#include "types.h" #include #include #include @@ -37,16 +38,14 @@ namespace stdext { template class shared_object_ptr; -typedef unsigned long refcount_t; - class shared_object { public: - shared_object() : m_refs(0) { } + shared_object() : refs(0) { } virtual ~shared_object() { } - void add_ref() { ++m_refs; assert(m_refs != 0xffffffff); } - void dec_ref() { if(--m_refs == 0) delete this; } - refcount_t ref_count() { return m_refs; } + void add_ref() { ++refs; } + void dec_ref() { if(--refs == 0) delete this; } + refcount_t ref_count() { return refs; } template stdext::shared_object_ptr static_self_cast() { return stdext::shared_object_ptr(static_cast(this)); } template stdext::shared_object_ptr dynamic_self_cast() { return stdext::shared_object_ptr(dynamic_cast(this)); } @@ -54,9 +53,9 @@ public: private: #ifdef THREAD_SAFE - std::atomic m_refs; + std::atomic refs; #else - refcount_t m_refs; + refcount_t refs; #endif }; @@ -78,7 +77,7 @@ public: ~shared_object_ptr() { if(px != nullptr) dec_ref(); } void reset() { shared_object_ptr().swap(*this); } - void reset(T* rhs) { shared_object_ptr( rhs ).swap(*this); } + void reset(T* rhs) { shared_object_ptr(rhs).swap(*this); } void swap(shared_object_ptr& rhs) { std::swap(px, rhs.px); } T* get() const { return px; } diff --git a/src/framework/stdext/shared_ptr.h b/src/framework/stdext/shared_ptr.h new file mode 100644 index 00000000..154a3292 --- /dev/null +++ b/src/framework/stdext/shared_ptr.h @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2010-2013 OTClient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef STDEXT_SHARED_PTR_H +#define STDEXT_SHARED_PTR_H + +#include "types.h" +#include "dumper.h" +#include +#include +#include +#include + +#ifdef THREAD_SAFE +#include +#endif + +namespace stdext { + +template +class shared_ptr; + +template +class weak_ptr; + +template +class shared_base +{ +public: + shared_base(T* p) : refs(1), weaks(0), px(p) { } + ~shared_base() { } + + void add_ref() { ++refs; } + void dec_ref() { + if(--refs == 0) { + delete px; + px = nullptr; + if(weaks == 0) + delete this; + } + } + + void add_weak_ref() { ++weaks; } + void dec_weak_ref() { + if(--weaks == 0 && refs == 0) + delete this; + } + + void set(T *p) { + T* tmp = px; + px = p; + if(tmp) + delete tmp; + } + T *get() { return px; } + + refcount_t ref_count() { return refs; } + refcount_t weak_count() { return weaks; } + bool expired() { return refs == 0; } + +private: +#ifdef THREAD_SAFE + std::atomic refs; + std::atomic weaks; + std::atomic px; +#else + refcount_t refs; + refcount_t weaks; + T* px; +#endif +}; + +template +class shared_ptr +{ +public: + typedef T element_type; + + shared_ptr() : base(nullptr) { } + shared_ptr(T* p) { if(p != nullptr) base = new shared_base(p); else base = nullptr; } + shared_ptr(shared_ptr const& rhs): base(rhs.base) { if(base != nullptr) base->add_ref(); } + template + shared_ptr(shared_ptr const& rhs, typename std::is_convertible::type* = nullptr) : base(rhs.base) { if(base != nullptr) base->add_ref(); } + ~shared_ptr() { if(base != nullptr) base->dec_ref(); } + + void reset() { shared_ptr().swap(*this); } + void reset(T* rhs) { shared_ptr(rhs).swap(*this); } + void swap(shared_ptr& rhs) { std::swap(base, rhs.base); } + + void set(T* p) { assert(p != nullptr); base->set(p); } + T* get() const { return base ? base->get() : nullptr; } + + refcount_t use_count() const { return base ? base->ref_count() : 0; } + refcount_t weak_count() const { return base ? base->weak_count() : 0; } + bool is_unique() const { return use_count() == 1; } + + T& operator*() const { assert(base != nullptr); return *base->get(); } + T* operator->() const { assert(base != nullptr); return base->get(); } + + template + shared_ptr& operator=(shared_ptr const& rhs) { shared_ptr(rhs).swap(*this); return *this; } + shared_ptr& operator=(shared_ptr const& rhs) { shared_ptr(rhs).swap(*this); return *this; } + shared_ptr& operator=(T* rhs) { shared_ptr(rhs).swap(*this); return *this; } + + // implicit conversion to bool + typedef shared_base* shared_ptr::*unspecified_bool_type; + operator unspecified_bool_type() const { return base == nullptr ? nullptr : &shared_ptr::base; } + bool operator!() const { return base == nullptr; } + + // std::move support + shared_ptr(shared_ptr&& rhs): base(rhs.base) { rhs.base = nullptr; } + shared_ptr& operator=(shared_ptr&& rhs) { shared_ptr(static_cast(rhs)).swap(*this); return *this; } + +private: + shared_ptr(shared_base *base) { + if(base && !base->expired()) { + base->add_ref(); + this->base = base; + } else + base = nullptr; + } + shared_base *base; + + friend class weak_ptr; +}; + +template +class weak_ptr { +public: + typedef T element_type; + + weak_ptr() : base(nullptr) { } + weak_ptr(shared_ptr const& rhs): base(rhs.base) { if(base != nullptr) base->add_weak_ref(); } + template + weak_ptr(shared_ptr const& rhs, typename std::is_convertible::type* = nullptr) : base(rhs.base) { if(base != nullptr) base->add_weak_ref(); } + weak_ptr(weak_ptr const& rhs): base(rhs.base) { if(base != nullptr) base->add_weak_ref(); } + template + weak_ptr(weak_ptr const& rhs, typename std::is_convertible::type* = nullptr) : base(rhs.base) { if(base != nullptr) base->add_weak_ref(); } + ~weak_ptr() { if(base != nullptr) base->dec_weak_ref(); } + + void reset() { weak_ptr().swap(*this); } + void swap(weak_ptr& rhs) { std::swap(base, rhs.base); } + + T* get() const { return base ? base->get() : nullptr; } + refcount_t use_count() const { return base ? base->ref_count() : 0; } + refcount_t weak_count() const { return base ? base->weak_count() : 0; } + bool expired() const { return base ? base->expired() : false; } + shared_ptr lock() { return shared_ptr(base); } + + weak_ptr& operator=(weak_ptr const& rhs) { weak_ptr(rhs).swap(*this); return *this; } + template + weak_ptr& operator=(shared_ptr const& rhs) { weak_ptr(rhs).swap(*this); return *this; } + template + weak_ptr& operator=(weak_ptr const& rhs) { weak_ptr(rhs).swap(*this); return *this; } + + // implicit conversion to bool + typedef shared_base* weak_ptr::*unspecified_bool_type; + operator unspecified_bool_type() const { return base == nullptr ? nullptr : &weak_ptr::base; } + bool operator!() const { return !expired(); } + + // std::move support + weak_ptr(weak_ptr&& rhs): base(rhs.base) { rhs.base = nullptr; } + weak_ptr& operator=(weak_ptr&& rhs) { weak_ptr(static_cast(rhs)).swap(*this); return *this; } + +private: + shared_base *base; +}; + +template bool operator==(shared_ptr const& a, shared_ptr const& b) { return a.get() == b.get(); } +template bool operator==(weak_ptr const& a, weak_ptr const& b) { return a.get() == b.get(); } +template bool operator==(shared_ptr const& a, weak_ptr const& b) { return a.get() == b.get(); } +template bool operator==(weak_ptr const& a, shared_ptr const& b) { return a.get() == b.get(); } +template bool operator!=(shared_ptr const& a, shared_ptr const& b) { return a.get() != b.get(); } +template bool operator!=(weak_ptr const& a, weak_ptr const& b) { return a.get() != b.get(); } +template bool operator!=(shared_ptr const& a, weak_ptr const& b) { return a.get() != b.get(); } +template bool operator!=(weak_ptr const& a, shared_ptr const& b) { return a.get() != b.get(); } +template bool operator==(shared_ptr const& a, U* b) { return a.get() == b; } +template bool operator==(weak_ptr const& a, U* b) { return a.get() == b; } +template bool operator!=(shared_ptr const& a, U* b) { return a.get() != b; } +template bool operator!=(weak_ptr const& a, U* b) { return a.get() != b; } +template bool operator==(T * a, shared_ptr const& b) { return a == b.get(); } +template bool operator==(T * a, weak_ptr const& b) { return a == b.get(); } +template bool operator!=(T * a, shared_ptr const& b) { return a != b.get(); } +template bool operator!=(T * a, weak_ptr const& b) { return a != b.get(); } +template bool operator<(shared_ptr const& a, shared_ptr const& b) { return std::less()(a.get(), b.get()); } +template bool operator<(weak_ptr const& a, weak_ptr const& b) { return std::less()(a.get(), b.get()); } + +template T* get_pointer(shared_ptr const& p) { return p.get(); } +template T* get_pointer(weak_ptr const& p) { return p.get(); } +template shared_ptr static_pointer_cast(shared_ptr const& p) { return static_cast(p.get()); } +template shared_ptr const_pointer_cast(shared_ptr const& p) { return const_cast(p.get()); } +template shared_ptr dynamic_pointer_cast(shared_ptr const& p) { return dynamic_cast(p.get()); } +template stdext::shared_ptr make_shared(Args... args) { return stdext::shared_ptr(new T(args...)); } + +// operator<< support +template std::basic_ostream& operator<<(std::basic_ostream& os, shared_ptr const& p) { os << p.get(); return os; } +template std::basic_ostream& operator<<(std::basic_ostream& os, weak_ptr const& p) { os << p.get(); return os; } + +} + +namespace std { + +// hash, for unordered_map support +template struct hash> { size_t operator()(const stdext::shared_ptr& p) const { return std::hash()(p.get()); } }; +template struct hash> { size_t operator()(const stdext::weak_ptr& p) const { return std::hash()(p.get()); } }; + +// swap support +template void swap(stdext::shared_ptr& lhs, stdext::shared_ptr& rhs) { lhs.swap(rhs); } +template void swap(stdext::weak_ptr& lhs, stdext::weak_ptr& rhs) { lhs.swap(rhs); } + +} + +#endif diff --git a/src/framework/stdext/types.h b/src/framework/stdext/types.h index a6824542..3f8754d6 100644 --- a/src/framework/stdext/types.h +++ b/src/framework/stdext/types.h @@ -41,6 +41,7 @@ typedef int16_t int16; typedef int8_t int8; typedef int64 ticks_t; +typedef uint_fast32_t refcount_t; using std::size_t; using std::ptrdiff_t;