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

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