xtypes
所属分类:collect
开发工具:C++
文件大小:0KB
下载次数:0
上传日期:2023-06-15 06:55:26
上 传 者:
sh-1993
说明: 基于DDS-XTYPES标准的实现(),
(Implementation based on DDS-XTYPES standard (),)
文件列表:
CMakeLists.txt (13241, 2023-06-14)
LICENSE (11357, 2023-06-14)
cmake/ (0, 2023-06-14)
cmake/config.cmake.in (292, 2023-06-14)
docs/ (0, 2023-06-14)
docs/Doxyfile (106215, 2023-06-14)
docs/inner-memory.png (1664, 2023-06-14)
docs/outer-memory.png (14778, 2023-06-14)
docs/standard-divergencies.md (1340, 2023-06-14)
docs/types_inheritance.puml (736, 2023-06-14)
examples/ (0, 2023-06-14)
examples/complex_type.cpp (7509, 2023-06-14)
examples/exceptions_asserts.cpp (4642, 2023-06-14)
examples/iterators.cpp (10742, 2023-06-14)
examples/module.cpp (1808, 2023-06-14)
include/ (0, 2023-06-14)
include/xtypes/ (0, 2023-06-14)
include/xtypes/AggregationType.hpp (4398, 2023-06-14)
include/xtypes/AliasType.hpp (4946, 2023-06-14)
include/xtypes/ArrayType.hpp (10750, 2023-06-14)
include/xtypes/Assert.hpp (12654, 2023-06-14)
include/xtypes/CollectionType.hpp (2348, 2023-06-14)
include/xtypes/DynamicData.hpp (59090, 2023-06-14)
include/xtypes/DynamicDataImpl.hpp (16825, 2023-06-14)
include/xtypes/DynamicType.hpp (9908, 2023-06-14)
include/xtypes/EnumeratedType.hpp (4853, 2023-06-14)
include/xtypes/EnumerationType.hpp (2367, 2023-06-14)
include/xtypes/Instanceable.hpp (7041, 2023-06-14)
include/xtypes/MapInstance.hpp (13697, 2023-06-14)
include/xtypes/MapType.hpp (8339, 2023-06-14)
include/xtypes/Member.hpp (3775, 2023-06-14)
include/xtypes/MutableCollectionType.hpp (1788, 2023-06-14)
include/xtypes/PairType.hpp (7039, 2023-06-14)
... ...
# xtypes
Fast and lightweight C++17 header-only implementation of [OMG DDS-XTYPES](https://www.omg.org/spec/DDS-XTypes) standard.
## Getting Started
Given the following IDL,
```c++
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*:
```c++
StructType inner("Inner");
inner.add_member("a", primitive_type());
StructType outer("Outer");
outer.add_member("b", primitive_type());
outer.add_member("c", inner);
```
or by [parsing the IDL](#parser):
```c++
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:
```c++
//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](https://www.omg.org/spec/DDS-XTypes/About-DDS-XTypes/) 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](https://github.com/yhirose/cpp-peglib) a CMake
cache variable is provided: `XTYPES_PEGLIB_VERSION`. If not specified defaults to master.
```bash
$ 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.
```bash
$ cmake .. -DXTYPES_BUILD_EXAMPLES=ON
$ make
```
### Tests
*xtypes* uses [GTest](https://github.com/google/googletest) 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.
```bash
$ 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/`, 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](examples).*
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:
![](https://www.plantuml.com/plantuml/img/ZP912i8m44NtSufUe3SGiQXBGMZ5zJGTIY1DwsGY53oy1g4seLMtyzydRvBid22Bxmp0cNMdHT-f6WVASZ_aZsrs62rsMeKH56tBrABetguX-zuOKj-8mcXqQ-4PDQzbK0fx9VCu4OABJGvE0IYOSPmJiJ2Sl61jQ7cDX0r2shPpOh4Ert_1acwUhABVv0c7tn0ShU-8KQYPmz4xJqooQrm5mDe9evBeIQPXUizJa1XDysLXPT2vs6zJRJ-jM2f4xqQoGmXsP9lNhtu2)
#### PrimitiveType
Represents the system's basic types.
In order to create a `PrimitiveType`, a helper function must be used:
```c++
const DynamicType& t = primitive_type();
```
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).
```c++
EnumerationType 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*](#pairtype). Equivalent to *C++* `std::map`.
```c++
ArrayType a1(primitive_type(), 10); //size 10
ArrayType a2(structure, 10); //Array of structures (structure previously defined as StructType)
SequenceType s1(primitive()); //unbounded sequence
SequenceType s2(primitive(),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()); // unbounded map, key of type string, value of type float.
MapType m2(primitive_type(), 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`.
```cpp
PairType pair(StringType(), primitive_type);
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:
```c++
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:
```c++
ArrayType array(ArrayType(primitive_type(), 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:
```c++
ArrayType array(primitive_type, {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.
```c++
StructType my_struct("MyStruct");
```
Once the `StructType` has been declared, any number of members can be added.
```c++
my_struct.add_member(Member("m_a", primitive_type()));
my_struct.add_member(Member("m_b", StringType()));
my_struct.add_member(Member("m_c", primitive_type().key().id(42))); //with annotations
my_struct.add_member("m_d", ArrayType(25)); //shortcut version
my_struct.add_member("m_e", other_struct); //member of structs
my_struct.add_member("m_f", SequenceType(other_struct)); //member of sequence of structs
```
Note: once a `DynamicType` is added to an struct, a copy is performed.
This allows modifications to `DynamicType` to be performed without side effects.
It also and facilitates the user's memory management duties.
##### StructType inheritance
A `StructType` can inherit from another `StructType` by using a pointer to the *parent* structure in the
constructor of the *child* struct.
The *child* struct will contain all the members defined by its *parent*, followed by its own members.
A struct can check if inherit from another struct by calling the `has_parent()` method.
The *child* struct can access to its *parent* using the `parent()` method, which should be called only if
`has_parent()` returns `true`.
```c++
StructType parent("ParentStruct");
parent.add_member(Member("parent_uint32", primitive_type()));
parent.add_member(Member("parent_string", StringType()));
StructType child("ChildStruct", &parent);
child.add_member(Member("child_string", StringType()));
StructType grand_child("GrandChildStruct", &child);
grand_child.add_member(Member("grand_child_float", primitive_type()));
grand_child.add_member(Member("grand_child_double", primitive_type()));
if (grand_child.has_parent())
{
std::cout << "Inherits from: " << grand_child.parent().name() << std::endl;
}
```
#### UnionType
Similar to a *C-like union* or a [StructType](#structtype) but with only one member active at the same time.
It is defined by a *discriminator* and a list of labels allowing to identify the current active member.
```c++
UnionType my_union("MyUnion", primitive_type());
```
The allowed *discriminator* types are all the **no floating point** primitives, EnumerationType, and AliasType that
solves (directly or indirectly) to any other allowed type.
Once the `UnionType` has been declared, any number of *case members* can be added, defining the labels that
belong to the case member.
It is possible to define a `default` case for one member, which will be selected when the DynamicData is built.
This can be done setting the flag `is_default` to *true* in the `add_case_member` method (*false* by default), or
defining a label named `default` when using a list of strings as labels.
```c++
my_union.add_case_member({'a', 'b'}, Member("m_ab", StringType());
std::vector label_list = {'c', 'd', 'e'};
my_union.add_case_member(label_list, Member("m_cde", primitive_type());
my_union.add_case_member({}, Member("m_default", primitive_type()), true);
```
This code is equivalent to the following one:
```c++
my_union.add_case_member({"a", "b"}, Member("m_ab", StringType());
std::vector label_list = {"c", "d", "e"};
my_union.add_case_member(label_list, Member("m_cde", primitive_type());
my_union.add_case_member({"default"}, Member("m_default", primitive_type()));
```
A *case member* without labels must be `default`.
#### AliasType
Acts as a *C-like typedef*, allowing to specify a custom name for an already existing type. They can be
used as any other *DynamicType*. Recursive aliasing is supported, meaning you can assign a new alias to
an already existing alias.
When a DynamicData is created using an AliasType as its type specificator, the inner type pointed by
the alias is retrieved and used to create the DynamicData field.
```c++
AliasType my_alias(primitive_type(), "unsigned32"); // As in C "typedef uint32_t unsigned32;"
AliasType my_alias2(my_alias, "u32"); // As in C "typedef unsigned32 u32;"
StructType my_struct("MyStruct");
my_struct.add_member("m_al", my_alias);
DynamicData struct_data(my_struct);
struct_data["m_al"] = 20u; // Internal uint32_t primitive type is accessed
DynamicData alias_data(my_alias2);
alias_data = 30u; // Internal uint32_t primitive type is accessed
```
#### Type Consistency (QoS policies)
Any pair of `DynamicType`s can be checked for their mutual compatibility.
```c++
TypeConsistency consistency = tested_type.is_compatible(other_type);
```
This line will evaluate consistency levels among the two types.
The returned `TypeConsistency` is going to be a subset of the following *QoS policies*:
- `NONE`: Unknown way to interpret both types as equivalents.
- `EQUALS`: The evaluation is analogous to an equal evaluation.
- `IGNORE_TYPE_SIGN`: the evaluation will be true independently of the sign.
- `IGNORE_TYPE_WIDTH`: the evaluation will be true if the width of the some primitive types are less or
equals than the other type.
- `IGNORE_SEQUENCE_BOUNDS`: the evaluation will be true if the bounds of the some sequences are less or
equals than the other type.
- `IGNORE_ARRAY_BOUNDS`: same as `IGNORE_SEQUENCE_BOUNDS` but for the case of arrays.
- `IGNORE_STRING_BOUNDS`: same as `IGNORE_SEQUENCE_BOUNDS` but for the case of string.
- `IGNORE_MEMBER_NAMES`: the evaluation will be true if the names of some members differs (but no the position).
- `IGNORE_MEMBERS`: the evaluation will be true if some members of `other_type` are ignored.
Note: `TypeConsistency` is an enum with `|` and `&` operators overriden to manage it as a set of QoS policies.
### Module
Modules are equivalent to C++ namespaces. They can store sets of StructType, Constants and other Modules
(as submodules).
They allow organizing types into different scopes, allowing scope solving when accessing the stored types.
```c++
Module root;
Module& submod_a = root.create_submodule("a");
Module& submod_b = root.create_submodule("b");
Module& submod_aa = submod_a.create_submodule("a");
root.structure(inner);
submod_aa.structure(outer);
std::cout << std::boolalpha;
std::cout << "Does a::a::OuterType exists?: " << root.has_structure("a::a::OuterType") << std::endl; // true
std::cout << "Does ::InnerType exists?: " << root.has_structure("::InnerType") << std::endl; // true
std::cout << "Does InnerType exists?: " << root.has_structure("InnerType") << std::endl; // true
std::cout << "Does OuterType exists?: " << root.has_structure("OuterType") << std::endl; // false
DynamicData module_data(root["a"]["a"].structure("OuterType")); // ::a::a::OuterType
module_data["om3"] = "This is a string.";
```
As can be seen in the example, a module allows the user to access their internal definitions in two ways:
Accessing directly using a scope name (`root.structure("a::a::OuterType")`), or navigating manually through the
inner modules (`root["a"]["a"].structure("OuterType")`).
### Data instance
#### Initialization
To instantiate a data, only is necessary a `DynamicType`:
```c++
DynamicData data(my_defined_type);
```
This line allocates all the memory necessary to hold the data defined by `my_defined_type`
and initializes their content to *0* or to the corresponding *default values*.
Please, note that the type must have a higher lifetime than the DynamicData,
since `DynamicData` only saves a reference to it.
Other ways to initialize a `DynamicData` are respectively *copy* and *compatible copy*.
```c++
DynamicData data1(type1); //default initalization
DynamicData data2(data1); //copy initialization
DynamicData data3(data1, type2); //compatible copy initialization
```
The last line creates a compatible `DynamicData` with the values of `data1` that can be accessed being a `type2`.
To achieve this, `type2` must be compatible with `type1`.
This compatibility can be checked with `is_compatible` function.
#### Internal data access
Depending on the type, the `DynamicData` will behave in different ways.
The following methods are available when:
1. `DynamicData` represents a `PrimitiveType`, `StringType` or `WStringType` (of `int32_t` as example):
```c++
data.value(42); //sets the value to 42
data = 23; // Analogous to the one above, assignment from primitive, sets the value to 23
int32_t value = data.value(); //read the value
int32_t value = data; //By casting operator
data = "Hello again!"; // set string value
data = L"Hello again! \u263A"; // set string value
```
1. `DynamicData` represents a `PairType`. Similar to *C++* `std::pair`, but using `operator[](size_t)`
to access each member, using 0 to access `first` and 1 to access `second`.
```c++
data[0] = first_value; // set "first" member value to "first_value".
data[1] = second_value; // set "second" member value to "second_value".
```
1. `DynamicData` represents an `AggregationType`
```c++
data["member_name"] = 42; //set value 42 to the int member called "member_name"
data[2] = 42; //set value 42 to the third int member.
int32_t value = data["member_name"]; // get the value from member_name member.
int32_t value = data[2]; // get the value from third member.
data["member_name"].value(dynamic_data_representing_a_value);
WritableDynamicDataRef ref = data["member_name"];
size_t size = data.size(); //number of members
for (ReadableDynamicDataRef::MemberPair&& elem : data.items()) // Iterate through its members.
{
if (elem.kind() == TypeKind::INT_32_TYPE)
{
std::cout << elem.type().name() << " " << elem.name() << ": " << elem.value() << std::endl;
}
}
``` ... ...
近期下载者:
相关文件:
收藏者: