| 1 | // |
|---|
| 2 | // MessagePack for C++ memory pool |
|---|
| 3 | // |
|---|
| 4 | // Copyright (C) 2008 FURUHASHI Sadayuki |
|---|
| 5 | // |
|---|
| 6 | // Licensed under the Apache License, Version 2.0 (the "License"); |
|---|
| 7 | // you may not use this file except in compliance with the License. |
|---|
| 8 | // You may obtain a copy of the License at |
|---|
| 9 | // |
|---|
| 10 | // http://www.apache.org/licenses/LICENSE-2.0 |
|---|
| 11 | // |
|---|
| 12 | // Unless required by applicable law or agreed to in writing, software |
|---|
| 13 | // distributed under the License is distributed on an "AS IS" BASIS, |
|---|
| 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|---|
| 15 | // See the License for the specific language governing permissions and |
|---|
| 16 | // limitations under the License. |
|---|
| 17 | // |
|---|
| 18 | #ifndef MSGPACK_ZONE_HPP__ |
|---|
| 19 | #define MSGPACK_ZONE_HPP__ |
|---|
| 20 | #include <iostream> |
|---|
| 21 | |
|---|
| 22 | #include "msgpack/object.hpp" |
|---|
| 23 | #include <string.h> |
|---|
| 24 | #include <stdlib.h> |
|---|
| 25 | #include <stdexcept> |
|---|
| 26 | |
|---|
| 27 | #ifndef MSGPACK_ZONE_CHUNK_SIZE |
|---|
| 28 | #define MSGPACK_ZONE_CHUNK_SIZE 1024 |
|---|
| 29 | #endif |
|---|
| 30 | |
|---|
| 31 | namespace msgpack { |
|---|
| 32 | |
|---|
| 33 | |
|---|
| 34 | static const size_t ZONE_CHUNK_SIZE = MSGPACK_ZONE_CHUNK_SIZE; |
|---|
| 35 | |
|---|
| 36 | |
|---|
| 37 | class zone { |
|---|
| 38 | public: |
|---|
| 39 | zone() : m_used(0) { } |
|---|
| 40 | ~zone() { clear(); } |
|---|
| 41 | |
|---|
| 42 | public: |
|---|
| 43 | template <typename T> |
|---|
| 44 | void push_finalizer(void (*func)(void* obj, void* user), T* obj, void* user); |
|---|
| 45 | |
|---|
| 46 | public: |
|---|
| 47 | object_nil* nnil () { return new (alloc()) object_nil(); } |
|---|
| 48 | object_true* ntrue () { return new (alloc()) object_true(); } |
|---|
| 49 | object_false* nfalse () { return new (alloc()) object_false(); } |
|---|
| 50 | object_u8* nu8 (uint8_t v) { return new (alloc()) object_u8(v); } |
|---|
| 51 | object_u16* nu16 (uint16_t v) { return new (alloc()) object_u16(v); } |
|---|
| 52 | object_u32* nu32 (uint32_t v) { return new (alloc()) object_u32(v); } |
|---|
| 53 | object_u64* nu64 (uint64_t v) { return new (alloc()) object_u64(v); } |
|---|
| 54 | object_i8* ni8 (int8_t v) { return new (alloc()) object_i8(v); } |
|---|
| 55 | object_i16* ni16 (int16_t v) { return new (alloc()) object_i16(v); } |
|---|
| 56 | object_i32* ni32 (int32_t v) { return new (alloc()) object_i32(v); } |
|---|
| 57 | object_i64* ni64 (int64_t v) { return new (alloc()) object_i64(v); } |
|---|
| 58 | object_float* nfloat (float v) { return new (alloc()) object_float(v); } |
|---|
| 59 | object_double* ndouble(double v) { return new (alloc()) object_double(v); } |
|---|
| 60 | |
|---|
| 61 | object_raw_ref* nraw_ref(void* ptr, uint32_t len) |
|---|
| 62 | { return new (alloc()) object_raw_ref(ptr, len); } |
|---|
| 63 | |
|---|
| 64 | object_const_raw_ref* nraw_ref(const void* ptr, uint32_t len) |
|---|
| 65 | { return new (alloc()) object_const_raw_ref(ptr, len); } |
|---|
| 66 | |
|---|
| 67 | object_raw_ref* nraw_copy(const void* ptr, uint32_t len) |
|---|
| 68 | { |
|---|
| 69 | void* copy = malloc(len); |
|---|
| 70 | if(!copy) { throw std::bad_alloc(); } |
|---|
| 71 | object_raw_ref* o; |
|---|
| 72 | try { |
|---|
| 73 | o = new (alloc()) object_raw_ref(copy, len); |
|---|
| 74 | push_finalizer<void>(&zone::finalize_free, NULL, copy); |
|---|
| 75 | } catch (...) { |
|---|
| 76 | free(copy); |
|---|
| 77 | throw; |
|---|
| 78 | } |
|---|
| 79 | memcpy(copy, ptr, len); |
|---|
| 80 | return o; |
|---|
| 81 | } |
|---|
| 82 | |
|---|
| 83 | object_array* narray() |
|---|
| 84 | { return new (alloc()) object_array(); } |
|---|
| 85 | |
|---|
| 86 | object_array* narray(size_t reserve_size) |
|---|
| 87 | { return new (alloc()) object_array(reserve_size); } |
|---|
| 88 | |
|---|
| 89 | object_map* nmap() |
|---|
| 90 | { return new (alloc()) object_map(); } |
|---|
| 91 | |
|---|
| 92 | <% GENERATION_SIZE = 16 %> |
|---|
| 93 | <% 1.upto(GENERATION_SIZE) {|i| %> |
|---|
| 94 | object_array* narray(<% 1.upto(i-1) {|n| %>object o<%=n%>, <% } %>object o<%=i%>) |
|---|
| 95 | { object_array* a = new (alloc()) object_array(<%=i%>); |
|---|
| 96 | <% 1.upto(i) {|n| %>a->push_back(o<%=n%>); |
|---|
| 97 | <% } %>return a; } |
|---|
| 98 | <% } %> |
|---|
| 99 | |
|---|
| 100 | <% 1.upto(GENERATION_SIZE) {|i| %> |
|---|
| 101 | object_map* nmap(<% 1.upto(i-1) {|n| %>object k<%=n%>, object v<%=n%>, <% } %>object k<%=i%>, object v<%=i%>) |
|---|
| 102 | { object_map* m = new (alloc()) object_map(); |
|---|
| 103 | <% 1.upto(i) {|n| %>m->store(k<%=n%>, v<%=n%>); |
|---|
| 104 | <% } %>return m; } |
|---|
| 105 | <% } %> |
|---|
| 106 | |
|---|
| 107 | public: |
|---|
| 108 | void clear(); |
|---|
| 109 | bool empty() const; |
|---|
| 110 | |
|---|
| 111 | private: |
|---|
| 112 | void* alloc(); |
|---|
| 113 | |
|---|
| 114 | private: |
|---|
| 115 | size_t m_used; |
|---|
| 116 | |
|---|
| 117 | static const size_t MAX_OBJECT_SIZE = |
|---|
| 118 | sizeof(object_raw_ref) > sizeof(object_array) |
|---|
| 119 | ? ( sizeof(object_raw_ref) > sizeof(object_map) |
|---|
| 120 | ? sizeof(object_raw_ref) |
|---|
| 121 | : sizeof(object_map) |
|---|
| 122 | ) |
|---|
| 123 | : ( sizeof(object_array) > sizeof(object_map) |
|---|
| 124 | ? sizeof(object_array) |
|---|
| 125 | : sizeof(object_map) |
|---|
| 126 | ) |
|---|
| 127 | ; |
|---|
| 128 | |
|---|
| 129 | struct cell_t { |
|---|
| 130 | char data[MAX_OBJECT_SIZE]; |
|---|
| 131 | }; |
|---|
| 132 | |
|---|
| 133 | typedef std::vector<cell_t*> pool_t; |
|---|
| 134 | pool_t m_pool; |
|---|
| 135 | |
|---|
| 136 | |
|---|
| 137 | class finalizer { |
|---|
| 138 | public: |
|---|
| 139 | finalizer(void (*func)(void*, void*), void* obj, void* user) : |
|---|
| 140 | m_obj(obj), m_user(user), m_func(func) {} |
|---|
| 141 | void call() { (*m_func)(m_obj, m_user); } |
|---|
| 142 | private: |
|---|
| 143 | void* m_obj; |
|---|
| 144 | void* m_user; |
|---|
| 145 | void (*m_func)(void*, void*); |
|---|
| 146 | }; |
|---|
| 147 | |
|---|
| 148 | typedef std::vector<finalizer> user_finalizer_t; |
|---|
| 149 | user_finalizer_t m_user_finalizer; |
|---|
| 150 | |
|---|
| 151 | private: |
|---|
| 152 | void expand_chunk(); |
|---|
| 153 | |
|---|
| 154 | public: |
|---|
| 155 | static void finalize_free(void* obj, void* user) |
|---|
| 156 | { free(user); } |
|---|
| 157 | |
|---|
| 158 | private: |
|---|
| 159 | zone(const zone&); |
|---|
| 160 | }; |
|---|
| 161 | |
|---|
| 162 | |
|---|
| 163 | template <typename T> |
|---|
| 164 | inline void zone::push_finalizer(void (*func)(void* obj, void* user), T* obj, void* user) |
|---|
| 165 | { |
|---|
| 166 | m_user_finalizer.push_back( finalizer( |
|---|
| 167 | func, reinterpret_cast<void*>(obj), |
|---|
| 168 | user) ); |
|---|
| 169 | } |
|---|
| 170 | |
|---|
| 171 | inline bool zone::empty() const |
|---|
| 172 | { |
|---|
| 173 | return m_used == 0 && m_user_finalizer.empty(); |
|---|
| 174 | } |
|---|
| 175 | |
|---|
| 176 | inline void* zone::alloc() |
|---|
| 177 | { |
|---|
| 178 | if(m_pool.size() <= m_used/ZONE_CHUNK_SIZE) { |
|---|
| 179 | expand_chunk(); |
|---|
| 180 | } |
|---|
| 181 | void* data = m_pool[m_used/ZONE_CHUNK_SIZE][m_used%ZONE_CHUNK_SIZE].data; |
|---|
| 182 | ++m_used; |
|---|
| 183 | return data; |
|---|
| 184 | } |
|---|
| 185 | |
|---|
| 186 | |
|---|
| 187 | } // namespace msgpack |
|---|
| 188 | |
|---|
| 189 | #endif /* msgpack/zone.hpp */ |
|---|
| 190 | |
|---|