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

1
.gitignore vendored
View File

@ -19,6 +19,7 @@ Makefile.in
/libtool
/msgpack.pc
/src/msgpack/version.h
/src/msgpack/version.hpp
/stamp-h1
Makefile
.deps

View File

@ -10,6 +10,18 @@ SET (exec_prefix "\${prefix}")
SET (libdir "\${exec_prefix}/lib")
SET (includedir "\${prefix}/include")
OPTION (MSGPACK_CXX11 "Using c++11 compiler" OFF)
IF (MSGPACK_CXX11)
IF ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
SET (CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")
ELSEIF ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
SET (CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")
ELSEIF ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
MESSAGE ( FATAL_ERROR "MSVC doesn't support C++11 yet.")
ENDIF ()
ENDIF ()
FIND_PACKAGE (GTest)
FIND_PACKAGE (ZLIB)
FIND_PACKAGE (Threads)
@ -17,6 +29,26 @@ IF (GTEST_FOUND AND ZLIB_FOUND AND THREADS_FOUND)
OPTION (MSGPACK_BUILD_TESTS "Build msgpack tests." ON)
ENDIF ()
# Files to copy
MACRO (COPY_FILE SOURCE DESTINATION)
# COPY_FILE (readme.txt dir1/dir2/) would add new target
# that will copy readme.txt to dir1/dir2 where dir1 will be located
# in current binary directory.
ADD_CUSTOM_COMMAND (
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${DESTINATION}/${SOURCE}
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/${DESTINATION}
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE} ${CMAKE_CURRENT_BINARY_DIR}/${DESTINATION}/${SOURCE}
)
ENDMACRO ()
IF (MSGPACK_CXX11)
COPY_FILE (cpp11/zone.hpp src/msgpack/zone.hpp)
COPY_FILE (cpp11/define.hpp src/msgpack/type/define.hpp)
COPY_FILE (cpp11/tuple.hpp src/msgpack/type/tuple.hpp)
ENDIF ()
OPTION (MSGPACK_ENABLE_CXX "Enable C++ interface." ON)
INCLUDE (CheckCXXSourceCompiles)
@ -109,6 +141,10 @@ CONFIGURE_FILE (
src/msgpack/version.h.in
${CMAKE_CURRENT_BINARY_DIR}/src/msgpack/version.h
)
CONFIGURE_FILE (
src/msgpack/version.hpp.in
${CMAKE_CURRENT_BINARY_DIR}/src/msgpack/version.hpp
)
CONFIGURE_FILE (
msgpack.pc.in

View File

@ -38,6 +38,16 @@ $ make
$ sudo make install
```
If you want to setup C++11 version of msgpack, execute the following command:
```
$ git clone https://github.com/msgpack/msgpack-c.git
$ cd msgpack-c
$ ./bootstrap
$ ./configure CXXFLAGS="-std=c++11"
```
You need the compiler that fully supports C++11.
##### Using cmake
You will need gcc (4.1.0 or higher), cmake.
@ -48,6 +58,16 @@ $ cmake .
$ make
```
If you want to setup C++11 version of msgpack, execute the following command:
```
$ git clone https://github.com/msgpack/msgpack-c.git
$ cd msgpack-c
$ cmake -DMSGPACK_CXX11=ON .
```
You need the compiler that fully supports C++11.
#### Install from package
##### UNIX-like platform with ./configure

View File

@ -3,6 +3,27 @@ AC_CONFIG_AUX_DIR(ac)
AM_INIT_AUTOMAKE(msgpack, 0.5.9)
AC_CONFIG_HEADER(config.h)
AC_LANG_PUSH([C++])
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
#if __cplusplus < 201103
#error
#endif
])],
[
./preprocess_cpp11
if test $? != 0; then
exit 1
fi
],
[
./preprocess
if test $? != 0; then
exit 1
fi
])
AC_LANG_POP()
AC_SUBST(CFLAGS)
CFLAGS="-O3 -Wall $CFLAGS"
@ -96,5 +117,6 @@ AC_OUTPUT([Makefile
msgpack.pc
src/Makefile
src/msgpack/version.h
src/msgpack/version.hpp
test/Makefile])

