15
15
#include < variant>
16
16
#include < vector>
17
17
18
+ #include < iostream>
19
+
18
20
#include < erl_nif.h>
19
21
20
22
#if defined(_MSVC_LANG)
@@ -164,17 +166,32 @@ template <typename... Args> class Error {
164
166
165
167
namespace __private__ {
166
168
template <typename T> struct ResourceWrapper {
167
- T resource;
168
- bool initialized;
169
+ enum { INITIALIZED = 0 };
170
+
171
+ union {
172
+ struct {
173
+ bool initialized;
174
+ };
175
+ std::max_align_t _unused;
176
+ };
177
+
178
+ const T *resource () const { return reinterpret_cast <const T *>(this + 1 ); }
179
+
180
+ T *resource () noexcept { return reinterpret_cast <T *>(this + 1 ); }
181
+
182
+ template <typename U, typename = std::enable_if_t <std::is_base_of_v<T, U>>>
183
+ static constexpr std::size_t byte_size () noexcept {
184
+ return sizeof (ResourceWrapper) + sizeof (U);
185
+ }
169
186
170
187
static void dtor (ErlNifEnv *env, void *ptr) {
171
188
auto resource_wrapper = reinterpret_cast <ResourceWrapper<T> *>(ptr);
172
189
173
190
if (resource_wrapper->initialized ) {
174
191
if constexpr (has_destructor<T>::value) {
175
- resource_wrapper->resource . destructor (env);
192
+ resource_wrapper->resource ()-> destructor (env);
176
193
}
177
- resource_wrapper->resource . ~T ();
194
+ resource_wrapper->resource ()-> ~T ();
178
195
}
179
196
}
180
197
@@ -221,11 +238,11 @@ template <typename T> class ResourcePtr {
221
238
return *this ;
222
239
}
223
240
224
- T &operator *() const { return this ->ptr ->resource ; }
241
+ T &operator *() const { return * this ->ptr ->resource () ; }
225
242
226
- T *operator ->() const { return & this ->ptr ->resource ; }
243
+ T *operator ->() const { return this ->ptr ->resource () ; }
227
244
228
- T *get () const { return & this ->ptr ->resource ; }
245
+ T *get () const { return this ->ptr ->resource () ; }
229
246
230
247
friend void swap (ResourcePtr<T> &left, ResourcePtr<T> &right) {
231
248
using std::swap;
@@ -241,12 +258,17 @@ template <typename T> class ResourcePtr {
241
258
// Friend functions that use the resource_type static member or the
242
259
// private constructor.
243
260
244
- template <typename U, typename ... Args>
261
+ template <typename U, typename V, typename ... Args, typename >
245
262
friend ResourcePtr<U> make_resource (Args &&...args);
246
263
264
+ template <typename U>
265
+ friend Term make_resource_binary (ErlNifEnv *env, ResourcePtr<U> resource,
266
+ const char *data, size_t size);
267
+
247
268
friend class Registration ;
248
269
249
270
friend struct Decoder <ResourcePtr<T>>;
271
+ friend struct Encoder <ResourcePtr<T>>;
250
272
251
273
inline static ErlNifResourceType *resource_type = nullptr ;
252
274
@@ -255,7 +277,8 @@ template <typename T> class ResourcePtr {
255
277
256
278
// Allocates a new resource object, invoking its constructor with the
257
279
// given arguments.
258
- template <typename T, typename ... Args>
280
+ template <typename T, typename U = T, typename ... Args,
281
+ typename = std::enable_if_t <std::is_base_of_v<T, U>>>
259
282
ResourcePtr<T> make_resource (Args &&...args) {
260
283
auto type = ResourcePtr<T>::resource_type;
261
284
@@ -265,10 +288,10 @@ ResourcePtr<T> make_resource(Args &&...args) {
265
288
" to register your resource type with the FINE_RESOURCE macro" );
266
289
}
267
290
268
- void *allocation_ptr =
269
- enif_alloc_resource ( type, sizeof ( __private__::ResourceWrapper<T>));
291
+ void *allocation_ptr = enif_alloc_resource (
292
+ type, __private__::ResourceWrapper<T>:: template byte_size<U>( ));
270
293
271
- auto resource_wrapper =
294
+ auto * resource_wrapper =
272
295
reinterpret_cast <__private__::ResourceWrapper<T> *>(allocation_ptr);
273
296
274
297
// We create ResourcePtr right away, to make sure the resource is
@@ -282,7 +305,8 @@ ResourcePtr<T> make_resource(Args &&...args) {
282
305
283
306
// Invoke the constructor with prefect forwarding to initialize the
284
307
// object at the VM-allocated memory
285
- new (&resource_wrapper->resource ) T (std::forward<Args>(args)...);
308
+ new (reinterpret_cast <U *>(resource_wrapper->resource ()))
309
+ U (std::forward<Args>(args)...);
286
310
287
311
resource_wrapper->initialized = true ;
288
312
@@ -296,8 +320,8 @@ ResourcePtr<T> make_resource(Args &&...args) {
296
320
template <typename T>
297
321
Term make_resource_binary (ErlNifEnv *env, ResourcePtr<T> resource,
298
322
const char *data, size_t size) {
299
- return enif_make_resource_binary (
300
- env, reinterpret_cast < void *>(resource. get ()), data, size);
323
+ return enif_make_resource_binary (env, reinterpret_cast < void *>(resource. ptr ),
324
+ data, size);
301
325
}
302
326
303
327
// Creates a binary term copying data from the given buffer.
@@ -811,7 +835,7 @@ template <typename K, typename V> struct Encoder<std::map<K, V>> {
811
835
812
836
template <typename T> struct Encoder <ResourcePtr<T>> {
813
837
static ERL_NIF_TERM encode (ErlNifEnv *env, const ResourcePtr<T> &resource) {
814
- return enif_make_resource (env, reinterpret_cast <void *>(resource.get () ));
838
+ return enif_make_resource (env, reinterpret_cast <void *>(resource.ptr ));
815
839
}
816
840
};
817
841
0 commit comments