mirror of
https://github.com/msgpack/msgpack-c.git
synced 2025-11-01 11:52:56 +01:00
Added header files that use c++11 variadic templates instead of ruby code generation.
When the compiler configured to support C++11 (e.g. CXXFLAG contains -std=c++11 is given), those files are used. Decoupled unpacker and msgpack_unpacker. This modification introduced C++11 dependency such as nullptr and unique_ptr. I will support C++11 and C++03, finally. Decoupled msgpack.hpp and msgpack.h. Decoupled sbuffer from msgpack_sbuffer. Decoupled vrefbuffer from msgpack_vrefbuffer. Decoupled zbuffer from msgpack_zbuffer. Added some z_stream initialization. Removed unpack macros. Removed CTX_CAST and CTX_REFERENCED. Embed ctx_ as a member variable (not a pointer). Modified zone free using C++ way.
This commit is contained in:
@@ -62,6 +62,7 @@ nobase_include_HEADERS += \
|
||||
msgpack/fbuffer.hpp \
|
||||
msgpack/pack.hpp \
|
||||
msgpack/unpack.hpp \
|
||||
msgpack/version.hpp \
|
||||
msgpack/object.hpp \
|
||||
msgpack/zone.hpp \
|
||||
msgpack/type.hpp \
|
||||
@@ -86,6 +87,7 @@ endif
|
||||
|
||||
EXTRA_DIST = \
|
||||
msgpack/version.h.in \
|
||||
msgpack/version.hpp.in \
|
||||
msgpack/zone.hpp.erb \
|
||||
msgpack/type/define.hpp.erb \
|
||||
msgpack/type/tuple.hpp.erb
|
||||
|
||||
@@ -21,4 +21,4 @@
|
||||
#include "msgpack/unpack.hpp"
|
||||
#include "msgpack/sbuffer.hpp"
|
||||
#include "msgpack/vrefbuffer.hpp"
|
||||
#include "msgpack.h"
|
||||
#include "msgpack/version.hpp"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//
|
||||
// MessagePack for C++ simple buffer implementation
|
||||
//
|
||||
// Copyright (C) 2008-2009 FURUHASHI Sadayuki
|
||||
// Copyright (C) 2008-2013 FURUHASHI Sadayuki and KONDO Takatoshi
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@@ -15,94 +15,99 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
#ifndef MSGPACK_SBUFFER_HPP__
|
||||
#define MSGPACK_SBUFFER_HPP__
|
||||
#ifndef MSGPACK_SBUFFER_HPP
|
||||
#define MSGPACK_SBUFFER_HPP
|
||||
|
||||
#include "sbuffer.h"
|
||||
#include <stdexcept>
|
||||
|
||||
#ifndef MSGPACK_SBUFFER_INIT_SIZE
|
||||
#define MSGPACK_SBUFFER_INIT_SIZE 8192
|
||||
#endif
|
||||
|
||||
namespace msgpack {
|
||||
|
||||
|
||||
class sbuffer : public msgpack_sbuffer {
|
||||
class sbuffer {
|
||||
public:
|
||||
sbuffer(size_t initsz = MSGPACK_SBUFFER_INIT_SIZE)
|
||||
sbuffer(size_t initsz = MSGPACK_SBUFFER_INIT_SIZE):size_(0), alloc_(initsz)
|
||||
{
|
||||
if(initsz == 0) {
|
||||
base::data = NULL;
|
||||
data_ = nullptr;
|
||||
} else {
|
||||
base::data = (char*)::malloc(initsz);
|
||||
if(!base::data) {
|
||||
data_ = (char*)::malloc(initsz);
|
||||
if(!data_) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
}
|
||||
|
||||
base::size = 0;
|
||||
base::alloc = initsz;
|
||||
}
|
||||
|
||||
~sbuffer()
|
||||
{
|
||||
::free(base::data);
|
||||
::free(data_);
|
||||
}
|
||||
|
||||
public:
|
||||
void write(const char* buf, size_t len)
|
||||
{
|
||||
if(base::alloc - base::size < len) {
|
||||
if(alloc_ - size_ < len) {
|
||||
expand_buffer(len);
|
||||
}
|
||||
memcpy(base::data + base::size, buf, len);
|
||||
base::size += len;
|
||||
::memcpy(data_ + size_, buf, len);
|
||||
size_ += len;
|
||||
}
|
||||
|
||||
char* data()
|
||||
{
|
||||
return base::data;
|
||||
return data_;
|
||||
}
|
||||
|
||||
const char* data() const
|
||||
{
|
||||
return base::data;
|
||||
return data_;
|
||||
}
|
||||
|
||||
size_t size() const
|
||||
{
|
||||
return base::size;
|
||||
return size_;
|
||||
}
|
||||
|
||||
char* release()
|
||||
{
|
||||
return msgpack_sbuffer_release(this);
|
||||
char* tmp = data_;
|
||||
size_ = 0;
|
||||
data_ = nullptr;
|
||||
alloc_ = 0;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
msgpack_sbuffer_clear(this);
|
||||
size_ = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
void expand_buffer(size_t len)
|
||||
{
|
||||
size_t nsize = (base::alloc > 0) ?
|
||||
base::alloc * 2 : MSGPACK_SBUFFER_INIT_SIZE;
|
||||
size_t nsize = (alloc_ > 0) ?
|
||||
alloc_ * 2 : MSGPACK_SBUFFER_INIT_SIZE;
|
||||
|
||||
while(nsize < base::size + len) { nsize *= 2; }
|
||||
while(nsize < size_ + len) { nsize *= 2; }
|
||||
|
||||
void* tmp = realloc(base::data, nsize);
|
||||
void* tmp = ::realloc(data_, nsize);
|
||||
if(!tmp) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
|
||||
base::data = (char*)tmp;
|
||||
base::alloc = nsize;
|
||||
data_ = (char*)tmp;
|
||||
alloc_ = nsize;
|
||||
}
|
||||
|
||||
private:
|
||||
typedef msgpack_sbuffer base;
|
||||
|
||||
private:
|
||||
sbuffer(const sbuffer&);
|
||||
private:
|
||||
size_t size_;
|
||||
char* data_;
|
||||
size_t alloc_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//
|
||||
// MessagePack for C++ deserializing routine
|
||||
//
|
||||
// Copyright (C) 2008-2009 FURUHASHI Sadayuki
|
||||
// Copyright (C) 2008-2013 FURUHASHI Sadayuki and KONDO Takatoshi
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@@ -15,22 +15,490 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
#ifndef MSGPACK_UNPACK_HPP__
|
||||
#define MSGPACK_UNPACK_HPP__
|
||||
#ifndef MSGPACK_UNPACK_HPP
|
||||
#define MSGPACK_UNPACK_HPP
|
||||
|
||||
#include "unpack.h"
|
||||
#include "object.hpp"
|
||||
#include "zone.hpp"
|
||||
#include "unpack_define.h"
|
||||
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
|
||||
|
||||
#define COUNTER_SIZE (sizeof(_msgpack_atomic_counter_t))
|
||||
|
||||
#ifndef MSGPACK_UNPACKER_INIT_BUFFER_SIZE
|
||||
#define MSGPACK_UNPACKER_INIT_BUFFER_SIZE (64*1024)
|
||||
#endif
|
||||
|
||||
#ifndef MSGPACK_UNPACKER_RESERVE_SIZE
|
||||
#define MSGPACK_UNPACKER_RESERVE_SIZE (32*1024)
|
||||
#endif
|
||||
|
||||
|
||||
// backward compatibility
|
||||
#ifndef MSGPACK_UNPACKER_DEFAULT_INITIAL_BUFFER_SIZE
|
||||
#define MSGPACK_UNPACKER_DEFAULT_INITIAL_BUFFER_SIZE MSGPACK_UNPACKER_INIT_BUFFER_SIZE
|
||||
#endif
|
||||
|
||||
|
||||
namespace msgpack {
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct unpack_user {
|
||||
zone* z;
|
||||
bool referenced;
|
||||
};
|
||||
|
||||
|
||||
static inline ::msgpack::object template_callback_root(unpack_user* u)
|
||||
{ ::msgpack::object o = {}; return o; }
|
||||
|
||||
static inline int template_callback_uint8(unpack_user* u, uint8_t d, ::msgpack::object* o)
|
||||
{ o->type = ::msgpack::type::POSITIVE_INTEGER; o->via.u64 = d; return 0; }
|
||||
|
||||
static inline int template_callback_uint16(unpack_user* u, uint16_t d, ::msgpack::object* o)
|
||||
{ o->type = ::msgpack::type::POSITIVE_INTEGER; o->via.u64 = d; return 0; }
|
||||
|
||||
static inline int template_callback_uint32(unpack_user* u, uint32_t d, ::msgpack::object* o)
|
||||
{ o->type = ::msgpack::type::POSITIVE_INTEGER; o->via.u64 = d; return 0; }
|
||||
|
||||
static inline int template_callback_uint64(unpack_user* u, uint64_t d, ::msgpack::object* o)
|
||||
{ o->type = ::msgpack::type::POSITIVE_INTEGER; o->via.u64 = d; return 0; }
|
||||
|
||||
static inline int template_callback_int8(unpack_user* u, int8_t d, ::msgpack::object* o)
|
||||
{ if(d >= 0) { o->type = ::msgpack::type::POSITIVE_INTEGER; o->via.u64 = d; return 0; }
|
||||
else { o->type = ::msgpack::type::NEGATIVE_INTEGER; o->via.i64 = d; return 0; } }
|
||||
|
||||
static inline int template_callback_int16(unpack_user* u, int16_t d, ::msgpack::object* o)
|
||||
{ if(d >= 0) { o->type = ::msgpack::type::POSITIVE_INTEGER; o->via.u64 = d; return 0; }
|
||||
else { o->type = ::msgpack::type::NEGATIVE_INTEGER; o->via.i64 = d; return 0; } }
|
||||
|
||||
static inline int template_callback_int32(unpack_user* u, int32_t d, ::msgpack::object* o)
|
||||
{ if(d >= 0) { o->type = ::msgpack::type::POSITIVE_INTEGER; o->via.u64 = d; return 0; }
|
||||
else { o->type = ::msgpack::type::NEGATIVE_INTEGER; o->via.i64 = d; return 0; } }
|
||||
|
||||
static inline int template_callback_int64(unpack_user* u, int64_t d, ::msgpack::object* o)
|
||||
{ if(d >= 0) { o->type = ::msgpack::type::POSITIVE_INTEGER; o->via.u64 = d; return 0; }
|
||||
else { o->type = ::msgpack::type::NEGATIVE_INTEGER; o->via.i64 = d; return 0; } }
|
||||
|
||||
static inline int template_callback_float(unpack_user* u, float d, ::msgpack::object* o)
|
||||
{ o->type = ::msgpack::type::DOUBLE; o->via.dec = d; return 0; }
|
||||
|
||||
static inline int template_callback_double(unpack_user* u, double d, ::msgpack::object* o)
|
||||
{ o->type = ::msgpack::type::DOUBLE; o->via.dec = d; return 0; }
|
||||
|
||||
static inline int template_callback_nil(unpack_user* u, ::msgpack::object* o)
|
||||
{ o->type = ::msgpack::type::NIL; return 0; }
|
||||
|
||||
static inline int template_callback_true(unpack_user* u, ::msgpack::object* o)
|
||||
{ o->type = ::msgpack::type::BOOLEAN; o->via.boolean = true; return 0; }
|
||||
|
||||
static inline int template_callback_false(unpack_user* u, ::msgpack::object* o)
|
||||
{ o->type = ::msgpack::type::BOOLEAN; o->via.boolean = false; return 0; }
|
||||
|
||||
static inline int template_callback_array(unpack_user* u, unsigned int n, ::msgpack::object* o)
|
||||
{
|
||||
o->type = ::msgpack::type::ARRAY;
|
||||
o->via.array.size = 0;
|
||||
o->via.array.ptr = (::msgpack::object*)u->z->malloc(n*sizeof(::msgpack::object));
|
||||
if(o->via.array.ptr == NULL) { return -1; }
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int template_callback_array_item(unpack_user* u, ::msgpack::object* c, ::msgpack::object o)
|
||||
{ c->via.array.ptr[c->via.array.size++] = o; return 0; }
|
||||
|
||||
static inline int template_callback_map(unpack_user* u, unsigned int n, ::msgpack::object* o)
|
||||
{
|
||||
o->type = ::msgpack::type::MAP;
|
||||
o->via.map.size = 0;
|
||||
o->via.map.ptr = (::msgpack::object_kv*)u->z->malloc(n*sizeof(::msgpack::object_kv));
|
||||
if(o->via.map.ptr == NULL) { return -1; }
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int template_callback_map_item(unpack_user* u, ::msgpack::object* c, ::msgpack::object k, ::msgpack::object v)
|
||||
{
|
||||
c->via.map.ptr[c->via.map.size].key = k;
|
||||
c->via.map.ptr[c->via.map.size].val = v;
|
||||
++c->via.map.size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int template_callback_raw(unpack_user* u, const char* b, const char* p, unsigned int l, ::msgpack::object* o)
|
||||
{
|
||||
o->type = ::msgpack::type::RAW;
|
||||
o->via.raw.ptr = p;
|
||||
o->via.raw.size = l;
|
||||
u->referenced = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct template_unpack_stack {
|
||||
::msgpack::object obj;
|
||||
size_t count;
|
||||
unsigned int ct;
|
||||
::msgpack::object map_key;
|
||||
};
|
||||
|
||||
struct template_context {
|
||||
unpack_user user;
|
||||
unsigned int cs;
|
||||
unsigned int trail;
|
||||
unsigned int top;
|
||||
template_unpack_stack stack[MSGPACK_EMBED_STACK_SIZE];
|
||||
};
|
||||
|
||||
|
||||
inline void init_count(void* buffer)
|
||||
{
|
||||
*(volatile _msgpack_atomic_counter_t*)buffer = 1;
|
||||
}
|
||||
|
||||
inline void decl_count(void* buffer)
|
||||
{
|
||||
// atomic if(--*(_msgpack_atomic_counter_t*)buffer == 0) { free(buffer); }
|
||||
if(_msgpack_sync_decr_and_fetch((volatile _msgpack_atomic_counter_t*)buffer) == 0) {
|
||||
free(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
inline void incr_count(void* buffer)
|
||||
{
|
||||
// atomic ++*(_msgpack_atomic_counter_t*)buffer;
|
||||
_msgpack_sync_incr_and_fetch((volatile _msgpack_atomic_counter_t*)buffer);
|
||||
}
|
||||
|
||||
inline _msgpack_atomic_counter_t get_count(void* buffer)
|
||||
{
|
||||
return *(volatile _msgpack_atomic_counter_t*)buffer;
|
||||
}
|
||||
|
||||
inline void template_init(template_context& ctx)
|
||||
{
|
||||
ctx.cs = CS_HEADER;
|
||||
ctx.trail = 0;
|
||||
ctx.top = 0;
|
||||
ctx.stack[0].obj = template_callback_root(&ctx.user);
|
||||
}
|
||||
|
||||
::msgpack::object template_data(template_context const& ctx)
|
||||
{
|
||||
return ctx.stack[0].obj;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline unsigned int next_cs(T p)
|
||||
{
|
||||
return (unsigned int)*p & 0x1f;
|
||||
}
|
||||
|
||||
int template_execute(template_context& ctx, const char* data, size_t len, size_t* off)
|
||||
{
|
||||
assert(len >= *off);
|
||||
|
||||
const unsigned char* p = (unsigned char*)data + *off;
|
||||
const unsigned char* const pe = (unsigned char*)data + len;
|
||||
const void* n = nullptr;
|
||||
|
||||
unsigned int trail = ctx.trail;
|
||||
unsigned int cs = ctx.cs;
|
||||
unsigned int top = ctx.top;
|
||||
detail::template_unpack_stack* stack = ctx.stack;
|
||||
/*
|
||||
unsigned int stack_size = ctx.stack_size;
|
||||
*/
|
||||
unpack_user* user = &ctx.user;
|
||||
|
||||
::msgpack::object obj;
|
||||
detail::template_unpack_stack* c = nullptr;
|
||||
|
||||
int ret;
|
||||
|
||||
|
||||
if(p == pe) { goto _out; }
|
||||
do {
|
||||
switch(cs) {
|
||||
case CS_HEADER:
|
||||
if (0) {
|
||||
} else if(0x00 <= *p && *p <= 0x7f) { // Positive Fixnum
|
||||
if(template_callback_uint8(user, *(uint8_t*)p, &obj) < 0) { goto _failed; }
|
||||
goto _push;
|
||||
} else if(0xe0 <= *p && *p <= 0xff) { // Negative Fixnum
|
||||
if(template_callback_int8(user, *(int8_t*)p, &obj) < 0) { goto _failed; }
|
||||
goto _push;
|
||||
} else if(0xc0 <= *p && *p <= 0xdf) { // Variable
|
||||
switch(*p) {
|
||||
case 0xc0: // nil
|
||||
if(template_callback_nil(user, &obj) < 0) { goto _failed; }
|
||||
goto _push;
|
||||
//case 0xc1: // string
|
||||
// again_terminal_trail(next_cs(p), p+1);
|
||||
case 0xc2: // false
|
||||
if(template_callback_false(user, &obj) < 0) { goto _failed; }
|
||||
goto _push;
|
||||
case 0xc3: // true
|
||||
if(template_callback_true(user, &obj) < 0) { goto _failed; }
|
||||
goto _push;
|
||||
case 0xc4: // bin 8
|
||||
case 0xc5: // bin 16
|
||||
case 0xc6: // bin 32
|
||||
trail = 1 << (((unsigned int)*p) & 0x03);
|
||||
cs = next_cs(p);
|
||||
goto _fixed_trail_again;
|
||||
|
||||
//case 0xc7:
|
||||
//case 0xc8:
|
||||
//case 0xc9:
|
||||
case 0xca: // float
|
||||
case 0xcb: // double
|
||||
case 0xcc: // unsigned int 8
|
||||
case 0xcd: // unsigned int 16
|
||||
case 0xce: // unsigned int 32
|
||||
case 0xcf: // unsigned int 64
|
||||
case 0xd0: // signed int 8
|
||||
case 0xd1: // signed int 16
|
||||
case 0xd2: // signed int 32
|
||||
case 0xd3: // signed int 64
|
||||
trail = 1 << (((unsigned int)*p) & 0x03);
|
||||
cs = next_cs(p);
|
||||
goto _fixed_trail_again;
|
||||
//case 0xd4:
|
||||
//case 0xd5:
|
||||
//case 0xd6: // big integer 16
|
||||
//case 0xd7: // big integer 32
|
||||
//case 0xd8: // big float 16
|
||||
case 0xd9: // raw 8 (str 8)
|
||||
case 0xda: // raw 16 (str 16)
|
||||
case 0xdb: // raw 32 (str 32)
|
||||
trail = 1 << ((((unsigned int)*p) & 0x03) - 1);
|
||||
cs = next_cs(p);
|
||||
goto _fixed_trail_again;
|
||||
case 0xdc: // array 16
|
||||
case 0xdd: // array 32
|
||||
case 0xde: // map 16
|
||||
case 0xdf: // map 32
|
||||
trail = 2 << (((unsigned int)*p) & 0x01);
|
||||
cs = next_cs(p);
|
||||
goto _fixed_trail_again;
|
||||
default:
|
||||
goto _failed;
|
||||
}
|
||||
} else if(0xa0 <= *p && *p <= 0xbf) { // FixRaw
|
||||
trail = (unsigned int)*p & 0x1f;
|
||||
if(trail == 0) { goto _raw_zero; }
|
||||
cs = ACS_RAW_VALUE;
|
||||
goto _fixed_trail_again;
|
||||
|
||||
} else if(0x90 <= *p && *p <= 0x9f) { // FixArray
|
||||
if(top >= MSGPACK_EMBED_STACK_SIZE) { goto _failed; } /* FIXME */
|
||||
if(template_callback_array(user, ((unsigned int)*p) & 0x0f, &stack[top].obj) < 0) { goto _failed; }
|
||||
if((((unsigned int)*p) & 0x0f) == 0) { obj = stack[top].obj; goto _push; }
|
||||
stack[top].ct = CT_ARRAY_ITEM;
|
||||
stack[top].count = ((unsigned int)*p) & 0x0f;
|
||||
++top;
|
||||
goto _header_again;
|
||||
|
||||
} else if(0x80 <= *p && *p <= 0x8f) { // FixMap
|
||||
if(top >= MSGPACK_EMBED_STACK_SIZE) { goto _failed; } /* FIXME */
|
||||
if(template_callback_map(user, ((unsigned int)*p) & 0x0f, &stack[top].obj) < 0) { goto _failed; }
|
||||
if((((unsigned int)*p) & 0x0f) == 0) { obj = stack[top].obj; goto _push; }
|
||||
stack[top].ct = CT_MAP_KEY;
|
||||
stack[top].count = ((unsigned int)*p) & 0x0f;
|
||||
++top;
|
||||
goto _header_again;
|
||||
|
||||
} else {
|
||||
goto _failed;
|
||||
}
|
||||
// end CS_HEADER
|
||||
|
||||
|
||||
_fixed_trail_again:
|
||||
++p;
|
||||
|
||||
default:
|
||||
if((size_t)(pe - p) < trail) { goto _out; }
|
||||
n = p; p += trail - 1;
|
||||
switch(cs) {
|
||||
//case CS_
|
||||
//case CS_
|
||||
case CS_FLOAT: {
|
||||
union { uint32_t i; float f; } mem;
|
||||
mem.i = _msgpack_load32(uint32_t,n);
|
||||
if(template_callback_float(user, mem.f, &obj) < 0) { goto _failed; }
|
||||
goto _push; }
|
||||
case CS_DOUBLE: {
|
||||
union { uint64_t i; double f; } mem;
|
||||
mem.i = _msgpack_load64(uint64_t,n);
|
||||
#if defined(__arm__) && !(__ARM_EABI__) // arm-oabi
|
||||
// https://github.com/msgpack/msgpack-perl/pull/1
|
||||
mem.i = (mem.i & 0xFFFFFFFFUL) << 32UL | (mem.i >> 32UL);
|
||||
#endif
|
||||
if(template_callback_double(user, mem.f, &obj) < 0) { goto _failed; }
|
||||
goto _push; }
|
||||
case CS_UINT_8:
|
||||
if(template_callback_uint8(user, *(uint8_t*)n, &obj) < 0) { goto _failed; }
|
||||
goto _push;
|
||||
case CS_UINT_16:
|
||||
if(template_callback_uint16(user, _msgpack_load16(uint16_t,n), &obj) < 0) { goto _failed; }
|
||||
goto _push;
|
||||
case CS_UINT_32:
|
||||
if(template_callback_uint32(user, _msgpack_load32(uint32_t,n), &obj) < 0) { goto _failed; }
|
||||
goto _push;
|
||||
case CS_UINT_64:
|
||||
if(template_callback_uint64(user, _msgpack_load64(uint64_t,n), &obj) < 0) { goto _failed; }
|
||||
goto _push;
|
||||
|
||||
case CS_INT_8:
|
||||
if(template_callback_int8(user, *(int8_t*)n, &obj) < 0) { goto _failed; }
|
||||
goto _push;
|
||||
case CS_INT_16:
|
||||
if(template_callback_int16(user, _msgpack_load16(int16_t,n), &obj) < 0) { goto _failed; }
|
||||
goto _push;
|
||||
case CS_INT_32:
|
||||
if(template_callback_int32(user, _msgpack_load32(int32_t,n), &obj) < 0) { goto _failed; }
|
||||
goto _push;
|
||||
case CS_INT_64:
|
||||
if(template_callback_int64(user, _msgpack_load64(int64_t,n), &obj) < 0) { goto _failed; }
|
||||
goto _push;
|
||||
|
||||
case CS_BIN_8:
|
||||
case CS_RAW_8:
|
||||
trail = *(uint8_t*)n;
|
||||
if(trail == 0) { goto _raw_zero; }
|
||||
cs = ACS_RAW_VALUE;
|
||||
goto _fixed_trail_again;
|
||||
case CS_BIN_16:
|
||||
case CS_RAW_16:
|
||||
trail = _msgpack_load16(uint16_t, n);
|
||||
if(trail == 0) { goto _raw_zero; }
|
||||
cs = ACS_RAW_VALUE;
|
||||
goto _fixed_trail_again;
|
||||
case CS_BIN_32:
|
||||
case CS_RAW_32:
|
||||
trail = _msgpack_load32(uint32_t, n);
|
||||
if(trail == 0) { goto _raw_zero; }
|
||||
cs = ACS_RAW_VALUE;
|
||||
goto _fixed_trail_again;
|
||||
case ACS_RAW_VALUE:
|
||||
_raw_zero:
|
||||
if(template_callback_raw(user, (const char*)data, (const char*)n, trail, &obj) < 0) { goto _failed; }
|
||||
goto _push;
|
||||
case CS_ARRAY_16:
|
||||
if(top >= MSGPACK_EMBED_STACK_SIZE) { goto _failed; } /* FIXME */
|
||||
if(template_callback_array(user, _msgpack_load16(uint16_t, n), &stack[top].obj) < 0) { goto _failed; }
|
||||
if(_msgpack_load16(uint16_t, n) == 0) { obj = stack[top].obj; goto _push; }
|
||||
stack[top].ct = CT_ARRAY_ITEM;
|
||||
stack[top].count = _msgpack_load16(uint16_t, n);
|
||||
++top;
|
||||
goto _header_again;
|
||||
case CS_ARRAY_32:
|
||||
/* FIXME security guard */
|
||||
if(top >= MSGPACK_EMBED_STACK_SIZE) { goto _failed; } /* FIXME */
|
||||
if(template_callback_array(user, _msgpack_load32(uint32_t, n), &stack[top].obj) < 0) { goto _failed; }
|
||||
if(_msgpack_load32(uint32_t, n) == 0) { obj = stack[top].obj; goto _push; }
|
||||
stack[top].ct = CT_ARRAY_ITEM;
|
||||
stack[top].count = _msgpack_load32(uint32_t, n);
|
||||
++top;
|
||||
goto _header_again;
|
||||
|
||||
case CS_MAP_16:
|
||||
if(top >= MSGPACK_EMBED_STACK_SIZE) { goto _failed; } /* FIXME */
|
||||
if(template_callback_map(user, _msgpack_load16(uint16_t, n), &stack[top].obj) < 0) { goto _failed; }
|
||||
if(_msgpack_load16(uint16_t, n) == 0) { obj = stack[top].obj; goto _push; }
|
||||
stack[top].ct = CT_MAP_KEY;
|
||||
stack[top].count = _msgpack_load16(uint16_t, n);
|
||||
++top;
|
||||
goto _header_again;
|
||||
case CS_MAP_32:
|
||||
/* FIXME security guard */
|
||||
if(top >= MSGPACK_EMBED_STACK_SIZE) { goto _failed; } /* FIXME */
|
||||
if(template_callback_map(user, _msgpack_load32(uint32_t, n), &stack[top].obj) < 0) { goto _failed; }
|
||||
if(_msgpack_load32(uint32_t, n) == 0) { obj = stack[top].obj; goto _push; }
|
||||
stack[top].ct = CT_MAP_KEY;
|
||||
stack[top].count = _msgpack_load32(uint32_t, n);
|
||||
++top;
|
||||
goto _header_again;
|
||||
|
||||
default:
|
||||
goto _failed;
|
||||
}
|
||||
}
|
||||
|
||||
_push:
|
||||
if(top == 0) { goto _finish; }
|
||||
c = &stack[top-1];
|
||||
switch(c->ct) {
|
||||
case CT_ARRAY_ITEM:
|
||||
if(template_callback_array_item(user, &c->obj, obj) < 0) { goto _failed; }
|
||||
if(--c->count == 0) {
|
||||
obj = c->obj;
|
||||
--top;
|
||||
/*printf("stack pop %d\n", top);*/
|
||||
goto _push;
|
||||
}
|
||||
goto _header_again;
|
||||
case CT_MAP_KEY:
|
||||
c->map_key = obj;
|
||||
c->ct = CT_MAP_VALUE;
|
||||
goto _header_again;
|
||||
case CT_MAP_VALUE:
|
||||
if(template_callback_map_item(user, &c->obj, c->map_key, obj) < 0) { goto _failed; }
|
||||
if(--c->count == 0) {
|
||||
obj = c->obj;
|
||||
--top;
|
||||
/*printf("stack pop %d\n", top);*/
|
||||
goto _push;
|
||||
}
|
||||
c->ct = CT_MAP_KEY;
|
||||
goto _header_again;
|
||||
|
||||
default:
|
||||
goto _failed;
|
||||
}
|
||||
|
||||
_header_again:
|
||||
cs = CS_HEADER;
|
||||
++p;
|
||||
} while(p != pe);
|
||||
goto _out;
|
||||
|
||||
|
||||
_finish:
|
||||
stack[0].obj = obj;
|
||||
++p;
|
||||
ret = 1;
|
||||
/*printf("-- finish --\n"); */
|
||||
goto _end;
|
||||
|
||||
_failed:
|
||||
/*printf("** FAILED **\n"); */
|
||||
ret = -1;
|
||||
goto _end;
|
||||
|
||||
_out:
|
||||
ret = 0;
|
||||
goto _end;
|
||||
|
||||
_end:
|
||||
ctx.cs = cs;
|
||||
ctx.trail = trail;
|
||||
ctx.top = top;
|
||||
*off = p - (const unsigned char*)data;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
} // detail
|
||||
|
||||
|
||||
struct unpack_error : public std::runtime_error {
|
||||
unpack_error(const std::string& msg) :
|
||||
@@ -42,8 +510,8 @@ class unpacked {
|
||||
public:
|
||||
unpacked() { }
|
||||
|
||||
unpacked(object obj, std::auto_ptr<msgpack::zone> z) :
|
||||
m_obj(obj), m_zone(z) { }
|
||||
unpacked(object obj, std::unique_ptr<msgpack::zone> z) :
|
||||
m_obj(obj), m_zone(std::move(z)) { }
|
||||
|
||||
object& get()
|
||||
{ return m_obj; }
|
||||
@@ -51,19 +519,19 @@ public:
|
||||
const object& get() const
|
||||
{ return m_obj; }
|
||||
|
||||
std::auto_ptr<msgpack::zone>& zone()
|
||||
std::unique_ptr<msgpack::zone>& zone()
|
||||
{ return m_zone; }
|
||||
|
||||
const std::auto_ptr<msgpack::zone>& zone() const
|
||||
const std::unique_ptr<msgpack::zone>& zone() const
|
||||
{ return m_zone; }
|
||||
|
||||
private:
|
||||
object m_obj;
|
||||
std::auto_ptr<msgpack::zone> m_zone;
|
||||
std::unique_ptr<msgpack::zone> m_zone;
|
||||
};
|
||||
|
||||
|
||||
class unpacker : public msgpack_unpacker {
|
||||
class unpacker {
|
||||
public:
|
||||
unpacker(size_t init_buffer_size = MSGPACK_UNPACKER_INIT_BUFFER_SIZE);
|
||||
~unpacker();
|
||||
@@ -154,7 +622,19 @@ public:
|
||||
void remove_nonparsed_buffer();
|
||||
|
||||
private:
|
||||
typedef msgpack_unpacker base;
|
||||
void expand_buffer(size_t size);
|
||||
int execute_imp();
|
||||
bool flush_zone();
|
||||
|
||||
private:
|
||||
char* buffer_;
|
||||
size_t used_;
|
||||
size_t free_;
|
||||
size_t off_;
|
||||
size_t parsed_;
|
||||
zone* z_;
|
||||
size_t initial_buffer_size_;
|
||||
detail::template_context ctx_;
|
||||
|
||||
private:
|
||||
unpacker(const unpacker&);
|
||||
@@ -184,42 +664,130 @@ static object unpack(const char* data, size_t len, zone& z, size_t* off = NULL);
|
||||
|
||||
inline unpacker::unpacker(size_t initial_buffer_size)
|
||||
{
|
||||
if(!msgpack_unpacker_init(this, initial_buffer_size)) {
|
||||
if(initial_buffer_size < COUNTER_SIZE) {
|
||||
initial_buffer_size = COUNTER_SIZE;
|
||||
}
|
||||
|
||||
char* buffer = (char*)::malloc(initial_buffer_size);
|
||||
if(!buffer) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
|
||||
zone* z = zone::create(MSGPACK_ZONE_CHUNK_SIZE);
|
||||
if(!z) {
|
||||
::free(buffer);
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
|
||||
buffer_ = buffer;
|
||||
used_ = COUNTER_SIZE;
|
||||
free_ = initial_buffer_size - used_;
|
||||
off_ = COUNTER_SIZE;
|
||||
parsed_ = 0;
|
||||
initial_buffer_size_ = initial_buffer_size;
|
||||
z_ = z;
|
||||
|
||||
detail::init_count(buffer_);
|
||||
|
||||
detail::template_init(ctx_);
|
||||
ctx_.user.z = z_;
|
||||
ctx_.user.referenced = false;
|
||||
}
|
||||
|
||||
inline unpacker::~unpacker()
|
||||
{
|
||||
msgpack_unpacker_destroy(this);
|
||||
zone::destroy(z_);
|
||||
detail::decl_count(buffer_);
|
||||
}
|
||||
|
||||
|
||||
inline void unpacker::reserve_buffer(size_t size)
|
||||
{
|
||||
if(!msgpack_unpacker_reserve_buffer(this, size)) {
|
||||
throw std::bad_alloc();
|
||||
if(free_ >= size) return;
|
||||
expand_buffer(size);
|
||||
}
|
||||
|
||||
inline void unpacker::expand_buffer(size_t size)
|
||||
{
|
||||
if(used_ == off_ && detail::get_count(buffer_) == 1
|
||||
&& !ctx_.user.referenced) {
|
||||
// rewind buffer
|
||||
free_ += used_ - COUNTER_SIZE;
|
||||
used_ = COUNTER_SIZE;
|
||||
off_ = COUNTER_SIZE;
|
||||
|
||||
if(free_ >= size) return;
|
||||
}
|
||||
|
||||
if(off_ == COUNTER_SIZE) {
|
||||
size_t next_size = (used_ + free_) * 2; // include COUNTER_SIZE
|
||||
while(next_size < size + used_) {
|
||||
next_size *= 2;
|
||||
}
|
||||
|
||||
char* tmp = (char*)::realloc(buffer_, next_size);
|
||||
if(!tmp) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
|
||||
buffer_ = tmp;
|
||||
free_ = next_size - used_;
|
||||
|
||||
} else {
|
||||
size_t next_size = initial_buffer_size_; // include COUNTER_SIZE
|
||||
size_t not_parsed = used_ - off_;
|
||||
while(next_size < size + not_parsed + COUNTER_SIZE) {
|
||||
next_size *= 2;
|
||||
}
|
||||
|
||||
char* tmp = (char*)::malloc(next_size);
|
||||
if(!tmp) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
|
||||
detail::init_count(tmp);
|
||||
|
||||
::memcpy(tmp+COUNTER_SIZE, buffer_ + off_, not_parsed);
|
||||
|
||||
if(ctx_.user.referenced) {
|
||||
try {
|
||||
z_->push_finalizer(&detail::decl_count, buffer_);
|
||||
}
|
||||
catch (...) {
|
||||
::free(tmp);
|
||||
throw;
|
||||
}
|
||||
ctx_.user.referenced = false;
|
||||
} else {
|
||||
detail::decl_count(buffer_);
|
||||
}
|
||||
|
||||
buffer_ = tmp;
|
||||
used_ = not_parsed + COUNTER_SIZE;
|
||||
free_ = next_size - used_;
|
||||
off_ = COUNTER_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
inline char* unpacker::buffer()
|
||||
{
|
||||
return msgpack_unpacker_buffer(this);
|
||||
return buffer_ + used_;
|
||||
}
|
||||
|
||||
inline size_t unpacker::buffer_capacity() const
|
||||
{
|
||||
return msgpack_unpacker_buffer_capacity(this);
|
||||
return free_;
|
||||
}
|
||||
|
||||
inline void unpacker::buffer_consumed(size_t size)
|
||||
{
|
||||
return msgpack_unpacker_buffer_consumed(this, size);
|
||||
used_ += size;
|
||||
free_ -= size;
|
||||
}
|
||||
|
||||
inline bool unpacker::next(unpacked* result)
|
||||
{
|
||||
int ret = msgpack_unpacker_execute(this);
|
||||
int ret = execute_imp();
|
||||
|
||||
if(ret < 0) {
|
||||
throw unpack_error("parse error");
|
||||
@@ -241,7 +809,7 @@ inline bool unpacker::next(unpacked* result)
|
||||
|
||||
inline bool unpacker::execute()
|
||||
{
|
||||
int ret = msgpack_unpacker_execute(this);
|
||||
int ret = execute_imp();
|
||||
if(ret < 0) {
|
||||
throw unpack_error("parse error");
|
||||
} else if(ret == 0) {
|
||||
@@ -251,77 +819,159 @@ inline bool unpacker::execute()
|
||||
}
|
||||
}
|
||||
|
||||
inline int unpacker::execute_imp()
|
||||
{
|
||||
size_t off = off_;
|
||||
int ret = detail::template_execute(ctx_,
|
||||
buffer_, used_, &off_);
|
||||
if(off_ > off) {
|
||||
parsed_ += off_ - off;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline object unpacker::data()
|
||||
{
|
||||
return msgpack_unpacker_data(this);
|
||||
return template_data(ctx_);
|
||||
}
|
||||
|
||||
inline zone* unpacker::release_zone()
|
||||
{
|
||||
return static_cast<msgpack::zone*>(msgpack_unpacker_release_zone(static_cast<msgpack_unpacker*>(this)));
|
||||
if(!flush_zone()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
zone* r = zone::create(MSGPACK_ZONE_CHUNK_SIZE);
|
||||
if(!r) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
zone* old = z_;
|
||||
z_ = r;
|
||||
ctx_.user.z = z_;
|
||||
|
||||
return old;
|
||||
}
|
||||
|
||||
inline void unpacker::reset_zone()
|
||||
{
|
||||
msgpack_unpacker_reset_zone(this);
|
||||
z_->clear();
|
||||
}
|
||||
|
||||
inline bool unpacker::flush_zone()
|
||||
{
|
||||
if(ctx_.user.referenced) {
|
||||
try {
|
||||
z_->push_finalizer(&detail::decl_count, buffer_);
|
||||
} catch (...) {
|
||||
return false;
|
||||
}
|
||||
ctx_.user.referenced = false;
|
||||
|
||||
detail::incr_count(buffer_);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void unpacker::reset()
|
||||
{
|
||||
msgpack_unpacker_reset(this);
|
||||
detail::template_init(ctx_);
|
||||
// don't reset referenced flag
|
||||
parsed_ = 0;
|
||||
}
|
||||
|
||||
|
||||
inline size_t unpacker::message_size() const
|
||||
{
|
||||
return msgpack_unpacker_message_size(this);
|
||||
return parsed_ - off_ + used_;
|
||||
}
|
||||
|
||||
inline size_t unpacker::parsed_size() const
|
||||
{
|
||||
return msgpack_unpacker_parsed_size(this);
|
||||
return parsed_;
|
||||
}
|
||||
|
||||
inline char* unpacker::nonparsed_buffer()
|
||||
{
|
||||
return base::buffer + base::off;
|
||||
return buffer_ + off_;
|
||||
}
|
||||
|
||||
inline size_t unpacker::nonparsed_size() const
|
||||
{
|
||||
return base::used - base::off;
|
||||
return used_ - off_;
|
||||
}
|
||||
|
||||
inline void unpacker::skip_nonparsed_buffer(size_t size)
|
||||
{
|
||||
base::off += size;
|
||||
off_ += size;
|
||||
}
|
||||
|
||||
inline void unpacker::remove_nonparsed_buffer()
|
||||
{
|
||||
base::used = base::off;
|
||||
used_ = off_;
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
inline unpack_return
|
||||
unpack_imp(const char* data, size_t len, size_t* off,
|
||||
zone* result_zone, ::msgpack::object* result)
|
||||
{
|
||||
size_t noff = 0;
|
||||
if(off != NULL) { noff = *off; }
|
||||
|
||||
if(len <= noff) {
|
||||
// FIXME
|
||||
return UNPACK_CONTINUE;
|
||||
}
|
||||
|
||||
detail::template_context ctx;
|
||||
detail::template_init(ctx);
|
||||
|
||||
ctx.user.z = result_zone;
|
||||
ctx.user.referenced = false;
|
||||
|
||||
int e = detail::template_execute(ctx, data, len, &noff);
|
||||
if(e < 0) {
|
||||
return UNPACK_PARSE_ERROR;
|
||||
}
|
||||
|
||||
if(off != NULL) { *off = noff; }
|
||||
|
||||
if(e == 0) {
|
||||
return UNPACK_CONTINUE;
|
||||
}
|
||||
|
||||
*result = detail::template_data(ctx);
|
||||
|
||||
if(noff < len) {
|
||||
return UNPACK_EXTRA_BYTES;
|
||||
}
|
||||
|
||||
return UNPACK_SUCCESS;
|
||||
}
|
||||
|
||||
} // detail
|
||||
|
||||
inline void unpack(unpacked* result,
|
||||
const char* data, size_t len, size_t* offset)
|
||||
{
|
||||
msgpack::object obj;
|
||||
std::auto_ptr<msgpack::zone> z(new zone());
|
||||
std::unique_ptr<msgpack::zone> z(new zone());
|
||||
|
||||
unpack_return ret = detail::unpack_imp(
|
||||
data, len, offset, z.get(), &obj);
|
||||
|
||||
unpack_return ret = (unpack_return)msgpack_unpack(
|
||||
data, len, offset, z.get(),
|
||||
reinterpret_cast<msgpack_object*>(&obj));
|
||||
|
||||
switch(ret) {
|
||||
case UNPACK_SUCCESS:
|
||||
result->get() = obj;
|
||||
result->zone() = z;
|
||||
result->zone() = std::move(z);
|
||||
return;
|
||||
|
||||
case UNPACK_EXTRA_BYTES:
|
||||
result->get() = obj;
|
||||
result->zone() = z;
|
||||
result->zone() = std::move(z);
|
||||
return;
|
||||
|
||||
case UNPACK_CONTINUE:
|
||||
@@ -338,8 +988,8 @@ inline void unpack(unpacked* result,
|
||||
inline unpack_return unpack(const char* data, size_t len, size_t* off,
|
||||
zone* z, object* result)
|
||||
{
|
||||
return (unpack_return)msgpack_unpack(data, len, off,
|
||||
z, reinterpret_cast<msgpack_object*>(result));
|
||||
return detail::unpack_imp(data, len, off,
|
||||
z, result);
|
||||
}
|
||||
|
||||
// obsolete
|
||||
@@ -367,7 +1017,6 @@ inline object unpack(const char* data, size_t len, zone& z, size_t* off)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace msgpack
|
||||
|
||||
#endif /* msgpack/unpack.hpp */
|
||||
|
||||
37
src/msgpack/version.hpp.in
Normal file
37
src/msgpack/version.hpp.in
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* MessagePack for C++ version information
|
||||
*
|
||||
* Copyright (C) 2008-2013 FURUHASHI Sadayuki and Takatoshi Kondo
|
||||
*
|
||||
* 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_VERSION_HPP
|
||||
#define MSGPACK_VERSION_HPP
|
||||
|
||||
#define MSGPACK_VERSION "@VERSION@"
|
||||
#define MSGPACK_VERSION_MAJOR @VERSION_MAJOR@
|
||||
#define MSGPACK_VERSION_MINOR @VERSION_MINOR@
|
||||
|
||||
inline const char* msgpack_version(void) {
|
||||
return MSGPACK_VERSION;
|
||||
}
|
||||
|
||||
inline int msgpack_version_major(void) {
|
||||
return MSGPACK_VERSION_MAJOR;
|
||||
}
|
||||
|
||||
inline int msgpack_version_minor(void) {
|
||||
return MSGPACK_VERSION_MINOR;
|
||||
}
|
||||
|
||||
#endif /* msgpack/version.hpp */
|
||||
@@ -1,7 +1,7 @@
|
||||
//
|
||||
// MessagePack for C++ zero-copy buffer implementation
|
||||
//
|
||||
// Copyright (C) 2008-2009 FURUHASHI Sadayuki
|
||||
// Copyright (C) 2008-2013 FURUHASHI Sadayuki and KONDO Takatoshi
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@@ -15,34 +15,96 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
#ifndef MSGPACK_VREFBUFFER_HPP__
|
||||
#define MSGPACK_VREFBUFFER_HPP__
|
||||
#ifndef MSGPACK_VREFBUFFER_HPP
|
||||
#define MSGPACK_VREFBUFFER_HPP
|
||||
|
||||
#include "vrefbuffer.h"
|
||||
#include <stdexcept>
|
||||
|
||||
#ifndef MSGPACK_VREFBUFFER_REF_SIZE
|
||||
#define MSGPACK_VREFBUFFER_REF_SIZE 32
|
||||
#endif
|
||||
|
||||
#ifndef MSGPACK_VREFBUFFER_CHUNK_SIZE
|
||||
#define MSGPACK_VREFBUFFER_CHUNK_SIZE 8192
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <sys/uio.h>
|
||||
#else
|
||||
struct iovec {
|
||||
void *iov_base;
|
||||
size_t iov_len;
|
||||
};
|
||||
#endif
|
||||
|
||||
namespace msgpack {
|
||||
|
||||
namespace detail {
|
||||
|
||||
class vrefbuffer : public msgpack_vrefbuffer {
|
||||
|
||||
} // detail
|
||||
|
||||
class vrefbuffer {
|
||||
private:
|
||||
struct chunk {
|
||||
chunk* next;
|
||||
};
|
||||
struct inner_buffer {
|
||||
size_t free;
|
||||
char* ptr;
|
||||
chunk* head;
|
||||
};
|
||||
public:
|
||||
vrefbuffer(size_t ref_size = MSGPACK_VREFBUFFER_REF_SIZE,
|
||||
size_t chunk_size = MSGPACK_VREFBUFFER_CHUNK_SIZE)
|
||||
:ref_size_(ref_size), chunk_size_(chunk_size)
|
||||
{
|
||||
if (!msgpack_vrefbuffer_init(this, ref_size, chunk_size)) {
|
||||
size_t nfirst = (sizeof(iovec) < 72/2) ?
|
||||
72 / sizeof(iovec) : 8;
|
||||
|
||||
iovec* array = (iovec*)::malloc(
|
||||
sizeof(iovec) * nfirst);
|
||||
if(!array) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
|
||||
tail_ = array;
|
||||
end_ = array + nfirst;
|
||||
array_ = array;
|
||||
|
||||
chunk* c = (chunk*)::malloc(sizeof(chunk) + chunk_size);
|
||||
if(!c) {
|
||||
::free(array);
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
inner_buffer* const ib = &inner_buffer_;
|
||||
|
||||
ib->free = chunk_size;
|
||||
ib->ptr = ((char*)c) + sizeof(chunk);
|
||||
ib->head = c;
|
||||
c->next = nullptr;
|
||||
|
||||
}
|
||||
|
||||
~vrefbuffer()
|
||||
{
|
||||
msgpack_vrefbuffer_destroy(this);
|
||||
chunk* c = inner_buffer_.head;
|
||||
while(true) {
|
||||
chunk* n = c->next;
|
||||
::free(c);
|
||||
if(n != NULL) {
|
||||
c = n;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
::free(array_);
|
||||
}
|
||||
|
||||
public:
|
||||
void write(const char* buf, size_t len)
|
||||
{
|
||||
if(len < base::ref_size) {
|
||||
if(len < ref_size_) {
|
||||
append_copy(buf, len);
|
||||
} else {
|
||||
append_ref(buf, len);
|
||||
@@ -51,45 +113,162 @@ public:
|
||||
|
||||
void append_ref(const char* buf, size_t len)
|
||||
{
|
||||
if(msgpack_vrefbuffer_append_ref(this, buf, len) < 0) {
|
||||
throw std::bad_alloc();
|
||||
if(tail_ == end_) {
|
||||
const size_t nused = tail_ - array_;
|
||||
const size_t nnext = nused * 2;
|
||||
|
||||
iovec* nvec = (iovec*)::realloc(
|
||||
array_, sizeof(iovec)*nnext);
|
||||
if(!nvec) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
|
||||
array_ = nvec;
|
||||
end_ = nvec + nnext;
|
||||
tail_ = nvec + nused;
|
||||
}
|
||||
|
||||
tail_->iov_base = (char*)buf;
|
||||
tail_->iov_len = len;
|
||||
++tail_;
|
||||
}
|
||||
|
||||
void append_copy(const char* buf, size_t len)
|
||||
{
|
||||
if(msgpack_vrefbuffer_append_copy(this, buf, len) < 0) {
|
||||
throw std::bad_alloc();
|
||||
inner_buffer* const ib = &inner_buffer_;
|
||||
|
||||
if(ib->free < len) {
|
||||
size_t sz = chunk_size_;
|
||||
if(sz < len) {
|
||||
sz = len;
|
||||
}
|
||||
|
||||
chunk* c = (chunk*)::malloc(sizeof(chunk) + sz);
|
||||
if(!c) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
|
||||
c->next = ib->head;
|
||||
ib->head = c;
|
||||
ib->free = sz;
|
||||
ib->ptr = ((char*)c) + sizeof(chunk);
|
||||
}
|
||||
|
||||
char* m = ib->ptr;
|
||||
::memcpy(m, buf, len);
|
||||
ib->free -= len;
|
||||
ib->ptr += len;
|
||||
|
||||
if(tail_ != array_ && m ==
|
||||
(const char*)((tail_ - 1)->iov_base) + (tail_ - 1)->iov_len) {
|
||||
(tail_ - 1)->iov_len += len;
|
||||
return;
|
||||
} else {
|
||||
append_ref( m, len);
|
||||
}
|
||||
}
|
||||
|
||||
const struct iovec* vector() const
|
||||
{
|
||||
return msgpack_vrefbuffer_vec(this);
|
||||
return array_;
|
||||
}
|
||||
|
||||
size_t vector_size() const
|
||||
{
|
||||
return msgpack_vrefbuffer_veclen(this);
|
||||
return tail_ - array_;
|
||||
}
|
||||
|
||||
void migrate(vrefbuffer* to)
|
||||
{
|
||||
if(msgpack_vrefbuffer_migrate(this, to) < 0) {
|
||||
size_t sz = chunk_size_;
|
||||
|
||||
chunk* empty = (chunk*)::malloc(sizeof(chunk) + sz);
|
||||
if(!empty) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
}
|
||||
|
||||
empty->next = nullptr;
|
||||
|
||||
const size_t nused = tail_ - array_;
|
||||
if(to->tail_ + nused < end_) {
|
||||
const size_t tosize = to->tail_ - to->array_;
|
||||
const size_t reqsize = nused + tosize;
|
||||
size_t nnext = (to->end_ - to->array_) * 2;
|
||||
while(nnext < reqsize) {
|
||||
nnext *= 2;
|
||||
}
|
||||
|
||||
iovec* nvec = (iovec*)::realloc(
|
||||
to->array_, sizeof(iovec)*nnext);
|
||||
if(!nvec) {
|
||||
::free(empty);
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
|
||||
to->array_ = nvec;
|
||||
to->end_ = nvec + nnext;
|
||||
to->tail_ = nvec + tosize;
|
||||
}
|
||||
|
||||
::memcpy(to->tail_, array_, sizeof(iovec)*nused);
|
||||
|
||||
to->tail_ += nused;
|
||||
tail_ = array_;
|
||||
|
||||
|
||||
inner_buffer* const ib = &inner_buffer_;
|
||||
inner_buffer* const toib = &to->inner_buffer_;
|
||||
|
||||
chunk* last = ib->head;
|
||||
while(last->next) {
|
||||
last = last->next;
|
||||
}
|
||||
last->next = toib->head;
|
||||
toib->head = ib->head;
|
||||
|
||||
if(toib->free < ib->free) {
|
||||
toib->free = ib->free;
|
||||
toib->ptr = ib->ptr;
|
||||
}
|
||||
|
||||
ib->head = empty;
|
||||
ib->free = sz;
|
||||
ib->ptr = ((char*)empty) + sizeof(chunk);
|
||||
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
msgpack_vrefbuffer_clear(this);
|
||||
}
|
||||
chunk* c = inner_buffer_.head->next;
|
||||
chunk* n;
|
||||
while(c) {
|
||||
n = c->next;
|
||||
::free(c);
|
||||
c = n;
|
||||
}
|
||||
|
||||
private:
|
||||
typedef msgpack_vrefbuffer base;
|
||||
inner_buffer* const ib = &inner_buffer_;
|
||||
c = ib->head;
|
||||
c->next = nullptr;
|
||||
ib->free = chunk_size_;
|
||||
ib->ptr = ((char*)c) + sizeof(chunk);
|
||||
|
||||
tail_ = array_;
|
||||
}
|
||||
|
||||
private:
|
||||
vrefbuffer(const vrefbuffer&);
|
||||
|
||||
private:
|
||||
iovec* tail_;
|
||||
iovec* end_;
|
||||
iovec* array_;
|
||||
|
||||
size_t ref_size_;
|
||||
size_t chunk_size_;
|
||||
|
||||
inner_buffer inner_buffer_;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//
|
||||
// MessagePack for C++ deflate buffer implementation
|
||||
//
|
||||
// Copyright (C) 2010 FURUHASHI Sadayuki
|
||||
// Copyright (C) 2010-2013 FURUHASHI Sadayuki and KONDO Takatoshi
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@@ -15,84 +15,144 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
#ifndef MSGPACK_ZBUFFER_HPP__
|
||||
#define MSGPACK_ZBUFFER_HPP__
|
||||
#ifndef MSGPACK_ZBUFFER_HPP
|
||||
#define MSGPACK_ZBUFFER_HPP
|
||||
|
||||
#include "zbuffer.h"
|
||||
#include <stdexcept>
|
||||
#include <zlib.h>
|
||||
|
||||
#ifndef MSGPACK_ZBUFFER_RESERVE_SIZE
|
||||
#define MSGPACK_ZBUFFER_RESERVE_SIZE 512
|
||||
#endif
|
||||
|
||||
#ifndef MSGPACK_ZBUFFER_INIT_SIZE
|
||||
#define MSGPACK_ZBUFFER_INIT_SIZE 8192
|
||||
#endif
|
||||
|
||||
namespace msgpack {
|
||||
|
||||
|
||||
class zbuffer : public msgpack_zbuffer {
|
||||
class zbuffer {
|
||||
public:
|
||||
zbuffer(int level = Z_DEFAULT_COMPRESSION,
|
||||
size_t init_size = MSGPACK_ZBUFFER_INIT_SIZE)
|
||||
: data_(nullptr), init_size_(init_size)
|
||||
{
|
||||
if (!msgpack_zbuffer_init(this, level, init_size)) {
|
||||
stream_.zalloc = Z_NULL;
|
||||
stream_.zfree = Z_NULL;
|
||||
stream_.opaque = Z_NULL;
|
||||
stream_.next_out = Z_NULL;
|
||||
stream_.avail_out = 0;
|
||||
if(deflateInit(&stream_, level) != Z_OK) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
}
|
||||
|
||||
~zbuffer()
|
||||
{
|
||||
msgpack_zbuffer_destroy(this);
|
||||
deflateEnd(&stream_);
|
||||
::free(data_);
|
||||
}
|
||||
|
||||
public:
|
||||
void write(const char* buf, size_t len)
|
||||
{
|
||||
if(msgpack_zbuffer_write(this, buf, len) < 0) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
stream_.next_in = (Bytef*)buf;
|
||||
stream_.avail_in = len;
|
||||
|
||||
do {
|
||||
if(stream_.avail_out < MSGPACK_ZBUFFER_RESERVE_SIZE) {
|
||||
if(!expand()) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
}
|
||||
|
||||
if(deflate(&stream_, Z_NO_FLUSH) != Z_OK) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
} while(stream_.avail_in > 0);
|
||||
}
|
||||
|
||||
char* flush()
|
||||
{
|
||||
char* buf = msgpack_zbuffer_flush(this);
|
||||
if(!buf) {
|
||||
throw std::bad_alloc();
|
||||
while(true) {
|
||||
switch(deflate(&stream_, Z_FINISH)) {
|
||||
case Z_STREAM_END:
|
||||
return data_;
|
||||
case Z_OK:
|
||||
if(!expand()) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
char* data()
|
||||
{
|
||||
return base::data;
|
||||
return data_;
|
||||
}
|
||||
|
||||
const char* data() const
|
||||
{
|
||||
return base::data;
|
||||
return data_;
|
||||
}
|
||||
|
||||
size_t size() const
|
||||
{
|
||||
return msgpack_zbuffer_size(this);
|
||||
return (char*)stream_.next_out - data_;
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
if(!msgpack_zbuffer_reset(this)) {
|
||||
if(deflateReset(&stream_) != Z_OK) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
reset_buffer();
|
||||
}
|
||||
|
||||
void reset_buffer()
|
||||
{
|
||||
msgpack_zbuffer_reset_buffer(this);
|
||||
stream_.avail_out += (char*)stream_.next_out - data_;
|
||||
stream_.next_out = (Bytef*)data_;
|
||||
}
|
||||
|
||||
char* release_buffer()
|
||||
{
|
||||
return msgpack_zbuffer_release_buffer(this);
|
||||
char* tmp = data_;
|
||||
data_ = NULL;
|
||||
stream_.next_out = NULL;
|
||||
stream_.avail_out = 0;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
private:
|
||||
typedef msgpack_zbuffer base;
|
||||
bool expand()
|
||||
{
|
||||
size_t used = (char*)stream_.next_out - data_;
|
||||
size_t csize = used + stream_.avail_out;
|
||||
size_t nsize = (csize == 0) ? init_size_ : csize * 2;
|
||||
|
||||
char* tmp = (char*)::realloc(data_, nsize);
|
||||
if(tmp == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
data_ = tmp;
|
||||
stream_.next_out = (Bytef*)(tmp + used);
|
||||
stream_.avail_out = nsize - used;
|
||||
|
||||
return true;
|
||||
}
|
||||
private:
|
||||
zbuffer(const zbuffer&);
|
||||
|
||||
private:
|
||||
z_stream stream_;
|
||||
char* data_;
|
||||
size_t init_size_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user