From f4d900dfb64d95f121dd8565dd269be061ef8509 Mon Sep 17 00:00:00 2001 From: Tim Foley Date: Thu, 29 Jun 2017 11:50:55 -0700 Subject: Overhaul `RefPtr` and `String` - `RefPtr` no longer tries to have distinct cases for interal-vs-external reference counts. Instead we always require an internal reference count. - Types the used `RefPtr` but weren't `RefObject` were made to inherit `RefObject` - The `ReferenceCounted` base class was removed, so that only `RefObject` remains - Implicit conversion from `RefPtr` to `T*` added - This created some complicates for other types that relied on implicit conversions, so this isn't a net cleanup right now - The main type that got messed up by the above was `String`, which previously held a `RefPtr`. This change thus *also* includes a major overhaul of `String`: - `String` now holds all its data via indirection, using a `StringRepresentation` that is a `RefObject`. This object holds a length, capacity, and directly stores the character data in its allocation. This means that `sizeof(String)==sizeof(void*)` - It is now possible to directly mutate a `String` by appending to its representation (we just need to ensure it has a reference count of `1`, possibly by cloning it). This means that `StringBuilder` is now basically just an idomatic use of `String` - A couple operations that just return sub-ranges of a `String` now return `StringSlice` to avoid allocation when it isn't needed. This required more work. - Indices into strings changed from `int` to `UInt` (which is pointer-sized). This had a bunch of follow-on changes because the value `-1` sometimes needs to be special-cased in code that uses indices. Further cleanups are probably needed here. --- source/core/smart-pointer.h | 593 ++++++++++++-------------------------------- 1 file changed, 161 insertions(+), 432 deletions(-) (limited to 'source/core/smart-pointer.h') diff --git a/source/core/smart-pointer.h b/source/core/smart-pointer.h index d307e4e13..c31cdefe0 100644 --- a/source/core/smart-pointer.h +++ b/source/core/smart-pointer.h @@ -3,462 +3,191 @@ #include "type-traits.h" +#include + namespace Slang { - class RefPtrDefaultDestructor - { - public: - template - void operator ()(T * ptr) - { - delete ptr; - } - }; - - class RefPtrArrayDestructor - { - public: - template - void operator() (T * ptr) - { - delete [] ptr; - } - }; + // TODO: Need to centralize these typedefs + typedef uintptr_t UInt; + + // Base class for all reference-counted objects + class RefObject + { + private: + UInt referenceCount; + + public: + RefObject() + : referenceCount(0) + {} + + RefObject(const RefObject &) + : referenceCount(0) + {} + + virtual ~RefObject() + {} + + void addReference() + { + referenceCount++; + } + + void releaseReference() + { + assert(referenceCount != 0); + if(--referenceCount == 0) + { + delete this; + } + } + + bool isUniquelyReferenced() + { + assert(referenceCount != 0); + return referenceCount == 1; + } + }; + + inline void addReference(RefObject* obj) + { + if(obj) obj->addReference(); + } + + inline void releaseReference(RefObject* obj) + { + if(obj) obj->releaseReference(); + } + + // "Smart" pointer to a reference-counted object + template + struct RefPtr + { + RefPtr() + : pointer(0) + {} + + RefPtr(T* p) + : pointer(p) + { + addReference(p); + } + + RefPtr(RefPtr const& p) + : pointer(p.pointer) + { + addReference(p.pointer); + } + + RefPtr(RefPtr&& p) + : pointer(p.pointer) + { + p.pointer = 0; + } + + template + RefPtr(RefPtr const& p, + typename EnableIf::Value, void>::type * = 0) + : pointer((U*) p) + { + addReference((U*) p); + } + +#if 0 + void operator=(T* p) + { + T* old = pointer; + addReference(p); + pointer = p; + releaseReference(old); + } +#endif + + void operator=(RefPtr const& p) + { + T* old = pointer; + addReference(p.pointer); + pointer = p.pointer; + releaseReference(old); + } + + void operator=(RefPtr&& p) + { + T* old = pointer; + pointer = p.pointer; + p.pointer = old; + } + + template + typename EnableIf::value, void>::type + operator=(RefPtr const& ptr) + { + T* old = pointer; + addReference(p.pointer); + pointer = p.pointer; + releaseReference(old); + } - class ReferenceCounted - { - template - friend class RefPtrImpl; - private: - int _refCount = 0; - public: - ReferenceCounted() {} - ReferenceCounted(const ReferenceCounted &) + int GetHashCode() { - _refCount = 0; + return (int)(long long)(void*)pointer; } - }; - - class RefObject : public ReferenceCounted - { - public: - virtual ~RefObject() - {} - }; + bool operator==(const T * ptr) const + { + return pointer == ptr; + } - template - class RefPtrImpl - { - }; + bool operator!=(const T * ptr) const + { + return pointer != ptr; + } - template - using RefPtr = RefPtrImpl::Value, Destructor>; - - template - class RefPtrImpl - { - template - friend class RefPtrImpl; - private: - T * pointer; - int * refCount; - - public: - RefPtrImpl() - { - pointer = 0; - refCount = 0; - } - RefPtrImpl(T * ptr) - : pointer(0), refCount(0) + bool operator==(RefPtr const& ptr) const { - this->operator=(ptr); - } - RefPtrImpl(const RefPtrImpl & ptr) - : pointer(0), refCount(0) - { - this->operator=(ptr); - } - RefPtrImpl(RefPtrImpl && str) - : pointer(0), refCount(0) - { - this->operator=(static_cast &&>(str)); + return pointer == ptr.pointer; } - template - RefPtrImpl(const RefPtrImpl& ptr, - typename EnableIf::Value, void>::type * = 0) - : pointer(0), refCount(0) + bool operator!=(RefPtr const& ptr) const { - pointer = ptr.pointer; - if (ptr) - { - refCount = ptr.refCount; - (*refCount)++; - } - else - refCount = 0; + return pointer != ptr.pointer; } - template - typename EnableIf::value, RefPtrImpl>::type& - operator=(const RefPtrImpl & ptr) - { - Unreference(); - - pointer = ptr; - if (ptr) - { - refCount = ptr.refCount; - (*refCount)++; - } - else - refCount = 0; - return *this; - } + template + RefPtr As() const + { + RefPtr result(dynamic_cast(pointer)); + return result; + } - RefPtrImpl& operator=(const RefPtrImpl & ptr) - { - Unreference(); - pointer = ptr.pointer; - if (ptr) - { - refCount = ptr.refCount; - (*refCount)++; - } - else - refCount = 0; - return *this; - } + ~RefPtr() + { + releaseReference(pointer); + } - RefPtrImpl& operator=(T * ptr) - { - if (ptr != pointer) - { - Unreference(); - - pointer = ptr; - if (ptr) - { - refCount = new int; - (*refCount) = 1; - } - else - refCount = 0; - } - return *this; - } - int GetHashCode() - { - return (int)(long long)(void*)pointer; - } - bool operator == (const T * ptr) const - { - return pointer == ptr; - } - bool operator != (const T * ptr) const - { - return pointer != ptr; - } - template - bool operator == (const RefPtr & ptr) const - { - return pointer == ptr.pointer; - } - template - bool operator != (const RefPtr & ptr) const - { - return pointer != ptr.pointer; - } - template - RefPtrImpl As() const - { - RefPtrImpl result; - if (pointer) - { - result.pointer = dynamic_cast(pointer); - if (result.pointer) - { - result.refCount = refCount; - (*refCount)++; - } - } - return result; - } + T& operator*() const + { + return *pointer; + } - T* operator +(int offset) const - { - return pointer+offset; - } - T& operator [](int idx) const - { - return *(pointer + idx); - } - RefPtrImpl& operator=(RefPtrImpl && ptr) - { - if(ptr.pointer != pointer) - { - Unreference(); - pointer = ptr.pointer; - refCount = ptr.refCount; - ptr.pointer = 0; - ptr.refCount = 0; - } - return *this; - } - T* Release() - { - if(pointer) - { - if((*refCount) > 1) - { - (*refCount)--; - } - else - { - delete refCount; - } - } - auto rs = pointer; - refCount = 0; - pointer = 0; - return rs; - } - ~RefPtrImpl() - { - Unreference(); - } + T* operator->() const + { + return pointer; + } - void Unreference() - { - if(pointer) - { - if((*refCount) > 1) - { - (*refCount)--; - } - else - { - Destructor destructor; - destructor(pointer); - delete refCount; - } - } - } - T & operator *() const - { - return *pointer; - } - T * operator->() const - { - return pointer; - } T * Ptr() const { return pointer; } - public: - explicit operator bool() const - { - if (pointer) - return true; - else - return false; - } - }; - - - template - class RefPtrImpl - { - template - friend class RefPtrImpl; - - private: - T * pointer; - public: - RefPtrImpl() - { - pointer = 0; - } - RefPtrImpl(T * ptr) - : pointer(0) - { - this->operator=(ptr); - } - RefPtrImpl(const RefPtrImpl & ptr) - : pointer(0) - { - this->operator=(ptr); - } - RefPtrImpl(RefPtrImpl && str) - : pointer(0) - { - this->operator=(static_cast &&>(str)); - } - template - RefPtrImpl(const RefPtrImpl& ptr, - typename EnableIf::Value, void>::type * = 0) - : pointer(0) - { - pointer = ptr.pointer; - if (ptr) - { - ptr->_refCount++; - } - } - template - typename EnableIf::value, RefPtrImpl&>::type - operator=(const RefPtrImpl & ptr) - { - Unreference(); - - pointer = ptr.pointer; - if (ptr) - { - ptr->_refCount++; - } - return *this; - } - RefPtrImpl& operator=(T * ptr) - { - if (ptr != pointer) - { - Unreference(); - - pointer = ptr; - if (ptr) - { - ptr->_refCount++; - } - } - return *this; - } - RefPtrImpl& operator=(const RefPtrImpl & ptr) - { - // Note: It is possible that the object this pointer references owns - // (directly or indirectly) the storage for the argument `ptr`. If - // that is the case and the `Unreference()` call below frees this - // object, then the argument would become invalid. - // - // We copy the pointer value out of the argument first, in order - // to protected against this case. - T* ptrPointer = ptr.pointer; - if (ptrPointer != pointer) - { - if (ptrPointer) - ptrPointer->_refCount++; - Unreference(); - pointer = ptrPointer; - } - return *this; - } - int GetHashCode() - { - return (int)(long long)(void*)pointer; - } - bool operator == (const T * ptr) const - { - return pointer == ptr; - } - bool operator != (const T * ptr) const - { - return pointer != ptr; - } - template - bool operator == (const RefPtr & ptr) const - { - return pointer == ptr.pointer; - } - template - bool operator != (const RefPtr & ptr) const - { - return pointer != ptr.pointer; - } - template - RefPtrImpl As() const - { - RefPtrImpl result; - if (pointer) - { - result.pointer = dynamic_cast(pointer); - if (result.pointer) - { - result.pointer->_refCount++; - } - } - return result; - } - T* operator +(int offset) const - { - return pointer + offset; - } - T& operator [](int idx) const - { - return *(pointer + idx); - } - RefPtrImpl& operator=(RefPtrImpl && ptr) - { - if (ptr.pointer != pointer) - { - Unreference(); - pointer = ptr.pointer; - ptr.pointer = nullptr; - } - return *this; - } - T* Release() - { - if (pointer) - { - pointer->_refCount--; - } - auto rs = pointer; - pointer = 0; - return rs; - } - ~RefPtrImpl() - { - Unreference(); - } + operator T*() const + { + return pointer; + } - void Unreference() - { - if (pointer) - { - if (pointer->_refCount > 1) - { - pointer->_refCount--; - } - else - { - Destructor destructor; - destructor(pointer); - } - } - } - T & operator *() const - { - return *pointer; - } - T * operator->() const - { - return pointer; - } - T * Ptr() const - { - return pointer; - } - public: - explicit operator bool() const - { - if (pointer) - return true; - else - return false; - } + private: + T* pointer; + }; } -- cgit v1.2.3