123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366 |
- //
- // 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 "msgpack/cpp_config.hpp"
- #include "msgpack/zone_decl.hpp"
- #include <cstdlib>
- #include <memory>
- #include <vector>
- 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(MSGPACK_NULLPTR), m_end(MSGPACK_NULLPTR), m_array(MSGPACK_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 = MSGPACK_NULLPTR;
- other.m_end = MSGPACK_NULLPTR;
- other.m_array = MSGPACK_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 = MSGPACK_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 = MSGPACK_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 = MSGPACK_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);
- static char* get_aligned(char* ptr, size_t align);
- char* 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 char* zone::get_aligned(char* ptr, size_t align)
- {
- return
- reinterpret_cast<char*>(
- reinterpret_cast<size_t>(
- (ptr + (align - 1))) / align * align);
- }
- inline void* zone::allocate_align(size_t size, size_t align)
- {
- char* aligned = get_aligned(m_chunk_list.m_ptr, align);
- size_t adjusted_size = size + (aligned - m_chunk_list.m_ptr);
- if (m_chunk_list.m_free < adjusted_size) {
- size_t enough_size = size + align - 1;
- char* ptr = allocate_expand(enough_size);
- aligned = get_aligned(ptr, align);
- adjusted_size = size + (aligned - m_chunk_list.m_ptr);
- }
- m_chunk_list.m_free -= adjusted_size;
- m_chunk_list.m_ptr += adjusted_size;
- return aligned;
- }
- inline void* zone::allocate_no_align(size_t size)
- {
- char* ptr = m_chunk_list.m_ptr;
- if(m_chunk_list.m_free < size) {
- ptr = allocate_expand(size);
- }
- m_chunk_list.m_free -= size;
- m_chunk_list.m_ptr += size;
- return ptr;
- }
- inline char* 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;
- cl->m_ptr = ptr;
- 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), MSGPACK_ZONE_ALIGNOF(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) {
- return (size + align - 1) / align * align;
- }
- /// @cond
- } // MSGPACK_API_VERSION_NAMESPACE(v1)
- /// @endcond
- } // namespace msgpack
- #endif // MSGPACK_CPP11_ZONE_HPP
|