1 //
2 // MessagePack for C++ static resolution routine
3 //
4 // Copyright (C) 2008-2015 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_TYPE_CPP11_TUPLE_HPP
11 #define MSGPACK_V1_TYPE_CPP11_TUPLE_HPP
12 
13 #include "msgpack/versioning.hpp"
14 #include "msgpack/adaptor/adaptor_base.hpp"
15 #include "msgpack/adaptor/check_container_size.hpp"
16 #include "msgpack/meta.hpp"
17 
18 #include <tuple>
19 
20 namespace msgpack {
21 
22 /// @cond
MSGPACK_API_VERSION_NAMESPACE(v1)23 MSGPACK_API_VERSION_NAMESPACE(v1) {
24 /// @endcond
25 
26 // --- Pack from tuple to packer stream ---
27 template <typename Stream, typename Tuple, std::size_t N>
28 struct StdTuplePacker {
29     static void pack(
30         msgpack::packer<Stream>& o,
31         const Tuple& v) {
32         StdTuplePacker<Stream, Tuple, N-1>::pack(o, v);
33         o.pack(std::get<N-1>(v));
34     }
35 };
36 
37 template <typename Stream, typename Tuple>
38 struct StdTuplePacker<Stream, Tuple, 0> {
39     static void pack (
40         msgpack::packer<Stream>&,
41         const Tuple&) {
42     }
43 };
44 
45 namespace adaptor {
46 
47 template <typename... Args>
48 struct pack<std::tuple<Args...>> {
49     template <typename Stream>
50     msgpack::packer<Stream>& operator()(
51         msgpack::packer<Stream>& o,
52         const std::tuple<Args...>& v) const {
53         uint32_t size = checked_get_container_size(sizeof...(Args));
54         o.pack_array(size);
55         StdTuplePacker<Stream, decltype(v), sizeof...(Args)>::pack(o, v);
56         return o;
57     }
58 };
59 
60 } // namespace adaptor
61 
62 // --- Convert from tuple to object ---
63 
64 template <typename... Args>
65 struct StdTupleAs;
66 
67 template <typename T, typename... Args>
68 struct StdTupleAsImpl {
69     static std::tuple<T, Args...> as(msgpack::object const& o) {
70         return std::tuple_cat(
71             std::make_tuple(o.via.array.ptr[o.via.array.size - sizeof...(Args) - 1].as<T>()),
72             StdTupleAs<Args...>::as(o));
73     }
74 };
75 
76 template <typename... Args>
77 struct StdTupleAs {
78     static std::tuple<Args...> as(msgpack::object const& o) {
79         return StdTupleAsImpl<Args...>::as(o);
80     }
81 };
82 
83 template <>
84 struct StdTupleAs<> {
85     static std::tuple<> as (msgpack::object const&) {
86         return std::tuple<>();
87     }
88 };
89 
90 template <typename Tuple, std::size_t N>
91 struct StdTupleConverter {
92     static void convert(
93         msgpack::object const& o,
94         Tuple& v) {
95         StdTupleConverter<Tuple, N-1>::convert(o, v);
96         if (o.via.array.size >= N)
97             o.via.array.ptr[N-1].convert<typename std::remove_reference<decltype(std::get<N-1>(v))>::type>(std::get<N-1>(v));
98     }
99 };
100 
101 template <typename Tuple>
102 struct StdTupleConverter<Tuple, 0> {
103     static void convert (
104         msgpack::object const&,
105         Tuple&) {
106     }
107 };
108 
109 namespace adaptor {
110 
111 template <typename... Args>
112 struct as<std::tuple<Args...>, typename std::enable_if<msgpack::any_of<msgpack::has_as, Args...>::value>::type>  {
113     std::tuple<Args...> operator()(
114         msgpack::object const& o) const {
115         if (o.type != msgpack::type::ARRAY) { throw msgpack::type_error(); }
116         return StdTupleAs<Args...>::as(o);
117     }
118 };
119 
120 template <typename... Args>
121 struct convert<std::tuple<Args...>> {
122     msgpack::object const& operator()(
123         msgpack::object const& o,
124         std::tuple<Args...>& v) const {
125         if(o.type != msgpack::type::ARRAY) { throw msgpack::type_error(); }
126         StdTupleConverter<decltype(v), sizeof...(Args)>::convert(o, v);
127         return o;
128     }
129 };
130 
131 } // namespace adaptor
132 
133 // --- Convert from tuple to object with zone ---
134 template <typename Tuple, std::size_t N>
135 struct StdTupleToObjectWithZone {
136     static void convert(
137         msgpack::object::with_zone& o,
138         const Tuple& v) {
139         StdTupleToObjectWithZone<Tuple, N-1>::convert(o, v);
140         o.via.array.ptr[N-1] = msgpack::object(std::get<N-1>(v), o.zone);
141     }
142 };
143 
144 template <typename Tuple>
145 struct StdTupleToObjectWithZone<Tuple, 0> {
146     static void convert (
147         msgpack::object::with_zone&,
148         const Tuple&) {
149     }
150 };
151 
152 namespace adaptor {
153 
154 template <typename... Args>
155 struct object_with_zone<std::tuple<Args...>> {
156     void operator()(
157         msgpack::object::with_zone& o,
158         std::tuple<Args...> const& v) const {
159         uint32_t size = checked_get_container_size(sizeof...(Args));
160         o.type = msgpack::type::ARRAY;
161         o.via.array.ptr = static_cast<msgpack::object*>(o.zone.allocate_align(sizeof(msgpack::object)*size, MSGPACK_ZONE_ALIGNOF(msgpack::object)));
162         o.via.array.size = size;
163         StdTupleToObjectWithZone<decltype(v), sizeof...(Args)>::convert(o, v);
164     }
165 };
166 
167 } // namespace adaptor
168 
169 /// @cond
170 } // MSGPACK_API_VERSION_NAMESPACE(v1)
171 /// @endcond
172 
173 } // namespace msgpack
174 
175 #endif // MSGPACK_V1_TYPE_CPP11_TUPLE_HPP
176