170
cpp11/define.hpp Normal file
View File

@ -0,0 +1,170 @@
//
// MessagePack for C++ static resolution routine
//
// 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.
// 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_TYPE_DEFINE_HPP
#define MSGPACK_TYPE_DEFINE_HPP
#define MSGPACK_DEFINE(...) \
template <typename Packer> \
void msgpack_pack(Packer& pk) const \
{ \
msgpack::type::make_define(__VA_ARGS__).msgpack_pack(pk); \
} \
void msgpack_unpack(msgpack::object o) \
{ \
msgpack::type::make_define(__VA_ARGS__).msgpack_unpack(o); \
}\
template <typename MSGPACK_OBJECT> \
void msgpack_object(MSGPACK_OBJECT* o, msgpack::zone* z) const \
{ \
msgpack::type::make_define(__VA_ARGS__).msgpack_object(o, z); \
}
// MSGPACK_ADD_ENUM must be used in the global namespace.
#define MSGPACK_ADD_ENUM(enum) \
namespace msgpack { \
template <> \
inline enum& operator>> (object o, enum& v) \
{ \
int tmp; \
o >> tmp; \
v = static_cast<enum>(tmp); \
return v; \
} \
template <> \
void operator<< (object::with_zone& o, const enum& v) \
{ \
int tmp = static_cast<enum>(v); \
o << tmp; \
} \
namespace detail { \
template <typename Stream> \
struct packer_serializer<Stream, enum> { \
static packer<Stream>& pack(packer<Stream>& o, const enum& v) { \
return o << static_cast<int>(v); \
} \
}; \
} \
}
namespace msgpack {
namespace type {
template <typename Tuple, std::size_t N>
struct define_imp {
template <typename Packer>
static void pack(Packer& pk, Tuple const& t) {
define_imp<Tuple, N-1>::pack(pk, t);
pk.pack(std::get<N-1>(t));
}
static void unpack(msgpack::object o, Tuple& t) {
define_imp<Tuple, N-1>::unpack(o, t);
const size_t size = o.via.array.size;
if(size <= N-1) { return; }
o.via.array.ptr[N-1].convert(&std::get<N-1>(t));
}
static void object(msgpack::object* o, msgpack::zone* z, Tuple const& t) {
define_imp<Tuple, N-1>::object(o, z, t);
o->via.array.ptr[N-1] = msgpack::object(std::get<N-1>(t), z);
}
};
template <typename Tuple>
struct define_imp<Tuple, 1> {
template <typename Packer>
static void pack(Packer& pk, Tuple const& t) {
pk.pack(std::get<0>(t));
}
static void unpack(msgpack::object o, Tuple& t) {
const size_t size = o.via.array.size;
if(size <= 0) { return; }
o.via.array.ptr[0].convert(&std::get<0>(t));
}
static void object(msgpack::object* o, msgpack::zone* z, Tuple const& t) {
o->via.array.ptr[0] = msgpack::object(std::get<0>(t), z);
}
};
template <typename... Args>
struct define {
typedef define<Args...> value_type;
typedef tuple<Args...> tuple_type;
define(Args&... args) :
a(args...) {}
template <typename Packer>
void msgpack_pack(Packer& pk) const
{
pk.pack_array(sizeof...(Args));
define_imp<tuple<Args&...>, sizeof...(Args)>::pack(pk, a);
}
void msgpack_unpack(msgpack::object o)
{
if(o.type != type::ARRAY) { throw type_error(); }
define_imp<tuple<Args&...>, sizeof...(Args)>::unpack(o, a);
}
void msgpack_object(msgpack::object* o, msgpack::zone* z) const
{
o->type = type::ARRAY;
o->via.array.ptr = (object*)z->malloc(sizeof(object)*sizeof...(Args));
o->via.array.size = sizeof...(Args);
define_imp<tuple<Args&...>, sizeof...(Args)>::object(o, z, a);
}
tuple<Args&...> a;
};
template <>
struct define<> {
typedef define<> value_type;
typedef tuple<> tuple_type;
template <typename Packer>
void msgpack_pack(Packer& pk) const
{
pk.pack_array(0);
}
void msgpack_unpack(msgpack::object o)
{
if(o.type != type::ARRAY) { throw type_error(); }
}
void msgpack_object(msgpack::object* o, msgpack::zone* z) const
{
o->type = type::ARRAY;
o->via.array.ptr = NULL;
o->via.array.size = 0;
}
};
inline define<> make_define()
{
return define<>();
}
template <typename... Args>
define<Args...> make_define(Args&... args)
{
return define<Args...>(args...);
}
} // namespace type
} // namespace msgpack
#endif /* msgpack/type/define.hpp */

