summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYorhel <git@yorhel.nl>2013-01-14 16:43:55 +0100
committerYorhel <git@yorhel.nl>2013-01-14 16:45:05 +0100
commit1f5b0b880bb81532737cef74615b68176b0b4ef7 (patch)
treefd8e1cb44d5f19eb58b44bac86d5306b3f71c1b0
parent06b08a6945caeb8a888457cf2cf16a3febf377cc (diff)
ecbuf: Added _unpush() to read back the value last push()ed + more docs
-rw-r--r--ecbuf.h54
1 files changed, 47 insertions, 7 deletions
diff --git a/ecbuf.h b/ecbuf.h
index c279c0e..6c0eacf 100644
--- a/ecbuf.h
+++ b/ecbuf.h
@@ -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--;