ADTF  3.18.2
ddstructure.h
Go to the documentation of this file.
1 
15 #ifndef DDSTRUCTURE_H_INCLUDED
16 #define DDSTRUCTURE_H_INCLUDED
17 
18 #include <ddl/dd/dd.h>
19 #include <ddl/dd/ddelement.h>
21 
22 #include <type_traits>
23 
24 namespace ddl {
25 
27 class DDElement;
29 
55 class DDStructure {
56 public:
61  DDStructure() = delete;
73  DDStructure(const DDStructure& other);
92  ~DDStructure() = default;
105  explicit DDStructure(const std::string& name,
106  const uint32_t struct_version = 1,
107  dd::OptionalSize alignment = {},
108  const std::string& comment = {},
109  const dd::Version& ddl_version = {});
122  explicit DDStructure(const std::string& name,
123  const std::string& xml_string,
124  const dd::Version& ddl_xml_file_version_to_parse = dd::Version(0, 0));
141  DDStructure& addElement(const std::string& element_name,
142  const dd::DataType& data_type,
143  size_t array_size = 1);
161  DDStructure& addElement(const std::string& element_name,
162  const dd::DataType& data_type,
163  size_t array_size,
164  size_t alignment);
182  DDStructure& addElement(const std::string& element_name,
183  const DDDataType& data_type,
184  size_t array_size = 1);
185 
204  DDStructure& addElement(const std::string& element_name,
205  const DDDataType& data_type,
206  size_t array_size,
207  size_t alignment);
227  template <typename PREDEF_DATA_TYPE>
228  DDStructure& addElement(const std::string& element_name,
229  size_t array_size = 1,
230  const std::string& special_type_name = {})
231  {
232  if (special_type_name.empty()) {
233  addElement(element_name, DataType<PREDEF_DATA_TYPE>(), array_size);
234  }
235  else {
236  addElement(element_name, DataType<PREDEF_DATA_TYPE>(special_type_name), array_size);
237  }
238  return *this;
239  }
240 
261  template <typename PREDEF_DATA_TYPE>
262  DDStructure& addElement(const std::string& element_name,
263  size_t array_size,
264  size_t alignment,
265  const std::string& special_type_name = {})
266  {
267  if (special_type_name.empty()) {
268  addElement(element_name, DataType<PREDEF_DATA_TYPE>(), array_size, alignment);
269  }
270  else {
271  addElement(
272  element_name, DataType<PREDEF_DATA_TYPE>(special_type_name), array_size, alignment);
273  }
274  return *this;
275  }
276 
293  DDStructure& addElement(const std::string& element_name,
294  const DDEnum& enum_type,
295  size_t array_size,
296  const std::string& constant_value = {});
297 
315  DDStructure& addElement(const std::string& element_name,
316  const DDEnum& enum_type,
317  size_t array_size,
318  size_t alignment,
319  const std::string& constant_value = {});
320 
336  DDStructure& addElement(const std::string& element_name,
337  const DDEnum& enum_type,
338  const std::string& constant_value = {});
339 
359  DDStructure& addElement(const std::string& element_name,
360  const DDStructure& struct_type,
361  size_t array_size = 1);
362 
383  DDStructure& addElement(const std::string& element_name,
384  const DDStructure& struct_type,
385  size_t array_size,
386  size_t alignment);
399  DDStructure& addElement(const DDElement& element);
417  DDStructure& addElements(const std::vector<DDElement>& elements);
418 
423 
430  {
431  return _struct_type->getElements().cbegin();
432  };
439  {
440  return _struct_type->getElements().cend();
441  }
448  {
449  return _struct_type->getElements().begin();
450  };
457  {
458  return _struct_type->getElements().end();
459  }
465  const dd::DataDefinition& getDD() const;
472 
478  std::string getStructDescription() const;
484  std::string getStructName() const;
485 
493  bool isCompatible(const DDStructure& other) const;
501  bool isEqual(const DDStructure& other) const;
502 
507  size_t getSize() const;
508 
513  size_t getAlignment() const;
514 
522  void setStructInfo(const std::string& comment);
540  void setElementInfo(const std::string& element_name,
541  const std::string& description = {},
542  const std::string& comment = {},
543  const std::string& value = {},
544  const std::string& minimum_value = {},
545  const std::string& maximum_value = {},
546  const std::string& default_value = {},
547  const std::string& scale = {},
548  const std::string& offset = {});
559  void setElementUnit(const std::string& element_name, const DDUnit& unit);
570  void setElementUnit(const std::string& element_name, const dd::BaseUnit& base_unit);
571 
572 private:
573  template <typename T, bool align_with_padding>
574  friend class DDStructureGenerator;
575 
576  void popLastElement();
577 
578  dd::DataDefinition _dd;
579  std::shared_ptr<dd::StructType> _struct_type;
580  dd::OptionalSize _initial_alignment = {};
581 };
582 
584 namespace detail {
585 
586 template <typename T, typename Enable = void>
587 struct arrayCount {
588  static constexpr size_t value = 1;
589 };
590 
591 template <typename T>
592 struct arrayCount<T, typename std::enable_if<std::is_array<T>::value>::type> {
593  static constexpr size_t value =
594  sizeof(T) / sizeof(typename std::remove_pointer<typename std::decay<T>::type>::type);
595 };
596 
597 template <typename T, typename MemberType>
598 size_t memberPointerToOffset(MemberType T::*member)
599 {
600  T* start = 0;
601  return reinterpret_cast<size_t>(&(start->*member));
602 }
603 
604 } // namespace detail
606 
643 template <typename T, bool align_with_padding = true>
645  static_assert(std::is_trivially_copyable<T>::value,
646  "You can only use structs with plain old datatypes and complex members. Do not "
647  "use pointers!");
648 
649 public:
656  explicit DDStructureGenerator(const std::string& name, uint32_t struct_version = 1)
657  : _structure(name, struct_version, alignof(T))
658  {
659  }
666  template <typename MemberType>
667  DDStructureGenerator& addElement(const std::string& name, MemberType T::*member_offset)
668  {
669  popAlignment();
670  _structure
671  .addElement<typename std::remove_pointer<typename std::decay<MemberType>::type>::type>(
672  name,
673  detail::arrayCount<MemberType>::value,
674  *evaluateAlignment(
675  name, detail::memberPointerToOffset(member_offset), alignof(MemberType)));
676  pushAlignment();
677  return *this;
678  }
679 
687  template <typename MemberType>
688  DDStructureGenerator& addElement(const std::string& name,
689  MemberType T::*member_offset,
690  const DDEnum& enum_type)
691  {
692  popAlignment();
693  _structure.addElement(name,
694  enum_type,
695  detail::arrayCount<MemberType>::value,
696  *evaluateAlignment(name,
697  detail::memberPointerToOffset(member_offset),
698  alignof(MemberType)));
699  pushAlignment();
700  return *this;
701  }
709  template <typename MemberType>
710  DDStructureGenerator& addElement(const std::string& name,
711  MemberType T::*member_offset,
712  const DDStructure& struct_type)
713  {
714  popAlignment();
715  _structure.addElement(name,
716  struct_type,
717  detail::arrayCount<MemberType>::value,
718  *evaluateAlignment(name,
719  detail::memberPointerToOffset(member_offset),
720  alignof(MemberType)));
721  pushAlignment();
722  return *this;
723  }
724 
730  std::string getStructDescription() const
731  {
732  validate();
733  return _structure.getStructDescription();
734  }
740  std::string getStructName() const
741  {
742  return _structure.getStructName();
743  }
744 
752  const dd::DataDefinition& getDD() const
753  {
754  validate();
755  return _structure.getDD();
756  }
757 
766  {
767  validate();
768  return _structure.getStructType();
769  }
777  const DDStructure& getStructure() const
778  {
779  validate();
780  return _structure;
781  }
782 
787  size_t getSize() const
788  {
789  return _structure.getSize();
790  }
791 
796  size_t getAlignment() const
797  {
798  return _structure.getAlignment();
799  }
800 
808  operator const DDStructure&() const
809  {
810  return getStructure();
811  }
812 
816  void setStructInfo(const std::string& comment)
817  {
818  _structure.setStructInfo(comment);
819  }
820 
824  void setElementInfo(const std::string& element_name,
825  const std::string& description = {},
826  const std::string& comment = {},
827  const std::string& value = {},
828  const std::string& minimum_value = {},
829  const std::string& maximum_value = {},
830  const std::string& default_value = {},
831  const std::string& scale = {},
832  const std::string& offset = {})
833  {
834  _structure.setElementInfo(element_name,
835  description,
836  comment,
837  value,
838  minimum_value,
839  maximum_value,
840  default_value,
841  scale,
842  offset);
843  }
854  void setElementUnit(const std::string& element_name, const DDUnit& unit)
855  {
856  _structure.setElementUnit(element_name, unit);
857  }
868  void setElementUnit(const std::string& element_name, const dd::BaseUnit& base_unit)
869  {
870  _structure.setElementUnit(element_name, base_unit);
871  }
872 
873 private:
874  void pushAlignment()
875  {
876  if (align_with_padding) {
877  auto current_struct_size = _structure.getSize();
878  if (sizeof(T) > current_struct_size) {
879  _structure.addElement<uint8_t>(
880  "__padding_final", sizeof(T) - current_struct_size, 1);
881  _padded_final = true;
882  }
883  }
884  }
885  void popAlignment()
886  {
887  if (align_with_padding) {
888  if (_padded_final) {
889  _structure.popLastElement();
890  _padded_final = false;
891  }
892  }
893  }
894  void validate() const
895  {
896  constexpr auto padding_aligned = align_with_padding;
897  if (!padding_aligned) {
898  if (_structure.getSize() != sizeof(T)) {
899  throw ddl::dd::Error(
900  "DDStructureGenerator::validate",
901  "The generated struct '" + _structure.getStructName() +
902  "' does not have the expected size of (" + std::to_string(sizeof(T)) +
903  ") - The evaluated a size is (" + std::to_string(_structure.getSize()) +
904  "). Check if there are missed or misordered elements. ");
905  }
906  }
907  }
908 
909  dd::OptionalSize evaluateAlignment(const std::string& element_name,
910  size_t member_offset,
911  size_t member_type_alignment)
912  {
913  // obtain the unaligned size
914  auto struct_access = _structure.getDD().getStructTypeAccess(getStructName());
915  auto current_struct_offset = struct_access.getStaticUnalignedStructSize();
916 
917  if (member_offset < current_struct_offset) {
918  throw ddl::dd::Error(
919  "evaluateAlignment",
920  {std::to_string(member_offset)},
921  "The evaluated struct size of '" + getStructName() + "' is already (" +
922  std::to_string(current_struct_offset) + ") - Trying to add a member at (" +
923  std::to_string(member_offset) +
924  ") at a address prior the last element. Check misordered addElement calls.");
925  }
926 
927  // evaluate difference between last added element and current offset
928  auto difference = member_offset - current_struct_offset;
929 
930  // find the minimum alignment to begin alignment discovery
931  // this is the data_type alignment or the struct alignment
932  size_t minimum_alignment = member_type_alignment;
933  if (member_type_alignment > alignof(T)) {
934  minimum_alignment = alignof(T);
935  }
936 
937  auto valid_alignment_range = {1u, 2u, 4u, 8u, 16u, 32u, 64u};
938 
939  // find a valid alignment in the range of member_type_alignment and struct_alignment
940  for (size_t alignment: valid_alignment_range) {
941  // maximum alignment is the alignment of the struct
942  if (alignment <= alignof(T)) {
943  if (alignment >= minimum_alignment) {
944  if (alignment > difference && member_offset % alignment == 0) {
945  // we do not add padding bytes between if it fits with alignment
946  return alignment;
947  }
948  }
949  }
950  else {
951  break;
952  }
953  }
954 
955  // if diffence is below minimum alignment and we could not reach the position
956  // the struct has been packed by the user to another alignment then the struct alignment
957  if (difference < minimum_alignment) {
958  for (size_t alignment: valid_alignment_range) {
959  if (alignment < minimum_alignment) {
960  if (alignment > difference && member_offset % alignment == 0) {
961  // we do not add padding bytes between if it fits with alignment
962  return alignment;
963  }
964  }
965  else {
966  break;
967  }
968  }
969  }
970 
971  // we could not reach the position with alignments, so we
972  // align with padding if switch on
973  if (align_with_padding) {
974  if (difference != 0) {
975  _structure.addElement<uint8_t>("__padding_" + element_name, difference, 1);
976  }
977  // We need to return alignment 1 to use the very next position
978  return 1;
979  }
980 
981  throw ddl::dd::Error(
982  "evaluateAlignment",
983  {std::to_string(member_offset)},
984  "For the generated struct '" + getStructName() +
985  "' it is not possible to find a valid member alignment to reach offset (" +
986  std::to_string(member_offset) + ") from position (" +
987  std::to_string(current_struct_offset) + ")");
988  }
989 
990  DDStructure _structure;
991  bool _padded_final = false;
992 };
993 
994 } // namespace ddl
995 
996 #endif // DDSTRUCTURE_H_INCLUDED
A DataType class holding the DD for a Datatype with dependencies.
Definition: dddatatype.h:30
Utility class for a complete valid data definition of one StructType::Element and its dependencies.
Definition: ddelement.h:36
Utility class for a complete valid data definition of one EnumType and its dependencies.
Definition: ddenum.h:29
Creating a valid Structure Data Definition by a existing type and its member types.
Definition: ddstructure.h:644
std::string getStructName() const
Gets the Struct Name.
Definition: ddstructure.h:740
std::string getStructDescription() const
Gets the Struct Data Description as XML String.
Definition: ddstructure.h:730
const dd::DataDefinition & getDD() const
returns a valid DDL.
Definition: ddstructure.h:752
DDStructureGenerator & addElement(const std::string &name, MemberType T::*member_offset, const DDEnum &enum_type)
Adds a new member of an enumeration type by member reference pointer.
Definition: ddstructure.h:688
DDStructureGenerator & addElement(const std::string &name, MemberType T::*member_offset)
Adds a new member of data type (POD) by member reference pointer.
Definition: ddstructure.h:667
DDStructureGenerator(const std::string &name, uint32_t struct_version=1)
CTOR to create a structure type based on a type.
Definition: ddstructure.h:656
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.h:868
const dd::StructType & getStructType() const
Get the Struct Type object.
Definition: ddstructure.h:765
size_t getAlignment() const
Retrieves the current evaluated alignment of the structure.
Definition: ddstructure.h:796
size_t getSize() const
Retrieves the current evaluated size of the structure.
Definition: ddstructure.h:787
void setStructInfo(const std::string &comment)
Set additional struct information like comment.
Definition: ddstructure.h:816
void setElementUnit(const std::string &element_name, const DDUnit &unit)
Sets additional element unit information to the given element_name.
Definition: ddstructure.h:854
const DDStructure & getStructure() const
Get the current valid DDStructure object.
Definition: ddstructure.h:777
DDStructureGenerator & addElement(const std::string &name, MemberType T::*member_offset, const DDStructure &struct_type)
Adds a new member of an structure type by member reference pointer.
Definition: ddstructure.h:710
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.h:824
Utility class for a complete valid data definition of one StructType and its dependencies.
Definition: ddstructure.h:55
std::string getStructName() const
Gets the Struct Name.
DDStructure(const DDStructure &other)
Construct a new DDStructure object.
DDStructure & addElement(const std::string &element_name, const dd::DataType &data_type, size_t array_size, size_t alignment)
Adds one element to the struct using a (POD) DataType.
std::string getStructDescription() const
Gets the Struct Data Description as XML String.
const_iterator begin() const
returns the first elenents iterator for range based iterations.
Definition: ddstructure.h:447
DDStructure & addElement(const std::string &element_name, const DDDataType &data_type, size_t array_size=1)
Adds one element to the struct using a (POD) DataType.
~DDStructure()=default
Destroy the DDStructure object.
bool isCompatible(const DDStructure &other) const
binary compares the structs
DDStructure & addElement(const std::string &element_name, const DDStructure &struct_type, size_t array_size=1)
Adds one element to the struct using the convenience class DDStructure.
const_iterator cbegin() const
returns the first elements iterator.
Definition: ddstructure.h:429
const dd::DataDefinition & getDD() const
returns a valid DDL.
DDStructure & addElement(const DDElement &element)
Adds one element to the struct using the convenience class DDElement.
dd::datamodel::StructType::Elements::const_iterator const_iterator
iterator to iterate the elements of the struct
Definition: ddstructure.h:422
DDStructure(const std::string &name, const uint32_t struct_version=1, dd::OptionalSize alignment={}, const std::string &comment={}, const dd::Version &ddl_version={})
Construct a new DDStructure object.
void setElementUnit(const std::string &element_name, const dd::BaseUnit &base_unit)
Sets additional element base unit information to the given element_name.
DDStructure & addElement(const std::string &element_name, const DDEnum &enum_type, const std::string &constant_value={})
Adds one element to the struct using the convenience class DDEnum.
const dd::StructType & getStructType() const
Get the Struct Type object.
DDStructure(const std::string &name, const std::string &xml_string, const dd::Version &ddl_xml_file_version_to_parse=dd::Version(0, 0))
Construct a new DDStructure object.
DDStructure()=delete
Construct a new DDStructure object.
size_t getAlignment() const
Retrieves the current evaluated alignment of the structure.
DDStructure & addElement(const std::string &element_name, size_t array_size=1, const std::string &special_type_name={})
Adds one element to the struct using a (POD) DataType.
Definition: ddstructure.h:228
DDStructure & addElement(const std::string &element_name, size_t array_size, size_t alignment, const std::string &special_type_name={})
Adds one element to the struct using a (POD) DataType.
Definition: ddstructure.h:262
const_iterator cend() const
returns the end elements iterator.
Definition: ddstructure.h:438
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.
DDStructure & addElement(const std::string &element_name, const DDDataType &data_type, size_t array_size, size_t alignment)
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.
DDStructure & addElements(const std::vector< DDElement > &elements)
Adds a list of element to the struct using the convenience class DDElement.
void setStructInfo(const std::string &comment)
Set additional struct information like comment.
void setElementUnit(const std::string &element_name, const DDUnit &unit)
Sets additional element unit information to the given element_name.
DDStructure & operator=(const DDStructure &other)
copy assignment operator
const_iterator end() const
returns the end elements iterator.
Definition: ddstructure.h:456
DDStructure & addElement(const std::string &element_name, const DDEnum &enum_type, size_t array_size, const std::string &constant_value={})
Adds one element to the struct using the convenience class DDEnum.
DDStructure & operator=(DDStructure &&other)
move assignment operator
DDStructure & addElement(const std::string &element_name, const DDStructure &struct_type, size_t array_size, size_t alignment)
Adds one element to the struct using the convenience class DDStructure.
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.
bool isEqual(const DDStructure &other) const
equal in names and descriptions
DDStructure(DDStructure &&other)
Construct a new DDStructure object.
DDStructure & addElement(const std::string &element_name, const DDEnum &enum_type, size_t array_size, size_t alignment, const std::string &constant_value={})
Adds one element to the struct using the convenience class DDEnum.
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.
The Data Definiton class uses the validation model to keep a Data Definition datamodel (ddl::dd::data...
Definition: dd.h:87
StructTypeAccess getStructTypeAccess(const std::string &type_name) const
Get the Struct Type Access, where to enter the type and calculated element position information.
size_t getStaticUnalignedStructSize() const
Get the known unaligned Static Struct Size of this instance (this is usually the last position + size...
observable DataDefinition object class to describe (POD) DataType.
observable DataDefinition object class to describe StructType.
container_type::const_iterator const_iterator
local definition of the container const_iterator
OO DataDefinition - Data Definition.
OO DataDefinition Element Header.
@ enum_type
value for enum type
Definition: ddl_capi.h:56
@ data_type
value for data type
Definition: ddl_capi.h:55
@ struct_type
value for struct type
Definition: ddl_capi.h:57
cString to_string(const tResult &i_oResult, eResultFormatFlags i_eFormatFlags=eResultFormatFlags::RFF_DisableNone, const tChar *i_strFormat=nullptr)
Copy all information of an assigned result object to a (formatted) string.
@ unit
the unit is a unit (Unit)
@ base_unit
the unit is a base unit (BaseUnit)
utility::Optional< size_t > OptionalSize
Optional Size Type.
Utility for the Neutrino gcc5 compiler which has really no std::to_string implementation!