emitter.c (7075B)
1 #include <stdlib.h> 2 3 #include "flatcc/flatcc_rtconfig.h" 4 #include "flatcc/flatcc_emitter.h" 5 6 static int advance_front(flatcc_emitter_t *E) 7 { 8 flatcc_emitter_page_t *p = 0; 9 10 if (E->front && E->front->prev != E->back) { 11 E->front->prev->page_offset = E->front->page_offset - FLATCC_EMITTER_PAGE_SIZE; 12 E->front = E->front->prev; 13 goto done; 14 } 15 if (!(p = FLATCC_EMITTER_ALLOC(sizeof(flatcc_emitter_page_t)))) { 16 return -1; 17 } 18 E->capacity += FLATCC_EMITTER_PAGE_SIZE; 19 if (E->front) { 20 p->prev = E->back; 21 p->next = E->front; 22 E->front->prev = p; 23 E->back->next = p; 24 E->front = p; 25 goto done; 26 } 27 /* 28 * The first page is shared between front and back to avoid 29 * double unecessary extra allocation. 30 */ 31 E->front = p; 32 E->back = p; 33 p->next = p; 34 p->prev = p; 35 E->front_cursor = E->front->page + FLATCC_EMITTER_PAGE_SIZE / 2; 36 E->back_cursor = E->front_cursor; 37 E->front_left = FLATCC_EMITTER_PAGE_SIZE / 2; 38 E->back_left = FLATCC_EMITTER_PAGE_SIZE - E->front_left; 39 p->page_offset = -(flatbuffers_soffset_t)E->front_left; 40 return 0; 41 done: 42 E->front_cursor = E->front->page + FLATCC_EMITTER_PAGE_SIZE; 43 E->front_left = FLATCC_EMITTER_PAGE_SIZE; 44 E->front->page_offset = E->front->next->page_offset - FLATCC_EMITTER_PAGE_SIZE; 45 return 0; 46 } 47 48 static int advance_back(flatcc_emitter_t *E) 49 { 50 flatcc_emitter_page_t *p = 0; 51 52 if (E->back && E->back->next != E->front) { 53 E->back = E->back->next; 54 goto done; 55 } 56 if (!(p = FLATCC_EMITTER_ALLOC(sizeof(flatcc_emitter_page_t)))) { 57 return -1; 58 } 59 E->capacity += FLATCC_EMITTER_PAGE_SIZE; 60 if (E->back) { 61 p->prev = E->back; 62 p->next = E->front; 63 E->front->prev = p; 64 E->back->next = p; 65 E->back = p; 66 goto done; 67 } 68 /* 69 * The first page is shared between front and back to avoid 70 * double unecessary extra allocation. 71 */ 72 E->front = p; 73 E->back = p; 74 p->next = p; 75 p->prev = p; 76 E->front_cursor = E->front->page + FLATCC_EMITTER_PAGE_SIZE / 2; 77 E->back_cursor = E->front_cursor; 78 E->front_left = FLATCC_EMITTER_PAGE_SIZE / 2; 79 E->back_left = FLATCC_EMITTER_PAGE_SIZE - E->front_left; 80 p->page_offset = -(flatbuffers_soffset_t)E->front_left; 81 return 0; 82 done: 83 E->back_cursor = E->back->page; 84 E->back_left = FLATCC_EMITTER_PAGE_SIZE; 85 E->back->page_offset = E->back->prev->page_offset + FLATCC_EMITTER_PAGE_SIZE; 86 return 0; 87 } 88 89 static int copy_front(flatcc_emitter_t *E, uint8_t *data, size_t size) 90 { 91 size_t k; 92 93 data += size; 94 while (size) { 95 k = size; 96 if (k > E->front_left) { 97 k = E->front_left; 98 if (k == 0) { 99 if (advance_front(E)) { 100 return -1; 101 } 102 continue; 103 } 104 } 105 E->front_cursor -= k; 106 E->front_left -= k; 107 data -= k; 108 size -= k; 109 memcpy(E->front_cursor, data, k); 110 }; 111 return 0; 112 } 113 114 static int copy_back(flatcc_emitter_t *E, uint8_t *data, size_t size) 115 { 116 size_t k; 117 118 while (size) { 119 k = size; 120 if (k > E->back_left) { 121 k = E->back_left; 122 if (k == 0) { 123 if (advance_back(E)) { 124 return -1; 125 } 126 continue; 127 } 128 } 129 memcpy(E->back_cursor, data, k); 130 size -= k; 131 data += k; 132 E->back_cursor += k; 133 E->back_left -= k; 134 } 135 return 0; 136 } 137 138 int flatcc_emitter_recycle_page(flatcc_emitter_t *E, flatcc_emitter_page_t *p) 139 { 140 if (p == E->front || p == E->back) { 141 return -1; 142 } 143 p->next->prev = p->prev; 144 p->prev->next = p->next; 145 p->prev = E->front->prev; 146 p->next = E->front; 147 p->prev->next = p; 148 p->next->prev = p; 149 return 0; 150 } 151 152 void flatcc_emitter_reset(flatcc_emitter_t *E) 153 { 154 flatcc_emitter_page_t *p = E->front; 155 156 if (!E->front) { 157 return; 158 } 159 E->back = E->front; 160 E->front_cursor = E->front->page + FLATCC_EMITTER_PAGE_SIZE / 2; 161 E->back_cursor = E->front_cursor; 162 E->front_left = FLATCC_EMITTER_PAGE_SIZE / 2; 163 E->back_left = FLATCC_EMITTER_PAGE_SIZE - FLATCC_EMITTER_PAGE_SIZE / 2; 164 E->front->page_offset = -(flatbuffers_soffset_t)E->front_left; 165 /* Heuristic to reduce peak allocation over time. */ 166 if (E->used_average == 0) { 167 E->used_average = E->used; 168 } 169 E->used_average = E->used_average * 3 / 4 + E->used / 4; 170 E->used = 0; 171 while (E->used_average * 2 < E->capacity && E->back->next != E->front) { 172 /* We deallocate the page after back since it is less likely to be hot in cache. */ 173 p = E->back->next; 174 E->back->next = p->next; 175 p->next->prev = E->back; 176 FLATCC_EMITTER_FREE(p); 177 E->capacity -= FLATCC_EMITTER_PAGE_SIZE; 178 } 179 } 180 181 void flatcc_emitter_clear(flatcc_emitter_t *E) 182 { 183 flatcc_emitter_page_t *p = E->front; 184 185 if (!p) { 186 return; 187 } 188 p->prev->next = 0; 189 while (p->next) { 190 p = p->next; 191 FLATCC_EMITTER_FREE(p->prev); 192 } 193 FLATCC_EMITTER_FREE(p); 194 memset(E, 0, sizeof(*E)); 195 } 196 197 int flatcc_emitter(void *emit_context, 198 const flatcc_iovec_t *iov, int iov_count, 199 flatbuffers_soffset_t offset, size_t len) 200 { 201 flatcc_emitter_t *E = emit_context; 202 uint8_t *p; 203 204 E->used += len; 205 if (offset < 0) { 206 if (len <= E->front_left) { 207 E->front_cursor -= len; 208 E->front_left -= len; 209 p = E->front_cursor; 210 goto copy; 211 } 212 iov += iov_count; 213 while (iov_count--) { 214 --iov; 215 if (copy_front(E, iov->iov_base, iov->iov_len)) { 216 return -1; 217 } 218 } 219 } else { 220 if (len <= E->back_left) { 221 p = E->back_cursor; 222 E->back_cursor += len; 223 E->back_left -= len; 224 goto copy; 225 } 226 while (iov_count--) { 227 if (copy_back(E, iov->iov_base, iov->iov_len)) { 228 return -1; 229 } 230 ++iov; 231 } 232 } 233 return 0; 234 copy: 235 while (iov_count--) { 236 memcpy(p, iov->iov_base, iov->iov_len); 237 p += iov->iov_len; 238 ++iov; 239 } 240 return 0; 241 } 242 243 void *flatcc_emitter_copy_buffer(flatcc_emitter_t *E, void *buf, size_t size) 244 { 245 flatcc_emitter_page_t *p; 246 size_t len; 247 248 if (size < E->used) { 249 return 0; 250 } 251 if (!E->front) { 252 return 0; 253 } 254 if (E->front == E->back) { 255 memcpy(buf, E->front_cursor, E->used); 256 return buf; 257 } 258 len = FLATCC_EMITTER_PAGE_SIZE - E->front_left; 259 memcpy(buf, E->front_cursor, len); 260 buf = (uint8_t *)buf + len; 261 p = E->front->next; 262 while (p != E->back) { 263 memcpy(buf, p->page, FLATCC_EMITTER_PAGE_SIZE); 264 buf = (uint8_t *)buf + FLATCC_EMITTER_PAGE_SIZE; 265 p = p->next; 266 } 267 memcpy(buf, p->page, FLATCC_EMITTER_PAGE_SIZE - E->back_left); 268 return buf; 269 }