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_CPP11_MSGPACK_TUPLE_HPP
11#define MSGPACK_CPP11_MSGPACK_TUPLE_HPP
12
13#include "msgpack/versioning.hpp"
14#include "msgpack/object_fwd.hpp"
15#include "msgpack/meta.hpp"
16
17#include <tuple>
18
19namespace msgpack {
20
21/// @cond
22MSGPACK_API_VERSION_NAMESPACE(v1) {
23/// @endcond
24
25namespace type {
26    // tuple
27    using std::get;
28    using std::tuple_size;
29    using std::tuple_element;
30    using std::uses_allocator;
31    using std::ignore;
32    using std::swap;
33
34    template< class... Types >
35    class tuple : public std::tuple<Types...> {
36    public:
37        using base = std::tuple<Types...>;
38
39
40        tuple(tuple const&) = default;
41        tuple(tuple&&) = default;
42
43        template<typename... OtherTypes>
44        tuple(OtherTypes&&... other):base(std::forward<OtherTypes>(other)...) {}
45
46        template<typename... OtherTypes>
47        tuple(tuple<OtherTypes...> const& other):base(static_cast<std::tuple<OtherTypes...> const&>(other)) {}
48        template<typename... OtherTypes>
49        tuple(tuple<OtherTypes...> && other):base(static_cast<std::tuple<OtherTypes...> &&>(other)) {}
50
51        tuple& operator=(tuple const&) = default;
52        tuple& operator=(tuple&&) = default;
53
54        template<typename... OtherTypes>
55        tuple& operator=(tuple<OtherTypes...> const& other) {
56            *static_cast<base*>(this) = static_cast<std::tuple<OtherTypes...> const&>(other);
57            return *this;
58        }
59        template<typename... OtherTypes>
60        tuple& operator=(tuple<OtherTypes...> && other) {
61            *static_cast<base*>(this) = static_cast<std::tuple<OtherTypes...> &&>(other);
62            return *this;
63        }
64
65        template< std::size_t I>
66        typename tuple_element<I, base >::type&
67        get() & { return std::get<I>(*this); }
68
69        template< std::size_t I>
70        typename tuple_element<I, base >::type const&
71        get() const& { return std::get<I>(*this); }
72
73        template< std::size_t I>
74        typename tuple_element<I, base >::type&&
75        get() && { return std::get<I>(*this); }
76    };
77
78    template <class... Args>
79    inline tuple<Args...> make_tuple(Args&&... args) {
80        return tuple<Args...>(args...);
81    }
82
83    template<class... Args>
84    inline tuple<Args&&...> forward_as_tuple (Args&&... args) noexcept {
85        return tuple<Args&&...>(std::forward<Args>(args)...);
86    }
87
88    template <class... Tuples>
89    inline auto tuple_cat(Tuples&&... args) ->
90        decltype(
91            std::tuple_cat(std::forward<typename std::remove_reference<Tuples>::type::base>(args)...)
92        ) {
93        return std::tuple_cat(std::forward<typename std::remove_reference<Tuples>::type::base>(args)...);
94    }
95    template <class... Args>
96    inline tuple<Args&...> tie(Args&... args) {
97        return tuple<Args&...>(args...);
98    }
99} // namespace type
100
101// --- Pack from tuple to packer stream ---
102template <typename Stream, typename Tuple, std::size_t N>
103struct MsgpackTuplePacker {
104    static void pack(
105        msgpack::packer<Stream>& o,
106        const Tuple& v) {
107        MsgpackTuplePacker<Stream, Tuple, N-1>::pack(o, v);
108        o.pack(type::get<N-1>(v));
109    }
110};
111
112template <typename Stream, typename Tuple>
113struct MsgpackTuplePacker<Stream, Tuple, 1> {
114    static void pack (
115        msgpack::packer<Stream>& o,
116        const Tuple& v) {
117        o.pack(type::get<0>(v));
118    }
119};
120
121template <typename Stream, typename Tuple>
122struct MsgpackTuplePacker<Stream, Tuple, 0> {
123    static void pack (
124        msgpack::packer<Stream>&,
125        const Tuple&) {
126    }
127};
128
129namespace adaptor {
130
131template <typename... Args>
132struct pack<msgpack::type::tuple<Args...>> {
133    template <typename Stream>
134    msgpack::packer<Stream>& operator()(
135        msgpack::packer<Stream>& o,
136        const msgpack::type::tuple<Args...>& v) const {
137        o.pack_array(sizeof...(Args));
138        MsgpackTuplePacker<Stream, decltype(v), sizeof...(Args)>::pack(o, v);
139        return o;
140    }
141};
142
143} // namespace adaptor
144
145// --- Convert from tuple to object ---
146
147template <typename... Args>
148struct MsgpackTupleAs;
149
150template <typename T, typename... Args>
151struct MsgpackTupleAsImpl {
152    static msgpack::type::tuple<T, Args...> as(msgpack::object const& o) {
153        return msgpack::type::tuple_cat(
154            msgpack::type::make_tuple(o.via.array.ptr[o.via.array.size - sizeof...(Args) - 1].as<T>()),
155            MsgpackTupleAs<Args...>::as(o));
156    }
157};
158
159template <typename... Args>
160struct MsgpackTupleAs {
161    static msgpack::type::tuple<Args...> as(msgpack::object const& o) {
162        return MsgpackTupleAsImpl<Args...>::as(o);
163    }
164};
165
166template <>
167struct MsgpackTupleAs<> {
168    static msgpack::type::tuple<> as (msgpack::object const&) {
169        return msgpack::type::tuple<>();
170    }
171};
172
173template <typename Tuple, std::size_t N>
174struct MsgpackTupleConverter {
175    static void convert(
176        msgpack::object const& o,
177        Tuple& v) {
178        MsgpackTupleConverter<Tuple, N-1>::convert(o, v);
179        o.via.array.ptr[N-1].convert<typename std::remove_reference<decltype(type::get<N-1>(v))>::type>(type::get<N-1>(v));
180    }
181};
182
183template <typename Tuple>
184struct MsgpackTupleConverter<Tuple, 1> {
185    static void convert (
186        msgpack::object const& o,
187        Tuple& v) {
188        o.via.array.ptr[0].convert<typename std::remove_reference<decltype(type::get<0>(v))>::type>(type::get<0>(v));
189    }
190};
191
192template <typename Tuple>
193struct MsgpackTupleConverter<Tuple, 0> {
194    static void convert (
195        msgpack::object const&,
196        Tuple&) {
197    }
198};
199
200namespace adaptor {
201
202template <typename... Args>
203struct as<msgpack::type::tuple<Args...>, typename std::enable_if<msgpack::all_of<msgpack::has_as, Args...>::value>::type>  {
204    msgpack::type::tuple<Args...> operator()(
205        msgpack::object const& o) const {
206        if (o.type != msgpack::type::ARRAY) { throw msgpack::type_error(); }
207        if (o.via.array.size < sizeof...(Args)) { throw msgpack::type_error(); }
208        return MsgpackTupleAs<Args...>::as(o);
209    }
210};
211
212template <typename... Args>
213struct convert<msgpack::type::tuple<Args...>> {
214    msgpack::object const& operator()(
215        msgpack::object const& o,
216        msgpack::type::tuple<Args...>& v) const {
217        if(o.type != msgpack::type::ARRAY) { throw msgpack::type_error(); }
218        if(o.via.array.size < sizeof...(Args)) { throw msgpack::type_error(); }
219        MsgpackTupleConverter<decltype(v), sizeof...(Args)>::convert(o, v);
220        return o;
221    }
222};
223
224} // namespace adaptor
225
226// --- Convert from tuple to object with zone ---
227template <typename Tuple, std::size_t N>
228struct MsgpackTupleToObjectWithZone {
229    static void convert(
230        msgpack::object::with_zone& o,
231        const Tuple& v) {
232        MsgpackTupleToObjectWithZone<Tuple, N-1>::convert(o, v);
233        o.via.array.ptr[N-1] = msgpack::object(type::get<N-1>(v), o.zone);
234    }
235};
236
237template <typename Tuple>
238struct MsgpackTupleToObjectWithZone<Tuple, 1> {
239    static void convert (
240        msgpack::object::with_zone& o,
241        const Tuple& v) {
242        o.via.array.ptr[0] = msgpack::object(type::get<0>(v), o.zone);
243    }
244};
245
246template <typename Tuple>
247struct MsgpackTupleToObjectWithZone<Tuple, 0> {
248    static void convert (
249        msgpack::object::with_zone&,
250        const Tuple&) {
251    }
252};
253
254namespace adaptor {
255
256template <typename... Args>
257    struct object_with_zone<msgpack::type::tuple<Args...>> {
258    void operator()(
259        msgpack::object::with_zone& o,
260        msgpack::type::tuple<Args...> const& v) const {
261        o.type = msgpack::type::ARRAY;
262        o.via.array.ptr = static_cast<msgpack::object*>(o.zone.allocate_align(sizeof(msgpack::object)*sizeof...(Args)));
263        o.via.array.size = sizeof...(Args);
264        MsgpackTupleToObjectWithZone<decltype(v), sizeof...(Args)>::convert(o, v);
265    }
266};
267
268}  // namespace adaptor
269
270/// @cond
271}  // MSGPACK_API_VERSION_NAMESPACE(v1)
272///@endcond
273
274}  // namespace msgpack
275
276#endif // MSGPACK_CPP11_MSGPACK_TUPLE_HPP
277