summaryrefslogtreecommitdiffstats
path: root/third_party/msgpack/src/vrefbuffer.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--third_party/msgpack/src/vrefbuffer.c232
1 files changed, 232 insertions, 0 deletions
diff --git a/third_party/msgpack/src/vrefbuffer.c b/third_party/msgpack/src/vrefbuffer.c
new file mode 100644
index 0000000000..2834747640
--- /dev/null
+++ b/third_party/msgpack/src/vrefbuffer.c
@@ -0,0 +1,232 @@
+/*
+ * MessagePack for C zero-copy buffer implementation
+ *
+ * Copyright (C) 2008-2009 FURUHASHI Sadayuki
+ *
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or copy at
+ * http://www.boost.org/LICENSE_1_0.txt)
+ */
+#include "msgpack/vrefbuffer.h"
+#include <stdlib.h>
+#include <string.h>
+
+#define MSGPACK_PACKER_MAX_BUFFER_SIZE 9
+
+struct msgpack_vrefbuffer_chunk {
+ struct msgpack_vrefbuffer_chunk* next;
+ /* data ... */
+};
+
+bool msgpack_vrefbuffer_init(msgpack_vrefbuffer* vbuf,
+ size_t ref_size, size_t chunk_size)
+{
+ size_t nfirst;
+ struct iovec* array;
+ msgpack_vrefbuffer_chunk* chunk;
+
+ vbuf->chunk_size = chunk_size;
+ vbuf->ref_size =
+ ref_size > MSGPACK_PACKER_MAX_BUFFER_SIZE + 1 ?
+ ref_size : MSGPACK_PACKER_MAX_BUFFER_SIZE + 1 ;
+
+ nfirst = (sizeof(struct iovec) < 72/2) ?
+ 72 / sizeof(struct iovec) : 8;
+
+ array = (struct iovec*)malloc(
+ sizeof(struct iovec) * nfirst);
+ if(array == NULL) {
+ return false;
+ }
+
+ vbuf->tail = array;
+ vbuf->end = array + nfirst;
+ vbuf->array = array;
+
+ chunk = (msgpack_vrefbuffer_chunk*)malloc(
+ sizeof(msgpack_vrefbuffer_chunk) + chunk_size);
+ if(chunk == NULL) {
+ free(array);
+ return false;
+ }
+ else {
+ msgpack_vrefbuffer_inner_buffer* const ib = &vbuf->inner_buffer;
+
+ ib->free = chunk_size;
+ ib->ptr = ((char*)chunk) + sizeof(msgpack_vrefbuffer_chunk);
+ ib->head = chunk;
+ chunk->next = NULL;
+
+ return true;
+ }
+}
+
+void msgpack_vrefbuffer_destroy(msgpack_vrefbuffer* vbuf)
+{
+ msgpack_vrefbuffer_chunk* c = vbuf->inner_buffer.head;
+ while(true) {
+ msgpack_vrefbuffer_chunk* n = c->next;
+ free(c);
+ if(n != NULL) {
+ c = n;
+ } else {
+ break;
+ }
+ }
+ free(vbuf->array);
+}
+
+void msgpack_vrefbuffer_clear(msgpack_vrefbuffer* vbuf)
+{
+ msgpack_vrefbuffer_chunk* c = vbuf->inner_buffer.head->next;
+ msgpack_vrefbuffer_chunk* n;
+ while(c != NULL) {
+ n = c->next;
+ free(c);
+ c = n;
+ }
+
+ {
+ msgpack_vrefbuffer_inner_buffer* const ib = &vbuf->inner_buffer;
+ msgpack_vrefbuffer_chunk* chunk = ib->head;
+ chunk->next = NULL;
+ ib->free = vbuf->chunk_size;
+ ib->ptr = ((char*)chunk) + sizeof(msgpack_vrefbuffer_chunk);
+
+ vbuf->tail = vbuf->array;
+ }
+}
+
+int msgpack_vrefbuffer_append_ref(msgpack_vrefbuffer* vbuf,
+ const char* buf, size_t len)
+{
+ if(vbuf->tail == vbuf->end) {
+ const size_t nused = (size_t)(vbuf->tail - vbuf->array);
+ const size_t nnext = nused * 2;
+
+ struct iovec* nvec = (struct iovec*)realloc(
+ vbuf->array, sizeof(struct iovec)*nnext);
+ if(nvec == NULL) {
+ return -1;
+ }
+
+ vbuf->array = nvec;
+ vbuf->end = nvec + nnext;
+ vbuf->tail = nvec + nused;
+ }
+
+ vbuf->tail->iov_base = (char*)buf;
+ vbuf->tail->iov_len = len;
+ ++vbuf->tail;
+
+ return 0;
+}
+
+int msgpack_vrefbuffer_append_copy(msgpack_vrefbuffer* vbuf,
+ const char* buf, size_t len)
+{
+ msgpack_vrefbuffer_inner_buffer* const ib = &vbuf->inner_buffer;
+ char* m;
+
+ if(ib->free < len) {
+ msgpack_vrefbuffer_chunk* chunk;
+ size_t sz = vbuf->chunk_size;
+ if(sz < len) {
+ sz = len;
+ }
+
+ chunk = (msgpack_vrefbuffer_chunk*)malloc(
+ sizeof(msgpack_vrefbuffer_chunk) + sz);
+ if(chunk == NULL) {
+ return -1;
+ }
+
+ chunk->next = ib->head;
+ ib->head = chunk;
+ ib->free = sz;
+ ib->ptr = ((char*)chunk) + sizeof(msgpack_vrefbuffer_chunk);
+ }
+
+ m = ib->ptr;
+ memcpy(m, buf, len);
+ ib->free -= len;
+ ib->ptr += len;
+
+ if(vbuf->tail != vbuf->array && m ==
+ (const char*)((vbuf->tail-1)->iov_base) + (vbuf->tail-1)->iov_len) {
+ (vbuf->tail-1)->iov_len += len;
+ return 0;
+ } else {
+ return msgpack_vrefbuffer_append_ref(vbuf, m, len);
+ }
+}
+
+int msgpack_vrefbuffer_migrate(msgpack_vrefbuffer* vbuf, msgpack_vrefbuffer* to)
+{
+ size_t sz = vbuf->chunk_size;
+
+ msgpack_vrefbuffer_chunk* empty = (msgpack_vrefbuffer_chunk*)malloc(
+ sizeof(msgpack_vrefbuffer_chunk) + sz);
+ if(empty == NULL) {
+ return -1;
+ }
+
+ empty->next = NULL;
+
+ {
+ const size_t nused = (size_t)(vbuf->tail - vbuf->array);
+ if(to->tail + nused < vbuf->end) {
+ struct iovec* nvec;
+ const size_t tosize = (size_t)(to->tail - to->array);
+ const size_t reqsize = nused + tosize;
+ size_t nnext = (size_t)(to->end - to->array) * 2;
+ while(nnext < reqsize) {
+ size_t tmp_nnext = nnext * 2;
+ if (tmp_nnext <= nnext) {
+ nnext = reqsize;
+ break;
+ }
+ nnext = tmp_nnext;
+ }
+
+ nvec = (struct iovec*)realloc(
+ to->array, sizeof(struct iovec)*nnext);
+ if(nvec == NULL) {
+ free(empty);
+ return -1;
+ }
+
+ to->array = nvec;
+ to->end = nvec + nnext;
+ to->tail = nvec + tosize;
+ }
+
+ memcpy(to->tail, vbuf->array, sizeof(struct iovec)*nused);
+
+ to->tail += nused;
+ vbuf->tail = vbuf->array;
+
+ {
+ msgpack_vrefbuffer_inner_buffer* const ib = &vbuf->inner_buffer;
+ msgpack_vrefbuffer_inner_buffer* const toib = &to->inner_buffer;
+
+ msgpack_vrefbuffer_chunk* last = ib->head;
+ while(last->next != NULL) {
+ last = last->next;
+ }
+ last->next = toib->head;
+ toib->head = ib->head;
+
+ if(toib->free < ib->free) {
+ toib->free = ib->free;
+ toib->ptr = ib->ptr;
+ }
+
+ ib->head = empty;
+ ib->free = sz;
+ ib->ptr = ((char*)empty) + sizeof(msgpack_vrefbuffer_chunk);
+ }
+ }
+
+ return 0;
+}