1//
2// MessagePack for C++ static resolution routine
3//
4// Copyright (C) 2008-2009 FURUHASHI Sadayuki
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_TYPE_ARRAY_REF_HPP
11#define MSGPACK_TYPE_ARRAY_REF_HPP
12
13#include "msgpack/versioning.hpp"
14#include "msgpack/adaptor/adaptor_base.hpp"
15#include "msgpack/adaptor/check_container_size.hpp"
16#include <cstring>
17#include <string>
18
19namespace msgpack {
20
21/// @cond
22MSGPACK_API_VERSION_NAMESPACE(v1) {
23/// @endcond
24
25namespace type {
26
27template <typename T>
28struct array_ref {
29    array_ref() : data(nullptr) {}
30    array_ref(T& t) : data(&t) {}
31
32    T* data;
33
34    template <typename U>
35    bool operator==(array_ref<U> const& t) const {
36        return *data == *t.data;
37    }
38    template <typename U>
39    bool operator!=(array_ref<U> const& t) const {
40        return !(*data == *t.data);
41    }
42    template <typename U>
43    bool operator< (array_ref<U> const& t) const
44    {
45        return *data < *t.data;
46    }
47    template <typename U>
48    bool operator> (array_ref<U> const& t) const
49    {
50        return *t.data < *data;
51    }
52    template <typename U>
53    bool operator<= (array_ref<U> const& t) const
54    {
55        return !(*t.data < *data);
56    }
57    template <typename U>
58    bool operator>= (array_ref<U> const& t) const
59    {
60        return !(*data < *t.data);
61    }
62};
63
64template <typename T>
65inline array_ref<T const> make_array_ref(T const& t) {
66    return array_ref<T const>(t);
67}
68
69template <typename T>
70inline array_ref<T> make_array_ref(T& t) {
71    return array_ref<T>(t);
72}
73
74
75} // namespace type
76
77namespace adaptor {
78
79template <typename T>
80struct convert<msgpack::type::array_ref<T> > {
81    msgpack::object const& operator()(msgpack::object const& o, msgpack::type::array_ref<T>& v) const {
82        if (!v.data) { throw msgpack::type_error(); }
83        if (o.type != msgpack::type::ARRAY) { throw msgpack::type_error(); }
84        if (v.data->size() < o.via.bin.size) { throw msgpack::type_error(); }
85        if (o.via.array.size > 0) {
86            msgpack::object* p = o.via.array.ptr;
87            msgpack::object* const pend = o.via.array.ptr + o.via.array.size;
88            typename T::iterator it = v.data->begin();
89            do {
90                p->convert(*it);
91                ++p;
92                ++it;
93            } while(p < pend);
94        }
95        return o;
96    }
97};
98
99template <typename T>
100struct convert<msgpack::type::array_ref<std::vector<T> > > {
101    msgpack::object const& operator()(msgpack::object const& o, msgpack::type::array_ref<std::vector<T> >& v) const {
102        if (!v.data) { throw msgpack::type_error(); }
103        if (o.type != msgpack::type::ARRAY) { throw msgpack::type_error(); }
104        v.data->resize(o.via.bin.size);
105        if (o.via.array.size > 0) {
106            msgpack::object* p = o.via.array.ptr;
107            msgpack::object* const pend = o.via.array.ptr + o.via.array.size;
108            typename std::vector<T>::iterator it = v.data->begin();
109            do {
110                p->convert(*it);
111                ++p;
112                ++it;
113            } while(p < pend);
114        }
115        return o;
116    }
117};
118
119template <typename T>
120struct pack<msgpack::type::array_ref<T> > {
121    template <typename Stream>
122    msgpack::packer<Stream>& operator()(msgpack::packer<Stream>& o, const msgpack::type::array_ref<T>& v) const {
123        if (!v.data) { throw msgpack::type_error(); }
124        uint32_t size = checked_get_container_size(v.data->size());
125        o.pack_array(size);
126        for (typename T::const_iterator it(v.data->begin()), it_end(v.data->end());
127            it != it_end; ++it) {
128            o.pack(*it);
129        }
130        return o;
131    }
132};
133
134template <typename T>
135struct object_with_zone<msgpack::type::array_ref<T> > {
136    void operator()(msgpack::object::with_zone& o, const msgpack::type::array_ref<T>& v) const {
137        if (!v.data) { throw msgpack::type_error(); }
138        o.type = msgpack::type::ARRAY;
139        if (v.data->empty()) {
140            o.via.array.ptr = nullptr;
141            o.via.array.size = 0;
142        }
143        else {
144            uint32_t size = checked_get_container_size(v.data->size());
145            msgpack::object* p = static_cast<msgpack::object*>(o.zone.allocate_align(sizeof(msgpack::object)*size));
146            msgpack::object* const pend = p + size;
147            o.via.array.ptr = p;
148            o.via.array.size = size;
149            typename T::const_iterator it(v.data->begin());
150            do {
151#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && !defined(__clang__)
152#pragma GCC diagnostic push
153#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
154#endif // (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && !defined(__clang__)
155                *p = msgpack::object(*it, o.zone);
156#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && !defined(__clang__)
157#pragma GCC diagnostic pop
158#endif // (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && !defined(__clang__)
159                ++p;
160                ++it;
161            } while(p < pend);
162        }
163    }
164};
165
166} // namespace adaptor
167
168/// @cond
169} // MSGPACK_API_VERSION_NAMESPACE(v1)
170/// @endcond
171
172} // namespace msgpack
173
174#endif // MSGPACK_TYPE_ARRAY_REF_HPP
175