1 //
2 // MessagePack for C++ static resolution routine
3 //
4 // Copyright (C) 2008-2016 FURUHASHI Sadayuki and KONDO Takatoshi
5 //
6 //    Distributed under the Boost Software License, Version 1.0.
7 //    (See accompanying file LICENSE_1_0.txt or copy at
8 //    http://www.boost.org/LICENSE_1_0.txt)
9 //
10 #ifndef MSGPACK_V1_CPP11_MSGPACK_TUPLE_HPP
11 #define MSGPACK_V1_CPP11_MSGPACK_TUPLE_HPP
12 
13 #include "msgpack/v1/adaptor/detail/cpp11_msgpack_tuple_decl.hpp"
14 #include "msgpack/adaptor/adaptor_base.hpp"
15 #include "msgpack/pack.hpp"
16 
17 namespace msgpack {
18 
19 /// @cond
MSGPACK_API_VERSION_NAMESPACE(v1)20 MSGPACK_API_VERSION_NAMESPACE(v1) {
21 /// @endcond
22 
23 namespace type {
24 
25 template <class... Args>
26 inline tuple<Args...> make_tuple(Args&&... args) {
27     return tuple<Args...>(std::forward<Args>(args)...);
28 }
29 
30 template<class... Args>
31 inline tuple<Args&&...> forward_as_tuple (Args&&... args) noexcept {
32     return tuple<Args&&...>(std::forward<Args>(args)...);
33 }
34 
35 template <class... Tuples>
36 inline auto tuple_cat(Tuples&&... args) ->
37     decltype(
38         std::tuple_cat(std::forward<typename std::remove_reference<Tuples>::type::base>(args)...)
39     ) {
40     return std::tuple_cat(std::forward<typename std::remove_reference<Tuples>::type::base>(args)...);
41 }
42 
43 template <class... Args>
44 inline tuple<Args&...> tie(Args&... args) {
45     return tuple<Args&...>(args...);
46 }
47 } // namespace type
48 
49 // --- Pack from tuple to packer stream ---
50 template <typename Stream, typename Tuple, std::size_t N>
51 struct MsgpackTuplePacker {
52     static void pack(
53         msgpack::packer<Stream>& o,
54         const Tuple& v) {
55         MsgpackTuplePacker<Stream, Tuple, N-1>::pack(o, v);
56         o.pack(type::get<N-1>(v));
57     }
58 };
59 
60 template <typename Stream, typename Tuple>
61 struct MsgpackTuplePacker<Stream, Tuple, 1> {
62     static void pack (
63         msgpack::packer<Stream>& o,
64         const Tuple& v) {
65         o.pack(type::get<0>(v));
66     }
67 };
68 
69 template <typename Stream, typename Tuple>
70 struct MsgpackTuplePacker<Stream, Tuple, 0> {
71     static void pack (
72         msgpack::packer<Stream>&,
73         const Tuple&) {
74     }
75 };
76 
77 namespace adaptor {
78 
79 template <typename... Args>
80 struct pack<msgpack::type::tuple<Args...>> {
81     template <typename Stream>
82     msgpack::packer<Stream>& operator()(
83         msgpack::packer<Stream>& o,
84         const msgpack::type::tuple<Args...>& v) const {
85         o.pack_array(sizeof...(Args));
86         MsgpackTuplePacker<Stream, decltype(v), sizeof...(Args)>::pack(o, v);
87         return o;
88     }
89 };
90 
91 } // namespace adaptor
92 
93 // --- Convert from tuple to object ---
94 
95 template <typename T, typename... Args>
96 struct MsgpackTupleAsImpl {
97     static msgpack::type::tuple<T, Args...> as(msgpack::object const& o) {
98         return msgpack::type::tuple_cat(
99             msgpack::type::make_tuple(o.via.array.ptr[o.via.array.size - sizeof...(Args) - 1].as<T>()),
100             MsgpackTupleAs<Args...>::as(o));
101     }
102 };
103 
104 template <typename... Args>
105 struct MsgpackTupleAs {
106     static msgpack::type::tuple<Args...> as(msgpack::object const& o) {
107         return MsgpackTupleAsImpl<Args...>::as(o);
108     }
109 };
110 
111 template <>
112 struct MsgpackTupleAs<> {
113     static msgpack::type::tuple<> as (msgpack::object const&) {
114         return msgpack::type::tuple<>();
115     }
116 };
117 
118 template <typename Tuple, std::size_t N>
119 struct MsgpackTupleConverter {
120     static void convert(
121         msgpack::object const& o,
122         Tuple& v) {
123         MsgpackTupleConverter<Tuple, N-1>::convert(o, v);
124         if (o.via.array.size >= N)
125             o.via.array.ptr[N-1].convert<typename std::remove_reference<decltype(type::get<N-1>(v))>::type>(type::get<N-1>(v));
126     }
127 };
128 
129 template <typename Tuple>
130 struct MsgpackTupleConverter<Tuple, 1> {
131     static void convert (
132         msgpack::object const& o,
133         Tuple& v) {
134         o.via.array.ptr[0].convert<typename std::remove_reference<decltype(type::get<0>(v))>::type>(type::get<0>(v));
135     }
136 };
137 
138 template <typename Tuple>
139 struct MsgpackTupleConverter<Tuple, 0> {
140     static void convert (
141         msgpack::object const&,
142         Tuple&) {
143     }
144 };
145 
146 namespace adaptor {
147 
148 template <typename... Args>
149 struct as<msgpack::type::tuple<Args...>, typename std::enable_if<msgpack::any_of<msgpack::has_as, Args...>::value>::type>  {
150     msgpack::type::tuple<Args...> operator()(
151         msgpack::object const& o) const {
152         if (o.type != msgpack::type::ARRAY) { throw msgpack::type_error(); }
153         return MsgpackTupleAs<Args...>::as(o);
154     }
155 };
156 
157 template <typename... Args>
158 struct convert<msgpack::type::tuple<Args...>> {
159     msgpack::object const& operator()(
160         msgpack::object const& o,
161         msgpack::type::tuple<Args...>& v) const {
162         if(o.type != msgpack::type::ARRAY) { throw msgpack::type_error(); }
163         MsgpackTupleConverter<decltype(v), sizeof...(Args)>::convert(o, v);
164         return o;
165     }
166 };
167 
168 } // namespace adaptor
169 
170 // --- Convert from tuple to object with zone ---
171 template <typename Tuple, std::size_t N>
172 struct MsgpackTupleToObjectWithZone {
173     static void convert(
174         msgpack::object::with_zone& o,
175         const Tuple& v) {
176         MsgpackTupleToObjectWithZone<Tuple, N-1>::convert(o, v);
177         o.via.array.ptr[N-1] = msgpack::object(type::get<N-1>(v), o.zone);
178     }
179 };
180 
181 template <typename Tuple>
182 struct MsgpackTupleToObjectWithZone<Tuple, 1> {
183     static void convert (
184         msgpack::object::with_zone& o,
185         const Tuple& v) {
186         o.via.array.ptr[0] = msgpack::object(type::get<0>(v), o.zone);
187     }
188 };
189 
190 template <typename Tuple>
191 struct MsgpackTupleToObjectWithZone<Tuple, 0> {
192     static void convert (
193         msgpack::object::with_zone&,
194         const Tuple&) {
195     }
196 };
197 
198 namespace adaptor {
199 
200 template <typename... Args>
201     struct object_with_zone<msgpack::type::tuple<Args...>> {
202     void operator()(
203         msgpack::object::with_zone& o,
204         msgpack::type::tuple<Args...> const& v) const {
205         o.type = msgpack::type::ARRAY;
206         o.via.array.ptr = static_cast<msgpack::object*>(o.zone.allocate_align(sizeof(msgpack::object)*sizeof...(Args), MSGPACK_ZONE_ALIGNOF(msgpack::object)));
207         o.via.array.size = sizeof...(Args);
208         MsgpackTupleToObjectWithZone<decltype(v), sizeof...(Args)>::convert(o, v);
209     }
210 };
211 
212 }  // namespace adaptor
213 
214 /// @cond
215 }  // MSGPACK_API_VERSION_NAMESPACE(v1)
216 ///@endcond
217 
218 }  // namespace msgpack
219 
220 #endif // MSGPACK_CPP11_MSGPACK_TUPLE_HPP
221