summaryrefslogtreecommitdiffstats
path: root/list.h
diff options
context:
space:
mode:
Diffstat (limited to 'list.h')
-rw-r--r--list.h140
1 files changed, 140 insertions, 0 deletions
diff --git a/list.h b/list.h
new file mode 100644
index 0000000..9f6ea60
--- /dev/null
+++ b/list.h
@@ -0,0 +1,140 @@
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include "libaco/aco.h"
+
+struct aco_list {
+ aco_t *co;
+ int fd;
+ struct aco_list *next, *prev;
+};
+
+struct aco_list *aco_list_new () {
+ struct aco_list *head = malloc (sizeof (struct aco_list));
+ memset (head, 0, sizeof (struct aco_list));
+ head->next = head->prev = head;
+ return head;
+}
+
+struct aco_list *aco_list_add (struct aco_list *head, aco_t *co) {
+ struct aco_list *node = malloc (sizeof (struct aco_list));
+ node->co = co;
+ node->prev = head->prev;
+ node->next = head;
+ head->prev = node;
+ return node;
+}
+
+void aco_list_remove (struct aco_list *iter) {
+ if (iter->next == iter)
+ abort();
+ iter->prev->next = iter->next;
+ iter->next->prev = iter->prev;
+}
+
+#define SBO_BUF_SMALL 0x80
+#define SBO_BUF_BIG 0x00
+#define SBO_BUF_MASK 0x80
+#define SBO_BUF_SIZEMASK 0x7f
+#define SBO_BUF_SMALL_MAX_SIZE 0x7f /* 0x80 - 0x1 */
+
+
+typedef struct sbo_buf {
+ unsigned char hdr;
+ union {
+ char small[SBO_BUF_SMALL_MAX_SIZE];
+ struct {
+ char *base;
+ size_t size;
+ size_t alloc;
+ } big;
+ } buf;
+} sbo_buf_t;
+
+
+int sbo_buf_init (sbo_buf_t *buf, char *init, size_t count);
+void sbo_buf_free (sbo_buf_t *buf);
+char *sbo_buf_mem (sbo_buf_t *buf);
+size_t sbo_buf_size (sbo_buf_t *buf);
+int sbo_buf_type (sbo_buf_t *buf);
+int sbo_buf_grow (sbo_buf_t *buf, char *grow, size_t count);
+
+
+int sbo_buf_init0 (sbo_buf_t *buf) {
+ memset (buf, 0, sizeof (*buf));
+ buf->hdr = 0 | SBO_BUF_SMALL;
+ return 0;
+}
+
+
+int sbo_buf_init (sbo_buf_t *buf, char *init, size_t count) {
+ if (count <= (size_t)SBO_BUF_SMALL_MAX_SIZE) {
+ buf->hdr = 0 | SBO_BUF_SMALL;
+ buf->hdr |= (unsigned char) count;
+ memcpy (buf->buf.small, init, count);
+ }
+ else {
+ buf->buf.big.base = malloc (count);
+ if (!buf->buf.big.base)
+ return errno;
+ buf->hdr = 0 | SBO_BUF_BIG;
+ buf->buf.big.size = count;
+ buf->buf.big.alloc = count;
+ }
+ return 0;
+}
+
+void sbo_buf_free (sbo_buf_t *buf) {
+ if (sbo_buf_type (buf) == SBO_BUF_BIG)
+ free (buf->buf.big.base);
+}
+
+inline char *sbo_buf_mem (sbo_buf_t *buf) {
+ if (sbo_buf_type (buf) == SBO_BUF_BIG)
+ return buf->buf.big.base;
+ return buf->buf.small;
+}
+
+inline size_t sbo_buf_size (sbo_buf_t *buf) {
+ if (sbo_buf_type (buf) == SBO_BUF_BIG)
+ return buf->buf.big.size;
+
+ return buf->hdr & SBO_BUF_SIZEMASK;
+}
+
+inline int sbo_buf_type (sbo_buf_t *buf) {
+ return buf->hdr & SBO_BUF_MASK;
+}
+
+int sbo_buf_grow (sbo_buf_t *buf, char *grow, size_t count) {
+ if (count == 0)
+ return 0;
+ //size_t bufsize = sbo_buf_size (buf);
+ if (sbo_buf_type (buf) == SBO_BUF_SMALL) {
+ size_t current_size = sbo_buf_size (buf);
+ if (current_size + count <= (size_t)SBO_BUF_SMALL_MAX_SIZE) {
+ /* no need to become big. just concat two existing buffers */
+ char *dst = sbo_buf_mem (buf) + current_size;
+ memcpy (dst, grow, count);
+ buf->hdr += count;
+ return 0;
+ }
+ /* fallthrough to realloc */
+ }
+
+ char *base = sbo_buf_mem (buf);
+ size_t len = sbo_buf_size (buf);
+ char *newbuf = malloc (len + count);
+ if (!newbuf)
+ return errno;
+
+ memcpy (newbuf, base, len);
+ memcpy (newbuf + len, grow, count);
+ sbo_buf_free (buf);
+ buf->hdr = 0 | SBO_BUF_BIG; /* We definitely exceeded small buffer */
+ buf->buf.big.base = newbuf;
+ buf->buf.big.alloc = len + count;
+ buf->buf.big.size = len + count;
+
+ return 0;
+} \ No newline at end of file