messagepack implementation for embedded systems (mbed / arduino)

Dependents:   hello_message_pack

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers vrefbuffer.hpp Source File

vrefbuffer.hpp

00001 //
00002 // MessagePack for C++ zero-copy buffer implementation
00003 //
00004 // Copyright (C) 2008-2013 FURUHASHI Sadayuki and KONDO Takatoshi
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 #ifndef MSGPACK_VREFBUFFER_HPP
00011 #define MSGPACK_VREFBUFFER_HPP
00012 
00013 #include "msgpack/versioning.hpp"
00014 
00015 #include <stdexcept>
00016 
00017 #ifndef MSGPACK_VREFBUFFER_REF_SIZE
00018 #define MSGPACK_VREFBUFFER_REF_SIZE 32
00019 #endif
00020 
00021 #ifndef MSGPACK_VREFBUFFER_CHUNK_SIZE
00022     #if defined(__MBED__)
00023         #define MSGPACK_VREFBUFFER_CHUNK_SIZE 512
00024     #elif defined(__AVR__)
00025         #define MSGPACK_VREFBUFFER_CHUNK_SIZE 128
00026     #else
00027         #define MSGPACK_VREFBUFFER_CHUNK_SIZE 8192
00028     #endif
00029 #endif
00030 
00031 #if !defined(_WIN32) && !defined(__MBED__) 
00032 #include <sys/uio.h>
00033 #else
00034 struct iovec {
00035     void  *iov_base;
00036     size_t iov_len;
00037 };
00038 #endif
00039 
00040 namespace msgpack {
00041 
00042 /// @cond
00043 MSGPACK_API_VERSION_NAMESPACE(v1) {
00044 /// @endcond
00045 
00046 namespace detail {
00047     // int64, uint64, double
00048     std::size_t const packer_max_buffer_size = 9;
00049 } // detail
00050 
00051 class vrefbuffer {
00052 private:
00053     struct chunk {
00054         chunk* next;
00055     };
00056     struct inner_buffer {
00057         size_t free;
00058         char*  ptr;
00059         chunk* head;
00060     };
00061 public:
00062     vrefbuffer(size_t ref_size = MSGPACK_VREFBUFFER_REF_SIZE,
00063                size_t chunk_size = MSGPACK_VREFBUFFER_CHUNK_SIZE)
00064         :m_ref_size(std::max(ref_size, detail::packer_max_buffer_size + 1)),
00065          m_chunk_size(chunk_size)
00066     {
00067         size_t nfirst = (sizeof(iovec) < 72/2) ?
00068             72 / sizeof(iovec) : 8;
00069 
00070         iovec* array = static_cast<iovec*>(::malloc(
00071             sizeof(iovec) * nfirst));
00072         if(!array) {
00073 //            throw std::bad_alloc();
00074         }
00075 
00076         m_tail  = array;
00077         m_end   = array + nfirst;
00078         m_array = array;
00079 
00080         chunk* c = static_cast<chunk*>(::malloc(sizeof(chunk) + chunk_size));
00081         if(!c) {
00082             ::free(array);
00083 //            throw std::bad_alloc();
00084         }
00085         inner_buffer* const ib = &m_inner_buffer;
00086 
00087         ib->free = chunk_size;
00088         ib->ptr      = reinterpret_cast<char*>(c) + sizeof(chunk);
00089         ib->head = c;
00090         c->next = nullptr;
00091 
00092     }
00093 
00094     ~vrefbuffer()
00095     {
00096         chunk* c = m_inner_buffer.head;
00097         while(true) {
00098             chunk* n = c->next;
00099             ::free(c);
00100             if(n != NULL) {
00101                 c = n;
00102             } else {
00103                 break;
00104             }
00105         }
00106         ::free(m_array);
00107     }
00108 
00109 public:
00110     void write(const char* buf, size_t len)
00111     {
00112         if(len < m_ref_size) {
00113             append_copy(buf, len);
00114         } else {
00115             append_ref(buf, len);
00116         }
00117     }
00118 
00119     void append_ref(const char* buf, size_t len)
00120     {
00121         if(m_tail == m_end) {
00122             const size_t nused = m_tail - m_array;
00123             const size_t nnext = nused * 2;
00124 
00125             iovec* nvec = static_cast<iovec*>(::realloc(
00126                 m_array, sizeof(iovec)*nnext));
00127             if(!nvec) {
00128 //                throw std::bad_alloc();
00129             }
00130 
00131             m_array = nvec;
00132             m_end   = nvec + nnext;
00133             m_tail  = nvec + nused;
00134         }
00135 
00136         m_tail->iov_base = const_cast<char*>(buf);
00137         m_tail->iov_len     = len;
00138         ++m_tail;
00139     }
00140 
00141     void append_copy(const char* buf, size_t len)
00142     {
00143         inner_buffer* const ib = &m_inner_buffer;
00144 
00145         if(ib->free < len) {
00146             size_t sz = m_chunk_size;
00147             if(sz < len) {
00148                 sz = len;
00149             }
00150 
00151             chunk* c = static_cast<chunk*>(::malloc(sizeof(chunk) + sz));
00152             if(!c) {
00153 //                throw std::bad_alloc();
00154             }
00155 
00156             c->next = ib->head;
00157             ib->head = c;
00158             ib->free = sz;
00159             ib->ptr      = reinterpret_cast<char*>(c) + sizeof(chunk);
00160         }
00161 
00162         char* m = ib->ptr;
00163         std::memcpy(m, buf, len);
00164         ib->free -= len;
00165         ib->ptr      += len;
00166 
00167         if(m_tail != m_array && m ==
00168             static_cast<const char*>(
00169                 const_cast<const void *>((m_tail - 1)->iov_base)
00170             ) + (m_tail - 1)->iov_len) {
00171             (m_tail - 1)->iov_len += len;
00172             return;
00173         } else {
00174             append_ref( m, len);
00175         }
00176     }
00177 
00178     const struct iovec* vector() const
00179     {
00180         return m_array;
00181     }
00182 
00183     size_t vector_size() const
00184     {
00185         return m_tail - m_array;
00186     }
00187 
00188     void migrate(vrefbuffer* to)
00189     {
00190         size_t sz = m_chunk_size;
00191 
00192         chunk* empty = static_cast<chunk*>(::malloc(sizeof(chunk) + sz));
00193         if(!empty) {
00194 //            throw std::bad_alloc();
00195         }
00196 
00197         empty->next = nullptr;
00198 
00199         const size_t nused = m_tail - m_array;
00200         if(to->m_tail + nused < m_end) {
00201             const size_t tosize = to->m_tail - to->m_array;
00202             const size_t reqsize = nused + tosize;
00203             size_t nnext = (to->m_end - to->m_array) * 2;
00204             while(nnext < reqsize) {
00205                 size_t tmp_nnext = nnext * 2;
00206                 if (tmp_nnext <= nnext) {
00207                     nnext = reqsize;
00208                     break;
00209                 }
00210                 nnext = tmp_nnext;
00211             }
00212 
00213             iovec* nvec = static_cast<iovec*>(::realloc(
00214                 to->m_array, sizeof(iovec)*nnext));
00215             if(!nvec) {
00216                 ::free(empty);
00217 //                throw std::bad_alloc();
00218             }
00219 
00220             to->m_array = nvec;
00221             to->m_end   = nvec + nnext;
00222             to->m_tail  = nvec + tosize;
00223         }
00224 
00225         std::memcpy(to->m_tail, m_array, sizeof(iovec)*nused);
00226 
00227         to->m_tail += nused;
00228         m_tail = m_array;
00229 
00230 
00231         inner_buffer* const ib = &m_inner_buffer;
00232         inner_buffer* const toib = &to->m_inner_buffer;
00233 
00234         chunk* last = ib->head;
00235         while(last->next) {
00236             last = last->next;
00237         }
00238         last->next = toib->head;
00239         toib->head = ib->head;
00240 
00241         if(toib->free < ib->free) {
00242             toib->free = ib->free;
00243             toib->ptr  = ib->ptr;
00244         }
00245 
00246         ib->head = empty;
00247         ib->free = sz;
00248         ib->ptr      = reinterpret_cast<char*>(empty) + sizeof(chunk);
00249 
00250     }
00251 
00252     void clear()
00253     {
00254         chunk* c = m_inner_buffer.head->next;
00255         chunk* n;
00256         while(c) {
00257             n = c->next;
00258             ::free(c);
00259             c = n;
00260         }
00261 
00262         inner_buffer* const ib = &m_inner_buffer;
00263         c = ib->head;
00264         c->next = nullptr;
00265         ib->free = m_chunk_size;
00266         ib->ptr      = reinterpret_cast<char*>(c) + sizeof(chunk);
00267 
00268         m_tail = m_array;
00269     }
00270 
00271 #if defined(MSGPACK_USE_CPP03)
00272 private:
00273     vrefbuffer(const vrefbuffer&);
00274     vrefbuffer& operator=(const vrefbuffer&);
00275 #else  // defined(MSGPACK_USE_CPP03)
00276     vrefbuffer(const vrefbuffer&) = delete;
00277     vrefbuffer& operator=(const vrefbuffer&) = delete;
00278 #endif // defined(MSGPACK_USE_CPP03)
00279 
00280 private:
00281     iovec* m_tail;
00282     iovec* m_end;
00283     iovec* m_array;
00284 
00285     size_t m_ref_size;
00286     size_t m_chunk_size;
00287 
00288     inner_buffer m_inner_buffer;
00289 
00290 };
00291 
00292 /// @cond
00293 }  // MSGPACK_API_VERSION_NAMESPACE(v1)
00294 /// @endcond
00295 
00296 }  // namespace msgpack
00297 
00298 #endif /* msgpack/vrefbuffer.hpp */