summaryrefslogtreecommitdiffstats
path: root/third_party/msgpack/include/msgpack/v1/vrefbuffer.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/msgpack/include/msgpack/v1/vrefbuffer.hpp')
-rw-r--r--third_party/msgpack/include/msgpack/v1/vrefbuffer.hpp292
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