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; } } ``` ... ...

近期下载者

相关文件


收藏者