yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
f65d756bf
master
1#ifndef SLANG_CORE_SMART_POINTER_H 2#define SLANG_CORE_SMART_POINTER_H 3 4#include "slang-common.h" 5#include "slang-hash.h" 6#include "slang-type-traits.h" 7#include "slang.h" 8 9namespace Slang 10{ 11// Base class for all reference-counted objects 12class SLANG_RT_API RefObject 13{ 14private : 15UInt referenceCount ; 16 17public : 18RefObject () 19 :referenceCount (0 ) 20 { 21 } 22 23RefObject (const RefObject & ) 24 :referenceCount (0 ) 25 { 26 } 27 28RefObject & operator = (const RefObject & ) {return * this ; } 29 30virtual ~RefObject () {} 31 32UInt addReference () {return ++ referenceCount ; } 33 34UInt decreaseReference () {return -- referenceCount ; } 35 36UInt releaseReference () 37 { 38SLANG_ASSERT (referenceCount != 0 ); 39if (-- referenceCount == 0 ) 40 { 41delete this ; 42return 0 ; 43 } 44return referenceCount ; 45 } 46 47bool isUniquelyReferenced () 48 { 49SLANG_ASSERT (referenceCount != 0 ); 50return referenceCount == 1 ; 51 } 52 53UInt debugGetReferenceCount () {return referenceCount ; } 54}; 55 56SLANG_FORCE_INLINE void addReference (RefObject * obj ) 57{ 58if (obj ) 59obj -> addReference (); 60} 61 62SLANG_FORCE_INLINE void releaseReference (RefObject * obj ) 63{ 64if (obj ) 65obj -> releaseReference (); 66} 67 68// For straight dynamic cast. 69// Use instead of dynamic_cast as it allows for replacement without using Rtti in the future 70template < typename T > 71SLANG_FORCE_INLINE T * dynamicCast (RefObject * obj ) 72{ 73return dynamic_cast < T *> (obj ); 74} 75template < typename T > 76SLANG_FORCE_INLINE const T * dynamicCast (const RefObject * obj ) 77{ 78return dynamic_cast < const T *> (obj ); 79} 80 81// Like a dynamicCast, but allows a type to implement a specific implementation that is suitable for 82// it 83template < typename T > 84SLANG_FORCE_INLINE T * as (RefObject * obj ) 85{ 86return dynamicCast < T > (obj ); 87} 88template < typename T > 89SLANG_FORCE_INLINE const T * as (const RefObject * obj ) 90{ 91return dynamicCast < T > (obj ); 92} 93 94// "Smart" pointer to a reference-counted object 95template < typename T > 96struct SLANG_RT_API RefPtr 97{ 98RefPtr () 99 :pointer (nullptr ) 100 { 101 } 102 103RefPtr (T * p ) 104 :pointer (p ) 105 { 106addReference (p ); 107 } 108 109RefPtr (RefPtr < T > const & p ) 110 :pointer (p .pointer ) 111 { 112addReference (p .pointer ); 113 } 114 115RefPtr (RefPtr < T >&& p ) 116 :pointer (p .pointer ) 117 { 118p .pointer = nullptr ; 119 } 120 121template < typename U > 122RefPtr (RefPtr < U > const & p ,typename EnableIf < IsConvertible < T * ,U *> ::Value ,void > ::type * = 0 ) 123 :pointer (static_cast < U *> (p )) 124 { 125addReference (static_cast < U *> (p )); 126 } 127 128#if 0 129void operator = (T * p ) 130 { 131T * old = pointer ; 132addReference (p ); 133pointer = p ; 134releaseReference (old ); 135 } 136#endif 137 138void operator = (RefPtr < T > const & p ) 139 { 140T * old = pointer ; 141addReference (p .pointer ); 142pointer = p .pointer ; 143releaseReference (old ); 144 } 145 146void operator = (RefPtr < T >&& p ) 147 { 148T * old = pointer ; 149pointer = p .pointer ; 150p .pointer = old ; 151 } 152 153template < typename U > 154typename EnableIf < IsConvertible < T * ,U *> ::value ,void > ::type operator = (RefPtr < U > const & p ) 155 { 156T * old = pointer ; 157addReference (p .pointer ); 158pointer = p .pointer ; 159releaseReference (old ); 160 } 161 162HashCode getHashCode ()const 163 { 164// Note: We need a `RefPtr<T>` to hash the same as a `T*`, 165// so that a `T*` can be used as a key in a dictionary with 166// `RefPtr<T>` keys, and vice versa. 167// 168return Slang ::getHashCode (pointer ); 169 } 170 171bool operator == (const T * ptr )const {return pointer == ptr ; } 172 173bool operator != (const T * ptr )const {return pointer != ptr ; } 174 175bool operator == (RefPtr < T > const & ptr )const {return pointer == ptr .pointer ; } 176 177bool operator != (RefPtr < T > const & ptr )const {return pointer != ptr .pointer ; } 178 179template < typename U > 180RefPtr < U > dynamicCast ()const 181 { 182return RefPtr < U > (Slang ::dynamicCast < U > (pointer )); 183 } 184 185template < typename U > 186RefPtr < U > as ()const 187 { 188return RefPtr < U > (Slang ::as < U > (pointer )); 189 } 190 191template < typename U > 192bool is ()const 193 { 194return Slang ::as < U > (pointer )!= nullptr ; 195 } 196 197 ~RefPtr () {releaseReference (static_cast < Slang ::RefObject * >(pointer)); } 198 199T & operator * () const { return * pointer; } 200 201T * operator -> () const { return pointer ; } 202 203T * Ptr() const { return pointer ; } 204 205T * get() const { return pointer ; } 206 207operator T * () const { return pointer ; } 208 209void attach ( T * p ) 210{ 211T * old = pointer ; 212pointer = p ; 213releaseReference( old ); 214} 215 216T * detach() 217{ 218auto rs = pointer ; 219pointer = nullptr ; 220return rs ; 221} 222 223void swapWith( RefPtr < T >& rhs ) 224{ 225auto rhsPtr = rhs. pointer ; 226rhs. pointer = pointer; 227pointer = rhsPtr; 228} 229 230SLANG_FORCE_INLINE void setNull () 231{ 232releaseReference (pointer); 233pointer = nullptr ; 234} 235 236/// Get ready for writing (nulls contents) 237SLANG_FORCE_INLINE T ** writeRef () 238{ 239* this = nullptr ; 240return & pointer; 241} 242 243/// Get for read access 244SLANG_FORCE_INLINE T * const * readRef () const { return & pointer; } 245 246private: 247T * pointer; 248}; 249 250// Helper type for implementing weak pointers. The object being pointed at weakly creates a WeakSink 251// object that other objects can reference and share. When the object is destroyed it detaches the 252// sink doing so will make other users call to 'get' return null. Thus any user of the WeakSink, 253// must check if the weakly pointed to things pointer is nullptr before using. 254template < typename T > 255class WeakSink : public RefObject 256{ 257public : 258WeakSink ( T * ptr) 259: m_ptr( ptr ) 260{ 261} 262 263SLANG_FORCE_INLINE T * get () const { return m_ptr; } 264SLANG_FORCE_INLINE void detach () { m_ptr = nullptr ; } 265 266private : 267T * m_ptr; 268}; 269 270// A pointer that can be transformed to hold either a weak reference or a strong reference. 271template < typename T > 272class TransformablePtr 273{ 274private : 275T * m_weakPtr = nullptr ; 276RefPtr < T > m_strongPtr; 277 278public : 279TransformablePtr () = default; 280TransformablePtr ( T * ptr) { * this = ptr; } 281TransformablePtr (RefPtr < T > ptr) { * this = ptr; } 282TransformablePtr( const TransformablePtr < T >& ptr) = default ; 283TransformablePtr < T >& operator = ( const TransformablePtr < T >& ptr) = default; 284 285void promoteToStrongReference () { m_strongPtr = m_weakPtr; } 286void demoteToWeakReference () { m_strongPtr = nullptr ; } 287bool isStrongReference () const { return m_strongPtr != nullptr ; } 288 289T & operator * () const { return * m_weakPtr; } 290 291T * operator -> () const { return m_weakPtr ; } 292 293T * Ptr() const { return m_weakPtr ; } 294T * get() const { return m_weakPtr ; } 295 296operator T * () const { return m_weakPtr ; } 297operator RefPtr < T > () const { return m_weakPtr ; } 298 299 300TransformablePtr < T >& operator = ( T * ptr ) 301{ 302m_weakPtr = ptr ; 303m_strongPtr = ptr ; 304return * this ; 305} 306template < typename U > 307TransformablePtr < T >& operator = ( const RefPtr < U >& ptr ) 308{ 309m_weakPtr = ptr .Ptr(); 310m_strongPtr = ptr ; 311return * this ; 312} 313 314HashCode getHashCode () const 315{ 316// Note: We need a `RefPtr<T>` to hash the same as a `T*`, 317// so that a `T*` can be used as a key in a dictionary with 318// `RefPtr<T>` keys, and vice versa. 319// 320return Slang ::getHashCode( m_weakPtr ); 321} 322 323bool operator == ( const T * ptr ) const { return m_weakPtr == ptr ; } 324 325bool operator != ( const T * ptr ) const { return m_weakPtr != ptr ; } 326 327bool operator == ( RefPtr < T > const & ptr ) const { return m_weakPtr == ptr .Ptr(); } 328 329bool operator != ( RefPtr < T > const & ptr ) const { return m_weakPtr != ptr .Ptr(); } 330 331bool operator == ( TransformablePtr < T > const & ptr ) const { return m_weakPtr == ptr . m_weakPtr ; } 332 333bool operator != ( TransformablePtr < T > const & ptr ) const { return m_weakPtr != ptr . m_weakPtr ; } 334}; 335} // namespace Slang 336#endif