Project

General

Profile

C mappings: From IDL types to C types

Scoped names

The C mappings always use the global name for a type or a constant. The C global name corresponding to a genom3 IDL global name is derived by converting occurrences of "::" to "_" (an underscore) and eliminating the leading underscore.

Mapping for constants

In C, constants defined in dotgen are mapped to a C constant. For instance, the following IDL:

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

would map into

      const uint32_t longint = 1;
      const char *str = "string example";

The identifier can be referenced at any point in the user’s code where a literal of that type is legal.

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. 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 an unsigned, 32 bits wide integer. Each enumerator in an enum is defined in an anonymous enum with an appropriate unsigned integer value conforming to the ordering constraints.

For instance, the following IDL:

      module m {
        enum e {
          value1,
          value2
        };
      };

would map, according to the scoped names rules, into

      typedef uint32_t m_e;
      enum {
        m_value1 = 0
        m_value2 = 1
      };

Mapping for strings

genom3 IDL bounded strings are mapped to nul terminated character arrays (i.e., C strings). Unbounded strings are mapped to a pointer on such a character array.

For instance, the following OMG IDL declarations:

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

would map into

      typedef char *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

      typedef struct {
         int32_t a;
         int32_t b;
      } s;

Mapping for union types

genom3 IDL unions map onto C struct. 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

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

Mapping for sequence types

genom3 IDL sequences mapping differ slightly for bounded or unbouded variations of the sequence. Both types maps onto a C struct, with a _maximum, _length and _buffer members.

For unbounded sequences, buffer points to a buffer of at most _maximum elements and containing _length valid elements. An additional member ` _release` is a function pointer that can be used to release the storage associated to the ` _buffer` and reallocate it. It is the responsibility of the user to maintain the consistency between those members.

For bounded sequences, ` buffer` is an array of at most _maximum elements and containing _length valid elements. Since _buffer is an array, no memory management is necessary for this data type.

For instance, the following IDL:

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

would map into

      typedef struct {
         uint32_t _maximum, _length;
         int32_t *_buffer;
         void (*release)(void *_buffer);
      } unbounded;

      typedef struct {
         uint32_t _maximum, _length;
         int32_t _buffer[16];
      } bounded;

A helper function for reserving space in unbounded sequences is available. It is defined as follow:

      int genom_sequence_reserve(sequence_type *s, uint32_t length);

where sequence_type is the actual type name of the sequence.

Given a pointer s on a valid, unbouded sequence, genom_sequence_reserve will allocate storage for up to length elements. If needed, the previous storage is first released using the function pointed to by _release. If the sequence already had enough space available, genom_sequence_reserve does nothing. New storage is allocated using malloc(), and the _release member is updated to point on the free() function. The _maximum member is updated to reflect the new maximum number of elements that the sequence may hold. Finally, the function returns 0 on success, or -1 if no memory could be allocated (in this case, the global variable errno is updated with the value ENOMEM).

Beware that genom_sequence_reserve is able to shrink a sequence if the length parameter happens to be smaller than the current length of a sequence. In this case, any elements previously stored beyond the new effective length will be definitely lost. The _length member will be updated accordingly.

The use of this function to reserve space in a sequence is purely optional. Any storage allocation strategy can be used, provided it maintains the consistency between the _maximum, _release and _buffer elements.

Mapping for optional types

genom3 IDL optional types map onto C struct with a _present and _value members.

For instance, the following IDL:

      typedef optional< long > opt;

would map into

      typedef struct {
         bool _present;
         int32_t _value;
      } opt;

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 an object-like C struct with a data() and read() or write() function members. The data() function takes no parameter and returns a pointer 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 genom_ok on success, or a genom_event exception representing an error code.

Ports defined with the multiple flag map onto a similar 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.

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

      typedef struct {
         double * (*data)(genom_context self);
         genom_event (*read)(genom_context self);
      } in_port;

      typedef struct {
         double * (*data)(const char *id, genom_context self);
         genom_event (*read)(const char *id, genom_context self);
      } multi_in_port;

      typedef struct {
         double * (*data)(genom_context self);
         genom_event (*write)(genom_context self);
      } out_port;

      typedef struct {
         double * (*data)(const char *id, genom_context self);
         genom_event (*write)(const char *id, genom_context self);
         genom_event (*open)(const char *id, genom_context self);
         genom_event (*close)(const char *id, genom_context self);
      } multi_out_port;

Mapping for remote services

Remote objects map onto an object-like C struct providing a call() method. call() takes the same parameters as the corresponing service definition and returns genom_ok on success, or a genom_event 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

      typedef struct c_f {
        genom_event (*call)(uint32_t i, double *o, genom_context self);
      } c_f;

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

      typedef struct opaque 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 struct tag and a typedef with the C global name for the exception suffixed by _detail. An identifier for the exception is also defined, as is a type-specific function for raising the exception. For example:

      exception foo {
        long dummy;
      };

yields the following C declarations:

      genom_event foo_id = <unique identifier for exception>;

      typedef struct foo_detail {
        uint32_t dummy;
      } foo_detail;

      genom_event foo(const foo_detail *detail, genom_context self);

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.

The function throwing the exception returns a genom_event that should be used as the return value of a codel. It makes a copy of the exception details.

Since exceptions are allowed to have no members, but C structs must have at least one member, exceptions with no members map to the C void type and the type-specific throw function takes no argument.