SkillAgentSearch skills...

Xtypes

Implementation based on DDS-XTYPES standard (https://www.omg.org/spec/DDS-XTypes)

Install / Use

/learn @eProsima/Xtypes
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

xtypes

Fast and lightweight C++17 header-only implementation of OMG DDS-XTYPES standard.

Getting Started

Given the following IDL,

struct Inner {
    long a;
};

struct Outer {
    long b;
    Inner c;
};

you can create the representative C++ code defining this IDL's types using xtypes API:

StructType inner("Inner");
inner.add_member("a", primitive_type<int32_t>());

StructType outer("Outer");
outer.add_member("b", primitive_type<int32_t>());
outer.add_member("c", inner);

or by parsing the IDL:

idl::Context context = idl::parse(my_idl);
const StructType& inner = context.module().structure("Inner");
const StructType& outer = context.module().structure("Outer");

Once these types have been defined, you can instantiate them and access their data:

//create the DynamicData accordingly with the recently created "Outer" DynamicType
DynamicData data(outer);

//write value
data["c"]["a"] = 42;

// read value
int32_t my_value = data["c"]["a"];

Why should you use eProsima xtypes?

  • OMG standard: eProsima xtypes is based on the DDS-XTYPES standard from the OMG.
  • C++17 API: eProsima xtypes uses C++17 latest features, providing an easy-to-use API.
  • Memory lightweight: data instances use the same memory as types built by the compiler. No memory penalty is introduced by using eProsima xtypes in relation to compiled types.
  • Fast: Accessing to data members is swift and quick.
  • Header only library: avoids the linking problems.
  • No external dependency: eProsima xtypes's only dependencies are from std and cpp-peglib (which is downloaded automatically).
  • Easy to use: Comprehensive API and intuitive concepts.

Build

eprosima xtypes is a header-only library: in order to use it you simply have to copy the files located in the include folder into your project and include them.

For a better management and version control, we recommend to make use of the CMake project that xtypes offers. Although there is no library generated by xtypes, you can do the linking with its target as following. This will enable the inclusion of xtypes headers:

target_link_libraries(${PROJECT_NAME} xtypes)

cpp-peglib library version

To link xtypes to a specific version of the cpp-peglib a CMake cache variable is provided: XTYPES_PEGLIB_VERSION. If not specified defaults to master.

$ cmake .. -DXTYPES_PEGLIB_VERSION="v1.8.2"
$ make

Examples

To compile the examples located in the examples/ folder, enable the XTYPES_BUILD_EXAMPLES cmake flag. Supposing you are in a build folder inside of xtypes top folder, you can run the following to compile the examples.

$ cmake .. -DXTYPES_BUILD_EXAMPLES=ON
$ make

Tests

xtypes uses GTest framework for testing. The CMake project will download this internally if you compile with the XTYPES_BUILD_TESTS flag enabled. Supposing you are in a build folder inside of xtypes top folder, you can run the following to compile the tests.

$ cmake .. -DXTYPES_BUILD_TESTS=ON
$ make

Tests are automatically deployed and executed via GitHub Actions each time new changes are introduced to the master branch or when a pull request is created. By default, Valgrind tests will be omitted; if the introduced changes are considered to be deep enough to need a complete memcheck, please name your branch using the pattern valgrind/<branch_name>, so that GitHub Action step for Valgrind does not get bypassed and the memory check tests are executed.

API usage

Examples can be found in example folder.

The API is divided into two different and yet related concepts.

  1. Type definition: classes and methods needed for your runtime type definition.
  2. Data instance: set of values organized accordingly with its own type definition.

Type definition

All types inherit from the base abstract type DynamicType as shown in the following diagram:

PrimitiveType

Represents the system's basic types. In order to create a PrimitiveType, a helper function must be used:

const DynamicType& t = primitive_type<T>();

with T being one of the following basic types: bool char wchar_t uint8_t int16_t uint16_t int32_t uint32_t int64_t uint64_t float double long double

Enumerated Type

EnumeratedTypes are a special kind of PrimitiveTypes. They are internally represented by a PrimitiveType, but only allows a user-defined subset of values.

EnumerationType

Similar to C++ enum, enumerations are the most basic kind of EnumeratedTypes. It can be bound to three different PrimitiveTypes, uint8_t, uint16_t, and uint32_t. The possible values for the enumeration are defined adding them as identifiers. The value can be explicitly specified or auto-assigned. Once an identifier is added, the next identifier's value must be greater than the previous one. By default, the first added value is zero (0).

EnumerationType<uint32_t> my_enum("MyEnum");
my_enum.add_enumerator("A");                // The value of MyEnum::A is 0. The default initial value.
my_enum.add_enumerator("B", 10);            // The value of MyEnum::B is 10. Explicitely defined.
my_enum.add_enumerator("C");                // The value of MyEnum::C is 11. Implicitely assigned.

DynamicData enum_data(my_enum);             // DynamicData of type "MyEnum".
enum_data = my_enum.value("C");             // Assign to the data the value of MyEnum::C.

uint32_t value = enum_data;                 // Retrieve the data as its primitive type.
DynamicData enum_data2 = enum_data;         // Copy the DynamicData.
enum_data2 = uint32_t(10);                  // Assign to the copy, a raw value from its primitive type.

Assign or retrieve enumeration data of a different primitive type isn't allowed, so the user should cast the value by himself.

Assign a value that doesn't belong to the enumeration isn't supported.

Collection Type

As pointed by the self-explanatory name, CollectionTypes provide a way to create the most various collections. There are several collection types:

  • ArrayType: fixed-size set of elements. Similar to C-like arrays.
  • SequenceType: variable-size set of elements. Equivalent to C++ std::vector
  • StringType: variable-size set of char-type elements. Similar to C++ std::string
  • WStringType: variable-size set of wchar-type elements. Similar to C++ std::wstring
  • MapType: variable-size set of pairs. Equivalent to C++ std::map.
ArrayType a1(primitive_type<int32_t>(), 10); //size 10
ArrayType a2(structure, 10); //Array of structures (structure previously defined as StructType)
SequenceType s1(primitive<float>()); //unbounded sequence
SequenceType s2(primitive<float>(),30); //bounded sequence, max size will be 30
SequenceType s3(SequenceType(structure), 20); //bounded sequence of unbounded sequences of structures.
StringType str1; //unbounded string
StringType str2(50); //bounded string
WStringType wstr(); //unbounded wstring
MapType m1(StringType(), primitive_type<float>()); // unbounded map, key of type string, value of type float.
MapType m2(primitive_type<uint32_t>(), structure, 10); // bounded map, max size of 10, key as uint32_t, value as struct.
size_t a1_bounds = a1.bounds(); // As a1 is an ArrayType, its bounds are equal to its size.
size_t s1_bounds = s1.bounds(); // As s1 is an unbounded sequence, its bounds are 0.
size_t s2_bounds = s2.bounds(); // As s2 is a bounded sequence, its bounds are 30.
size_t s3_bounds = s3.bounds(); // As s3 is a bounded sequence, its bounds are 20.
size_t str1_bounds = str1.bounds(); // As str1 is an unbounded string, its bounds are 0.
size_t str2_bounds = str2.bounds(); // As str2 is a bounded string, its bounds are 50.
size_t m1_bounds = m1.bounds(); // As m1 is an unbounded map, its bounds are 0.
size_t m2_bounds = m2.bounds(); // As m2 is a bounded map, its bounds are 10.
PairType

MapType is a specialization of CollectionType which content is a set of pairs. These pairs are represented internally by an auxiliar type named PairType.

PairType pair(StringType(), primitive_type<uint32_t>);
std::cout << pair.first().name() << std::endl; // Prints "std::string".
std::cout << pair.second().name() << std::endl; // Prints "uint32_t".
Multidimensional ArrayType

In a C-like language, the programmer can define multidimensional arrays as an array of array. For example:

int array[2][3];

Using ArrayType, the same can be achieved just creating an array, and then using it as the content of the outer array:

ArrayType array(ArrayType(primitive_type<int32_t>(), 3), 2); // Conceptually equivalent to "int array[2][3];"

Note that the dimensions are swapped, because the inner array is the second index. To ease this kind of type definition, ArrayType provides a constructor that receives an std::vector of dimensions (uint32_t). This constructor receives the indexes in the natural order, like in the C-like example:

ArrayType array(primitive_type<int32_t>, {2, 3});

StructType

Similarly to a C-like struct, a StructType represents an aggregation of members. You can specify a StructType given the type name of the structure.

StructType my_struct("MyStruct");

Once the StructType has been declared, any number of members can be added.

my_struct.add_member(Member("
View on GitHub
GitHub Stars24
CategoryProduct
Updated2mo ago
Forks11

Languages

C++

Security Score

90/100

Audited on Jan 12, 2026

No findings