Next: Synchrony
Up: Basics
Previous: dicerc file
  Contents
Types
A type in DICElib is a variable type. To share variables between
computers, DICElib has to store them internally in such a way that
it may be sent to the other nodes.
Types are registed automatically when you start your program. Once
registered, a type will exist until DICElib is closed. Types consume
a very small amount of memory, and you may register as many as you
like. Note that types are case sensitive.
If you want to define a new type, you must write three functions:
-
- char *foo_pack (void *data, int *n);
void *foo_unpack (char *data, int *n);
void foo_free (void *data);
if any of the three is not available, the type won't be registered.
Now, what do these functions do?
- [foo_pack]receives the data of the type you registered, cast to void
*, and a pointer to an integer. Its function is to return a string,
which you made from the data, and to store the string size in the
pointer.
- [foo_unpack]receives a string that was packed by foo_pack, and a
pointer to an integer. Its function is to parse the string and convert
it to the variable type foo, returning this value, and to return the
number of bytes that were used of the original string. Remember: there
may be more data in the string that is part of another variable. The
only guarantee you have is that the first character of the string
is also the first character of your packed data.
- [foo_free]frees the foo type. It's useful for composed types, such
as structures, etc.
You can access these three functions indirectly, using respectively:
-
- char *DICE_type_pack ( char *type, void *data, int *n );
void *DICE_type_unpack ( char *type, char *packet, int *n );
int DICE_type_free ( char *type, void *data );
They are work exactly like the above description, but receive the
type as an extra argument.
DICElib provides some default types2.1. All of them receive pointers to the data, so pass by reference:
- [unsigned_char]Unsigned char. Supposed to be a one-byte,
unsigned integer.
- [signed_char]Signed char. Supposed to be a one-byte, signed
integer.
- [unsigned_short]Unsigned short. Supposed to be a two-byte,
unsigned integer.
- [signed_short]Signed short. Supposed to be a two-byte, signed
integer.
- [unsigned_long]Unsigned long. Supposed to be a four-byte,
unsigned integer.
- [signed_long]Signed long. Supposed to be a four-byte, signed
integer.
- [float]Floating number, 6 digits of precision (uses 6 bytes).
- [double]Floating number, 16 digits of precision (uses 12
bytes).
- [float754]IEEE 754 float (4 bytes). No loss of precision.
- [double754]IEEE 754 float (8 bytes). No loss of precision.
- [string]A `\0' terminated string of chars.
Last, but not least, in order for DICElib to find your new
types automatically, you must define the DICE_MyTypes variable:
-
- DICE_Type DICE_MyTypes[] = {
-
- { "foo type", foo_pack, foo_unpack, foo_free },
{ NULL, NULL, NULL, NULL }
};
It's a simple array of structures, and each structure should get (in
this order): the type name, the pack functions, the unpack function,
and the free function. Important: the last element of the array
must be { NULL, NULL, NULL, NULL }.
If you don't create any new types, you have to add this line
to your code, declaring it as you would declare a global variable:
-
- DICE_no_types;
Since I'm sure you are completely lost, it's time for an example.
Suppose your application works with 3D floating points vectors, like:
-
- float vec[3];
and you want to share this type. You may consider it as 3 floats,
etc, but it's easier to work it as a whole thing. So, here are the
three functions:
-
- char *float3_pack ( void *data, int *n ) {
-
- char *buf, *t;
float *vec;
int m;
/* reconvert the data to float, so we can work with it */
vec = (float *)data;
/* allocate memory for the packet *//
buf = (char *)malloc(3*4);
if ( !buf )
-
- return NULL;
/* now pack it using DICElib's floats */
t = DICE_type_pack("float", (void *)&vec[0], &m);
memcpy(buf, t, 4);
free(t);
t = DICE_type_pack("float", (void *)&vec[1], &m);
memcpy(buf+4, t, 4);
free(t);
t = DICE_type_pack("float", (void *)&vec[2], &m);
memcpy(buf+8, t, 4);
free(t);
*n = 12;
return buf;
}
void *float3_unpack ( char *data, int *n ) {
-
- float *vec, *f;
int m;
/* malloc memory for the float */
vec = (float *)malloc(3*sizeof(float));
/* three floats */
if ( !vec )
-
- return NULL;
f = (float *)DICE_type_unpack("float", data, &m);
vec[0] = *f;
free(f);
f = (float *)DICE_type_unpack("float", data+4, &m);
vec[1] = *f; free(f);
f = (float *)DICE_type_unpack("float", data+8, &m);
vec[2] = *f;
free(f);
*n = 12;
return (void *)vec;
}
void float3_free ( void *data ) {
-
- if ( data ) free(data);
}
DICE_Type DICE_MyTypes[] = {
-
- { "float3", float3_pack, float3_unpack, float3_free },
{ NULL, NULL, NULL, NULL }
};
The new type name is float3. The pack and unpack functions
use the existing float type to send it. This is a simple example,
and it supposes that the float type is 4 bytes long, etc.
Take a look at the tests/ subdirectory, in special the var_test
and rotate programs, for more examples.
Declaration of variables is dealt in the next chapters. Take notice
that, while it's practical to setup arrays as a type, the entire array
is transferred even if just one variable is changed, so it might not
be the wisest solution.
Next: Synchrony
Up: Basics
Previous: dicerc file
  Contents
2001-12-09