1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
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;
}
|