yum-mirror/slang

Making it easier to work with shaders

git clone https://git.yummers.dev/yum-mirror/slang

Ellie Hermaszewskaformatf65d756bf

master
7.8 KiB336 linesraw
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:
15    UInt referenceCount;
16
17public:
18    RefObject()
19        : referenceCount(0)
20    {
21    }
22
23    RefObject(const RefObject&)
24        : referenceCount(0)
25    {
26    }
27
28    RefObject& operator=(const RefObject&) { return *this; }
29
30    virtual ~RefObject() {}
31
32    UInt addReference() { return ++referenceCount; }
33
34    UInt decreaseReference() { return --referenceCount; }
35
36    UInt releaseReference()
37    {
38        SLANG_ASSERT(referenceCount != 0);
39        if (--referenceCount == 0)
40        {
41            delete this;
42            return 0;
43        }
44        return referenceCount;
45    }
46
47    bool isUniquelyReferenced()
48    {
49        SLANG_ASSERT(referenceCount != 0);
50        return referenceCount == 1;
51    }
52
53    UInt debugGetReferenceCount() { return referenceCount; }
54};
55
56SLANG_FORCE_INLINE void addReference(RefObject* obj)
57{
58    if (obj)
59        obj->addReference();
60}
61
62SLANG_FORCE_INLINE void releaseReference(RefObject* obj)
63{
64    if (obj)
65        obj->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{
73    return dynamic_cast<T*>(obj);
74}
75template<typename T>
76SLANG_FORCE_INLINE const T* dynamicCast(const RefObject* obj)
77{
78    return 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{
86    return dynamicCast<T>(obj);
87}
88template<typename T>
89SLANG_FORCE_INLINE const T* as(const RefObject* obj)
90{
91    return dynamicCast<T>(obj);
92}
93
94// "Smart" pointer to a reference-counted object
95template<typename T>
96struct SLANG_RT_API RefPtr
97{
98    RefPtr()
99        : pointer(nullptr)
100    {
101    }
102
103    RefPtr(T* p)
104        : pointer(p)
105    {
106        addReference(p);
107    }
108
109    RefPtr(RefPtr<T> const& p)
110        : pointer(p.pointer)
111    {
112        addReference(p.pointer);
113    }
114
115    RefPtr(RefPtr<T>&& p)
116        : pointer(p.pointer)
117    {
118        p.pointer = nullptr;
119    }
120
121    template<typename U>
122    RefPtr(RefPtr<U> const& p, typename EnableIf<IsConvertible<T*, U*>::Value, void>::type* = 0)
123        : pointer(static_cast<U*>(p))
124    {
125        addReference(static_cast<U*>(p));
126    }
127
128#if 0
129        void operator=(T* p)
130        {
131            T* old = pointer;
132            addReference(p);
133            pointer = p;
134            releaseReference(old);
135        }
136#endif
137
138    void operator=(RefPtr<T> const& p)
139    {
140        T* old = pointer;
141        addReference(p.pointer);
142        pointer = p.pointer;
143        releaseReference(old);
144    }
145
146    void operator=(RefPtr<T>&& p)
147    {
148        T* old = pointer;
149        pointer = p.pointer;
150        p.pointer = old;
151    }
152
153    template<typename U>
154    typename EnableIf<IsConvertible<T*, U*>::value, void>::type operator=(RefPtr<U> const& p)
155    {
156        T* old = pointer;
157        addReference(p.pointer);
158        pointer = p.pointer;
159        releaseReference(old);
160    }
161
162    HashCode 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        //
168        return Slang::getHashCode(pointer);
169    }
170
171    bool operator==(const T* ptr) const { return pointer == ptr; }
172
173    bool operator!=(const T* ptr) const { return pointer != ptr; }
174
175    bool operator==(RefPtr<T> const& ptr) const { return pointer == ptr.pointer; }
176
177    bool operator!=(RefPtr<T> const& ptr) const { return pointer != ptr.pointer; }
178
179    template<typename U>
180    RefPtr<U> dynamicCast() const
181    {
182        return RefPtr<U>(Slang::dynamicCast<U>(pointer));
183    }
184
185    template<typename U>
186    RefPtr<U> as() const
187    {
188        return RefPtr<U>(Slang::as<U>(pointer));
189    }
190
191    template<typename U>
192    bool is() const
193    {
194        return Slang::as<U>(pointer) != nullptr;
195    }
196
197    ~RefPtr() { releaseReference(static_cast<Slang::RefObject*>(pointer)); }
198
199    T& operator*() const { return *pointer; }
200
201    T* operator->() const { return pointer; }
202
203    T* Ptr() const { return pointer; }
204
205    T* get() const { return pointer; }
206
207    operator T*() const { return pointer; }
208
209    void attach(T* p)
210    {
211        T* old = pointer;
212        pointer = p;
213        releaseReference(old);
214    }
215
216    T* detach()
217    {
218        auto rs = pointer;
219        pointer = nullptr;
220        return rs;
221    }
222
223    void swapWith(RefPtr<T>& rhs)
224    {
225        auto rhsPtr = rhs.pointer;
226        rhs.pointer = pointer;
227        pointer = rhsPtr;
228    }
229
230    SLANG_FORCE_INLINE void setNull()
231    {
232        releaseReference(pointer);
233        pointer = nullptr;
234    }
235
236    /// Get ready for writing (nulls contents)
237    SLANG_FORCE_INLINE T** writeRef()
238    {
239        *this = nullptr;
240        return &pointer;
241    }
242
243    /// Get for read access
244    SLANG_FORCE_INLINE T* const* readRef() const { return &pointer; }
245
246private:
247    T* 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:
258    WeakSink(T* ptr)
259        : m_ptr(ptr)
260    {
261    }
262
263    SLANG_FORCE_INLINE T* get() const { return m_ptr; }
264    SLANG_FORCE_INLINE void detach() { m_ptr = nullptr; }
265
266private:
267    T* 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:
275    T* m_weakPtr = nullptr;
276    RefPtr<T> m_strongPtr;
277
278public:
279    TransformablePtr() = default;
280    TransformablePtr(T* ptr) { *this = ptr; }
281    TransformablePtr(RefPtr<T> ptr) { *this = ptr; }
282    TransformablePtr(const TransformablePtr<T>& ptr) = default;
283    TransformablePtr<T>& operator=(const TransformablePtr<T>& ptr) = default;
284
285    void promoteToStrongReference() { m_strongPtr = m_weakPtr; }
286    void demoteToWeakReference() { m_strongPtr = nullptr; }
287    bool isStrongReference() const { return m_strongPtr != nullptr; }
288
289    T& operator*() const { return *m_weakPtr; }
290
291    T* operator->() const { return m_weakPtr; }
292
293    T* Ptr() const { return m_weakPtr; }
294    T* get() const { return m_weakPtr; }
295
296    operator T*() const { return m_weakPtr; }
297    operator RefPtr<T>() const { return m_weakPtr; }
298
299
300    TransformablePtr<T>& operator=(T* ptr)
301    {
302        m_weakPtr = ptr;
303        m_strongPtr = ptr;
304        return *this;
305    }
306    template<typename U>
307    TransformablePtr<T>& operator=(const RefPtr<U>& ptr)
308    {
309        m_weakPtr = ptr.Ptr();
310        m_strongPtr = ptr;
311        return *this;
312    }
313
314    HashCode 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        //
320        return Slang::getHashCode(m_weakPtr);
321    }
322
323    bool operator==(const T* ptr) const { return m_weakPtr == ptr; }
324
325    bool operator!=(const T* ptr) const { return m_weakPtr != ptr; }
326
327    bool operator==(RefPtr<T> const& ptr) const { return m_weakPtr == ptr.Ptr(); }
328
329    bool operator!=(RefPtr<T> const& ptr) const { return m_weakPtr != ptr.Ptr(); }
330
331    bool operator==(TransformablePtr<T> const& ptr) const { return m_weakPtr == ptr.m_weakPtr; }
332
333    bool operator!=(TransformablePtr<T> const& ptr) const { return m_weakPtr != ptr.m_weakPtr; }
334};
335} // namespace Slang
336#endif