yum-mirror/slang

Making it easier to work with shaders

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

Ellie Hermaszewskaformatf65d756bf

master
5.4 KiB210 linesraw
1#ifndef SLANG_COM_PTR_H
2#define SLANG_COM_PTR_H
3
4#include "slang-com-helper.h"
5
6#include <assert.h>
7#include <cstddef>
8
9namespace Slang
10{
11
12/*! \brief ComPtr is a simple smart pointer that manages types which implement COM based interfaces.
13\details A class that implements a COM, must derive from the IUnknown interface or a type that
14matches it's layout exactly (such as ISlangUnknown). Trying to use this template with a class that
15doesn't follow these rules, will lead to undefined behavior. This is a 'strong' pointer type, and
16will AddRef when a non null pointer is set and Release when the pointer leaves scope. Using 'detach'
17allows a pointer to be removed from the management of the ComPtr. To set the smart pointer to null,
18there is the method setNull, or alternatively just assign SLANG_NULL/nullptr.
19
20One edge case using the template is that sometimes you want access as a pointer to a pointer.
21Sometimes this is to write into the smart pointer, other times to pass as an array. To handle these
22different behaviors there are the methods readRef and writeRef, which are used instead of the &
23(ref) operator. For example
24
25\code
26Void doSomething(ID3D12Resource** resources, IndexT numResources);
27// ...
28ComPtr<ID3D12Resource> resources[3];
29doSomething(resources[0].readRef(), SLANG_COUNT_OF(resource));
30\endcode
31
32A more common scenario writing to the pointer
33
34\code
35IUnknown* unk = ...;
36
37ComPtr<ID3D12Resource> resource;
38Result res = unk->QueryInterface(resource.writeRef());
39\endcode
40*/
41
42// Enum to force initializing as an attach (without adding a reference)
43enum InitAttach
44{
45    INIT_ATTACH
46};
47
48template<class T>
49class ComPtr
50{
51public:
52    typedef T Type;
53    typedef ComPtr ThisType;
54    typedef ISlangUnknown* Ptr;
55
56    /// Constructors
57    /// Default Ctor. Sets to nullptr
58    SLANG_FORCE_INLINE ComPtr()
59        : m_ptr(nullptr)
60    {
61    }
62    SLANG_FORCE_INLINE ComPtr(std::nullptr_t)
63        : m_ptr(nullptr)
64    {
65    }
66    /// Sets, and ref counts.
67    SLANG_FORCE_INLINE explicit ComPtr(T* ptr)
68        : m_ptr(ptr)
69    {
70        if (ptr)
71            ((Ptr)ptr)->addRef();
72    }
73    /// The copy ctor
74    SLANG_FORCE_INLINE ComPtr(const ThisType& rhs)
75        : m_ptr(rhs.m_ptr)
76    {
77        if (m_ptr)
78            ((Ptr)m_ptr)->addRef();
79    }
80
81    /// Ctor without adding to ref count.
82    SLANG_FORCE_INLINE explicit ComPtr(InitAttach, T* ptr)
83        : m_ptr(ptr)
84    {
85    }
86    /// Ctor without adding to ref count
87    SLANG_FORCE_INLINE ComPtr(InitAttach, const ThisType& rhs)
88        : m_ptr(rhs.m_ptr)
89    {
90    }
91
92#ifdef SLANG_HAS_MOVE_SEMANTICS
93    /// Move Ctor
94    SLANG_FORCE_INLINE ComPtr(ThisType&& rhs)
95        : m_ptr(rhs.m_ptr)
96    {
97        rhs.m_ptr = nullptr;
98    }
99    /// Move assign
100    SLANG_FORCE_INLINE ComPtr& operator=(ThisType&& rhs)
101    {
102        T* swap = m_ptr;
103        m_ptr = rhs.m_ptr;
104        rhs.m_ptr = swap;
105        return *this;
106    }
107#endif
108
109    /// Destructor releases the pointer, assuming it is set
110    SLANG_FORCE_INLINE ~ComPtr()
111    {
112        if (m_ptr)
113            ((Ptr)m_ptr)->release();
114    }
115
116    // !!! Operators !!!
117
118    /// Returns the dumb pointer
119    SLANG_FORCE_INLINE operator T*() const { return m_ptr; }
120
121    SLANG_FORCE_INLINE T& operator*() { return *m_ptr; }
122    /// For making method invocations through the smart pointer work through the dumb pointer
123    SLANG_FORCE_INLINE T* operator->() const { return m_ptr; }
124
125    /// Assign
126    SLANG_FORCE_INLINE const ThisType& operator=(const ThisType& rhs);
127    /// Assign from dumb ptr
128    SLANG_FORCE_INLINE T* operator=(T* in);
129
130    /// Get the pointer and don't ref
131    SLANG_FORCE_INLINE T* get() const { return m_ptr; }
132    /// Release a contained nullptr pointer if set
133    SLANG_FORCE_INLINE void setNull();
134
135    /// Detach
136    SLANG_FORCE_INLINE T* detach()
137    {
138        T* ptr = m_ptr;
139        m_ptr = nullptr;
140        return ptr;
141    }
142    /// Set to a pointer without changing the ref count
143    SLANG_FORCE_INLINE void attach(T* in) { m_ptr = in; }
144
145    /// Get ready for writing (nulls contents)
146    SLANG_FORCE_INLINE T** writeRef()
147    {
148        setNull();
149        return &m_ptr;
150    }
151    /// Get for read access
152    SLANG_FORCE_INLINE T* const* readRef() const { return &m_ptr; }
153
154    /// Swap
155    void swap(ThisType& rhs);
156
157protected:
158    /// Gets the address of the dumb pointer.
159    // Disabled: use writeRef and readRef to get a reference based on usage.
160#ifndef SLANG_COM_PTR_ENABLE_REF_OPERATOR
161    SLANG_FORCE_INLINE T** operator&() = delete;
162#endif
163
164    T* m_ptr;
165};
166
167//----------------------------------------------------------------------------
168template<typename T>
169void ComPtr<T>::setNull()
170{
171    if (m_ptr)
172    {
173        ((Ptr)m_ptr)->release();
174        m_ptr = nullptr;
175    }
176}
177//----------------------------------------------------------------------------
178template<typename T>
179const ComPtr<T>& ComPtr<T>::operator=(const ThisType& rhs)
180{
181    if (rhs.m_ptr)
182        ((Ptr)rhs.m_ptr)->addRef();
183    if (m_ptr)
184        ((Ptr)m_ptr)->release();
185    m_ptr = rhs.m_ptr;
186    return *this;
187}
188//----------------------------------------------------------------------------
189template<typename T>
190T* ComPtr<T>::operator=(T* ptr)
191{
192    if (ptr)
193        ((Ptr)ptr)->addRef();
194    if (m_ptr)
195        ((Ptr)m_ptr)->release();
196    m_ptr = ptr;
197    return m_ptr;
198}
199//----------------------------------------------------------------------------
200template<typename T>
201void ComPtr<T>::swap(ThisType& rhs)
202{
203    T* tmp = m_ptr;
204    m_ptr = rhs.m_ptr;
205    rhs.m_ptr = tmp;
206}
207
208} // namespace Slang
209
210#endif // SLANG_COM_PTR_H