125
cpp11/tuple.hpp Normal file
View File

@ -0,0 +1,125 @@
//
// MessagePack for C++ static resolution routine
//
// 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.
// 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_TYPE_TUPLE_HPP
#define MSGPACK_TYPE_TUPLE_HPP
#include "msgpack/object.hpp"
#include <tuple>
namespace msgpack {
namespace type {
template <typename... Args>
using tuple = std::tuple<Args...>;
} // type
// --- Pack ( from tuple to packer stream ---
template <typename Stream, typename Tuple, std::size_t N>
struct Packer {
static void pack(
packer<Stream>& o,
const Tuple& v) {
Packer<Stream, Tuple, N-1>::pack(o, v);
o.pack(std::get<N-1>(v));
}
};
template <typename Stream, typename Tuple>
struct Packer<Stream, Tuple, 1> {
static void pack (
packer<Stream>& o,
const Tuple& v) {
o.pack(std::get<0>(v));
}
};
template <typename Stream, typename... Args>
const packer<Stream>& operator<< (
packer<Stream>& o,
const type::tuple<Args...>& v) {
o.pack_array(sizeof...(Args));
Packer<Stream, decltype(v), sizeof...(Args)>::pack(o, v);
return o;
}
// --- Convert from tuple to object ---
template <typename Tuple, std::size_t N>
struct Converter {
static void convert(
object o,
Tuple& v) {
Converter<Tuple, N-1>::convert(o, v);
o.via.array.ptr[N-1].convert<typename std::remove_reference<decltype(std::get<N-1>(v))>::type>(&std::get<N-1>(v));
}
};
template <typename Tuple>
struct Converter<Tuple, 1> {
static void convert (
object o,
Tuple& v) {
o.via.array.ptr[0].convert<typename std::remove_reference<decltype(std::get<0>(v))>::type>(&std::get<0>(v));
}
};
template <typename... Args>
type::tuple<Args...>& operator>> (
object o,
type::tuple<Args...>& v) {
if(o.type != type::ARRAY) { throw type_error(); }
if(o.via.array.size < sizeof...(Args)) { throw type_error(); }
Converter<decltype(v), sizeof...(Args)>::convert(o, v);
return v;
}
// --- Convert from tuple to object with zone ---
template <typename Tuple, std::size_t N>
struct TupleToObjectWithZone {
static void convert(
object::with_zone& o,
const Tuple& v) {
TupleToObjectWithZone<Tuple, N-1>::convert(o, v);
o.via.array.ptr[N-1] = object(std::get<N-1>(v), o.zone);
}
};
template <typename Tuple>
struct TupleToObjectWithZone<Tuple, 1> {
static void convert (
object::with_zone& o,
const Tuple& v) {
o.via.array.ptr[0] = object(std::get<0>(v), o.zone);
}
};
template <typename... Args>
inline void operator<< (
object::with_zone& o,
type::tuple<Args...>& v) {
o.type = type::ARRAY;
o.via.array.ptr = (object*)o.zone->malloc(sizeof(object)*sizeof...(Args));
o.via.array.size = sizeof...(Args);
TupleToObjectWithZone<decltype(v), sizeof...(Args)>::convert(o, v);
}
} // msgpack
#endif /* msgpack/type/tuple.hpp */

