From 5b3a168b86b5f87593e007e68a075fa27c731c11 Mon Sep 17 00:00:00 2001 From: Takatoshi Kondo Date: Thu, 29 Aug 2013 13:44:34 +0900 Subject: [PATCH] Supported C++03. --- cpp11/tuple.hpp | 20 +-- cpp11/zone.hpp | 6 +- src/msgpack/cpp_config.hpp | 86 ++++++++++ src/msgpack/type/tuple.hpp.erb | 8 +- src/msgpack/unpack.hpp | 19 ++- src/msgpack/zone.hpp.erb | 294 ++++++++++++++++++++++++--------- test/msgpack_test.cpp | 8 +- test/streaming.cc | 12 +- test/zone.cc | 4 +- 9 files changed, 346 insertions(+), 111 deletions(-) create mode 100644 src/msgpack/cpp_config.hpp diff --git a/cpp11/tuple.hpp b/cpp11/tuple.hpp index 0fb015a4..a29ad257 100644 --- a/cpp11/tuple.hpp +++ b/cpp11/tuple.hpp @@ -19,15 +19,9 @@ #define MSGPACK_TYPE_TUPLE_HPP #include "msgpack/object.hpp" -#include +#include "msgpack/cpp_config.hpp" namespace msgpack { -namespace type { - -template -using tuple = std::tuple; - -} // type // --- Pack ( from tuple to packer stream --- template @@ -36,7 +30,7 @@ struct Packer { packer& o, const Tuple& v) { Packer::pack(o, v); - o.pack(std::get(v)); + o.pack(type::get(v)); } }; @@ -45,7 +39,7 @@ struct Packer { static void pack ( packer& o, const Tuple& v) { - o.pack(std::get<0>(v)); + o.pack(type::get<0>(v)); } }; @@ -66,7 +60,7 @@ struct Converter { object o, Tuple& v) { Converter::convert(o, v); - o.via.array.ptr[N-1].convert(v))>::type>(&std::get(v)); + o.via.array.ptr[N-1].convert(v))>::type>(&type::get(v)); } }; @@ -75,7 +69,7 @@ struct Converter { static void convert ( object o, Tuple& v) { - o.via.array.ptr[0].convert(v))>::type>(&std::get<0>(v)); + o.via.array.ptr[0].convert(v))>::type>(&type::get<0>(v)); } }; @@ -96,7 +90,7 @@ struct TupleToObjectWithZone { object::with_zone& o, const Tuple& v) { TupleToObjectWithZone::convert(o, v); - o.via.array.ptr[N-1] = object(std::get(v), o.zone); + o.via.array.ptr[N-1] = object(type::get(v), o.zone); } }; @@ -105,7 +99,7 @@ struct TupleToObjectWithZone { static void convert ( object::with_zone& o, const Tuple& v) { - o.via.array.ptr[0] = object(std::get<0>(v), o.zone); + o.via.array.ptr[0] = object(type::get<0>(v), o.zone); } }; diff --git a/cpp11/zone.hpp b/cpp11/zone.hpp index f15733ab..3f223ced 100644 --- a/cpp11/zone.hpp +++ b/cpp11/zone.hpp @@ -22,6 +22,8 @@ #include #include +#include "cpp_config.hpp" + #ifndef MSGPACK_ZONE_CHUNK_SIZE #define MSGPACK_ZONE_CHUNK_SIZE 8192 #endif @@ -158,7 +160,7 @@ public: void push_finalizer(void (*func)(void*), void* data); template - void push_finalizer(std::unique_ptr obj); + void push_finalizer(msgpack::unique_ptr obj); void clear(); @@ -250,7 +252,7 @@ inline void zone::push_finalizer(void (*func)(void*), void* data) } template -inline void zone::push_finalizer(std::unique_ptr obj) +inline void zone::push_finalizer(msgpack::unique_ptr obj) { finalizer_array_.push(&zone::object_destructor, obj.get()); obj.release(); diff --git a/src/msgpack/cpp_config.hpp b/src/msgpack/cpp_config.hpp new file mode 100644 index 00000000..9c1dbb0c --- /dev/null +++ b/src/msgpack/cpp_config.hpp @@ -0,0 +1,86 @@ +// +// MessagePack for C++ C++03/C++11 Adaptation +// +// Copyright (C) 2013 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_CPP_CONFIG_HPP +#define MSGPACK_CPP_CONFIG_HPP + +#if defined __cplusplus +#if __cplusplus < 201103 + +#define nullptr (0) + +namespace msgpack { + +template +struct unique_ptr : std::auto_ptr { + explicit unique_ptr(T* p = 0) throw() : std::auto_ptr(p) {} + unique_ptr(unique_ptr& a) throw() : std::auto_ptr(a) {} + template + unique_ptr (unique_ptr& a) throw() : std::auto_ptr(a) {} +}; + +template +T& move(T& t) +{ + return t; +} + +template +T const& move(T const& t) +{ + return t; +} + +} // msgpack + + +#else // __cplusplus < 201103 + +#include +#include + +namespace msgpack { + // unique_ptr + using std::unique_ptr; + // using std::make_unique; // since C++14 + using std::hash; + + // utility + using std::move; + using std::swap; + + namespace type { + // tuple + using std::tuple; + using std::get; + using std::make_tuple; + using std::tie; + using std::forward_as_tuple; + using std::tuple_cat; + using std::tuple_size; + using std::tuple_element; + using std::uses_allocator; + using std::ignore; + } +} // msgpack + + +#endif // __cplusplus < 201103 + +#endif // __cplusplus + +#endif /* msgpack/cpp_config.hpp */ diff --git a/src/msgpack/type/tuple.hpp.erb b/src/msgpack/type/tuple.hpp.erb index ebef8163..1ba6dc1b 100644 --- a/src/msgpack/type/tuple.hpp.erb +++ b/src/msgpack/type/tuple.hpp.erb @@ -110,6 +110,13 @@ struct tuple, A<%=j%><%}%>> { <%0.upto(i) {|j|%> A<%=j%> a<%=j%>;<%}%> }; + +template , typename A<%=j%><%}%>> +inline typename type::tuple_element, A<%=j%><%}%>>, N>::reference get(type::tuple, A<%=j%><%}%>>& t) +{ return t.get(); } +template , typename A<%=j%><%}%>> +inline typename type::const_tuple_element, A<%=j%><%}%>>, N>::const_reference get(type::tuple, A<%=j%><%}%>> const& t) +{ return t.get(); } <%}%> inline tuple<> make_tuple() @@ -126,7 +133,6 @@ tuple, A<%=j%><%}%>> make_tuple(typename tuple_type::tr } // namespace type - inline type::tuple<>& operator>> ( object o, type::tuple<>& v) { diff --git a/src/msgpack/unpack.hpp b/src/msgpack/unpack.hpp index 8f9c62f8..1ad7f5a7 100644 --- a/src/msgpack/unpack.hpp +++ b/src/msgpack/unpack.hpp @@ -21,6 +21,7 @@ #include "object.hpp" #include "zone.hpp" #include "unpack_define.h" +#include "cpp_config.hpp" #include #include @@ -59,7 +60,7 @@ private: }; static inline object template_callback_root(unpack_user* u) -{ object o = {}; return o; } +{ object o; return o; } static inline int template_callback_uint8(unpack_user* u, uint8_t d, object* o) { o->type = type::POSITIVE_INTEGER; o->via.u64 = d; return 0; } @@ -538,8 +539,8 @@ class unpacked { public: unpacked() { } - unpacked(object obj, std::unique_ptr z) : - m_obj(obj), m_zone(std::move(z)) { } + unpacked(object obj, msgpack::unique_ptr z) : + m_obj(obj), m_zone(msgpack::move(z)) { } object& get() { return m_obj; } @@ -547,15 +548,15 @@ public: const object& get() const { return m_obj; } - std::unique_ptr& zone() + msgpack::unique_ptr& zone() { return m_zone; } - const std::unique_ptr& zone() const + const msgpack::unique_ptr& zone() const { return m_zone; } private: object m_obj; - std::unique_ptr m_zone; + msgpack::unique_ptr m_zone; }; @@ -984,7 +985,7 @@ inline void unpack(unpacked* result, const char* data, size_t len, size_t* offset) { object obj; - std::unique_ptr z(new zone()); + msgpack::unique_ptr z(new zone()); unpack_return ret = detail::unpack_imp( data, len, offset, z.get(), &obj); @@ -993,12 +994,12 @@ inline void unpack(unpacked* result, switch(ret) { case UNPACK_SUCCESS: result->get() = obj; - result->zone() = std::move(z); + result->zone() = msgpack::move(z); return; case UNPACK_EXTRA_BYTES: result->get() = obj; - result->zone() = std::move(z); + result->zone() = msgpack::move(z); return; case UNPACK_CONTINUE: diff --git a/src/msgpack/zone.hpp.erb b/src/msgpack/zone.hpp.erb index b2c19db0..d8b5820a 100644 --- a/src/msgpack/zone.hpp.erb +++ b/src/msgpack/zone.hpp.erb @@ -15,146 +15,292 @@ // See the License for the specific language governing permissions and // limitations under the License. // -#ifndef MSGPACK_ZONE_HPP__ -#define MSGPACK_ZONE_HPP__ +#ifndef MSGPACK_ZONE_HPP +#define MSGPACK_ZONE_HPP -#include "zone.h" #include #include #include +#include "cpp_config.hpp" + +#ifndef MSGPACK_ZONE_CHUNK_SIZE +#define MSGPACK_ZONE_CHUNK_SIZE 8192 +#endif + +#ifndef MSGPACK_ZONE_ALIGN +#define MSGPACK_ZONE_ALIGN sizeof(int) +#endif + <% GENERATION_LIMIT = 15 %> namespace msgpack { +class zone { + 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); -class zone : public msgpack_zone { + ++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); - ~zone(); + zone(size_t chunk_size = MSGPACK_ZONE_CHUNK_SIZE); public: - void* malloc(size_t size); - void* malloc_no_align(size_t size); + 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); + void push_finalizer(void (*func)(void*), void* data); - template - void push_finalizer(std::auto_ptr obj); + template + void push_finalizer(msgpack::unique_ptr obj); - void clear(); + void clear(); - void swap(zone& o); - static void* operator new(std::size_t size) throw(std::bad_alloc) - { - void* p = ::malloc(size); - if (!p) throw std::bad_alloc(); - return p; - } - static void operator delete(void *p) throw() - { - ::free(p); - } - <%0.upto(GENERATION_LIMIT) {|i|%> - template , typename A<%=j%><%}%>> - T* allocate(<%=(1..i).map{|j|"A#{j} a#{j}"}.join(', ')%>); - <%}%> + void swap(zone& o); + + <%0.upto(GENERATION_LIMIT) {|i|%> + template , typename A<%=j%><%}%>> + T* allocate(<%=(1..i).map{|j|"A#{j} a#{j}"}.join(', ')%>); + <%}%> private: - void undo_malloc(size_t size); + void undo_malloc(size_t size); - template - static void object_destructor(void* obj); + template + static void object_destructor(void* obj); - typedef msgpack_zone base; - -private: - zone(const zone&); + void* malloc_expand(size_t size); }; - -inline zone::zone(size_t chunk_size) +inline zone* zone::create(size_t chunk_size) { - msgpack_zone_init(this, 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 zone::~zone() +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_) { - msgpack_zone_destroy(this); } inline void* zone::malloc(size_t size) { - void* ptr = msgpack_zone_malloc(this, size); - if(!ptr) { - throw std::bad_alloc(); - } - return ptr; + return malloc_no_align( + ((size)+((MSGPACK_ZONE_ALIGN)-1)) & ~((MSGPACK_ZONE_ALIGN)-1)); } inline void* zone::malloc_no_align(size_t size) { - void* ptr = msgpack_zone_malloc_no_align(this, size); - if(!ptr) { - throw std::bad_alloc(); - } - return ptr; + 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) { - if(!msgpack_zone_push_finalizer(this, func, data)) { - throw std::bad_alloc(); - } + finalizer_array_.push(func, data); } template -inline void zone::push_finalizer(std::auto_ptr obj) +inline void zone::push_finalizer(msgpack::unique_ptr obj) { - if(!msgpack_zone_push_finalizer(this, &zone::object_destructor, obj.get())) { - throw std::bad_alloc(); - } - obj.release(); + finalizer_array_.push(&zone::object_destructor, obj.get()); + obj.release(); } inline void zone::clear() { - msgpack_zone_clear(this); + finalizer_array_.clear(); + chunk_list_.clear(chunk_size_); } inline void zone::swap(zone& o) { - msgpack_zone_swap(this, &o); + std::swap(*this, o); } template void zone::object_destructor(void* obj) { - reinterpret_cast(obj)->~T(); + reinterpret_cast(obj)->~T(); } inline void zone::undo_malloc(size_t size) { - base::chunk_list.ptr -= size; - base::chunk_list.free += size; + chunk_list_.ptr_ -= size; + chunk_list_.free_ += size; } <%0.upto(GENERATION_LIMIT) {|i|%> template , typename A<%=j%><%}%>> T* zone::allocate(<%=(1..i).map{|j|"A#{j} a#{j}"}.join(', ')%>) { - void* x = malloc(sizeof(T)); - if(!msgpack_zone_push_finalizer(this, &zone::object_destructor, x)) { - undo_malloc(sizeof(T)); - throw std::bad_alloc(); - } - try { - return new (x) T(<%=(1..i).map{|j|"a#{j}"}.join(', ')%>); - } catch (...) { - --base::finalizer_array.tail; - undo_malloc(sizeof(T)); - throw; - } + void* x = malloc(sizeof(T)); + try { + finalizer_array_.push(&zone::object_destructor, x); + } catch (...) { + undo_malloc(sizeof(T)); + throw; + } + try { + return new (x) T(<%=(1..i).map{|j|"a#{j}"}.join(', ')%>); + } catch (...) { + --finalizer_array_.tail_; + undo_malloc(sizeof(T)); + throw; + } } <%}%> diff --git a/test/msgpack_test.cpp b/test/msgpack_test.cpp index 937806de..b14caae1 100644 --- a/test/msgpack_test.cpp +++ b/test/msgpack_test.cpp @@ -1,6 +1,6 @@ #include "msgpack.hpp" -#include +#include #include #include #include @@ -901,11 +901,11 @@ public: msgpack::type::tuple tuple; o.convert(&tuple); - is_double = get<0>(tuple); + is_double = msgpack::type::get<0>(tuple); if (is_double) - get<1>(tuple).convert(&value.f); + msgpack::type::get<1>(tuple).convert(&value.f); else - get<1>(tuple).convert(&value.i); + msgpack::type::get<1>(tuple).convert(&value.i); } }; diff --git a/test/streaming.cc b/test/streaming.cc index 465dea23..551cf842 100644 --- a/test/streaming.cc +++ b/test/streaming.cc @@ -69,7 +69,7 @@ public: msgpack::unpacked result; while(pac.next(&result)) { - on_message(result.get(), std::move(result.zone())); + on_message(result.get(), msgpack::move(result.zone())); } if(pac.message_size() > 10*1024*1024) { @@ -78,7 +78,7 @@ public: } } - void on_message(msgpack::object obj, std::unique_ptr z) + void on_message(msgpack::object obj, msgpack::unique_ptr z) { EXPECT_EQ(expect, obj.as()); } @@ -133,7 +133,7 @@ TEST(streaming, basic_compat) pac.buffer_consumed(len); while(pac.execute()) { - std::unique_ptr z(pac.release_zone()); + msgpack::unique_ptr z(pac.release_zone()); msgpack::object obj = pac.data(); pac.reset(); @@ -174,10 +174,10 @@ public: pac.buffer_consumed(len); while(pac.execute()) { - std::unique_ptr z(pac.release_zone()); + msgpack::unique_ptr z(pac.release_zone()); msgpack::object obj = pac.data(); pac.reset(); - on_message(obj, std::move(z)); + on_message(obj, msgpack::move(z)); } if(pac.message_size() > 10*1024*1024) { @@ -186,7 +186,7 @@ public: } } - void on_message(msgpack::object obj, std::unique_ptr z) + void on_message(msgpack::object obj, msgpack::unique_ptr z) { EXPECT_EQ(expect, obj.as()); } diff --git a/test/zone.cc b/test/zone.cc index be7b89fc..5c771028 100644 --- a/test/zone.cc +++ b/test/zone.cc @@ -63,8 +63,8 @@ TEST(zone, push_finalizer) TEST(zone, push_finalizer_unique_ptr) { msgpack::zone z; - std::unique_ptr am(new myclass()); - z.push_finalizer(std::move(am)); + msgpack::unique_ptr am(new myclass()); + z.push_finalizer(msgpack::move(am)); }