GCC Code Coverage Report


Directory: src/gate/
File: src/gate/structs.hpp
Date: 2025-09-14 13:10:38
Exec Total Coverage
Lines: 104 109 95.4%
Functions: 97 121 80.2%
Branches: 11 30 36.7%

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