diff options
author | Yorhel <git@yorhel.nl> | 2013-01-14 16:43:55 +0100 |
---|---|---|
committer | Yorhel <git@yorhel.nl> | 2013-01-14 16:45:05 +0100 |
commit | 1f5b0b880bb81532737cef74615b68176b0b4ef7 (patch) | |
tree | fd8e1cb44d5f19eb58b44bac86d5306b3f71c1b0 | |
parent | 06b08a6945caeb8a888457cf2cf16a3febf377cc (diff) |
ecbuf: Added _unpush() to read back the value last push()ed + more docs
-rw-r--r-- | ecbuf.h | 54 |
1 files changed, 47 insertions, 7 deletions
@@ -26,34 +26,53 @@ * * Usage: * - * ecbuf_t(int) queue; + * ecbuf_t(int) queue, iter; * ecbuf_init(queue); * - * // Writing + * // Writing (by value) * ecbuf_push(queue, 3); * ecbuf_push(queue, 5); * ecbuf_push(queue, 7); - * ecbuf_push(queue, 11); + * // Writing (by pointer) + * int *ptr = ecbuf_pushp(queue); + * *ptr = 11; * * // = 3 * printf("Least recently queued = %d\n", ecbuf_peek(queue)); * // = 4 * printf("Queue length = %d\n", ecbuf_len(queue)); * - * // Reading - * while(!ecbuf_empty(queue)) { + * // Iterating over the items in the same order that they were _push()ed. + * iter = queue; + * while(!ecbuf_empty(iter)) + * printf("Item: %d\n", ecbuf_pop(iter)); + * + * // Iterating over the items in the reverse order. + * iter = queue; + * while(!ecbuf_empty(iter)) + * printf("Item: %d\n", ecbuf_unpush(iter)); + * + * // Reading items in the same order that they were _push()ed. + * // Only difference is that this doesn't use an iterator. Same can be + * // done with _unpush() to read from the other end of the queue. + * while(!ecbuf_empty(queue)) * printf("Item: %d\n", ecbuf_pop(queue)); - * } * * ecbuf_destroy(queue); * + * // Similar to ecbuf_pushp(), there is ecbuf_popp() and ecbuf_unpushp() + * // which return a pointer into the circular buffer. These remain valid + * // until the next ecbuf_push(). Iterators, as illustrated above, also + * // remain valid until the next ecbuf_push(). Modifying a value returned + * // from an iterator will modify it in the main list, too. + * * This library requires the 'typeof' operator of C99 and may therefore not * work in C++. A workaround for this should be quite trivial, however. * * The concept is explained at * http://blog.labix.org/2010/12/23/efficient-algorithm-for-expanding-circular-buffers * - * This implementation is slightly different, in that it is slightly smaller + * This implementation is slightly different, in that it offers more operations * and requires one less variable to keep track of. */ @@ -136,6 +155,27 @@ static inline void *ecbuf__push(ecbuf_vars_t *v, void **a, size_t alen) { #define ecbuf_push(e, x) (*ecbuf_pushp(e) = (x)) +static inline int ecbuf__unpush(ecbuf_vars_t *v) { + int i = v->l + v->o - 1; + if(v->bn != v->cn) i -= v->b + 1; + if(v->o <= v->b) i += v->cn; + i &= v->bn-1; + v->l--; + if(ecbuf__unlikely(i == v->cn)) { + v->b = -1; + /* This change causes bn to be smaller than the actual size of the + * allocated buffer, but this isn't too important. If the extra space + * is needed in the future, _push() will just do a (no-op) realloc() + * and the extra space will be available again. */ + v->bn = v->cn; + } + return i; +} + +#define ecbuf_unpushp(e) ((e).a + ecbuf__unpush(&(e).v)) +#define ecbuf_unpush(e) (*ecbuf_unpushp(e)) + + static inline int ecbuf__pop(ecbuf_vars_t *v) { int l = v->o; v->l--; |