RigsofRods
Soft-body Physics Simulation
RefCountingObjectPtr.h
Go to the documentation of this file.
1 
2 // RefCountingObject system for AngelScript
3 // Copyright (c) 2022 Petr Ohlidal
4 // https://github.com/only-a-ptr/RefCountingObject-AngelScript
5 // See license (MIT) at the bottom of this file.
6 
7 // Adopted from "scripthandle" AngelScript addon, distributed with AngelScript SDK.
8 
9 #pragma once
10 
11 #include <angelscript.h>
12 #include <stdio.h> // snprintf
13 
14 #if !defined(RefCoutingObjectPtr_DEBUGTRACE)
15 # define RefCoutingObjectPtr_DEBUGTRACE(_Expr)
16 #endif
17 
18 #if !defined(RefCountingObjectPtr_ASSERT)
19 # include <cassert>
20 # define RefCountingObjectPtr_ASSERT(_Expr_) assert(_Expr_)
21 #endif
22 
23 template<class T>
25 {
26 public:
27  // Constructors
28  RefCountingObjectPtr(T* ref);
32 
33  // Assignments
35  // Intentionally omitting raw-pointer assignment, for simplicity - see raw pointer constructor.
36 
37  // Compare smart ptr
38  bool operator==(const RefCountingObjectPtr<T> &o) const { return m_ref == o.m_ref; }
39  bool operator!=(const RefCountingObjectPtr<T> &o) const { return m_ref != o.m_ref; }
40 
41  // Compare pointer
42  bool operator==(const T* o) const { return m_ref == o; }
43  bool operator!=(const T* o) const { return m_ref != o; }
44 
45  // Compare nullptr
46  bool operator==(const nullptr_t) const { return m_ref == nullptr; }
47  bool operator!=(const nullptr_t) const { return m_ref != nullptr; }
48 
49  // Get the reference
50  T *GetRef() { return m_ref; } // To be invoked from C++ only!!
51  T *GetRef() const { return m_ref; } // To be invoked from C++ only!!
52  T* operator->() { return m_ref; }
53  T* operator->() const { return m_ref; }
54 
55  // Identity conversion (classic `if (foo) {}` pointer check... and also `std::map<>` identity comparsion)
56  operator long long() const { return reinterpret_cast<long long>(m_ref); }
57 
58  // GC callback
59  void EnumReferences(AS_NAMESPACE_QUALIFIER asIScriptEngine *engine);
60  void ReleaseReferences(AS_NAMESPACE_QUALIFIER asIScriptEngine *engine);
61 
62  static void RegisterRefCountingObjectPtr(AS_NAMESPACE_QUALIFIER asIScriptEngine* engine, const char* handle_name, const char* obj_name);
63 
64 protected:
65 
66  void Set(T* ref);
67  void ReleaseHandle();
68  void AddRefHandle();
69 
70  // Wrapper functions, to be invoked by AngelScript only!
72  static void ConstructCopy(RefCountingObjectPtr<T> *self, const RefCountingObjectPtr &o) { new(self) RefCountingObjectPtr(o); }
73  static void ConstructRef(RefCountingObjectPtr<T>* self, void** objhandle);
74  static void Destruct(RefCountingObjectPtr<T> *self) { self->~RefCountingObjectPtr(); }
75  static T* OpImplCast(RefCountingObjectPtr<T>* self);
76  static RefCountingObjectPtr & OpAssign(RefCountingObjectPtr<T>* self, void** objhandle);
77  static bool OpEquals(RefCountingObjectPtr<T>* self, void** objhandle);
78  static T* DereferenceHandle(void** objhandle);
79 
80  T *m_ref;
81 };
82 
83 template<class T>
84 void RefCountingObjectPtr<T>::RegisterRefCountingObjectPtr(AS_NAMESPACE_QUALIFIER asIScriptEngine* engine, const char* handle_name, const char* obj_name)
85 {
86  int r;
87  const size_t DECLBUF_MAX = 300;
88  char decl_buf[DECLBUF_MAX];
89 
90 #if defined(AS_USE_NAMESPACE)
91  using namespace AngelScript;
92 #endif
93 
94  // With C++11 it is possible to use asGetTypeTraits to automatically determine the flags that represent the C++ class
95  r = engine->RegisterObjectType(handle_name, sizeof(RefCountingObjectPtr), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | asGetTypeTraits<RefCountingObjectPtr>()); RefCountingObjectPtr_ASSERT( r >= 0 );
96 
97  // construct/destruct
98  r = engine->RegisterObjectBehaviour(handle_name, asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(RefCountingObjectPtr::ConstructDefault), asCALL_CDECL_OBJFIRST); RefCountingObjectPtr_ASSERT( r >= 0 );
99  snprintf(decl_buf, DECLBUF_MAX, "void f(%s @&in)", obj_name);
100  r = engine->RegisterObjectBehaviour(handle_name, asBEHAVE_CONSTRUCT, decl_buf, asFUNCTION(RefCountingObjectPtr::ConstructRef), asCALL_CDECL_OBJFIRST); RefCountingObjectPtr_ASSERT( r >= 0 );
101  snprintf(decl_buf, DECLBUF_MAX, "void f(const %s &in)", handle_name);
102  r = engine->RegisterObjectBehaviour(handle_name, asBEHAVE_CONSTRUCT, decl_buf, asFUNCTION(RefCountingObjectPtr::ConstructCopy), asCALL_CDECL_OBJFIRST); RefCountingObjectPtr_ASSERT( r >= 0 );
103  r = engine->RegisterObjectBehaviour(handle_name, asBEHAVE_DESTRUCT, "void f()", asFUNCTION(RefCountingObjectPtr::Destruct), asCALL_CDECL_OBJFIRST); RefCountingObjectPtr_ASSERT( r >= 0 );
104 
105  // GC
106  r = engine->RegisterObjectBehaviour(handle_name, asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(RefCountingObjectPtr,EnumReferences), asCALL_THISCALL); RefCountingObjectPtr_ASSERT(r >= 0);
107  r = engine->RegisterObjectBehaviour(handle_name, asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(RefCountingObjectPtr, ReleaseReferences), asCALL_THISCALL); RefCountingObjectPtr_ASSERT(r >= 0);
108 
109  // Cast
110  snprintf(decl_buf, DECLBUF_MAX, "%s @ opImplCast()", obj_name);
111  r = engine->RegisterObjectMethod(handle_name, decl_buf, asFUNCTION(RefCountingObjectPtr::OpImplCast), asCALL_CDECL_OBJFIRST); RefCountingObjectPtr_ASSERT( r >= 0 );
112 
113  // GetRef
114  snprintf(decl_buf, DECLBUF_MAX, "%s @ getHandle()", obj_name);
115  r = engine->RegisterObjectMethod(handle_name, decl_buf, asFUNCTION(RefCountingObjectPtr::OpImplCast), asCALL_CDECL_OBJFIRST); RefCountingObjectPtr_ASSERT( r >= 0 );
116 
117  // Assign
118  snprintf(decl_buf, DECLBUF_MAX, "%s &opHndlAssign(const %s &in)", handle_name, handle_name);
119  r = engine->RegisterObjectMethod(handle_name, decl_buf, asMETHOD(RefCountingObjectPtr, operator=), asCALL_THISCALL); RefCountingObjectPtr_ASSERT( r >= 0 );
120  snprintf(decl_buf, DECLBUF_MAX, "%s &opHndlAssign(const %s @&in)", handle_name, obj_name);
121  r = engine->RegisterObjectMethod(handle_name, decl_buf, asFUNCTION(RefCountingObjectPtr::OpAssign), asCALL_CDECL_OBJFIRST); RefCountingObjectPtr_ASSERT( r >= 0 );
122 
123  // Equals
124  snprintf(decl_buf, DECLBUF_MAX, "bool opEquals(const %s &in) const", handle_name);
125  r = engine->RegisterObjectMethod(handle_name, decl_buf, asMETHODPR(RefCountingObjectPtr, operator==, (const RefCountingObjectPtr &) const, bool), asCALL_THISCALL); RefCountingObjectPtr_ASSERT( r >= 0 );
126  snprintf(decl_buf, DECLBUF_MAX, "bool opEquals(const %s @&in) const", obj_name);
127  r = engine->RegisterObjectMethod(handle_name, decl_buf, asFUNCTION(RefCountingObjectPtr::OpEquals), asCALL_CDECL_OBJFIRST); RefCountingObjectPtr_ASSERT( r >= 0 );
128 }
129 
130 
131 // ---------------------------- Internals ------------------------------
132 
133 template<class T>
135 {
136  // Dereference the handle to get the object itself (see AngelScript SDK, addon 'generic handle', function `Assign()` or `Equals()`).
137  return static_cast<T*>(*objhandle);
138 }
139 
140 template<class T>
142 {
143  T* ref = DereferenceHandle(objhandle);
144  new(self)RefCountingObjectPtr(ref);
145 
146  // Increase refcount manually because constructor is designed for C++ use only.
147  if (ref)
148  ref->AddRef();
149 }
150 
151 template<class T>
153 {
154  T* ref = self->GetRef();
155  if (ref)
156  ref->AddRef();
157  return ref;
158 }
159 
160 template<class T>
162 {
163  T* ref = DereferenceHandle(objhandle);
164  self->Set(ref);
165  return *self;
166 }
167 
168 template<class T>
169 inline bool RefCountingObjectPtr<T>::OpEquals(RefCountingObjectPtr<T>* self, void** objhandle)
170 {
171  T* ref = DereferenceHandle(objhandle);
172  return self->GetRef() == ref;
173 }
174 
175 template<class T>
177  : m_ref(nullptr)
178 {
179  RefCoutingObjectPtr_DEBUGTRACE((T*)nullptr);
180  this->Set(ref);
181 }
182 
183 template<class T>
185  : m_ref(nullptr)
186 {
187  RefCoutingObjectPtr_DEBUGTRACE((T*)nullptr);
188 }
189 
190 template<class T>
192 {
194  m_ref = other.m_ref;
195  AddRefHandle();
196 }
197 
198 template<class T>
200 {
201  RefCoutingObjectPtr_DEBUGTRACE((T*)nullptr);
202  ReleaseHandle();
203 }
204 
205 template<class T>
207 {
208  RefCoutingObjectPtr_DEBUGTRACE((T*)nullptr);
209 
210  if( m_ref )
211  {
212  m_ref->Release();
213  m_ref = nullptr;
214  }
215 }
216 
217 template<class T>
219 {
220  RefCoutingObjectPtr_DEBUGTRACE((T*)nullptr);
221 
222  if( m_ref )
223  {
224  m_ref->AddRef();
225  }
226 }
227 
228 template<class T>
230 {
232  Set(other.m_ref);
233  return *this;
234 }
235 
236 template<class T>
237 inline void RefCountingObjectPtr<T>::Set(T* ref)
238 {
239  if( m_ref == ref )
240  return;
241 
242  ReleaseHandle();
243  m_ref = ref;
244  AddRefHandle();
245 }
246 
247 template<class T>
248 inline void RefCountingObjectPtr<T>::EnumReferences(AS_NAMESPACE_QUALIFIER asIScriptEngine *inEngine)
249 {
250  // If we're holding a reference, we'll notify the garbage collector of it
251  if (m_ref)
252  inEngine->GCEnumCallback(m_ref);
253 }
254 
255 template<class T>
256 inline void RefCountingObjectPtr<T>::ReleaseReferences(AS_NAMESPACE_QUALIFIER asIScriptEngine * /*inEngine*/)
257 {
258  // Simply clear the content to release the references
259  Set(nullptr);
260 }
261 
262 /*
263 MIT License
264 
265 Copyright (c) 2022 Petr OhlĂ­dal
266 
267 Permission is hereby granted, free of charge, to any person obtaining a copy
268 of this software and associated documentation files (the "Software"), to deal
269 in the Software without restriction, including without limitation the rights
270 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
271 copies of the Software, and to permit persons to whom the Software is
272 furnished to do so, subject to the following conditions:
273 
274 The above copyright notice and this permission notice shall be included in all
275 copies or substantial portions of the Software.
276 
277 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
278 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
279 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
280 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
281 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
282 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
283 SOFTWARE.
284 */
RefCountingObjectPtr::operator->
T * operator->()
Definition: RefCountingObjectPtr.h:52
RefCountingObjectPtr::RegisterRefCountingObjectPtr
static void RegisterRefCountingObjectPtr(AS_NAMESPACE_QUALIFIER asIScriptEngine *engine, const char *handle_name, const char *obj_name)
Definition: RefCountingObjectPtr.h:84
RefCountingObjectPtr::ReleaseReferences
void ReleaseReferences(AS_NAMESPACE_QUALIFIER asIScriptEngine *engine)
Definition: RefCountingObjectPtr.h:256
RefCountingObjectPtr::m_ref
T * m_ref
Definition: RefCountingObjectPtr.h:80
RefCountingObjectPtr::DereferenceHandle
static T * DereferenceHandle(void **objhandle)
Definition: RefCountingObjectPtr.h:134
RefCountingObjectPtr::operator!=
bool operator!=(const RefCountingObjectPtr< T > &o) const
Definition: RefCountingObjectPtr.h:39
RefCountingObjectPtr
Definition: RefCountingObjectPtr.h:24
RefCountingObjectPtr::operator->
T * operator->() const
Definition: RefCountingObjectPtr.h:53
RefCountingObjectPtr::EnumReferences
void EnumReferences(AS_NAMESPACE_QUALIFIER asIScriptEngine *engine)
Definition: RefCountingObjectPtr.h:248
RefCountingObjectPtr::ConstructDefault
static void ConstructDefault(RefCountingObjectPtr< T > *self)
Definition: RefCountingObjectPtr.h:71
RefCountingObjectPtr::Destruct
static void Destruct(RefCountingObjectPtr< T > *self)
Definition: RefCountingObjectPtr.h:74
RefCountingObjectPtr::~RefCountingObjectPtr
~RefCountingObjectPtr()
Definition: RefCountingObjectPtr.h:199
RefCoutingObjectPtr_DEBUGTRACE
#define RefCoutingObjectPtr_DEBUGTRACE(_Expr)
Definition: RefCountingObjectPtr.h:15
RefCountingObjectPtr::OpImplCast
static T * OpImplCast(RefCountingObjectPtr< T > *self)
Definition: RefCountingObjectPtr.h:152
RefCountingObjectPtr::Set
void Set(T *ref)
Definition: RefCountingObjectPtr.h:237
RefCountingObjectPtr::ConstructRef
static void ConstructRef(RefCountingObjectPtr< T > *self, void **objhandle)
Definition: RefCountingObjectPtr.h:141
RefCountingObjectPtr::GetRef
T * GetRef()
Definition: RefCountingObjectPtr.h:50
RefCountingObjectPtr::OpAssign
static RefCountingObjectPtr & OpAssign(RefCountingObjectPtr< T > *self, void **objhandle)
Definition: RefCountingObjectPtr.h:161
RefCountingObjectPtr::operator==
bool operator==(const T *o) const
Definition: RefCountingObjectPtr.h:42
RefCountingObjectPtr::AddRefHandle
void AddRefHandle()
Definition: RefCountingObjectPtr.h:218
RefCountingObjectPtr::GetRef
T * GetRef() const
Definition: RefCountingObjectPtr.h:51
RefCountingObjectPtr::RefCountingObjectPtr
RefCountingObjectPtr()
Definition: RefCountingObjectPtr.h:184
RefCountingObjectPtr::operator=
RefCountingObjectPtr & operator=(const RefCountingObjectPtr< T > &other)
Definition: RefCountingObjectPtr.h:229
RefCountingObjectPtr::operator==
bool operator==(const RefCountingObjectPtr< T > &o) const
Definition: RefCountingObjectPtr.h:38
RefCountingObjectPtr_ASSERT
#define RefCountingObjectPtr_ASSERT(_Expr_)
Definition: RefCountingObjectPtr.h:20
RefCountingObjectPtr::operator!=
bool operator!=(const T *o) const
Definition: RefCountingObjectPtr.h:43
RefCountingObjectPtr::operator==
bool operator==(const nullptr_t) const
Definition: RefCountingObjectPtr.h:46
RefCountingObjectPtr::ConstructCopy
static void ConstructCopy(RefCountingObjectPtr< T > *self, const RefCountingObjectPtr &o)
Definition: RefCountingObjectPtr.h:72
RefCountingObjectPtr::OpEquals
static bool OpEquals(RefCountingObjectPtr< T > *self, void **objhandle)
Definition: RefCountingObjectPtr.h:169
RefCountingObjectPtr::ReleaseHandle
void ReleaseHandle()
Definition: RefCountingObjectPtr.h:206
RefCountingObjectPtr::operator!=
bool operator!=(const nullptr_t) const
Definition: RefCountingObjectPtr.h:47