PreviousNext

The transmit_as Attribute

The [transmit_as] attribute provides applications a way to do their own marshalling of data types. This is primarily useful as a way to deal with data structures that the stubs cannot marshall efficiently, such as sparse arrays. Following is an example of code to compress and reconstruct a large array by removing and then replacing all the zero-valued elements:

The .idl declarations are as follows:

/*
* Transmit_as example: Here we turn a large sparse array into
* a small conformant array for transmission. The server is able
* to reconstitute the sparse array.
*/

const long int S_ARRAY_SIZE = 32;

typedef struct{
unsigned32 value;
unsigned32 subscript;
} a_element;

typedef struct{
unsigned32 size;
[size_is(size)] a_element array[];
}compact_array_t;

typedef [transmit_as(compact_array_t)] unsigned32 sparse_array_t[S_ARRAY_SIZE];

void ship_array(
[in] handle_t handle,
[in] sparse_array_t *array,
[out] error_status_t *status

);

All the callback routines are placed in a single module that is linked with both client and server (in this case, for the test interface). As an alternative, the appropriate callbacks could be declared separately within the client and server modules:

/*
* test_xmit.c:
*
* The routines required to implement a [transmit_as] type.
*/

#include "test.h"

/* The to_xmit routine must allocate all space for the transmitted
* type. In general, the stubs have no way to determine how to allocate
* space for the transmitted type. Here, for example, the to_xmit
* routine determines the size of a conformant array.
*/

void sparse_array_t_to_xmit(sparse_array_t *s_array,
compact_array_t **c_array
)
{
unsigned32 i,j;
unsigned32 csize;

/* Count up the number of nonzero elements in the sparse array */

for (i = 0, csize = 0; i < S_ARRAY_SIZE; i++)
{
if ((*s_array)[i] != 0)
{
csize++;
}
}

/* Allocate a structure to hold the compact array */

*c_array = (compact_array_t *)calloc(csize*2 + 1, sizeof(unsigned32));
((compact_array_t)**c_array).size = csize;

/* Fill in the compact array from the nonzero elements */

for (i = 0, j = 0; i < S_ARRAY_SIZE; i++)
{
if ((*s_array)[i] != 0)
{
((compact_array_t)**c_array).array[j].value = (*s_array)[i];
((compact_array_t)**c_array).array[j++].subscript = i;
}
}
}
/*
* The from_xmit routine may not have to allocate any space for the
* presented type. The presented type is always of a definite size
* (conformant, varying, etc. types are not permitted), so the stub
* provides an instance of the top level of the presented type. In
* this case, for example, s_array points to an instance of a sparse
* array. If the presented type contains any pointers, the from_xmit
* routine needs to allocate space for the referents and the free_inst
* routine needs to free them.
*/

void sparse_array_t_from_xmit(compact_array_t *c_array,
sparse_array_t *s_array)
{
unsigned32 i,j;
for (i = 0; i < ((compact_array_t) * c_array).size; i++)
{
j = ((compact_array_t)*c_array).array[i].subscript;
(*s_array)[j] = ((compact_array_t)*c_array).array[i].value;
}
}

/* This routine is called to free anything allocated by the
* to_xmit routine.
*/

void sparse_array_t_free_xmit(compact_array_t *c_array)
{
free(c_array);
}

/* This routine is called to free anything allocated by the
* from_xmit routine. Since from_xmit doesn't allocate anything
* this is a null routine.
*/

void sparse_array_t_free_inst(sparse_array_t *s_array)
{

}

The client code to exercise the sparse array transmitted type is as follows:

sparse_array_t test_array;

/* Create a sparse array with only three nonzero members */

memset(test_array,0,sizeof(unsigned32)*S_ARRAY_SIZE);
test_array[0] = 2;
test_array[20] = 4;
test_array[31] = 8;

/*
* When compressed, this array requires 7 32-bit integers, as opposed
* 32 32-bit integers for the uncompressed array. If you don't care
* about reconstructing the sparse array on the server side, you can
* get even more efficiency.
*/

ship_array(binding_h, &test_array, &status);

The server manager code is as follows:

void ship_array(
handle_t binding_h,
sparse_array_t *array,
error_status_t *status
)
{
int i;

/*
* Print the elements of the sparse array.
*/

for (i = 0; i < S_ARRAY_SIZE; i++)
{
printf("%i0, (*array)[i]);
}
*status = error_status_ok;
}

Note that the free_inst routine will not be needed if the transmitted type does not contain pointers. However, the routine is called by the stub automatically in any case, so at least a null routine must be provided. As an exercise, you might add printf( )s to each callback to see when it is called. You could also add code to show the format of the transmitted array before it is reconstructed by the from_xmit routine. Finally, you can create an even more efficient compression by not attempting to reconstruct the original array on the server side.