C++ mappings: From IDL types to C++ types

## Contents

- Your rights

- Introduction

- Component model

- Component description file

- GenoM IDL mappings

  - `C` mappings

    - Scoped name

    - Constant

    - Basic type

    - Enumerated type

    - String

    - Array

    - Struct

    - Union

    - Sequence

    - Optional

    - Port

    - Remote

    - Native

    - Exception

  - `C++` mappings

    - Scoped name

    - Constant

    - Basic type

    - Enumerated type

    - String

    - Array

    - Struct

    - Union

    - Sequence

    - Optional

    - Port

    - Remote

    - Native

    - Exception

- Running GenoM

- Tutorials

- Templates

## `C++` mappings: From IDL types to `C++` types

### Scoped names

The `C++` mappings for scoped names use `C++` scopes. IDL `module` are mapped to `namespace`. For instance, the following IDL:

          module m {
             const string str = "scoped string";
          };

would map into

          namespace m {
             const std::string str = "scoped string";
          }

### Mapping for constants

`genom3` IDL constants are mapped to a `C++` constant. For instance, the following IDL:

       const long longint = 1;
       const string str = "string example";

would map into

       const int32_t longint = 1;
       const std::string str = "string example";

### Mapping for basic data types

The basic data types have the mappings shown in the table below. Integer types use the `C99` fixed size integer types as provided by the `stdint.h` standard header (since the `C++` `cstdint` header is not part of the `C++` at the time of writing this document). Users do not have to include this header: the template mapping generation procedure output the appropriate `#include` directive along with the mappings for the integer types.

Table 1. Basic data types mappings in `C++`
IDL | `C++`
--- | ---
`boolean` | `bool`
`unsigned short` | `uint16_t`
`short` | `int16_t`
`unsigned long` | `uint32_t`
`long` | `int32_t`
`unsigned long long` | `uint64_t`
`long long` | `int64_t`
`float` | `float`
`double` | `double`
`char` | `int8_t`
`octet` | `uint8_t`
`any` | type any not implemented yet

### Mapping for enumerated types

The `C++` mapping of an IDL `enum` type is the corresponding `C++` `enum`. An additional constant is generated to guarantee that the type occupies a 32 bits wide integer.

For instance, the following IDL:

          enum e {
             value1,
             value2
          };

would map, according to the scoped names rules, into

          enum e {
             value1,
             value2,
             _unused = 0xffffffff,
          };

### Mapping for strings

`genom3` IDL bounded strings are mapped to nul terminated character arrays (i.e., C strings). Unbounded strings are mapped to `std::string` provided by the `C++` standard.

For instance, the following OMG IDL declarations:

          typedef string unbounded;
          typedef string\<16> bounded;

would map into

          typedef std::string unbounded;
          typedef char bounded[16];

### Mapping for arrays

`genom3` IDL arrays map directly to `C++` arrays. All array indices run from 0 to `size-1`.

For instance, the following IDL:

          typedef long array[4][16];

would map into

          typedef int32_t array[4][16];

### Mapping for structure types

`genom3` IDL structures map directly onto `C++` `struct`s. Note that these structures may potentially include padding.

For instance, the following IDL:

          struct s {
             long a;
             long b;
          };

would map into

          struct s {
             int32_t a;
             int32_t b;
          };

### Mapping for union types

`genom3` IDL unions map onto C `struct`s. The discriminator in the enum is referred to as `_d`, the union itself is referred to as `_u`.

For instance, the following IDL:

          union u switch(long) {
             case 1: long a;
             case 2: float b;
             default: char c;
          };

would map into

          struct u {
             int32_t _d;
             union {
                int32_t a;
                float b;
                char c;
             } _u;
          };

Note that the `C++` standard does not allow union members that have a non-trivial constructor. Consequently, the `C++` mapping for such kind of unions is not allowed in `genom3` either. This concerns `sequence`s and `string`s, and structures or unions that contain such a type. You should thus avoid to define such datatypes in `genom3` IDL in order to maximize the portability of your definitions.

### Mapping for sequence types

`genom3` IDL sequences mapping differ for bounded or unbouded variations of the sequence. The unbounded sequences maps onto the `std::vector` template class provided by the `C++` standard. The bounded sequence maps onto a `C++` `genom::bounded_sequence` template class. The definition of `genom::bounded_sequence` is very similar to `std::array` but provides a variable number of elements.

For instance, the following IDL:

          typedef sequence<long> unbounded;
          typedef sequence<long,16> bounded;

would map into

          typedef std::vector<int32_t> unbounded;
          typedef genom::bounded_sequence<int32_t, 16> bounded;

