diff options
Diffstat (limited to 'list.h')
-rw-r--r-- | list.h | 140 |
1 files changed, 140 insertions, 0 deletions
@@ -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 |