The public C sequence interface uses mco_seq_iterator_t, declared in mcoseq.h, both as a
cursor over stored sequence values and as a node in a lazy sequence-expression pipeline.
typedef struct mco_seq_iterator_t_ mco_seq_iterator_t;
typedef mco_seq_iterator_t* mco_seq_iterator_h;
The complete structure is public so that applications can allocate iterators without an additional heap allocation and advanced code can process tiles directly. Most fields contain implementation state. Applications should initialize an iterator to zero, pass its address to an iterator constructor, and use public sequence functions to consume or reset it.
An iterator constructor can be a generated sequence-field function such as classname_fieldname_iterator(),
or a generic operation such as mco_seq_add_float(). Generic operations normally store pointers to their
operand iterators rather than copying or materializing them.
mco_seq_tee().memcpy.The preferred traversal interface is mco_seq_next_TYPE():
MCO_RET mco_seq_next_TYPE(mco_seq_iterator_h iterator,
mco_TYPE* value);
TYPE is one of the scalar type suffixes supported by the operation. A successful call returns
MCO_S_OK and one logical sequence element. MCO_S_CURSOR_END indicates normal exhaustion.
For a NULL element, the function returns MCO_E_SEQ_NULL_VALUE, advances the iterator, and leaves the
payload unspecified.
Typed traversal has the same logical behavior with plain and RLE sequence libraries. The RLE implementation expands each run so that the application receives one value per logical element.
Iterator constructors install the correct reset callback for the iterator and its operand shape. Use that callback when a pipeline must be traversed again:
MCO_RET rc;
if (iterator.reset == NULL)
rc = MCO_E_ILLEGAL_PARAM;
else
rc = iterator.reset(&iterator);
The public functions mco_seq_reset_iterator(), mco_seq_reset_unary_iterator(), and
mco_seq_reset_binary_iterator() implement the standard reset callbacks for source, unary, and binary
iterators. They are useful when implementing a custom iterator. Normal application code should call the callback
already installed in the iterator instead of selecting one of these functions itself.
Direct tile traversal avoids one function call per logical element but couples the application to the physical
representation. Call the iterator's next callback to load a tile. The following fields are relevant
after next returns MCO_S_OK:
elem_type and elem_sizetile_size
tile.u.arr_TYPE
tile.null_bitmap
first_seq_no, next_seq_no, and last_seq_noThe current tile container is declared as follows:
typedef union mco_seq_payload_t_ {
/* arr_int1, arr_int2, ..., arr_datetime,
arr_float, arr_double, and arr_char */
} mco_seq_payload_t;
typedef struct mco_seq_tile_t_ {
mco_bitmap_word_t null_bitmap[MCO_SEQ_NULL_BITMAP_SIZE];
mco_seq_payload_t u;
} mco_seq_tile_t;
The following example correctly sums a float iterator with either sequence implementation. With plain
sequences, mco_seq_rle_count() returns 1. With RLE, it returns the logical multiplicity of the physical run:
mco_uint2 i;
mco_seq_rle_count_t count;
double sum = 0.0;
MCO_RET rc;
while ((rc = iterator.next(&iterator)) == MCO_S_OK)
{
for (i = 0; i < iterator.tile_size; ++i)
{
count = mco_seq_rle_count(&iterator, (int)i);
if (!MCO_SEQ_IS_NULL(&iterator, i))
sum += (double)iterator.tile.u.arr_float[i] * count;
}
}
if (rc == MCO_S_CURSOR_END)
rc = MCO_S_OK;
Do not zip independently compressed RLE fields by physical tile index. Their run boundaries can differ even when their logical lengths are equal. Use typed logical traversal, decode each stream, or use an RLE-aware multi-input sequence operator.
The callback fields use the following public types:
typedef MCO_RET (*mco_seq_iterator_next_t)(
mco_seq_iterator_h iterator);
typedef MCO_RET (*mco_seq_iterator_reset_t)(
mco_seq_iterator_h iterator);
typedef MCO_RET (*mco_seq_iterator_prepare_t)(
mco_seq_iterator_h iterator);
typedef MCO_RET (*mco_seq_iterator_merge_t)(
mco_seq_iterator_h dst,
mco_seq_iterator_h src);
next produces the next physical tile, reset rewinds local and operand state, and
prepare and merge support operators that can be evaluated in parallel. Applications
consuming standard iterators call the installed callbacks; only custom iterator implementations assign them.
The callback pointers next, reset, prepare, and merge; operand
pointers; context storage; buffer ownership flags; RLE offsets; parallel-processing fields; and binding state are
maintained by sequence constructors. Do not modify them unless implementing a custom iterator according to the
contracts in mcoseq.h.
Some operators allocate temporary memory, and some hash operators maintain separate hash state. Follow the lifecycle
documented for the constructing function. mco_seq_free_buffer() releases only a buffer owned by the
specified iterator and does not recursively release its operands.
Generated search and range functions use mco_seq_boundary_kind_t:
typedef enum mco_seq_boundary_kind_t_ {
MCO_SEQ_BOUNDARY_OPEN,
MCO_SEQ_BOUNDARY_INCLUSIVE,
MCO_SEQ_BOUNDARY_EXCLUSIVE
} mco_seq_boundary_kind_t;
An open boundary omits that end of the range. Inclusive and exclusive boundaries include or exclude the specified key. Sequence positions and boundaries are logical element positions for both plain and RLE implementations.