Dev Essential  1.6.3
Loading...
Searching...
No Matches
ddstructure_generator.h
Go to the documentation of this file.
1
14
15#ifndef DDSTRUCTURE_GENERATOR_H_INCLUDED
16#define DDSTRUCTURE_GENERATOR_H_INCLUDED
17
18#include <ddl/dd/dd.h>
19#include <ddl/dd/ddstructure.h>
21
22#include <type_traits>
23
24namespace ddl {
25
27namespace detail {
28
29template <typename T>
30struct ArrayMember {
31 using value_type = T;
32 static constexpr size_t array_size = 1;
33};
34
35// if zero-sized array as placeholder for dynamic arrays
36template <typename T>
37struct ArrayMember<T[]> {
38 using value_type = T;
39 static constexpr size_t array_size = 0;
40};
41
42// if std::array
43template <typename ValueType, size_t value_array_size>
44struct ArrayMember<std::array<ValueType, value_array_size>> {
45 using value_type = ValueType;
46 static constexpr size_t array_size = value_array_size;
47};
48
49// if bounded array
50template <typename ValueType, size_t value_array_size>
51struct ArrayMember<ValueType[value_array_size]> {
52 using value_type = ValueType;
53 static constexpr size_t array_size = value_array_size;
54};
55
56template <typename T>
57struct MemberTypeCheck {
58 using member_type = typename std::remove_pointer<T>::type;
59 using value_type = typename ArrayMember<member_type>::value_type;
60 static constexpr size_t array_size = ArrayMember<member_type>::array_size;
61};
62
63template <typename T, typename MemberType>
64size_t getOffsetOfMember(MemberType T::*member)
65{
66 T* start = 0;
67#ifdef _MSC_VER
68#pragma warning(push)
69#pragma warning(disable : 6011)
70#endif
71 return reinterpret_cast<size_t>(&(start->*member));
72#ifdef _MSC_VER
73#pragma warning(pop)
74#endif
75}
76
77} // namespace detail
79
116template <typename T, bool align_with_padding = true>
118 static_assert(std::is_trivially_copyable<T>::value,
119 "You can only use structs with plain old datatypes and complex members. Do not "
120 "use pointers!");
121
122public:
129 explicit DDStructureGenerator(const std::string& name, uint32_t struct_version = 1)
130 : _structure(name, struct_version, alignof(T))
131 {
132 }
133
140 template <typename MemberType>
141 DDElementRef createElement(const std::string& name, MemberType T::*member_offset)
142 {
143 using ValueType = typename detail::MemberTypeCheck<MemberType>::value_type;
144
145 static_assert(!std::is_enum<ValueType>::value,
146 "For elements with enum type you must specify the DDEnum before! "
147 "Use createElement(name, member_offset, dd_enum);");
148 static_assert(std::is_arithmetic<ValueType>::value,
149 "For elements with complex structure types you must specify the used "
150 "DDStructure before! Use createElement(name, member_offset, dd_structure);");
151 static_assert(detail::MemberTypeCheck<MemberType>::array_size != 0,
152 "For dynamic arrays the array_size must be specified! Use "
153 "createElement(name, member_offset, array_size_name);");
154
155 PaddingAlignmentGuard padding_alignment_guard(*this);
156 return createElement(
157 name,
158 *evaluateAlignment(name, detail::getOffsetOfMember(member_offset), alignof(MemberType)),
160 detail::MemberTypeCheck<MemberType>::array_size);
161 }
162
176 template <typename MemberType>
177 DDElementRef createElement(const std::string& name,
178 MemberType T::*member_offset,
179 const std::string& valid_element_count_or_array_size_name)
180 {
181 using ValueType = typename detail::MemberTypeCheck<MemberType>::value_type;
182
183 static_assert(!std::is_enum<ValueType>::value,
184 "For elements with enum type you must specify the DDEnum before! "
185 "Use createElement(name, member_offset, dd_enum);");
186 static_assert(std::is_arithmetic<ValueType>::value,
187 "For elements with complex structure types you must specify the used "
188 "DDStructure before! Use createElement(name, member_offset, dd_structure);");
189
190 PaddingAlignmentGuard padding_alignment_guard(*this);
191 using ValueType = typename detail::MemberTypeCheck<MemberType>::value_type;
192 return createArrayElement(
193 name,
194 *evaluateAlignment(name, detail::getOffsetOfMember(member_offset), alignof(MemberType)),
196 detail::MemberTypeCheck<MemberType>::array_size,
197 valid_element_count_or_array_size_name);
198 }
199
206 template <typename MemberType>
207 DDStructureGenerator& addElement(const std::string& name, MemberType T::*member_offset)
208 {
209 createElement(name, member_offset);
210 return *this;
211 }
212
226 template <typename MemberType>
227 DDStructureGenerator& addElement(const std::string& name,
228 MemberType T::*member_offset,
229 const std::string& valid_element_count_or_array_size_name)
230 {
231 createElement(name, member_offset, valid_element_count_or_array_size_name);
232 return *this;
233 }
234
242 template <typename MemberType>
243 DDElementRef createElement(const std::string& name,
244 MemberType T::*member_offset,
245 const DDEnum& enum_type)
246 {
247 static_assert(
248 detail::MemberTypeCheck<MemberType>::array_size != 0,
249 "For dynamic arrays the array_size must be specified! Use createElement(name, "
250 "member_offset, array_size_name);");
251
252 PaddingAlignmentGuard padding_alignment_guard(*this);
253 return createElement(
254 name,
255 *evaluateAlignment(name, detail::getOffsetOfMember(member_offset), alignof(MemberType)),
256 enum_type,
257 detail::MemberTypeCheck<MemberType>::array_size);
258 }
259
274 template <typename MemberType>
275 DDElement createElement(const std::string& name,
276 MemberType T::*member_offset,
277 const DDEnum& enum_type,
278 const std::string& valid_element_count_or_array_size_name)
279 {
280 PaddingAlignmentGuard padding_alignment_guard(*this);
281 return createArrayElement(
282 name,
283 *evaluateAlignment(name, detail::getOffsetOfMember(member_offset), alignof(MemberType)),
284 enum_type,
285 detail::MemberTypeCheck<MemberType>::array_size,
286 valid_element_count_or_array_size_name);
287 }
288
296 template <typename MemberType>
297 DDStructureGenerator& addElement(const std::string& name,
298 MemberType T::*member_offset,
299 const DDEnum& enum_type)
300 {
301 createElement(name, member_offset, enum_type);
302 return *this;
303 }
304
319 template <typename MemberType>
320 DDStructureGenerator& addElement(const std::string& name,
321 MemberType T::*member_offset,
322 const DDEnum& enum_type,
323 const std::string& valid_element_count_or_array_size_name)
324 {
325 createElement(name, member_offset, enum_type, valid_element_count_or_array_size_name);
326 return *this;
327 }
328
336 template <typename MemberType>
337 DDElementRef createElement(const std::string& name,
338 MemberType T::*member_offset,
339 const DDStructure& struct_type)
340 {
341 static_assert(detail::MemberTypeCheck<MemberType>::array_size != 0,
342 "For dynamic arrays the array_size must be specified! Use addElement(name, "
343 "member_offset, array_size_name);");
344
345 PaddingAlignmentGuard padding_alignment_guard(*this);
346 return createElement(
347 name,
348 *evaluateAlignment(name, detail::getOffsetOfMember(member_offset), alignof(MemberType)),
349 struct_type,
350 detail::MemberTypeCheck<MemberType>::array_size);
351 }
352
367 template <typename MemberType>
368 DDElementRef createElement(const std::string& name,
369 MemberType T::*member_offset,
370 const DDStructure& struct_type,
371 const std::string& valid_element_count_or_array_size_name)
372 {
373 PaddingAlignmentGuard padding_alignment_guard(*this);
374 return createElement(
375 name,
376 *evaluateAlignment(name, detail::getOffsetOfMember(member_offset), alignof(MemberType)),
377 struct_type,
378 detail::MemberTypeCheck<MemberType>::array_size,
379 valid_element_count_or_array_size_name);
380 }
381
389 template <typename MemberType>
390 DDStructureGenerator& addElement(const std::string& name,
391 MemberType T::*member_offset,
392 const DDStructure& struct_type)
393 {
394 createElement(name, member_offset, struct_type);
395 return *this;
396 }
397
412 template <typename MemberType>
413 DDStructureGenerator& addElement(const std::string& name,
414 MemberType T::*member_offset,
415 const DDStructure& struct_type,
416 const std::string& valid_element_count_or_array_size_name)
417 {
418 createElement(name, member_offset, struct_type).setValidElementCount(valid_element_count_or_array_size_name);
419 return *this;
420 }
421
427 std::string getStructDescription() const
428 {
429 validate();
430 return _structure.getStructDescription();
431 }
432
437 std::string getStructName() const
438 {
439 return _structure.getStructName();
440 }
441
450 {
451 validate();
452 return _structure.getDD();
453 }
454
463 {
464 validate();
465 return _structure.getStructType();
466 }
467
475 {
476 validate();
477 return _structure;
478 }
479
484 size_t getSize() const
485 {
486 return _structure.getSize();
487 }
488
493 size_t getAlignment() const
494 {
495 return _structure.getAlignment();
496 }
497
505 operator const DDStructure&() const
506 {
507 return getStructure();
508 }
509
513 void setStructInfo(const std::string& comment)
514 {
515 _structure.setStructInfo(comment);
516 }
517
521 void setElementInfo(const std::string& element_name,
522 const std::string& description = {},
523 const std::string& comment = {},
524 const std::string& value = {},
525 const std::string& minimum_value = {},
526 const std::string& maximum_value = {},
527 const std::string& default_value = {},
528 const std::string& scale = {},
529 const std::string& offset = {})
530 {
531 _structure.setElementInfo(element_name,
532 description,
533 comment,
534 value,
535 minimum_value,
536 maximum_value,
537 default_value,
538 scale,
539 offset);
540 }
541
551 void setElementUnit(const std::string& element_name, const DDUnit& unit)
552 {
553 _structure.setElementUnit(element_name, unit);
554 }
555
565 void setElementUnit(const std::string& element_name, const dd::BaseUnit& base_unit)
566 {
567 _structure.setElementUnit(element_name, base_unit);
568 }
569
577 DDElementRef getElement(const std::string& element_name)
578 {
579 return _structure.getElement(element_name);
580 }
581
582private:
583 void pushAlignment()
584 {
585 if constexpr (align_with_padding) {
586 const auto current_struct_size = _structure.getSize();
587 if (sizeof(T) > current_struct_size) {
588 _structure.addElement<uint8_t>(
589 "__padding_final", sizeof(T) - current_struct_size, 1);
590 _padded_final = true;
591 }
592 }
593 }
594
595 void popAlignment()
596 {
597 if constexpr (align_with_padding) {
598 if (_padded_final) {
599 _structure.popLastElement();
600 _padded_final = false;
601 }
602 }
603 }
604
605 struct PaddingAlignmentGuard {
606 PaddingAlignmentGuard(DDStructureGenerator& padded_structure)
607 : _padded_structure(padded_structure)
608 {
609 padded_structure.popAlignment();
610 }
611
612 ~PaddingAlignmentGuard()
613 {
614 _padded_structure.pushAlignment();
615 }
616
617 private:
618 DDStructureGenerator& _padded_structure;
619 };
620
621 void validate() const
622 {
623 if constexpr (!align_with_padding) {
624 if (_structure.getSize() != sizeof(T)) {
625 throw ddl::dd::Error(
626 "DDStructureGenerator::validate",
627 "The generated struct '" + _structure.getStructName() +
628 "' does not have the expected size of (" + std::to_string(sizeof(T)) +
629 ") - The evaluated a size is (" + std::to_string(_structure.getSize()) +
630 "). Check if there are missing or misordered elements. ");
631 }
632 }
633 }
634
635 dd::OptionalSize evaluateAlignment(const std::string& element_name,
636 size_t member_offset,
637 size_t member_type_alignment)
638 {
639 // obtain the unaligned size
640 const auto struct_access = _structure.getDD().getStructTypeAccess(getStructName());
641 const auto current_struct_offset = struct_access.getStaticUnalignedStructSize();
642
643 if (member_offset < current_struct_offset) {
644 throw ddl::dd::Error(
645 "evaluateAlignment",
646 {std::to_string(member_offset)},
647 "The evaluated struct size of '" + getStructName() + "' is already (" +
648 std::to_string(current_struct_offset) + ") - Trying to add a member at (" +
649 std::to_string(member_offset) +
650 ") at a address prior the last element. Check misordered addElement calls.");
651 }
652
653 // evaluate difference between last added element and current offset
654 const auto difference = member_offset - current_struct_offset;
655
656 // find the minimum alignment to begin alignment discovery
657 // this is the data_type alignment or the struct alignment
658 const size_t minimum_alignment =
659 member_type_alignment > alignof(T) ? alignof(T) : member_type_alignment;
660
661 const auto valid_alignment_range = {1u, 2u, 4u, 8u, 16u, 32u, 64u};
662
663 // find a valid alignment in the range of member_type_alignment and struct_alignment
664 for (const size_t alignment: valid_alignment_range) {
665 // maximum alignment is the alignment of the struct
666 if (alignment <= alignof(T)) {
667 if (alignment >= minimum_alignment) {
668 if ((alignment > difference) && ((member_offset % alignment) == 0)) {
669 // we do not add padding bytes between if it fits with alignment
670 return alignment;
671 }
672 }
673 }
674 else {
675 break;
676 }
677 }
678
679 // if difference is below minimum alignment and we could not reach the position
680 // the struct has been packed by the user to another alignment then the struct alignment
681 if (difference < minimum_alignment) {
682 for (const size_t alignment: valid_alignment_range) {
683 if (alignment < minimum_alignment) {
684 if ((alignment > difference) && ((member_offset % alignment) == 0)) {
685 // we do not add padding bytes between if it fits with alignment
686 return alignment;
687 }
688 }
689 else {
690 break;
691 }
692 }
693 }
694
695 // we could not reach the position with alignments, so we
696 // align with padding if switch on
697 if constexpr (align_with_padding) {
698 if (difference != 0) {
699 _structure.addElement<uint8_t>("__padding_" + element_name, difference, 1);
700 }
701 // We need to return alignment 1 to use the very next position
702 return 1;
703 }
704 else {
705 throw ddl::dd::Error(
706 "evaluateAlignment",
707 {std::to_string(member_offset)},
708 "For the generated struct '" + getStructName() +
709 "' it is not possible to find a valid member alignment to reach offset (" +
710 std::to_string(member_offset) + ") from position (" +
711 std::to_string(current_struct_offset) + ")");
712 }
713 }
714
715 template <typename DDMemberType>
716 DDElementRef createElement(const std::string& name,
717 size_t alignment,
718 const DDMemberType& used_type,
719 size_t array_size)
720 {
721 return _structure.createElement(name, used_type, array_size, alignment);
722 }
723
724 template <typename DDMemberType>
725 DDElementRef createArrayElement(const std::string& name,
726 size_t alignment,
727 const DDMemberType& used_type,
728 size_t array_size,
729 const std::string& corresponding_element_name)
730 {
731 if (array_size == 0) {
732 // this is a zerobased array so we add a dynamic array!
733 return _structure.createElement(DDElement(name,
734 used_type,
735 DDElement::Deserialized(alignment),
736 {},
737 dd::ArraySize(corresponding_element_name)));
738 }
739 else {
740 auto element = _structure.createElement(name, used_type, array_size, alignment);
741 element.setValidElementCount(corresponding_element_name);
742 return element;
743 }
744 }
745
746 DDStructure _structure;
747 bool _padded_final = false;
748};
749
750} // namespace ddl
751
752#endif // DDSTRUCTURE_GENERATOR_H_INCLUDED
Utility class for a complete valid data definition of one StructType::Element and its dependencies....
Definition ddelement_ref.h:35
const dd::StructType::Element & getElement() const
Get the Element object.
DDElementRef & setValidElementCount(const std::string &valid_element_count)
Sets the 'valid_element_count' attribute to the element.
Utility class for a complete valid data definition of one StructType::Element and its dependencies....
Definition ddelement.h:36
dd::datamodel::StructType::DeserializedInfo Deserialized
Deserialized definiton for one element.
Definition ddelement.h:41
Utility class for a complete valid data definition of one EnumType and its dependencies....
Definition ddenum.h:29
DDElementRef createElement(const std::string &name, MemberType T::*member_offset, const DDStructure &struct_type)
Definition ddstructure_generator.h:337
const dd::StructType & getStructType() const
Get the Struct Type object.
Definition ddstructure_generator.h:462
DDElementRef getElement(const std::string &element_name)
Gets a element reference to the element with name element_name owned by the DDStructureGenerator.
Definition ddstructure_generator.h:577
DDStructureGenerator & addElement(const std::string &name, MemberType T::*member_offset)
Definition ddstructure_generator.h:207
void setElementInfo(const std::string &element_name, const std::string &description={}, const std::string &comment={}, const std::string &value={}, const std::string &minimum_value={}, const std::string &maximum_value={}, const std::string &default_value={}, const std::string &scale={}, const std::string &offset={})
Set additional element information to the given element_name.
Definition ddstructure_generator.h:521
DDStructureGenerator(const std::string &name, uint32_t struct_version=1)
CTOR to create a structure type based on a type.
Definition ddstructure_generator.h:129
DDStructureGenerator & addElement(const std::string &name, MemberType T::*member_offset, const DDStructure &struct_type, const std::string &valid_element_count_or_array_size_name)
Definition ddstructure_generator.h:413
const dd::DataDefinition & getDD() const
returns a valid DDL.
Definition ddstructure_generator.h:449
DDElement createElement(const std::string &name, MemberType T::*member_offset, const DDEnum &enum_type, const std::string &valid_element_count_or_array_size_name)
Definition ddstructure_generator.h:275
DDStructureGenerator & addElement(const std::string &name, MemberType T::*member_offset, const DDEnum &enum_type)
Definition ddstructure_generator.h:297
std::string getStructDescription() const
Gets the structs data definition as XML String.
Definition ddstructure_generator.h:427
void setElementUnit(const std::string &element_name, const DDUnit &unit)
Sets additional element unit information to the given element_name. Any other unit information will b...
Definition ddstructure_generator.h:551
void setElementUnit(const std::string &element_name, const dd::BaseUnit &base_unit)
Sets additional element base unit information to the given element_name.
Definition ddstructure_generator.h:565
DDStructureGenerator & addElement(const std::string &name, MemberType T::*member_offset, const std::string &valid_element_count_or_array_size_name)
Definition ddstructure_generator.h:227
size_t getAlignment() const
Retrieves the current evaluated alignment of the structure.
Definition ddstructure_generator.h:493
DDStructureGenerator & addElement(const std::string &name, MemberType T::*member_offset, const DDStructure &struct_type)
Definition ddstructure_generator.h:390
DDElementRef createElement(const std::string &name, MemberType T::*member_offset, const DDStructure &struct_type, const std::string &valid_element_count_or_array_size_name)
Definition ddstructure_generator.h:368
DDElementRef createElement(const std::string &name, MemberType T::*member_offset, const DDEnum &enum_type)
Definition ddstructure_generator.h:243
void setStructInfo(const std::string &comment)
Set additional struct information like comment. This is important to create additional info in type r...
Definition ddstructure_generator.h:513
DDStructureGenerator & addElement(const std::string &name, MemberType T::*member_offset, const DDEnum &enum_type, const std::string &valid_element_count_or_array_size_name)
Definition ddstructure_generator.h:320
const DDStructure & getStructure() const
Get the current valid DDStructure object.
Definition ddstructure_generator.h:474
size_t getSize() const
Retrieves the current evaluated size of the structure.
Definition ddstructure_generator.h:484
DDElementRef createElement(const std::string &name, MemberType T::*member_offset)
Definition ddstructure_generator.h:141
std::string getStructName() const
Gets the Struct Name.
Definition ddstructure_generator.h:437
DDElementRef createElement(const std::string &name, MemberType T::*member_offset, const std::string &valid_element_count_or_array_size_name)
Definition ddstructure_generator.h:177
Utility class for a complete valid data definition of one StructType and its dependencies....
Definition ddstructure.h:57
DDStructure & addElement(const std::string &element_name, const dd::DataType &data_type, size_t array_size=1)
Adds one element to the struct using a (POD) DataType.
size_t getSize() const
Retrieves the current evaluated deserialized size (in bytes) of the structure.
The unit class holding a reference to its complete DD (references to baseunits and prefixes)
Definition ddunit.h:92
Generator template to create DataType for the plain c-types.
Definition dd_predefined_datatypes.h:38
The Data Definiton class uses the validation model to keep a Data Definition datamodel (ddl::dd::data...
Definition dd.h:92
datamodel::StructType StructType
Definition dd.h:59
utility::Optional< size_t > OptionalSize
Optional Size Type.
Definition dd_common_types.h:38
datamodel::BaseUnit BaseUnit
Definition dd.h:39
definiton of the unit namespace
Definition dd_predefined_units.h:55
definition of the ddl namespace
Definition codec.h:21