Line | Branch | Exec | Source |
---|---|---|---|
1 | /* GATE PROJECT LICENSE: | ||
2 | +----------------------------------------------------------------------------+ | ||
3 | | Copyright(c) 2018-2025, Stefan Meislinger <sm@opengate.at> | | ||
4 | | All rights reserved. | | ||
5 | | | | ||
6 | | Redistribution and use in source and binary forms, with or without | | ||
7 | | modification, are permitted provided that the following conditions are met:| | ||
8 | | | | ||
9 | | 1. Redistributions of source code must retain the above copyright notice, | | ||
10 | | this list of conditions and the following disclaimer. | | ||
11 | | 2. Redistributions in binary form must reproduce the above copyright | | ||
12 | | notice, this list of conditions and the following disclaimer in the | | ||
13 | | documentation and/or other materials provided with the distribution. | | ||
14 | | | | ||
15 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"| | ||
16 | | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | ||
17 | | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | ||
18 | | ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | | ||
19 | | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | ||
20 | | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | ||
21 | | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | ||
22 | | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | ||
23 | | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | ||
24 | | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | | ||
25 | | THE POSSIBILITY OF SUCH DAMAGE. | | ||
26 | +----------------------------------------------------------------------------+ | ||
27 | */ | ||
28 | |||
29 | /** @file | ||
30 | * @brief Structure serialization | ||
31 | * @ingroup gatecore_cpp | ||
32 | * | ||
33 | * @details To access and serialize C++ data structures, a C-struct descriptor | ||
34 | * is needed to generalize member access. | ||
35 | * This module provides classes to simplify generation of C-struct descriptors | ||
36 | * and wrapper classes to access those structures. | ||
37 | */ | ||
38 | |||
39 | #ifndef GATE_STRUCTS_HPP_INCLUDED | ||
40 | #define GATE_STRUCTS_HPP_INCLUDED | ||
41 | |||
42 | #include "gate/structs.h" | ||
43 | #include "gate/typeids.h" | ||
44 | #include "gate/typeids.hpp" | ||
45 | #include "gate/arrays.hpp" | ||
46 | #include "gate/gatetypes.hpp" | ||
47 | #include "gate/exceptions.hpp" | ||
48 | #include "gate/strings.hpp" | ||
49 | |||
50 | namespace gate | ||
51 | { | ||
52 | namespace structs | ||
53 | { | ||
54 | namespace | ||
55 | { | ||
56 | template<class struct_type> | ||
57 | union StructStorageHelper | ||
58 | { | ||
59 | size_t align_dummy1; | ||
60 | void* align_dummy2; | ||
61 | double align_dummy3; | ||
62 | char instance[sizeof(struct_type)]; | ||
63 | }; | ||
64 | } | ||
65 | |||
66 | template<class member_type, class struct_type> | ||
67 | 12 | size_t offset_of_member(member_type(struct_type::* ptr_member)) | |
68 | { | ||
69 | StructStorageHelper<struct_type> storage; | ||
70 | 12 | struct_type* const ptr_obj = reinterpret_cast<struct_type*>(&storage); | |
71 | 12 | member_type const* const ptr_value = &(ptr_obj->*ptr_member); | |
72 | 12 | void const* const vptr_value = ptr_value; | |
73 | 12 | void const* const vptr_obj = ptr_obj; | |
74 | 12 | return static_cast<char const*>(vptr_value) - static_cast<char const*>(vptr_obj); | |
75 | } | ||
76 | } | ||
77 | |||
78 | |||
79 | /// @brief StructBase builds a C++ struct that includes a GATE C struct-descriptor and a native C++ struct type | ||
80 | /// @tparam cpp_struct_type | ||
81 | template<class cpp_struct_type> | ||
82 | struct StructBase : public gate_struct_t, public cpp_struct_type | ||
83 | { | ||
84 | public: | ||
85 | typedef StructBase<cpp_struct_type> self_t; | ||
86 | |||
87 | 1 | gate_struct_t const* c_impl() const noexcept | |
88 | { | ||
89 | 1 | return this; | |
90 | } | ||
91 | |||
92 | gate_struct_t* c_impl() noexcept | ||
93 | { | ||
94 | return this; | ||
95 | } | ||
96 | |||
97 | /// @brief Initializes an instance with an external descriptor pointer and a native C++ structure | ||
98 | /// @param descriptor pointer to C-struct-descriptor | ||
99 | /// @param cpp_struct reference to already initialize native C++ structure to copy data from | ||
100 | 1 | StructBase(gate_struct_descriptor_t const* descriptor = NULL, cpp_struct_type const& cpp_struct = cpp_struct_type()) | |
101 | 1 | : gate_struct_t(), cpp_struct_type(cpp_struct) | |
102 | { | ||
103 | 1 | gate_struct_t* const ptr_struct = this; | |
104 | 1 | ptr_struct->struct_descriptor = descriptor; | |
105 | 1 | } | |
106 | |||
107 | /// @brief Copy an existing StructBase instance | ||
108 | /// @param src | ||
109 | StructBase(self_t const& src) | ||
110 | : gate_struct_t(src), cpp_struct_type(src) | ||
111 | { | ||
112 | } | ||
113 | |||
114 | /// @brief Overwrite instance data with another instance's data | ||
115 | /// @param src | ||
116 | /// @return | ||
117 | self_t& operator=(self_t const& src) | ||
118 | { | ||
119 | if (this != &src) | ||
120 | { | ||
121 | cpp_struct_type& content = *this; | ||
122 | content = static_cast<cpp_struct_type const&>(src); | ||
123 | this->struct_descriptor = src.struct_descriptor; | ||
124 | } | ||
125 | return *this; | ||
126 | } | ||
127 | |||
128 | 1 | ~StructBase() noexcept | |
129 | { | ||
130 | 1 | } | |
131 | }; | ||
132 | |||
133 | /// @brief Initializes a C-struct desriptor and provides methods to create member items | ||
134 | /// @tparam cpp_struct_type | ||
135 | template<class cpp_struct_type> | ||
136 | struct StructDescriptorBase : public gate_struct_descriptor | ||
137 | { | ||
138 | public: | ||
139 | typedef cpp_struct_type struct_type_t; | ||
140 | |||
141 | typedef StructBase<struct_type_t> struct_base_t; | ||
142 | |||
143 | 1 | StructDescriptorBase(char const* struct_name) | |
144 | { | ||
145 | 1 | gate_struct_descriptor_t& descr = *this; | |
146 | 1 | descr.name = struct_name; | |
147 | 1 | descr.items = NULL; | |
148 | 1 | descr.item_count = 0; | |
149 | 1 | descr.struct_length = sizeof(struct_base_t); | |
150 | 1 | } | |
151 | |||
152 | /// @brief Builds a member item record based on a c++ member pointer and meta informations | ||
153 | /// @tparam member_type Type of member to be referenced | ||
154 | /// @param memberPtr Pointer to member in covered c++ struct | ||
155 | /// @param name Static name string of referenced member | ||
156 | /// @param description Optional static description text of referenced member | ||
157 | /// @param flags Optional flags describing the member's behavior | ||
158 | /// @return generated item record with all required fields | ||
159 | template<class member_type> | ||
160 | 12 | gate_struct_item_t buildMemberItem(member_type cpp_struct_type::* memberPtr, char const* name, char const* description = NULL, enumint_t flags = 0) | |
161 | { | ||
162 | static size_t const substruct_offset = sizeof(struct_base_t) - sizeof(struct_type_t); | ||
163 | gate_struct_item_t item; | ||
164 | 12 | gate_mem_clear(&item, sizeof(item)); | |
165 | |||
166 | 12 | item.name = name; | |
167 | 12 | item.description = description; | |
168 | 12 | item.offset = substruct_offset + gate::structs::offset_of_member(memberPtr); | |
169 | 12 | item.flags = flags; | |
170 | 12 | item.type = TypeId<member_type>::value(); | |
171 | 12 | return item; | |
172 | } | ||
173 | |||
174 | /// @brief Sets the descriptor's items and count fields | ||
175 | /// @param items | ||
176 | /// @param items_count | ||
177 | 1 | void setMemberItems(gate_struct_item_t const* items, gate_size_t items_count) | |
178 | { | ||
179 | 1 | gate_struct_descriptor_t& descr = *this; | |
180 | 1 | descr.items = items; | |
181 | 1 | descr.item_count = items_count; | |
182 | 1 | } | |
183 | }; | ||
184 | |||
185 | |||
186 | /// @brief Builds a C-struct descriptor dynamically | ||
187 | /// @tparam cpp_struct_type | ||
188 | template<class cpp_struct_type> | ||
189 | struct DynStructDescriptorBase : public StructDescriptorBase<cpp_struct_type> | ||
190 | { | ||
191 | private: | ||
192 | ArrayList<gate_struct_item_t> items; | ||
193 | public: | ||
194 | typedef cpp_struct_type struct_type_t; | ||
195 | typedef StructDescriptorBase<struct_type_t> struct_descriptor_base_t; | ||
196 | |||
197 | 1 | DynStructDescriptorBase(char const* struct_name) | |
198 | 1 | : struct_descriptor_base_t(struct_name) | |
199 | { | ||
200 | 1 | } | |
201 | |||
202 | protected: | ||
203 | /// @brief Adds a member item to the internal item-array storage | ||
204 | /// @tparam member_type Type of member to be referenced | ||
205 | /// @param memberPtr Pointer to member in covered struct | ||
206 | /// @param name static string name of member | ||
207 | /// @param description optional string description of member | ||
208 | /// @param flags optional member flags | ||
209 | template<class member_type> | ||
210 | 12 | void addMember(member_type cpp_struct_type::* memberPtr, char const* name, char const* description = NULL, enumint_t flags = 0) | |
211 | { | ||
212 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
12 | gate_struct_item_t item = this->buildMemberItem(memberPtr, name, description, flags); |
213 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
12 | this->items.add(item); |
214 | 12 | } | |
215 | |||
216 | /// @brief Updates the public struct desriptor with current state of the internal item-array storage | ||
217 | /// @details Needs to be called after the last member was added | ||
218 | 1 | void updateDescriptor() | |
219 | { | ||
220 | 1 | this->setMemberItems(this->items.getItemPtr(0), this->items.length()); | |
221 | 1 | } | |
222 | }; | ||
223 | |||
224 | |||
225 | /// @brief This template needs a specialized implemention for each class that is used with `Struct<>` | ||
226 | /// @tparam cpp_struct_type | ||
227 | template<class cpp_struct_type> | ||
228 | struct StructDescriptor; | ||
229 | |||
230 | |||
231 | template<class cpp_struct_type> | ||
232 | struct Struct : public StructBase<cpp_struct_type> | ||
233 | { | ||
234 | private: | ||
235 | typedef cpp_struct_type struct_type_t; | ||
236 | typedef Struct<struct_type_t> self_t; | ||
237 | typedef StructBase<struct_type_t> struct_base_t; | ||
238 | static StructDescriptor<struct_type_t> descriptor_instance; | ||
239 | public: | ||
240 | 1 | Struct(struct_type_t const& copy_instance = struct_type_t()) | |
241 | 1 | : struct_base_t(&descriptor_instance, copy_instance) | |
242 | { | ||
243 | 1 | } | |
244 | }; | ||
245 | |||
246 | |||
247 | template<class cpp_struct_type> | ||
248 | StructDescriptor<cpp_struct_type> Struct<cpp_struct_type>::descriptor_instance = StructDescriptor<cpp_struct_type>(); | ||
249 | |||
250 | |||
251 | |||
252 | |||
253 | |||
254 | class GATE_CORE_CPP_API ConstStruct | ||
255 | { | ||
256 | public: | ||
257 | ConstStruct(gate_struct_t const* ptr) noexcept; | ||
258 | ConstStruct(ConstStruct const& src) noexcept; | ||
259 | |||
260 | 1 | template<class T> ConstStruct(Struct<T> const& instance) noexcept | |
261 | 1 | : impl(instance.c_impl()) | |
262 | { | ||
263 | 1 | } | |
264 | |||
265 | ConstStruct& operator=(ConstStruct const& src) noexcept; | ||
266 | ~ConstStruct() noexcept; | ||
267 | |||
268 | gate_struct_t const* c_impl() const; | ||
269 | |||
270 | size_t getStructSize() const; | ||
271 | String getStructName() const; | ||
272 | |||
273 | size_t getMemberCount() const; | ||
274 | gate_type_id_t getMemberType(size_t index) const; | ||
275 | String getMemberName(size_t index) const; | ||
276 | size_t getMemberIndex(String const& memberName) const; | ||
277 | gate_type_id_t getMemberType(String const& memberName) const; | ||
278 | |||
279 | void const* getMemberPtr(size_t index) const; | ||
280 | void const* getMemberPtr(String const& memberName) const; | ||
281 | |||
282 | 24 | template<class T> result_t getMember(size_t index, T& outValue) const | |
283 | { | ||
284 | 24 | gate_type_id_t const tid = this->getMemberType(index); | |
285 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
|
24 | if (TypeId<T>::value() != tid) |
286 | { | ||
287 | ✗ | return results::IncorrectType; | |
288 | } | ||
289 | 24 | void const* ptr = this->getMemberPtr(index); | |
290 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
24 | if (!ptr) |
291 | { | ||
292 | ✗ | return results::NotAvailable; | |
293 | } | ||
294 | 24 | outValue = *static_cast<T const*>(ptr); | |
295 | 24 | return results::Ok; | |
296 | } | ||
297 | 6 | template<class T> result_t getMember(String const& name, T& outValue) const | |
298 | { | ||
299 | 6 | size_t index = this->getMemberIndex(name); | |
300 | 6 | return this->getMember(index, outValue); | |
301 | } | ||
302 | template<class T> T getMember(size_t index) const | ||
303 | { | ||
304 | T value; | ||
305 | result_t result = this->getMember(index, value); | ||
306 | GATEXX_CHECK_EXCEPTION(result); | ||
307 | return value; | ||
308 | } | ||
309 | template<class T> T getMember(String const& name) const | ||
310 | { | ||
311 | T value; | ||
312 | result_t result = this->getMember(name, value); | ||
313 | GATEXX_CHECK_EXCEPTION(result); | ||
314 | return value; | ||
315 | } | ||
316 | |||
317 | protected: | ||
318 | gate_struct_t const* impl; | ||
319 | }; | ||
320 | |||
321 | class GATE_CORE_CPP_API MutableStruct : public ConstStruct | ||
322 | { | ||
323 | public: | ||
324 | MutableStruct(gate_struct_t* ptr) noexcept; | ||
325 | MutableStruct(MutableStruct const& src) noexcept; | ||
326 | |||
327 | template<class T> MutableStruct(Struct<T>& instance) noexcept | ||
328 | : ConstStruct(instance), | ||
329 | mut_impl(instance.c_impl()) | ||
330 | { | ||
331 | } | ||
332 | |||
333 | MutableStruct& operator=(MutableStruct const& src) noexcept; | ||
334 | ~MutableStruct() noexcept; | ||
335 | |||
336 | gate_struct_t* c_impl(); | ||
337 | |||
338 | void* getMemberPtr(size_t index); | ||
339 | void* getMemberPtr(String const& memberName); | ||
340 | protected: | ||
341 | gate_struct_t* mut_impl; | ||
342 | }; | ||
343 | |||
344 | |||
345 | template<class T> class StructRef | ||
346 | { | ||
347 | public: | ||
348 | typedef T instance_t; | ||
349 | typedef StructRef<instance_t> self_t; | ||
350 | |||
351 | protected: | ||
352 | gate_struct_t* impl; | ||
353 | gate_bool_t impl_owned; | ||
354 | gate_bool_t impl_dealloc; | ||
355 | |||
356 | 166 | StructRef() | |
357 | 166 | : impl(NULL), impl_owned(false), impl_dealloc(false) | |
358 | { | ||
359 | 166 | } | |
360 | |||
361 | public: | ||
362 | StructRef(instance_t* ptr_struct, gate_bool_t take_ownership = false, gate_bool_t deallocate = false) | ||
363 | : impl_owned(take_ownership), | ||
364 | impl_dealloc(deallocate) | ||
365 | { | ||
366 | this->impl = (gate_struct_t*)ptr_struct; | ||
367 | } | ||
368 | |||
369 | StructRef(self_t const& src) | ||
370 | : impl(src.impl), | ||
371 | impl_owned(src.impl_owned), | ||
372 | impl_dealloc(src.impl_dealloc) | ||
373 | { | ||
374 | if (this->impl_owned) | ||
375 | { | ||
376 | gate_size_t len = gate_struct_length(src.impl); | ||
377 | this->impl = (gate_struct_t*)gate_mem_alloc(len); | ||
378 | if (this->impl == 0) | ||
379 | { | ||
380 | GATEXX_RAISE_ERROR(results::OutOfMemory); | ||
381 | } | ||
382 | result_t result = gate_struct_copy(this->impl, src.impl); | ||
383 | if (GATE_FAILED(result)) | ||
384 | { | ||
385 | gate_mem_dealloc(this->impl); | ||
386 | GATEXX_CHECK_ERROR(result); | ||
387 | } | ||
388 | this->impl_dealloc = true; | ||
389 | } | ||
390 | } | ||
391 | |||
392 | self_t& operator=(self_t const& src) | ||
393 | { | ||
394 | if (this != &src) | ||
395 | { | ||
396 | gate_struct_t* new_impl = src.impl; | ||
397 | if (src.impl_owned) | ||
398 | { | ||
399 | gate_size_t len = gate_struct_length(src.impl); | ||
400 | new_impl = (gate_struct_t*)gate_mem_alloc(len); | ||
401 | if (new_impl == 0) | ||
402 | { | ||
403 | GATEXX_RAISE_ERROR(results::OutOfMemory); | ||
404 | } | ||
405 | result_t result = gate_struct_copy(new_impl, src.impl); | ||
406 | if (GATE_FAILED(result)) | ||
407 | { | ||
408 | gate_mem_dealloc(this->impl); | ||
409 | GATEXX_CHECK_ERROR(result); | ||
410 | } | ||
411 | } | ||
412 | |||
413 | if (this->impl_owned) | ||
414 | { | ||
415 | gate_struct_release(this->impl); | ||
416 | if (this->impl_dealloc) | ||
417 | { | ||
418 | gate_mem_dealloc(this->impl); | ||
419 | } | ||
420 | } | ||
421 | |||
422 | this->impl = new_impl; | ||
423 | this->impl_owned = src.impl_owned; | ||
424 | this->impl_dealloc = src.impl_owned; /* if source was owned, the new copy needs always deallocation */ | ||
425 | } | ||
426 | return *this; | ||
427 | } | ||
428 | |||
429 | 166 | ~StructRef() noexcept | |
430 | { | ||
431 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 83 times.
|
166 | if (this->impl_owned) |
432 | { | ||
433 | ✗ | gate_struct_release(this->impl); | |
434 | ✗ | if (this->impl_dealloc) | |
435 | { | ||
436 | ✗ | gate_mem_dealloc(this->impl); | |
437 | } | ||
438 | } | ||
439 | 166 | } | |
440 | |||
441 | gate_struct_t const* c_impl() const | ||
442 | { | ||
443 | return this->impl; | ||
444 | } | ||
445 | gate_struct_t* c_impl() | ||
446 | { | ||
447 | return this->impl; | ||
448 | } | ||
449 | |||
450 | 404 | instance_t const* c_instance() const | |
451 | { | ||
452 | 404 | return (instance_t const*)this->impl; | |
453 | } | ||
454 | 28 | instance_t* c_instance() | |
455 | { | ||
456 | 28 | return (instance_t*)this->impl; | |
457 | } | ||
458 | |||
459 | 404 | instance_t const* operator->() const | |
460 | { | ||
461 | 404 | return this->c_instance(); | |
462 | } | ||
463 | 4 | instance_t* operator->() | |
464 | { | ||
465 | 4 | return this->c_instance(); | |
466 | } | ||
467 | instance_t const& operator*() const | ||
468 | { | ||
469 | return *this->c_instance(); | ||
470 | } | ||
471 | instance_t& operator*() | ||
472 | { | ||
473 | return *this->c_instance(); | ||
474 | } | ||
475 | }; | ||
476 | |||
477 | |||
478 | |||
479 | |||
480 | template<class T> class StructInstance : public StructRef<T> | ||
481 | { | ||
482 | public: | ||
483 | typedef T instance_t; | ||
484 | typedef StructRef<T> base_t; | ||
485 | typedef StructInstance<T> self_t; | ||
486 | typedef result_t(*init_function_t)(gate_struct_t* obj); | ||
487 | |||
488 | protected: | ||
489 | instance_t instance; | ||
490 | |||
491 | public: | ||
492 | |||
493 | 24 | StructInstance(init_function_t init_func) | |
494 | 24 | : base_t(), instance() | |
495 | { | ||
496 | 24 | gate_struct_t* ptr_struct = (gate_struct_t*)&this->instance; | |
497 | 24 | this->impl = ptr_struct; | |
498 |
1/2✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
|
24 | result_t result = init_func(ptr_struct); |
499 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
24 | GATEXX_CHECK_ERROR(result); |
500 | 24 | this->impl_owned = true; | |
501 | 24 | } | |
502 | |||
503 | 20 | StructInstance(instance_t const& src) | |
504 | 20 | : base_t(), instance() | |
505 | { | ||
506 | 20 | gate_struct_t* ptr_struct = (gate_struct_t*)&this->instance; | |
507 | 20 | this->impl = ptr_struct; | |
508 |
1/2✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
|
20 | result_t result = gate_struct_copy(ptr_struct, (gate_struct_t const*)&src); |
509 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
20 | GATEXX_CHECK_ERROR(result); |
510 | 20 | this->impl_owned = true; | |
511 | 20 | } | |
512 | |||
513 | 51 | StructInstance(self_t const& src) | |
514 | 51 | : base_t(), instance() | |
515 | { | ||
516 | 51 | gate_struct_t* ptr_struct = (gate_struct_t*)&this->instance; | |
517 | 51 | this->impl = (gate_struct_t*)&this->instance; | |
518 |
1/2✓ Branch 1 taken 51 times.
✗ Branch 2 not taken.
|
51 | result_t result = gate_struct_copy(ptr_struct, (gate_struct_t const*)&src.instance); |
519 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 51 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
51 | GATEXX_CHECK_ERROR(result); |
520 | 51 | this->impl_owned = true; | |
521 | 51 | } | |
522 | |||
523 | self_t& operator=(self_t const& src) | ||
524 | { | ||
525 | gate_struct_t* ptr_struct = (gate_struct_t*)&this->instance; | ||
526 | if (this != &src) | ||
527 | { | ||
528 | gate_struct_release(ptr_struct); | ||
529 | result_t result = gate_struct_copy(ptr_struct, src.impl); | ||
530 | GATEXX_CHECK_ERROR(result); | ||
531 | } | ||
532 | return *this; | ||
533 | } | ||
534 | |||
535 | 95 | ~StructInstance() noexcept | |
536 | { | ||
537 | 95 | gate_struct_release((gate_struct_t*)&this->instance); | |
538 | 95 | this->impl_owned = false; | |
539 | 95 | this->impl = NULL; | |
540 | 95 | } | |
541 | }; | ||
542 | |||
543 | |||
544 | } // end of namespace gate | ||
545 | |||
546 | |||
547 | #endif | ||
548 |