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:
Takatoshi Kondo
2013-08-22 17:21:47 +09:00
parent 197ed8c983
commit c2ca709d68
19 changed files with 1761 additions and 134 deletions

View File

@@ -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

View File

@@ -21,4 +21,4 @@
#include "msgpack/unpack.hpp"
#include "msgpack/sbuffer.hpp"
#include "msgpack/vrefbuffer.hpp"
#include "msgpack.h"
#include "msgpack/version.hpp"

View File

@@ -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_;
};

View File

@@ -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 */

View 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 */

View File

@@ -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_;
};

View File

@@ -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_;
};