304
cpp11/zone.hpp Normal file
View File

@ -0,0 +1,304 @@
//
// MessagePack for C++ memory pool
//
// 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.
// 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_ZONE_HPP
#define MSGPACK_ZONE_HPP
#include <cstdlib>
#include <memory>
#include <vector>
#ifndef MSGPACK_ZONE_CHUNK_SIZE
#define MSGPACK_ZONE_CHUNK_SIZE 8192
#endif
#ifndef MSGPACK_ZONE_ALIGN
#define MSGPACK_ZONE_ALIGN sizeof(int)
#endif
namespace msgpack {
class zone {
private:
struct finalizer {
finalizer(void (*func)(void*), void* data):func_(func), data_(data) {}
void operator()() { func_(data_); }
void (*func_)(void*);
void* data_;
};
struct finalizer_array {
finalizer_array():tail_(nullptr), end_(nullptr), array_(nullptr) {}
void call() {
finalizer* fin = tail_;
for(; fin != array_; --fin) (*(fin-1))();
}
~finalizer_array() {
call();
::free(array_);
}
void clear() {
call();
tail_ = array_;
}
void push(void (*func)(void* data), void* data)
{
finalizer* fin = tail_;
if(fin == end_) {
push_expand(func, data);
return;
}
fin->func_ = func;
fin->data_ = data;
++tail_;
}
void push_expand(void (*func)(void*), void* data) {
const size_t nused = end_ - array_;
size_t nnext;
if(nused == 0) {
nnext = (sizeof(finalizer) < 72/2) ?
72 / sizeof(finalizer) : 8;
} else {
nnext = nused * 2;
}
finalizer* tmp =
(finalizer*)::realloc(array_, sizeof(finalizer) * nnext);
if(!tmp) {
throw std::bad_alloc();
}
array_ = tmp;
end_ = tmp + nnext;
tail_ = tmp + nused;
new (tail_) finalizer(func, data);
++tail_;
}
finalizer* tail_;
finalizer* end_;
finalizer* array_;
};
struct chunk {
chunk* next_;
};
struct chunk_list {
chunk_list(size_t chunk_size)
{
chunk* c = (chunk*)::malloc(sizeof(chunk) + chunk_size);
if(!c) {
throw std::bad_alloc();
}
head_ = c;
free_ = chunk_size;
ptr_ = ((char*)c) + sizeof(chunk);
c->next_ = nullptr;
}
~chunk_list()
{
chunk* c = head_;
while(true) {
chunk* n = c->next_;
::free(c);
if(n) {
c = n;
} else {
break;
}
}
}
void clear(size_t chunk_size)
{
chunk* c = head_;
while(true) {
chunk* n = c->next_;
if(n) {
::free(c);
c = n;
} else {
break;
}
}
head_->next_ = nullptr;
free_ = chunk_size;
ptr_ = ((char*)head_) + sizeof(chunk);
}
size_t free_;
char* ptr_;
chunk* head_;
};
size_t chunk_size_;
chunk_list chunk_list_;
finalizer_array finalizer_array_;
public:
zone(size_t chunk_size = MSGPACK_ZONE_CHUNK_SIZE);
public:
static zone* create(size_t chunk_size);
static void destroy(zone* zone);
void* malloc(size_t size);
void* malloc_no_align(size_t size);
void push_finalizer(void (*func)(void*), void* data);
template <typename T>
void push_finalizer(std::unique_ptr<T> obj);
void clear();
void swap(zone& o);
template <typename T, typename... Args>
T* allocate(Args... args);
private:
void undo_malloc(size_t size);
template <typename T>
static void object_destructor(void* obj);
void* malloc_expand(size_t size);
};
inline zone* zone::create(size_t chunk_size)
{
zone* z = (zone*)::malloc(sizeof(zone) + chunk_size);
if (!z) {
return nullptr;
}
try {
new (z) zone(chunk_size);
}
catch (...) {
::free(z);
return nullptr;
}
return z;
}
inline void zone::destroy(zone* z)
{
z->~zone();
::free(z);
}
inline zone::zone(size_t chunk_size):chunk_size_(chunk_size), chunk_list_(chunk_size_)
{
}
inline void* zone::malloc(size_t size)
{
return malloc_no_align(
((size)+((MSGPACK_ZONE_ALIGN)-1)) & ~((MSGPACK_ZONE_ALIGN)-1));
}
inline void* zone::malloc_no_align(size_t size)
{
if(chunk_list_.free_ < size) {
return malloc_expand(size);
}
char* ptr = chunk_list_.ptr_;
chunk_list_.free_ -= size;
chunk_list_.ptr_ += size;
return ptr;
}
inline void* zone::malloc_expand(size_t size)
{
chunk_list* const cl = &chunk_list_;
size_t sz = chunk_size_;
while(sz < size) {
sz *= 2;
}
chunk* c = (chunk*)::malloc(sizeof(chunk) + sz);
char* ptr = ((char*)c) + sizeof(chunk);
c->next_ = cl->head_;
cl->head_ = c;
cl->free_ = sz - size;
cl->ptr_ = ptr + size;
return ptr;
}
inline void zone::push_finalizer(void (*func)(void*), void* data)
{
finalizer_array_.push(func, data);
}
template <typename T>
inline void zone::push_finalizer(std::unique_ptr<T> obj)
{
finalizer_array_.push(&zone::object_destructor<T>, obj.get());
obj.release();
}
inline void zone::clear()
{
finalizer_array_.clear();
chunk_list_.clear(chunk_size_);
}
inline void zone::swap(zone& o)
{
std::swap(*this, o);
}
template <typename T>
void zone::object_destructor(void* obj)
{
reinterpret_cast<T*>(obj)->~T();
}
inline void zone::undo_malloc(size_t size)
{
chunk_list_.ptr_ -= size;
chunk_list_.free_ += size;
}
template <typename T, typename... Args>
T* zone::allocate(Args... args)
{
void* x = malloc(sizeof(T));
try {
finalizer_array_.push(&zone::object_destructor<T>, x);
} catch (...) {
undo_malloc(sizeof(T));
throw;
}
try {
return new (x) T(args...);
} catch (...) {
--finalizer_array_.tail_;
undo_malloc(sizeof(T));
throw;
}
}
} // namespace msgpack
#endif /* msgpack/zone.hpp */

