/src/mozilla-central/third_party/msgpack/src/vrefbuffer.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * MessagePack for C zero-copy buffer implementation |
3 | | * |
4 | | * Copyright (C) 2008-2009 FURUHASHI Sadayuki |
5 | | * |
6 | | * Distributed under the Boost Software License, Version 1.0. |
7 | | * (See accompanying file LICENSE_1_0.txt or copy at |
8 | | * http://www.boost.org/LICENSE_1_0.txt) |
9 | | */ |
10 | | #include "msgpack/vrefbuffer.h" |
11 | | #include <stdlib.h> |
12 | | #include <string.h> |
13 | | |
14 | 0 | #define MSGPACK_PACKER_MAX_BUFFER_SIZE 9 |
15 | | |
16 | | struct msgpack_vrefbuffer_chunk { |
17 | | struct msgpack_vrefbuffer_chunk* next; |
18 | | /* data ... */ |
19 | | }; |
20 | | |
21 | | bool msgpack_vrefbuffer_init(msgpack_vrefbuffer* vbuf, |
22 | | size_t ref_size, size_t chunk_size) |
23 | 0 | { |
24 | 0 | size_t nfirst; |
25 | 0 | struct iovec* array; |
26 | 0 | msgpack_vrefbuffer_chunk* chunk; |
27 | 0 |
|
28 | 0 | vbuf->chunk_size = chunk_size; |
29 | 0 | vbuf->ref_size = |
30 | 0 | ref_size > MSGPACK_PACKER_MAX_BUFFER_SIZE + 1 ? |
31 | 0 | ref_size : MSGPACK_PACKER_MAX_BUFFER_SIZE + 1 ; |
32 | 0 |
|
33 | 0 | nfirst = (sizeof(struct iovec) < 72/2) ? |
34 | 0 | 72 / sizeof(struct iovec) : 8; |
35 | 0 |
|
36 | 0 | array = (struct iovec*)malloc( |
37 | 0 | sizeof(struct iovec) * nfirst); |
38 | 0 | if(array == NULL) { |
39 | 0 | return false; |
40 | 0 | } |
41 | 0 | |
42 | 0 | vbuf->tail = array; |
43 | 0 | vbuf->end = array + nfirst; |
44 | 0 | vbuf->array = array; |
45 | 0 |
|
46 | 0 | chunk = (msgpack_vrefbuffer_chunk*)malloc( |
47 | 0 | sizeof(msgpack_vrefbuffer_chunk) + chunk_size); |
48 | 0 | if(chunk == NULL) { |
49 | 0 | free(array); |
50 | 0 | return false; |
51 | 0 | } |
52 | 0 | else { |
53 | 0 | msgpack_vrefbuffer_inner_buffer* const ib = &vbuf->inner_buffer; |
54 | 0 |
|
55 | 0 | ib->free = chunk_size; |
56 | 0 | ib->ptr = ((char*)chunk) + sizeof(msgpack_vrefbuffer_chunk); |
57 | 0 | ib->head = chunk; |
58 | 0 | chunk->next = NULL; |
59 | 0 |
|
60 | 0 | return true; |
61 | 0 | } |
62 | 0 | } |
63 | | |
64 | | void msgpack_vrefbuffer_destroy(msgpack_vrefbuffer* vbuf) |
65 | 0 | { |
66 | 0 | msgpack_vrefbuffer_chunk* c = vbuf->inner_buffer.head; |
67 | 0 | while(true) { |
68 | 0 | msgpack_vrefbuffer_chunk* n = c->next; |
69 | 0 | free(c); |
70 | 0 | if(n != NULL) { |
71 | 0 | c = n; |
72 | 0 | } else { |
73 | 0 | break; |
74 | 0 | } |
75 | 0 | } |
76 | 0 | free(vbuf->array); |
77 | 0 | } |
78 | | |
79 | | void msgpack_vrefbuffer_clear(msgpack_vrefbuffer* vbuf) |
80 | 0 | { |
81 | 0 | msgpack_vrefbuffer_chunk* c = vbuf->inner_buffer.head->next; |
82 | 0 | msgpack_vrefbuffer_chunk* n; |
83 | 0 | while(c != NULL) { |
84 | 0 | n = c->next; |
85 | 0 | free(c); |
86 | 0 | c = n; |
87 | 0 | } |
88 | 0 |
|
89 | 0 | { |
90 | 0 | msgpack_vrefbuffer_inner_buffer* const ib = &vbuf->inner_buffer; |
91 | 0 | msgpack_vrefbuffer_chunk* chunk = ib->head; |
92 | 0 | chunk->next = NULL; |
93 | 0 | ib->free = vbuf->chunk_size; |
94 | 0 | ib->ptr = ((char*)chunk) + sizeof(msgpack_vrefbuffer_chunk); |
95 | 0 |
|
96 | 0 | vbuf->tail = vbuf->array; |
97 | 0 | } |
98 | 0 | } |
99 | | |
100 | | int msgpack_vrefbuffer_append_ref(msgpack_vrefbuffer* vbuf, |
101 | | const char* buf, size_t len) |
102 | 0 | { |
103 | 0 | if(vbuf->tail == vbuf->end) { |
104 | 0 | const size_t nused = (size_t)(vbuf->tail - vbuf->array); |
105 | 0 | const size_t nnext = nused * 2; |
106 | 0 |
|
107 | 0 | struct iovec* nvec = (struct iovec*)realloc( |
108 | 0 | vbuf->array, sizeof(struct iovec)*nnext); |
109 | 0 | if(nvec == NULL) { |
110 | 0 | return -1; |
111 | 0 | } |
112 | 0 | |
113 | 0 | vbuf->array = nvec; |
114 | 0 | vbuf->end = nvec + nnext; |
115 | 0 | vbuf->tail = nvec + nused; |
116 | 0 | } |
117 | 0 |
|
118 | 0 | vbuf->tail->iov_base = (char*)buf; |
119 | 0 | vbuf->tail->iov_len = len; |
120 | 0 | ++vbuf->tail; |
121 | 0 |
|
122 | 0 | return 0; |
123 | 0 | } |
124 | | |
125 | | int msgpack_vrefbuffer_append_copy(msgpack_vrefbuffer* vbuf, |
126 | | const char* buf, size_t len) |
127 | 0 | { |
128 | 0 | msgpack_vrefbuffer_inner_buffer* const ib = &vbuf->inner_buffer; |
129 | 0 | char* m; |
130 | 0 |
|
131 | 0 | if(ib->free < len) { |
132 | 0 | msgpack_vrefbuffer_chunk* chunk; |
133 | 0 | size_t sz = vbuf->chunk_size; |
134 | 0 | if(sz < len) { |
135 | 0 | sz = len; |
136 | 0 | } |
137 | 0 |
|
138 | 0 | chunk = (msgpack_vrefbuffer_chunk*)malloc( |
139 | 0 | sizeof(msgpack_vrefbuffer_chunk) + sz); |
140 | 0 | if(chunk == NULL) { |
141 | 0 | return -1; |
142 | 0 | } |
143 | 0 | |
144 | 0 | chunk->next = ib->head; |
145 | 0 | ib->head = chunk; |
146 | 0 | ib->free = sz; |
147 | 0 | ib->ptr = ((char*)chunk) + sizeof(msgpack_vrefbuffer_chunk); |
148 | 0 | } |
149 | 0 |
|
150 | 0 | m = ib->ptr; |
151 | 0 | memcpy(m, buf, len); |
152 | 0 | ib->free -= len; |
153 | 0 | ib->ptr += len; |
154 | 0 |
|
155 | 0 | if(vbuf->tail != vbuf->array && m == |
156 | 0 | (const char*)((vbuf->tail-1)->iov_base) + (vbuf->tail-1)->iov_len) { |
157 | 0 | (vbuf->tail-1)->iov_len += len; |
158 | 0 | return 0; |
159 | 0 | } else { |
160 | 0 | return msgpack_vrefbuffer_append_ref(vbuf, m, len); |
161 | 0 | } |
162 | 0 | } |
163 | | |
164 | | int msgpack_vrefbuffer_migrate(msgpack_vrefbuffer* vbuf, msgpack_vrefbuffer* to) |
165 | 0 | { |
166 | 0 | size_t sz = vbuf->chunk_size; |
167 | 0 |
|
168 | 0 | msgpack_vrefbuffer_chunk* empty = (msgpack_vrefbuffer_chunk*)malloc( |
169 | 0 | sizeof(msgpack_vrefbuffer_chunk) + sz); |
170 | 0 | if(empty == NULL) { |
171 | 0 | return -1; |
172 | 0 | } |
173 | 0 | |
174 | 0 | empty->next = NULL; |
175 | 0 |
|
176 | 0 | { |
177 | 0 | const size_t nused = (size_t)(vbuf->tail - vbuf->array); |
178 | 0 | if(to->tail + nused < vbuf->end) { |
179 | 0 | struct iovec* nvec; |
180 | 0 | const size_t tosize = (size_t)(to->tail - to->array); |
181 | 0 | const size_t reqsize = nused + tosize; |
182 | 0 | size_t nnext = (size_t)(to->end - to->array) * 2; |
183 | 0 | while(nnext < reqsize) { |
184 | 0 | size_t tmp_nnext = nnext * 2; |
185 | 0 | if (tmp_nnext <= nnext) { |
186 | 0 | nnext = reqsize; |
187 | 0 | break; |
188 | 0 | } |
189 | 0 | nnext = tmp_nnext; |
190 | 0 | } |
191 | 0 |
|
192 | 0 | nvec = (struct iovec*)realloc( |
193 | 0 | to->array, sizeof(struct iovec)*nnext); |
194 | 0 | if(nvec == NULL) { |
195 | 0 | free(empty); |
196 | 0 | return -1; |
197 | 0 | } |
198 | 0 | |
199 | 0 | to->array = nvec; |
200 | 0 | to->end = nvec + nnext; |
201 | 0 | to->tail = nvec + tosize; |
202 | 0 | } |
203 | 0 |
|
204 | 0 | memcpy(to->tail, vbuf->array, sizeof(struct iovec)*nused); |
205 | 0 |
|
206 | 0 | to->tail += nused; |
207 | 0 | vbuf->tail = vbuf->array; |
208 | 0 |
|
209 | 0 | { |
210 | 0 | msgpack_vrefbuffer_inner_buffer* const ib = &vbuf->inner_buffer; |
211 | 0 | msgpack_vrefbuffer_inner_buffer* const toib = &to->inner_buffer; |
212 | 0 |
|
213 | 0 | msgpack_vrefbuffer_chunk* last = ib->head; |
214 | 0 | while(last->next != NULL) { |
215 | 0 | last = last->next; |
216 | 0 | } |
217 | 0 | last->next = toib->head; |
218 | 0 | toib->head = ib->head; |
219 | 0 |
|
220 | 0 | if(toib->free < ib->free) { |
221 | 0 | toib->free = ib->free; |
222 | 0 | toib->ptr = ib->ptr; |
223 | 0 | } |
224 | 0 |
|
225 | 0 | ib->head = empty; |
226 | 0 | ib->free = sz; |
227 | 0 | ib->ptr = ((char*)empty) + sizeof(msgpack_vrefbuffer_chunk); |
228 | 0 | } |
229 | 0 | } |
230 | 0 |
|
231 | 0 | return 0; |
232 | 0 | } |