* Both the head and tail of the queue can be accessed and pushed to,
* but only the head can be popped from.
*
- * @note The implementation uses a singly linked list of blocks
+ * @note The implementation uses a singly linked list of blocks ("chunks")
* where each block stores an array of values (for better efficiency).
*
* Example usage:
struct queue_chunk;
struct queue {
- size_t len;
- uint16_t chunk_cap, item_size;
- struct queue_chunk *head, *tail;
+ size_t len; /**< the current number of items in queue */
+ uint16_t chunk_cap; /**< max. number of items in each chunk */
+ uint16_t item_size; /**< sizeof() each item */
+ struct queue_chunk *head, *tail; /*< first and last chunk (or NULLs) */
};
struct queue_chunk {
- struct queue_chunk *next; /*< head -> ... -> tail */
+ struct queue_chunk *next; /*< *head -> ... -> *tail; each is non-empty */
int16_t begin, end, cap, pad_; /*< indices: zero is closest to head */
/*< We could fit into uint8_t for example, but the choice of (3+1)*2 bytes
* is a compromise between wasting space and getting a good alignment.
* In particular, queue_t(type*) will store the pointers on addresses
- * aligned to the pointer size, in both 64-bit and 32-bit platforms.
+ * aligned to the pointer size, on both 64-bit and 32-bit platforms.
*/
char data[];
/**< The item data. We use "char" to satisfy the C99+ aliasing rules.
{
assert(q);
struct queue_chunk *h = q->head;
- if (unlikely(!h))
- return NULL;
- assert(h->end > h->begin);
+ assert(h && h->end > h->begin);
return h->data + h->begin * q->item_size;
}
{
assert(q);
struct queue_chunk *t = q->tail;
- if (unlikely(!t))
- return NULL;
- assert(t->end > t->begin);
+ assert(t && t->end > t->begin);
return t->data + (t->end - 1) * q->item_size;
}