The interface of `genom::bounded_sequence` is the following:

      template <typename T, size_t N>
      struct bounded_sequence {
        // types:
        typedef T                                     value_type;
        typedef value_type&                           reference;
        typedef const value_type&                     const_reference;
        typedef value_type*                           iterator;
        typedef const value_type*                     const_iterator;
        typedef value_type*                           pointer;
        typedef const value_type*                     const_pointer;
        typedef size_t                                size_type;
        typedef ptrdiff_t                             difference_type;
        typedef std::reverse_iterator<iterator>       reverse_iterator;
        typedef std::reverse_iterator<const_iterator> const_reverse_iterator;

        value_type e[N];
        size_type n;

        // No explicit construct/copy/destroy for aggregate type

        void fill(const value_type &u);

        // iterators:
        iterator begin();
        iterator end();
        const_iterator begin() const;
        const_iterator end() const;

        reverse_iterator rbegin();
        reverse_iterator rend();
        const_reverse_iterator rbegin() const;
        const_reverse_iterator rend() const;

        const_iterator cbegin() const;
        const_iterator cend() const;
        const_reverse_iterator crbegin() const;
        const_reverse_iterator crend() const;

        // capacity:
        size_type size() const;
        void resize(size_type l, value_type u = value_type());
        size_type max_size() const;
        bool empty() const;

        // element access:
        reference operator[](size_type i);
        const_reference operator[](size_type i) const;
        reference at(size_type i);
        const_reference at(size_type i) const;

        reference front();
        const_reference front() const;
        reference back();
        const_reference back() const;
        value_type *data();
        const value_type *data() const;

        // modifiers
        void swap(bounded_sequence &a);
        void clear();
      };

### Mapping for optional types

`genom3` IDL optional types map onto the `genom::optional` template class.

For instance, the following IDL:

          typedef optional< long > opt;

would map into

          typedef genom::optional< int32_t > opt;

The interface of `genom::optional` is the following:

      template <typename T>
      struct optional {
        // types:
        typedef T                                     value_type;
        typedef value_type&                           reference;
        typedef const value_type&                     const_reference;

        bool _present;
        value_type _value;
      };

The `_present` member, when `true`, indicates the presence of valid data in `_value`. When `_present` is `false`, the `_value` should be ignored.

### Mapping for port types

Simple ports map onto a pure virtual `struct` providing a `data()` and `read()` or `write()` methods. The `data()` method takes no parameter and returns a constant reference on the current port data. Input ports may refresh their data by invoking the `read()` method, while output ports may publish new data by invoking the `write()` method. Both `read()` and `write()` return no value (`void`).

Ports defined with the `multiple` flag map onto a similar pure virtual `struct`, with the difference that `data()`, `read()` and `write()` methods take an additional string (`const char *`) parameter representing the port element name. Multiple output ports have two additional `open()` and `close()` members (also accepting a single string parameter) that dynamically create or destroy ports.

All these method may throw a `genom::exception` representing an error code.

For instance, the following IDL:

          port in double in_port;
          port multiple in double multi_in_port;
          port out double out_port;
          port multiple out double multi_out_port;

would map into

          struct in_port {
             virtual const double &data(void) const = 0;
             virtual void read(void) = 0;
          };

          struct multi_in_port {
             virtual const double &data(const char *id) const = 0;
             virtual void read(const char *id) = 0;
          };

          struct out_port {
             virtual double &data(void) const = 0;
             virtual void write(void) = 0;
          };

          struct multi_out_port {
             virtual double &data(const char *id) const = 0;
             virtual void write(const char *id) = 0;
             virtual void open(const char *id) = 0;
             virtual void close(const char *id) = 0;
          };

### Mapping for remote services

Remote objects map onto a pure virtual `struct` providing a `call()` method. `call()` takes the same parameters as the corresponing service definition and return no data (`void`). It may throw a `genom::exception` representing an error code.

For instance, the following IDL:

          interface i {
            function f(in long i, out double o);
          };

          component c {
            uses i;
          };

would map into

          namespace c {
            struct f {
              virtual void call(uint32_t i, double &o) = 0;
            };
          }

The remote service is invoked in a synchronous manner.

### Mapping for native types

`genom3` IDL native types map to a `C++` `struct`. The mapping provides only a forward declaration, and the user has to provide the actual definition.

For instance, the following IDL:

          native opaque;

would map into

          struct opaque;

The definition of the structure body is free, and will typically use native `C++` types that cannot be described in IDL. When used as a parameter of a function, a native type will be passed around as a pointer on the structure data. Memory management associated with that pointer must be handled by the user.

### Mapping for exceptions

Each defined exception type is defined as a `C++` `struct` that derives from the generic `genom::exception` type and implements a `what()` method returning a unique identifier for the exception. Exceptions with members define an additional `struct detail` type inside the scope of the exception as well a a `detail` member of that type. A global identifier for the exception is also defined (it is identical to the return value of the `what` method).

For example:

          exception foo {
            long dummy;
          };

yields the following `C++` declarations:

          genom_event foo_id = <unique identifier for exception>;

          struct foo : public genom::exception {
            struct detail {
              uint32_t dummy;
            } detail;

            const char *what();
          } foo_detail;

Exceptions must be thrown with the `C++` `throw` operator.

The identifier for the exception uniquely identifies this exception type, so that any data of type `genom_event` can be compared to an exception id with the `==` operator.