mirror of
https://github.com/msgpack/msgpack-c.git
synced 2025-04-24 00:57:07 +02:00
333 lines
8.3 KiB
Plaintext
333 lines
8.3 KiB
Plaintext
//
|
|
// MessagePack for C++ memory pool
|
|
//
|
|
// Copyright (C) 2008-2010 FURUHASHI Sadayuki
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//
|
|
#ifndef MSGPACK_CPP03_ZONE_HPP
|
|
#define MSGPACK_CPP03_ZONE_HPP
|
|
|
|
#include <cstdlib>
|
|
#include <memory>
|
|
#include <vector>
|
|
|
|
#include "msgpack/versioning.hpp"
|
|
|
|
#ifndef MSGPACK_ZONE_CHUNK_SIZE
|
|
#define MSGPACK_ZONE_CHUNK_SIZE 8192
|
|
#endif
|
|
|
|
#ifndef MSGPACK_ZONE_ALIGN
|
|
#define MSGPACK_ZONE_ALIGN sizeof(int)
|
|
#endif
|
|
|
|
<% GENERATION_LIMIT = 15 %>
|
|
namespace msgpack {
|
|
|
|
MSGPACK_API_VERSION_NAMESPACE(v1) {
|
|
|
|
class zone {
|
|
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* m_tail;
|
|
finalizer* m_end;
|
|
finalizer* m_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 {
|
|
break;
|
|
}
|
|
}
|
|
m_head->m_next = nullptr;
|
|
m_free = chunk_size;
|
|
m_ptr = reinterpret_cast<char*>(m_head) + sizeof(chunk);
|
|
}
|
|
size_t m_free;
|
|
char* m_ptr;
|
|
chunk* m_head;
|
|
};
|
|
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) /* throw() */;
|
|
|
|
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) /* throw() */
|
|
{
|
|
::free(p);
|
|
}
|
|
static void* operator new(std::size_t size, void* place) /* throw() */
|
|
{
|
|
return ::operator new(size, place);
|
|
}
|
|
static void operator delete(void* p, void* place) /* throw() */
|
|
{
|
|
::operator delete(p, place);
|
|
}
|
|
<%0.upto(GENERATION_LIMIT) {|i|%>
|
|
template <typename T<%1.upto(i) {|j|%>, typename A<%=j%><%}%>>
|
|
T* allocate(<%=(1..i).map{|j|"A#{j} a#{j}"}.join(', ')%>);
|
|
<%}%>
|
|
|
|
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);
|
|
private:
|
|
zone(const zone&);
|
|
zone& operator=(const zone&);
|
|
};
|
|
|
|
inline zone::zone(size_t chunk_size) /* throw() */ :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)
|
|
{
|
|
using std::swap;
|
|
swap(m_chunk_size, o.m_chunk_size);
|
|
swap(m_chunk_list, o.m_chunk_list);
|
|
swap(m_finalizer_array, o.m_finalizer_array);
|
|
}
|
|
|
|
template <typename T>
|
|
void zone::object_destruct(void* obj)
|
|
{
|
|
static_cast<T*>(obj)->~T();
|
|
}
|
|
|
|
template <typename T>
|
|
void zone::object_delete(void* obj)
|
|
{
|
|
delete static_cast<T*>(obj);
|
|
}
|
|
|
|
inline void zone::undo_allocate(size_t size)
|
|
{
|
|
m_chunk_list.m_ptr -= size;
|
|
m_chunk_list.m_free += size;
|
|
}
|
|
|
|
<%0.upto(GENERATION_LIMIT) {|i|%>
|
|
template <typename T<%1.upto(i) {|j|%>, typename A<%=j%><%}%>>
|
|
T* zone::allocate(<%=(1..i).map{|j|"A#{j} a#{j}"}.join(', ')%>)
|
|
{
|
|
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(<%=(1..i).map{|j|"a#{j}"}.join(', ')%>);
|
|
} catch (...) {
|
|
--m_finalizer_array.m_tail;
|
|
undo_allocate(sizeof(T));
|
|
throw;
|
|
}
|
|
}
|
|
<%}%>
|
|
|
|
} // MSGPACK_API_VERSION_NAMESPACE(v1)
|
|
|
|
} // namespace msgpack
|
|
|
|
#endif // MSGPACK_CPP03_ZONE_HPP
|