C
mappings: From IDL types to C
typesThe 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.
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.
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.
IDL | C |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
type any not implemented yet |
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 };
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];
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];
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;
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;
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.
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.
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;
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.
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.
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.