Rigs of Rods 2023.09
Soft-body Physics Simulation
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
Loading...
Searching...
No Matches
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
23template<class T>
25{
26public:
27 // Constructors
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 std::nullptr_t) const { return m_ref == nullptr; }
47 bool operator!=(const std::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
64protected:
65
66 void Set(T* ref);
69
70 // Wrapper functions, to be invoked by AngelScript only!
73 static void ConstructRef(RefCountingObjectPtr<T>* self, void** objhandle);
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
81};
82
83template<class T>
84void 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
133template<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
140template<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
151template<class T>
153{
154 T* ref = self->GetRef();
155 if (ref)
156 ref->AddRef();
157 return ref;
158}
159
160template<class T>
162{
163 T* ref = DereferenceHandle(objhandle);
164 self->Set(ref);
165 return *self;
166}
167
168template<class T>
170{
171 T* ref = DereferenceHandle(objhandle);
172 return self->GetRef() == ref;
173}
174
175template<class T>
177 : m_ref(nullptr)
178{
180 this->Set(ref);
181}
182
183template<class T>
185 : m_ref(nullptr)
186{
188}
189
190template<class T>
192{
194 m_ref = other.m_ref;
195 AddRefHandle();
196}
197
198template<class T>
200{
202 ReleaseHandle();
203}
204
205template<class T>
207{
209
210 if( m_ref )
211 {
212 m_ref->Release();
213 m_ref = nullptr;
214 }
215}
216
217template<class T>
219{
221
222 if( m_ref )
223 {
224 m_ref->AddRef();
225 }
226}
227
228template<class T>
230{
232 Set(other.m_ref);
233 return *this;
234}
235
236template<class T>
238{
239 if( m_ref == ref )
240 return;
241
242 ReleaseHandle();
243 m_ref = ref;
244 AddRefHandle();
245}
246
247template<class T>
248inline 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
255template<class T>
256inline 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/*
263MIT License
264
265Copyright (c) 2022 Petr Ohlídal
266
267Permission is hereby granted, free of charge, to any person obtaining a copy
268of this software and associated documentation files (the "Software"), to deal
269in the Software without restriction, including without limitation the rights
270to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
271copies of the Software, and to permit persons to whom the Software is
272furnished to do so, subject to the following conditions:
273
274The above copyright notice and this permission notice shall be included in all
275copies or substantial portions of the Software.
276
277THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
278IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
279FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
280AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
281LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
282OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
283SOFTWARE.
284*/
#define RefCoutingObjectPtr_DEBUGTRACE(_Expr)
#define RefCountingObjectPtr_ASSERT(_Expr_)
static void RegisterRefCountingObjectPtr(AS_NAMESPACE_QUALIFIER asIScriptEngine *engine, const char *handle_name, const char *obj_name)
void ReleaseReferences(AS_NAMESPACE_QUALIFIER asIScriptEngine *engine)
bool operator==(const std::nullptr_t) const
static bool OpEquals(RefCountingObjectPtr< T > *self, void **objhandle)
static void ConstructCopy(RefCountingObjectPtr< T > *self, const RefCountingObjectPtr &o)
static RefCountingObjectPtr & OpAssign(RefCountingObjectPtr< T > *self, void **objhandle)
static void Destruct(RefCountingObjectPtr< T > *self)
bool operator==(const RefCountingObjectPtr< T > &o) const
bool operator!=(const T *o) const
static T * DereferenceHandle(void **objhandle)
static void ConstructRef(RefCountingObjectPtr< T > *self, void **objhandle)
void EnumReferences(AS_NAMESPACE_QUALIFIER asIScriptEngine *engine)
bool operator==(const T *o) const
static void ConstructDefault(RefCountingObjectPtr< T > *self)
bool operator!=(const RefCountingObjectPtr< T > &o) const
RefCountingObjectPtr & operator=(const RefCountingObjectPtr< T > &other)
RefCountingObjectPtr(const RefCountingObjectPtr< T > &other)
bool operator!=(const std::nullptr_t) const
static T * OpImplCast(RefCountingObjectPtr< T > *self)