17
preprocess_cpp11 Executable file
View File

@ -0,0 +1,17 @@
#!/bin/sh
if [ "$1" = "clean" ];then
rm -f src/msgpack/type/tuple.hpp
rm -f src/msgpack/type/define.hpp
rm -f src/msgpack/zone.hpp
else
cp -f cpp11/zone.hpp src/msgpack/
cp -f cpp11/tuple.hpp src/msgpack/type/
cp -f cpp11/define.hpp src/msgpack/type/
fi
cp -f cases.mpac test/
cp -f cases_compact.mpac test/
sed -e 's/8\.00/9.00/' < msgpack_vc8.vcproj > msgpack_vc2008.vcproj
sed -e 's/9\.00/10.00/' -e 's/msgpack_vc8/msgpack_vc2008/' < msgpack_vc8.sln > msgpack_vc2008.sln

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

View File

@ -1,4 +1,4 @@
#include <msgpack.hpp>
#include <msgpack.h>
#include <gtest/gtest.h>
TEST(fixint, size)

View File

@ -170,10 +170,10 @@ TEST(MSGPACK, simple_buffer_float)
float val2;
obj.convert(&val2);
if (isnan(val1))
EXPECT_TRUE(isnan(val2));
else if (isinf(val1))
EXPECT_TRUE(isinf(val2));
if (std::isnan(val1))
EXPECT_TRUE(std::isnan(val2));
else if (std::isinf(val1))
EXPECT_TRUE(std::isinf(val2));
else
EXPECT_TRUE(fabs(val2 - val1) <= kEPS);
}
@ -260,10 +260,10 @@ TEST(MSGPACK, simple_buffer_double)
double val2;
obj.convert(&val2);
if (isnan(val1))
EXPECT_TRUE(isnan(val2));
else if (isinf(val1))
EXPECT_TRUE(isinf(val2));
if (std::isnan(val1))
EXPECT_TRUE(std::isnan(val2));
else if (std::isinf(val1))
EXPECT_TRUE(std::isinf(val2));
else
EXPECT_TRUE(fabs(val2 - val1) <= kEPS);
}
@ -901,11 +901,11 @@ public:
msgpack::type::tuple<bool, msgpack::object> tuple;
o.convert(&tuple);
is_double = tuple.get<0>();
is_double = get<0>(tuple);
if (is_double)
tuple.get<1>().convert(&value.f);
get<1>(tuple).convert(&value.f);
else
tuple.get<1>().convert(&value.i);
get<1>(tuple).convert(&value.i);
}
};
@ -1097,7 +1097,7 @@ TEST(MSGPACK, vrefbuffer_int64)
obj.convert(&val); \
EXPECT_EQ(*it, val); \
++it; \
msgpack_zone_free(life); \
msgpack::zone::destroy(life); \
} \
p += sz; \
} \

