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/detail/cpp11_zone.hpp	Sat Feb 13 01:53:11 2016 +0000
@@ -0,0 +1,374 @@
+//
+// MessagePack for C++ memory pool
+//
+// 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_CPP11_ZONE_HPP
+#define MSGPACK_CPP11_ZONE_HPP
+
+#include "msgpack/versioning.hpp"
+
+#include <cstdlib>
+#include <memory>
+#include <vector>
+
+#include "msgpack/cpp_config.hpp"
+
+#ifndef MSGPACK_ZONE_CHUNK_SIZE
+    #if defined(__MBED__)
+        #define MSGPACK_ZONE_CHUNK_SIZE 1024
+    #elif defined(__AVR__)
+        #define MSGPACK_ZONE_CHUNK_SIZE 128
+    #else
+        #define MSGPACK_ZONE_CHUNK_SIZE 8192
+    #endif
+#endif
+
+#ifndef MSGPACK_ZONE_ALIGN
+#define MSGPACK_ZONE_ALIGN sizeof(void*)
+#endif
+
+namespace msgpack {
+
+/// @cond
+MSGPACK_API_VERSION_NAMESPACE(v1) {
+/// @endcond
+
+class zone {
+private:
+    struct finalizer {
+        finalizer(void (*func)(void*), void* data):m_func(func), m_data(data) {}
+        void operator()() { m_func(m_data); }
+        void (*m_func)(void*);
+        void* m_data;
+    };
+    struct finalizer_array {
+        finalizer_array():m_tail(nullptr), m_end(nullptr), m_array(nullptr) {}
+        void call() {
+            finalizer* fin = m_tail;
+            for(; fin != m_array; --fin) (*(fin-1))();
+        }
+        ~finalizer_array() {
+            call();
+            ::free(m_array);
+        }
+        void clear() {
+            call();
+            m_tail = m_array;
+        }
+        void push(void (*func)(void* data), void* data)
+        {
+            finalizer* fin = m_tail;
+
+            if(fin == m_end) {
+                push_expand(func, data);
+                return;
+            }
+
+            fin->m_func = func;
+            fin->m_data = data;
+
+            ++m_tail;
+        }
+        void push_expand(void (*func)(void*), void* data) {
+            const size_t nused = m_end - m_array;
+            size_t nnext;
+            if(nused == 0) {
+                nnext = (sizeof(finalizer) < 72/2) ?
+                    72 / sizeof(finalizer) : 8;
+            } else {
+                nnext = nused * 2;
+            }
+            finalizer* tmp =
+                static_cast<finalizer*>(::realloc(m_array, sizeof(finalizer) * nnext));
+            if(!tmp) {
+                throw std::bad_alloc();
+            }
+            m_array     = tmp;
+            m_end   = tmp + nnext;
+            m_tail  = tmp + nused;
+            new (m_tail) finalizer(func, data);
+
+            ++m_tail;
+        }
+        finalizer_array(finalizer_array&& other) noexcept
+            :m_tail(other.m_tail), m_end(other.m_end), m_array(other.m_array)
+        {
+            other.m_tail = nullptr;
+            other.m_end = nullptr;
+            other.m_array = nullptr;
+        }
+        finalizer_array& operator=(finalizer_array&& other) noexcept
+        {
+            this->~finalizer_array();
+            new (this) finalizer_array(std::move(other));
+            return *this;
+        }
+
+        finalizer* m_tail;
+        finalizer* m_end;
+        finalizer* m_array;
+
+    private:
+        finalizer_array(const finalizer_array&);
+        finalizer_array& operator=(const finalizer_array&);
+    };
+    struct chunk {
+        chunk* m_next;
+    };
+    struct chunk_list {
+        chunk_list(size_t chunk_size)
+        {
+            chunk* c = static_cast<chunk*>(::malloc(sizeof(chunk) + chunk_size));
+            if(!c) {
+                throw std::bad_alloc();
+            }
+
+            m_head = c;
+            m_free = chunk_size;
+            m_ptr  = reinterpret_cast<char*>(c) + sizeof(chunk);
+            c->m_next = nullptr;
+        }
+        ~chunk_list()
+        {
+            chunk* c = m_head;
+            while(c) {
+                chunk* n = c->m_next;
+                ::free(c);
+                c = n;
+            }
+        }
+        void clear(size_t chunk_size)
+        {
+            chunk* c = m_head;
+            while(true) {
+                chunk* n = c->m_next;
+                if(n) {
+                    ::free(c);
+                    c = n;
+                } else {
+                    m_head = c;
+                    break;
+                }
+            }
+            m_head->m_next = nullptr;
+            m_free = chunk_size;
+            m_ptr  = reinterpret_cast<char*>(m_head) + sizeof(chunk);
+        }
+        chunk_list(chunk_list&& other) noexcept
+            :m_free(other.m_free), m_ptr(other.m_ptr), m_head(other.m_head)
+        {
+            other.m_head = nullptr;
+        }
+        chunk_list& operator=(chunk_list&& other) noexcept
+        {
+            this->~chunk_list();
+            new (this) chunk_list(std::move(other));
+            return *this;
+        }
+
+        size_t m_free;
+        char* m_ptr;
+        chunk* m_head;
+    private:
+        chunk_list(const chunk_list&);
+        chunk_list& operator=(const chunk_list&);
+    };
+    size_t m_chunk_size;
+    chunk_list m_chunk_list;
+    finalizer_array m_finalizer_array;
+
+public:
+    zone(size_t chunk_size = MSGPACK_ZONE_CHUNK_SIZE) noexcept;
+
+public:
+    void* allocate_align(size_t size, size_t align = MSGPACK_ZONE_ALIGN);
+    void* allocate_no_align(size_t size);
+
+    void push_finalizer(void (*func)(void*), void* data);
+
+    template <typename T>
+    void push_finalizer(msgpack::unique_ptr<T> obj);
+
+    void clear();
+
+    void swap(zone& o);
+
+
+    static void* operator new(std::size_t size)
+    {
+        void* p = ::malloc(size);
+        if (!p) throw std::bad_alloc();
+        return p;
+    }
+    static void operator delete(void *p) noexcept
+    {
+        ::free(p);
+    }
+    static void* operator new(std::size_t /*size*/, void* mem) noexcept
+    {
+        return mem;
+    }
+    static void operator delete(void * /*p*/, void* /*mem*/) noexcept
+    {
+    }
+
+    template <typename T, typename... Args>
+    T* allocate(Args... args);
+
+    zone(zone&&) = default;
+    zone& operator=(zone&&) = default;
+    zone(const zone&) = delete;
+    zone& operator=(const zone&) = delete;
+
+private:
+    void undo_allocate(size_t size);
+
+    template <typename T>
+    static void object_destruct(void* obj);
+
+    template <typename T>
+    static void object_delete(void* obj);
+
+    void* allocate_expand(size_t size);
+};
+
+inline zone::zone(size_t chunk_size) noexcept:m_chunk_size(chunk_size), m_chunk_list(m_chunk_size)
+{
+}
+
+inline void* zone::allocate_align(size_t size, size_t align)
+{
+    char* aligned =
+        reinterpret_cast<char*>(
+            reinterpret_cast<size_t>(
+                (m_chunk_list.m_ptr + (align - 1))) / align * align);
+    size_t adjusted_size = size + (aligned - m_chunk_list.m_ptr);
+    if(m_chunk_list.m_free >= adjusted_size) {
+        m_chunk_list.m_free -= adjusted_size;
+        m_chunk_list.m_ptr  += adjusted_size;
+        return aligned;
+    }
+    return reinterpret_cast<char*>(
+        reinterpret_cast<size_t>(
+            allocate_expand(size + (align - 1))) / align * align);
+}
+
+inline void* zone::allocate_no_align(size_t size)
+{
+    if(m_chunk_list.m_free < size) {
+        return allocate_expand(size);
+    }
+
+    char* ptr = m_chunk_list.m_ptr;
+    m_chunk_list.m_free -= size;
+    m_chunk_list.m_ptr  += size;
+
+    return ptr;
+}
+
+inline void* zone::allocate_expand(size_t size)
+{
+    chunk_list* const cl = &m_chunk_list;
+
+    size_t sz = m_chunk_size;
+
+    while(sz < size) {
+        size_t tmp_sz = sz * 2;
+        if (tmp_sz <= sz) {
+            sz = size;
+            break;
+        }
+        sz = tmp_sz;
+    }
+
+    chunk* c = static_cast<chunk*>(::malloc(sizeof(chunk) + sz));
+    if (!c) throw std::bad_alloc();
+
+    char* ptr = reinterpret_cast<char*>(c) + sizeof(chunk);
+
+    c->m_next  = cl->m_head;
+    cl->m_head = c;
+    cl->m_free = sz - size;
+    cl->m_ptr  = ptr + size;
+
+    return ptr;
+}
+
+inline void zone::push_finalizer(void (*func)(void*), void* data)
+{
+    m_finalizer_array.push(func, data);
+}
+
+template <typename T>
+inline void zone::push_finalizer(msgpack::unique_ptr<T> obj)
+{
+    m_finalizer_array.push(&zone::object_delete<T>, obj.release());
+}
+
+inline void zone::clear()
+{
+    m_finalizer_array.clear();
+    m_chunk_list.clear(m_chunk_size);
+}
+
+inline void zone::swap(zone& o)
+{
+    std::swap(*this, o);
+}
+
+template <typename T>
+void zone::object_delete(void* obj)
+{
+    delete static_cast<T*>(obj);
+}
+
+template <typename T>
+void zone::object_destruct(void* obj)
+{
+    static_cast<T*>(obj)->~T();
+}
+
+inline void zone::undo_allocate(size_t size)
+{
+    m_chunk_list.m_ptr  -= size;
+    m_chunk_list.m_free += size;
+}
+
+
+template <typename T, typename... Args>
+T* zone::allocate(Args... args)
+{
+    void* x = allocate_align(sizeof(T));
+    try {
+        m_finalizer_array.push(&zone::object_destruct<T>, x);
+    } catch (...) {
+        undo_allocate(sizeof(T));
+        throw;
+    }
+    try {
+        return new (x) T(args...);
+    } catch (...) {
+        --m_finalizer_array.m_tail;
+        undo_allocate(sizeof(T));
+        throw;
+    }
+}
+
+inline std::size_t aligned_size(
+    std::size_t size,
+    std::size_t align = MSGPACK_ZONE_ALIGN) {
+    return (size + align - 1) / align * align;
+}
+
+/// @cond
+}  // MSGPACK_API_VERSION_NAMESPACE(v1)
+/// @endcond
+
+}  // namespace msgpack
+
+#endif // MSGPACK_CPP11_ZONE_HPP