messagepack implementation for embedded systems (mbed / arduino)
Dependents: hello_message_pack
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 */
Generated on Tue Jul 12 2022 22:51:46 by 1.7.2