View File

@ -69,7 +69,7 @@ public:
msgpack::unpacked result;
while(pac.next(&result)) {
on_message(result.get(), result.zone());
on_message(result.get(), std::move(result.zone()));
}
if(pac.message_size() > 10*1024*1024) {
@ -78,7 +78,7 @@ public:
}
}
void on_message(msgpack::object obj, std::auto_ptr<msgpack::zone> z)
void on_message(msgpack::object obj, std::unique_ptr<msgpack::zone> z)
{
EXPECT_EQ(expect, obj.as<int>());
}
@ -133,7 +133,7 @@ TEST(streaming, basic_compat)
pac.buffer_consumed(len);
while(pac.execute()) {
std::auto_ptr<msgpack::zone> z(pac.release_zone());
std::unique_ptr<msgpack::zone> z(pac.release_zone());
msgpack::object obj = pac.data();
pac.reset();
@ -174,10 +174,10 @@ public:
pac.buffer_consumed(len);
while(pac.execute()) {
std::auto_ptr<msgpack::zone> z(pac.release_zone());
std::unique_ptr<msgpack::zone> z(pac.release_zone());
msgpack::object obj = pac.data();
pac.reset();
on_message(obj, z);
on_message(obj, std::move(z));
}
if(pac.message_size() > 10*1024*1024) {
@ -186,7 +186,7 @@ public:
}
}
void on_message(msgpack::object obj, std::auto_ptr<msgpack::zone> z)
void on_message(msgpack::object obj, std::unique_ptr<msgpack::zone> z)
{
EXPECT_EQ(expect, obj.as<int>());
}

View File

@ -60,11 +60,11 @@ TEST(zone, push_finalizer)
}
TEST(zone, push_finalizer_auto_ptr)
TEST(zone, push_finalizer_unique_ptr)
{
msgpack::zone z;
std::auto_ptr<myclass> am(new myclass());
z.push_finalizer(am);
std::unique_ptr<myclass> am(new myclass());
z.push_finalizer(std::move(am));
}