Next: Data Packet Creation and Deletion, Previous: Manipulating Data Packet Fields, Up: Manipulating Data Packet Fields
Unlike header fields, which always use a name and index combination to
access field information, there are two methods of accessing data packet
fields. If a single data packet is being read or written, and the same
memory is used for all packets, and all that is required is a
pointer to the data in the data packet, then the simplest approach is to
use bpipe_dpktf_datap
. Note that bpipe_dpktf_datap
must
be called after the core image is mapped (via bpipe_map
or
bpipe_map_alloc
).
Here's an approach if you only need to look at one field in a data packet:
BPipe *bpipe; DVector3 *pos; void *core; /* create bpipe, set input stream */ ... /* map data packet images */ if ( NULL == ( core = bpipe_map_alloc( bpipe, 1, NULL ) ) ) { (error handling code) } /* get pointer to position field in data packet */ if ( NULL == ( pos = (DVector3 *) bpipe_dpktf_datap( bpipe, core, "position", BPDType_DVector3 ) ) ) { (error handling code) }
This usually gets unwieldy if there is more than one data field that is being accessed. Here's a way around that:
DVector3 *pos; DVector3 *dir; pos = (DVector3 *) dpktf_data( bpipe, core, "position", BPDType_DVector3 ); dir = (DVector3 *) dpktf_data( bpipe, core, "direction", BPDType_DVector3 ); ... void * dpktf_data( BPipe *bpipe, char *name, void *core_image, BPDataType *type ) { void *data = bpipe_dpktf_datap( bpipe, core_image, name, type ); if ( NULL == data ) { (error handling code) } return data; }
Note that in these examples, space for a single data packet is allocated and used for each data packet, so the addresses of the data packet fields are constant. This is typical of most applications. In this situation all data offsets should be determined before reading in the data.
However, if multiple data packets are processed at once (e.g., several
are read in at a time), it is necessary to redetermine the positions of
the fields for each data packet processed. Since
bpipe_dpktf_datap
is a function, this can be expensive. The
solution to this is to use a different access mechanism, via data packet
field handles. Because one can obtaining a pointer to the field in the
data packet directly from the handle (via a C
preprocessor macro,
rather than a function) this is a much more efficient way of accessing
data from within a loop, especially if processing several data packets
at once.
A data packet field handle is first retrieved via bpipe_dpktf
.
(This routine can also be used to determine if a data packet field
already exists.) After mapping of the images, the offset of the data
field in the core image is available, and can be retrieved with
bpipe_dpktf_offset
. Pointers into the core image of the data
packet are available from bpipe_dpktf_arr
and
bpipe_dpktf_data
. Field data is available only after a
data packet has been read in via bpipe_read_dpkts
. At that point
the data can be retrieved with bpipe_dpktf_val
or
bpipe_dpktf_valn
.
The following example illustrates a few ways of getting at the data in this situation.
BPipe *bpipe; DpktField *dpktf; DVector3 *pos; void *core_image; size_t core_image_size, n_pkts, pos_offset; /* create bpipe, set input stream */ ... /* map data packet images */ if ( NULL == ( core_image = bpipe_map_alloc( bpipe, NPKTS, &core_image_size ) ) ) { (error handling code) } if ( NULL == ( dpktf = bpipe_dpktf( bpipe, "position" ) ) { (error handling code) } pos = (DVector3 *) bpipe_dpktf_data(dpktf, core_image); pos_offset = bpipe_dpktf_offset( dpktf ); bpipe_errno = BPNOERROR; while ( (n_pkts = bpipe_read_dpkts( bpipe, core_image, NPKTS)) > 0 ) { DVector3 *tpos = pos; /* location of the "position" data */ void *pkt = core_image; void *pkt_lim = core_image + n_pkts; /* tpos will point at the location of the "position" data in the current data packet. this algorithm uses the fact that the data in a succeeding packet are always core_image_size bytes from those in the preceeding packet */ for (; pkt < pkt_lim ; pkt += core_image_size, tpos += core_image_size ) { double dist2; /* tpos may be calculated as above, or directly calculated here as follows */ tpos = (DVector3 *) ((char *) pkt + pos_offset); dist2 = tpos->x * tpos->x + tpos->y * tpos->y + tpos->z * tpos->z; } } if ( bpipe_errno != BPNOERR ) { (error handling code) }
Retrieval of all other field information requires a data packet field handle as well.
If the program needs to go through the list of fields sequentially,
repeated calls to bpipe_dpktf_next
will step through the
the fields, retrieving handles for each field.
Some information is available before the mapping of data packet images
by bpipe_map
or bpipe_map_alloc
. This includes a field's
matrix (bpipe_dpktf_matrix
), type (bpipe_dpktf_type
). and
name (bpipe_dpktf_name
). The latter is useful when stepping
through the list of fields via bpipe_dpktf_next
. For an
interesting application of this, see bpipe_dump.