Hideaki Tai / msgpack-embedded

Dependents:   hello_message_pack

Revision:
0:3f9dbf1e2cb0
Child:
3:a56553e46a9a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/msgpack/vrefbuffer.hpp	Sat Feb 13 01:53:11 2016 +0000
@@ -0,0 +1,298 @@
+//
+// MessagePack for C++ zero-copy buffer implementation
+//
+// Copyright (C) 2008-2013 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_VREFBUFFER_HPP
+#define MSGPACK_VREFBUFFER_HPP
+
+#include "msgpack/versioning.hpp"
+
+#include <stdexcept>
+
+#ifndef MSGPACK_VREFBUFFER_REF_SIZE
+#define MSGPACK_VREFBUFFER_REF_SIZE 32
+#endif
+
+#ifndef MSGPACK_VREFBUFFER_CHUNK_SIZE
+    #if defined(__MBED__)
+        #define MSGPACK_VREFBUFFER_CHUNK_SIZE 1024
+    #elif defined(__AVR__)
+        #define MSGPACK_VREFBUFFER_CHUNK_SIZE 128
+    #else
+        #define MSGPACK_VREFBUFFER_CHUNK_SIZE 8192
+    #endif
+#endif
+
+#if !defined(_WIN32) && !defined(__MBED__) 
+#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 = 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 = 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 = 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/vrefbuffer.hpp */