diff --git a/CMakeLists.txt b/CMakeLists.txt index 4e29263c..c6ad7dad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -105,6 +105,7 @@ IF (MSGPACK_ENABLE_CXX) include/msgpack.hpp include/msgpack/adaptor/adaptor_base.hpp include/msgpack/adaptor/bool.hpp + include/msgpack/adaptor/boost/fusion.hpp include/msgpack/adaptor/boost/optional.hpp include/msgpack/adaptor/boost/string_ref.hpp include/msgpack/adaptor/char_ptr.hpp diff --git a/include/msgpack/adaptor/adaptor_base.hpp b/include/msgpack/adaptor/adaptor_base.hpp index e5f1560c..e318eedd 100644 --- a/include/msgpack/adaptor/adaptor_base.hpp +++ b/include/msgpack/adaptor/adaptor_base.hpp @@ -33,23 +33,23 @@ namespace adaptor { // Adaptor functors -template +template struct convert { msgpack::object const& operator()(msgpack::object const& o, T& v) const; }; -template +template struct pack { template msgpack::packer& operator()(msgpack::packer& o, T const& v) const; }; -template +template struct object { void operator()(msgpack::object& o, T const& v) const; }; -template +template struct object_with_zone { void operator()(msgpack::object::with_zone& o, T const& v) const; }; diff --git a/include/msgpack/adaptor/boost/fusion.hpp b/include/msgpack/adaptor/boost/fusion.hpp new file mode 100644 index 00000000..b0f0e7df --- /dev/null +++ b/include/msgpack/adaptor/boost/fusion.hpp @@ -0,0 +1,113 @@ +// +// MessagePack for C++ static resolution routine +// +// Copyright (C) 2015 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_BOOST_FUSION_HPP +#define MSGPACK_TYPE_BOOST_FUSION_HPP + +#include "msgpack/versioning.hpp" +#include "msgpack/adaptor/adaptor_base.hpp" +#include "msgpack/adaptor/check_container_size.hpp" + +#include +#include +#include + +namespace msgpack { + +/// @cond +MSGPACK_API_VERSION_NAMESPACE(v1) { +/// @endcond + +namespace adaptor { + +template +struct convert::value>::type > { + msgpack::object const& operator()(msgpack::object const& o, T& v) const { + if(o.type != msgpack::type::ARRAY) { throw msgpack::type_error(); } + if(o.via.array.size != checked_get_container_size(boost::fusion::size(v))) { + throw msgpack::type_error(); + } + uint32_t index = 0; + boost::fusion::for_each(v, convert_imp(o, index)); + return o; + } +private: + struct convert_imp { + convert_imp(msgpack::object const& obj, uint32_t& index):obj_(obj), index_(index) {} + template + void operator()(U& v) const { + msgpack::adaptor::convert()(obj_.via.array.ptr[index_++], v); + } + private: + msgpack::object const& obj_; + uint32_t& index_; + }; +}; + +template +struct pack::value>::type > { + template + msgpack::packer& operator()(msgpack::packer& o, const T& v) const { + uint32_t size = checked_get_container_size(boost::fusion::size(v)); + o.pack_array(size); + boost::fusion::for_each(v, pack_imp(o)); + return o; + } +private: + template + struct pack_imp { + pack_imp(msgpack::packer& stream):stream_(stream) {} + template + void operator()(U const& v) const { + stream_.pack(v); + } + private: + msgpack::packer& stream_; + }; +}; + +template +struct object_with_zone::value>::type > { + void operator()(msgpack::object::with_zone& o, const T& v) const { + uint32_t size = checked_get_container_size(boost::fusion::size(v)); + o.type = msgpack::type::ARRAY; + o.via.array.ptr = static_cast(o.zone.allocate_align(sizeof(msgpack::object)*size)); + o.via.array.size = size; + uint32_t count = 0; + boost::fusion::for_each(v, with_zone_imp(o, count)); + } +private: + struct with_zone_imp { + with_zone_imp(msgpack::object::with_zone const& obj, uint32_t& count):obj_(obj), count_(count) {} + template + void operator()(U const& v) const { + obj_.via.array.ptr[count_++] = msgpack::object(v, obj_.zone); + } + msgpack::object::with_zone const& obj_; + uint32_t& count_; + }; +}; + +} // namespace adaptor + +/// @cond +} // MSGPACK_API_VERSION_NAMESPACE(v1) +/// @endcond + +} // namespace msgpack + +#endif // MSGPACK_TYPE_BOOST_FUSION_HPP diff --git a/include/msgpack/object.hpp b/include/msgpack/object.hpp index fcf28044..660bc7f3 100644 --- a/include/msgpack/object.hpp +++ b/include/msgpack/object.hpp @@ -170,26 +170,26 @@ struct packer_serializer { } // namespace detail // Adaptor functors' member functions definitions. -template +template inline msgpack::object const& -msgpack::adaptor::convert::operator()(msgpack::object const& o, T& v) const { +msgpack::adaptor::convert::operator()(msgpack::object const& o, T& v) const { v.msgpack_unpack(o.convert()); return o; } -template +template template inline msgpack::packer& -msgpack::adaptor::pack::operator()(msgpack::packer& o, T const& v) const { +msgpack::adaptor::pack::operator()(msgpack::packer& o, T const& v) const { return detail::packer_serializer::pack(o, v); } -template +template inline void -msgpack::adaptor::object_with_zone::operator()(msgpack::object::with_zone& o, T const& v) const { +msgpack::adaptor::object_with_zone::operator()(msgpack::object::with_zone& o, T const& v) const { v.msgpack_object(static_cast(&o), o.zone); } diff --git a/include/msgpack/type.hpp b/include/msgpack/type.hpp index 22f06439..db867bed 100644 --- a/include/msgpack/type.hpp +++ b/include/msgpack/type.hpp @@ -37,6 +37,7 @@ #if defined(MSGPACK_USE_BOOST) +#include "adaptor/boost/fusion.hpp" #include "adaptor/boost/optional.hpp" #include "adaptor/boost/string_ref.hpp" diff --git a/src/Makefile.am b/src/Makefile.am index 57160f4f..c2db950a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -56,6 +56,7 @@ nobase_include_HEADERS += \ ../include/msgpack.hpp \ ../include/msgpack/adaptor/adaptor_base.hpp \ ../include/msgpack/adaptor/bool.hpp \ + ../include/msgpack/adaptor/boost/fusion.hpp \ ../include/msgpack/adaptor/boost/optional.hpp \ ../include/msgpack/adaptor/boost/string_ref.hpp \ ../include/msgpack/adaptor/char_ptr.hpp \ diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 59628d5b..793d3aca 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -35,6 +35,7 @@ LIST (APPEND check_PROGRAMS IF (MSGPACK_BOOST) LIST (APPEND check_PROGRAMS + boost_fusion.cpp boost_optional.cpp boost_string_ref.cpp ) diff --git a/test/Makefile.am b/test/Makefile.am index b6913610..215e66e2 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -29,6 +29,7 @@ check_PROGRAMS = \ json \ raw \ iterator_cpp11 \ + boost_fusion \ boost_optional \ boost_string_ref @@ -87,6 +88,8 @@ raw_SOURCES = raw.cpp iterator_cpp11_SOURCES = iterator_cpp11.cpp +boost_fusion_SOURCES = boost_fusion.cpp + boost_optional_SOURCES = boost_optional.cpp boost_string_ref_SOURCES = boost_string_ref.cpp diff --git a/test/boost_fusion.cpp b/test/boost_fusion.cpp new file mode 100644 index 00000000..a0fb24f6 --- /dev/null +++ b/test/boost_fusion.cpp @@ -0,0 +1,51 @@ +#include +#include +#include +#include + +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if defined(MSGPACK_USE_BOOST) + +#include + +const double kEPS = 1e-10; + +BOOST_FUSION_DEFINE_STRUCT( + BOOST_PP_EMPTY(), + mystruct, + (int, f1) + (double, f2) + ) + +TEST(MSGPACK_BOOST, fusion_pack_unpack_convert) +{ + std::stringstream ss; + mystruct val1; + val1.f1 = 42; + val1.f2 = 123.45; + msgpack::pack(ss, val1); + msgpack::unpacked ret; + msgpack::unpack(ret, ss.str().data(), ss.str().size()); + mystruct val2 = ret.get().as(); + EXPECT_TRUE(val1.f1 == val2.f1); + EXPECT_TRUE(fabs(val2.f2 - val1.f2) <= kEPS); +} + +TEST(MSGPACK_BOOST, object_with_zone_convert) +{ + mystruct val1; + val1.f1 = 42; + val1.f2 = 123.45; + msgpack::zone z; + msgpack::object obj(val1, z); + mystruct val2 = obj.as(); + EXPECT_TRUE(val1.f1 == val2.f1); + EXPECT_TRUE(fabs(val2.f2 - val1.f2) <= kEPS); +} + +#endif // defined(MSGPACK_USE_BOOST)