mirror of
				https://github.com/msgpack/msgpack-c.git
				synced 2025-11-04 12:17:38 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			347 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			347 lines
		
	
	
		
			8.5 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(void*)
 | 
						|
#endif
 | 
						|
 | 
						|
<% GENERATION_LIMIT = 15 %>
 | 
						|
namespace msgpack {
 | 
						|
 | 
						|
/// @cond
 | 
						|
MSGPACK_API_VERSION_NAMESPACE(v1) {
 | 
						|
/// @endcond
 | 
						|
 | 
						|
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);
 | 
						|
    }
 | 
						|
    /// @cond
 | 
						|
    <%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(', ')%>);
 | 
						|
    <%}%>
 | 
						|
    /// @endcond
 | 
						|
 | 
						|
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;
 | 
						|
}
 | 
						|
 | 
						|
inline std::size_t aligned_size(
 | 
						|
    std::size_t size,
 | 
						|
    std::size_t align = MSGPACK_ZONE_ALIGN) {
 | 
						|
    return (size + align - 1) / align * align;
 | 
						|
}
 | 
						|
 | 
						|
/// @cond
 | 
						|
<%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;
 | 
						|
    }
 | 
						|
}
 | 
						|
<%}%>
 | 
						|
/// @endcond
 | 
						|
 | 
						|
/// @cond
 | 
						|
}  // MSGPACK_API_VERSION_NAMESPACE(v1)
 | 
						|
/// @endcond
 | 
						|
 | 
						|
}  // namespace msgpack
 | 
						|
 | 
						|
#endif // MSGPACK_CPP03_ZONE_HPP
 |