messagepack implementation for embedded systems (mbed / arduino)

Dependents:   hello_message_pack

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers vrefbuffer.c Source File

vrefbuffer.c

00001 /*
00002  * MessagePack for C zero-copy buffer implementation
00003  *
00004  * Copyright (C) 2008-2009 FURUHASHI Sadayuki
00005  *
00006  *    Distributed under the Boost Software License, Version 1.0.
00007  *    (See accompanying file LICENSE_1_0.txt or copy at
00008  *    http://www.boost.org/LICENSE_1_0.txt)
00009  */
00010 #include "include/vrefbuffer.h"
00011 #include <stdlib.h>
00012 #include <string.h>
00013 
00014 #define MSGPACK_PACKER_MAX_BUFFER_SIZE 9
00015 
00016 struct msgpack_vrefbuffer_chunk {
00017     struct msgpack_vrefbuffer_chunk* next;
00018     /* data ... */
00019 };
00020 
00021 bool msgpack_vrefbuffer_init(msgpack_vrefbuffer* vbuf,
00022         size_t ref_size, size_t chunk_size)
00023 {
00024     size_t nfirst;
00025     struct iovec* array;
00026     msgpack_vrefbuffer_chunk* chunk;
00027 
00028     vbuf->chunk_size = chunk_size;
00029     vbuf->ref_size =
00030         ref_size > MSGPACK_PACKER_MAX_BUFFER_SIZE + 1 ?
00031         ref_size : MSGPACK_PACKER_MAX_BUFFER_SIZE + 1 ;
00032 
00033     nfirst = (sizeof(struct iovec) < 72/2) ?
00034             72 / sizeof(struct iovec) : 8;
00035 
00036     array = (struct iovec*)malloc(
00037             sizeof(struct iovec) * nfirst);
00038     if(array == NULL) {
00039         return false;
00040     }
00041 
00042     vbuf->tail  = array;
00043     vbuf->end   = array + nfirst;
00044     vbuf->array = array;
00045 
00046     chunk = (msgpack_vrefbuffer_chunk*)malloc(
00047             sizeof(msgpack_vrefbuffer_chunk) + chunk_size);
00048     if(chunk == NULL) {
00049         free(array);
00050         return false;
00051     }
00052     else {
00053         msgpack_vrefbuffer_inner_buffer* const ib = &vbuf->inner_buffer;
00054 
00055         ib->free = chunk_size;
00056         ib->ptr  = ((char*)chunk) + sizeof(msgpack_vrefbuffer_chunk);
00057         ib->head = chunk;
00058         chunk->next = NULL;
00059 
00060         return true;
00061     }
00062 }
00063 
00064 void msgpack_vrefbuffer_destroy(msgpack_vrefbuffer* vbuf)
00065 {
00066     msgpack_vrefbuffer_chunk* c = vbuf->inner_buffer.head;
00067     while(true) {
00068         msgpack_vrefbuffer_chunk* n = c->next;
00069         free(c);
00070         if(n != NULL) {
00071             c = n;
00072         } else {
00073             break;
00074         }
00075     }
00076     free(vbuf->array);
00077 }
00078 
00079 void msgpack_vrefbuffer_clear(msgpack_vrefbuffer* vbuf)
00080 {
00081     msgpack_vrefbuffer_chunk* c = vbuf->inner_buffer.head->next;
00082     msgpack_vrefbuffer_chunk* n;
00083     while(c != NULL) {
00084         n = c->next;
00085         free(c);
00086         c = n;
00087     }
00088 
00089     {
00090         msgpack_vrefbuffer_inner_buffer* const ib = &vbuf->inner_buffer;
00091         msgpack_vrefbuffer_chunk* chunk = ib->head;
00092         chunk->next = NULL;
00093         ib->free = vbuf->chunk_size;
00094         ib->ptr  = ((char*)chunk) + sizeof(msgpack_vrefbuffer_chunk);
00095 
00096         vbuf->tail = vbuf->array;
00097     }
00098 }
00099 
00100 int msgpack_vrefbuffer_append_ref(msgpack_vrefbuffer* vbuf,
00101         const char* buf, size_t len)
00102 {
00103     if(vbuf->tail == vbuf->end) {
00104         const size_t nused = (size_t)(vbuf->tail - vbuf->array);
00105         const size_t nnext = nused * 2;
00106 
00107         struct iovec* nvec = (struct iovec*)realloc(
00108                 vbuf->array, sizeof(struct iovec)*nnext);
00109         if(nvec == NULL) {
00110             return -1;
00111         }
00112 
00113         vbuf->array = nvec;
00114         vbuf->end   = nvec + nnext;
00115         vbuf->tail  = nvec + nused;
00116     }
00117 
00118     vbuf->tail->iov_base = (char*)buf;
00119     vbuf->tail->iov_len  = len;
00120     ++vbuf->tail;
00121 
00122     return 0;
00123 }
00124 
00125 int msgpack_vrefbuffer_append_copy(msgpack_vrefbuffer* vbuf,
00126         const char* buf, size_t len)
00127 {
00128     msgpack_vrefbuffer_inner_buffer* const ib = &vbuf->inner_buffer;
00129     char* m;
00130 
00131     if(ib->free < len) {
00132         msgpack_vrefbuffer_chunk* chunk;
00133         size_t sz = vbuf->chunk_size;
00134         if(sz < len) {
00135             sz = len;
00136         }
00137 
00138         chunk = (msgpack_vrefbuffer_chunk*)malloc(
00139                 sizeof(msgpack_vrefbuffer_chunk) + sz);
00140         if(chunk == NULL) {
00141             return -1;
00142         }
00143 
00144         chunk->next = ib->head;
00145         ib->head = chunk;
00146         ib->free = sz;
00147         ib->ptr  = ((char*)chunk) + sizeof(msgpack_vrefbuffer_chunk);
00148     }
00149 
00150     m = ib->ptr;
00151     memcpy(m, buf, len);
00152     ib->free -= len;
00153     ib->ptr  += len;
00154 
00155     if(vbuf->tail != vbuf->array && m ==
00156             (const char*)((vbuf->tail-1)->iov_base) + (vbuf->tail-1)->iov_len) {
00157         (vbuf->tail-1)->iov_len += len;
00158         return 0;
00159     } else {
00160         return msgpack_vrefbuffer_append_ref(vbuf, m, len);
00161     }
00162 }
00163 
00164 int msgpack_vrefbuffer_migrate(msgpack_vrefbuffer* vbuf, msgpack_vrefbuffer* to)
00165 {
00166     size_t sz = vbuf->chunk_size;
00167 
00168     msgpack_vrefbuffer_chunk* empty = (msgpack_vrefbuffer_chunk*)malloc(
00169             sizeof(msgpack_vrefbuffer_chunk) + sz);
00170     if(empty == NULL) {
00171         return -1;
00172     }
00173 
00174     empty->next = NULL;
00175 
00176     {
00177         const size_t nused = (size_t)(vbuf->tail - vbuf->array);
00178         if(to->tail + nused < vbuf->end) {
00179             struct iovec* nvec;
00180             const size_t tosize = (size_t)(to->tail - to->array);
00181             const size_t reqsize = nused + tosize;
00182             size_t nnext = (size_t)(to->end - to->array) * 2;
00183             while(nnext < reqsize) {
00184                 size_t tmp_nnext = nnext * 2;
00185                 if (tmp_nnext <= nnext) {
00186                     nnext = reqsize;
00187                     break;
00188                 }
00189                 nnext = tmp_nnext;
00190             }
00191 
00192             nvec = (struct iovec*)realloc(
00193                     to->array, sizeof(struct iovec)*nnext);
00194             if(nvec == NULL) {
00195                 free(empty);
00196                 return -1;
00197             }
00198 
00199             to->array = nvec;
00200             to->end   = nvec + nnext;
00201             to->tail  = nvec + tosize;
00202         }
00203 
00204         memcpy(to->tail, vbuf->array, sizeof(struct iovec)*nused);
00205 
00206         to->tail += nused;
00207         vbuf->tail = vbuf->array;
00208 
00209         {
00210             msgpack_vrefbuffer_inner_buffer* const ib = &vbuf->inner_buffer;
00211             msgpack_vrefbuffer_inner_buffer* const toib = &to->inner_buffer;
00212 
00213             msgpack_vrefbuffer_chunk* last = ib->head;
00214             while(last->next != NULL) {
00215                 last = last->next;
00216             }
00217             last->next = toib->head;
00218             toib->head = ib->head;
00219 
00220             if(toib->free < ib->free) {
00221                 toib->free = ib->free;
00222                 toib->ptr  = ib->ptr;
00223             }
00224 
00225             ib->head = empty;
00226             ib->free = sz;
00227             ib->ptr  = ((char*)empty) + sizeof(msgpack_vrefbuffer_chunk);
00228         }
00229     }
00230 
00231     return 0;
00232 }