diff options
Diffstat (limited to 'third_party/msgpack/include/msgpack/v1/vrefbuffer.hpp')
-rw-r--r-- | third_party/msgpack/include/msgpack/v1/vrefbuffer.hpp | 292 |
1 files changed, 292 insertions, 0 deletions
diff --git a/third_party/msgpack/include/msgpack/v1/vrefbuffer.hpp b/third_party/msgpack/include/msgpack/v1/vrefbuffer.hpp new file mode 100644 index 0000000000..6d52a15e60 --- /dev/null +++ b/third_party/msgpack/include/msgpack/v1/vrefbuffer.hpp @@ -0,0 +1,292 @@ +// +// 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) + { + 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; + } + + 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; + + 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 |