123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304 |
- //
- // MessagePack for C++ zero-copy buffer implementation
- //
- // Copyright (C) 2008-2017 FURUHASHI Sadayuki and KONDO Takatoshi
- //
- // 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)
- //
- #ifndef MSGPACK_V1_VREFBUFFER_HPP
- #define MSGPACK_V1_VREFBUFFER_HPP
- #include "msgpack/v1/vrefbuffer_decl.hpp"
- #include <stdexcept>
- #include <algorithm>
- #if defined(_MSC_VER)
- // avoiding confliction std::max, std::min, and macro in windows.h
- #ifndef NOMINMAX
- #define NOMINMAX
- #endif
- #endif // defined(_MSC_VER)
- #if defined(unix) || defined(__unix) || defined(__APPLE__) || defined(__OpenBSD__)
- #include <sys/uio.h>
- #else
- struct iovec {
- void *iov_base;
- size_t iov_len;
- };
- #endif
- namespace msgpack {
- /// @cond
- MSGPACK_API_VERSION_NAMESPACE(v1) {
- /// @endcond
- namespace detail {
- // int64, uint64, double
- std::size_t const packer_max_buffer_size = 9;
- } // detail
- class vrefbuffer {
- private:
- struct chunk {
- chunk* next;
- };
- struct inner_buffer {
- size_t free;
- char* ptr;
- chunk* head;
- };
- public:
- vrefbuffer(size_t ref_size = MSGPACK_VREFBUFFER_REF_SIZE,
- size_t chunk_size = MSGPACK_VREFBUFFER_CHUNK_SIZE)
- :m_ref_size(std::max(ref_size, detail::packer_max_buffer_size + 1)),
- m_chunk_size(chunk_size)
- {
- if((sizeof(chunk) + chunk_size) < chunk_size) {
- throw std::bad_alloc();
- }
- size_t nfirst = (sizeof(iovec) < 72/2) ?
- 72 / sizeof(iovec) : 8;
- iovec* array = static_cast<iovec*>(::malloc(
- sizeof(iovec) * nfirst));
- if(!array) {
- throw std::bad_alloc();
- }
- m_tail = array;
- m_end = array + nfirst;
- m_array = array;
- chunk* c = static_cast<chunk*>(::malloc(sizeof(chunk) + chunk_size));
- if(!c) {
- ::free(array);
- throw std::bad_alloc();
- }
- inner_buffer* const ib = &m_inner_buffer;
- ib->free = chunk_size;
- ib->ptr = reinterpret_cast<char*>(c) + sizeof(chunk);
- ib->head = c;
- c->next = MSGPACK_NULLPTR;
- }
- ~vrefbuffer()
- {
- chunk* c = m_inner_buffer.head;
- while(true) {
- chunk* n = c->next;
- ::free(c);
- if(n != NULL) {
- c = n;
- } else {
- break;
- }
- }
- ::free(m_array);
- }
- public:
- void write(const char* buf, size_t len)
- {
- if(len < m_ref_size) {
- append_copy(buf, len);
- } else {
- append_ref(buf, len);
- }
- }
- void append_ref(const char* buf, size_t len)
- {
- if(m_tail == m_end) {
- const size_t nused = m_tail - m_array;
- const size_t nnext = nused * 2;
- iovec* nvec = static_cast<iovec*>(::realloc(
- m_array, sizeof(iovec)*nnext));
- if(!nvec) {
- throw std::bad_alloc();
- }
- m_array = nvec;
- m_end = nvec + nnext;
- m_tail = nvec + nused;
- }
- m_tail->iov_base = const_cast<char*>(buf);
- m_tail->iov_len = len;
- ++m_tail;
- }
- void append_copy(const char* buf, size_t len)
- {
- inner_buffer* const ib = &m_inner_buffer;
- if(ib->free < len) {
- size_t sz = m_chunk_size;
- if(sz < len) {
- sz = len;
- }
-
- if(sizeof(chunk) + sz < sz){
- throw std::bad_alloc();
- }
-
- chunk* c = static_cast<chunk*>(::malloc(sizeof(chunk) + sz));
- if(!c) {
- throw std::bad_alloc();
- }
- c->next = ib->head;
- ib->head = c;
- ib->free = sz;
- ib->ptr = reinterpret_cast<char*>(c) + sizeof(chunk);
- }
- char* m = ib->ptr;
- std::memcpy(m, buf, len);
- ib->free -= len;
- ib->ptr += len;
- if(m_tail != m_array && m ==
- static_cast<const char*>(
- const_cast<const void *>((m_tail - 1)->iov_base)
- ) + (m_tail - 1)->iov_len) {
- (m_tail - 1)->iov_len += len;
- return;
- } else {
- append_ref( m, len);
- }
- }
- const struct iovec* vector() const
- {
- return m_array;
- }
- size_t vector_size() const
- {
- return m_tail - m_array;
- }
- void migrate(vrefbuffer* to)
- {
- size_t sz = m_chunk_size;
- if((sizeof(chunk) + sz) < sz){
- throw std::bad_alloc();
- }
- chunk* empty = static_cast<chunk*>(::malloc(sizeof(chunk) + sz));
- if(!empty) {
- throw std::bad_alloc();
- }
- empty->next = MSGPACK_NULLPTR;
- const size_t nused = m_tail - m_array;
- if(to->m_tail + nused < m_end) {
- const size_t tosize = to->m_tail - to->m_array;
- const size_t reqsize = nused + tosize;
- size_t nnext = (to->m_end - to->m_array) * 2;
- while(nnext < reqsize) {
- size_t tmp_nnext = nnext * 2;
- if (tmp_nnext <= nnext) {
- nnext = reqsize;
- break;
- }
- nnext = tmp_nnext;
- }
- iovec* nvec = static_cast<iovec*>(::realloc(
- to->m_array, sizeof(iovec)*nnext));
- if(!nvec) {
- ::free(empty);
- throw std::bad_alloc();
- }
- to->m_array = nvec;
- to->m_end = nvec + nnext;
- to->m_tail = nvec + tosize;
- }
- std::memcpy(to->m_tail, m_array, sizeof(iovec)*nused);
- to->m_tail += nused;
- m_tail = m_array;
- inner_buffer* const ib = &m_inner_buffer;
- inner_buffer* const toib = &to->m_inner_buffer;
- chunk* last = ib->head;
- while(last->next) {
- 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 = reinterpret_cast<char*>(empty) + sizeof(chunk);
- }
- void clear()
- {
- chunk* c = m_inner_buffer.head->next;
- chunk* n;
- while(c) {
- n = c->next;
- ::free(c);
- c = n;
- }
- inner_buffer* const ib = &m_inner_buffer;
- c = ib->head;
- c->next = MSGPACK_NULLPTR;
- ib->free = m_chunk_size;
- ib->ptr = reinterpret_cast<char*>(c) + sizeof(chunk);
- m_tail = m_array;
- }
- #if defined(MSGPACK_USE_CPP03)
- private:
- vrefbuffer(const vrefbuffer&);
- vrefbuffer& operator=(const vrefbuffer&);
- #else // defined(MSGPACK_USE_CPP03)
- vrefbuffer(const vrefbuffer&) = delete;
- vrefbuffer& operator=(const vrefbuffer&) = delete;
- #endif // defined(MSGPACK_USE_CPP03)
- private:
- iovec* m_tail;
- iovec* m_end;
- iovec* m_array;
- size_t m_ref_size;
- size_t m_chunk_size;
- inner_buffer m_inner_buffer;
- };
- /// @cond
- } // MSGPACK_API_VERSION_NAMESPACE(v1)
- /// @endcond
- } // namespace msgpack
- #endif // MSGPACK_V1_VREFBUFFER_HPP
|