]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /*============================================================================= |
2 | Copyright (c) 2014-2015 Kohei Takahashi | |
3 | ||
4 | Distributed under the Boost Software License, Version 1.0. (See accompanying | |
5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
6 | ==============================================================================*/ | |
7 | #ifndef FUSION_VECTOR_11052014_1625 | |
8 | #define FUSION_VECTOR_11052014_1625 | |
9 | ||
10 | #include <boost/config.hpp> | |
11 | #include <boost/fusion/support/config.hpp> | |
12 | #include <boost/fusion/container/vector/detail/config.hpp> | |
13 | #include <boost/fusion/container/vector/vector_fwd.hpp> | |
14 | ||
15 | /////////////////////////////////////////////////////////////////////////////// | |
16 | // Without variadics, we will use the PP version | |
17 | /////////////////////////////////////////////////////////////////////////////// | |
18 | #if !defined(BOOST_FUSION_HAS_VARIADIC_VECTOR) | |
19 | # include <boost/fusion/container/vector/detail/cpp03/vector.hpp> | |
20 | #else | |
21 | ||
22 | /////////////////////////////////////////////////////////////////////////////// | |
23 | // C++11 interface | |
24 | /////////////////////////////////////////////////////////////////////////////// | |
25 | #include <boost/fusion/support/sequence_base.hpp> | |
26 | #include <boost/fusion/support/is_sequence.hpp> | |
27 | #include <boost/fusion/support/detail/and.hpp> | |
28 | #include <boost/fusion/support/detail/index_sequence.hpp> | |
29 | #include <boost/fusion/container/vector/detail/at_impl.hpp> | |
30 | #include <boost/fusion/container/vector/detail/value_at_impl.hpp> | |
31 | #include <boost/fusion/container/vector/detail/begin_impl.hpp> | |
32 | #include <boost/fusion/container/vector/detail/end_impl.hpp> | |
33 | #include <boost/fusion/sequence/intrinsic/begin.hpp> | |
34 | #include <boost/fusion/sequence/intrinsic/size.hpp> | |
35 | #include <boost/fusion/iterator/advance.hpp> | |
36 | #include <boost/fusion/iterator/deref.hpp> | |
37 | #include <boost/core/enable_if.hpp> | |
38 | #include <boost/mpl/int.hpp> | |
39 | #include <boost/type_traits/integral_constant.hpp> | |
40 | #include <boost/type_traits/is_base_of.hpp> | |
41 | #include <boost/type_traits/is_convertible.hpp> | |
42 | #include <boost/type_traits/remove_reference.hpp> | |
43 | #include <cstddef> | |
44 | #include <utility> | |
45 | ||
46 | namespace boost { namespace fusion | |
47 | { | |
48 | struct vector_tag; | |
49 | struct random_access_traversal_tag; | |
50 | ||
51 | namespace vector_detail | |
52 | { | |
53 | struct each_elem {}; | |
54 | ||
55 | template < | |
56 | typename This, typename T, typename T_, std::size_t Size, bool IsSeq | |
57 | > | |
58 | struct can_convert_impl : false_type {}; | |
59 | ||
60 | template <typename This, typename T, typename Sequence, std::size_t Size> | |
61 | struct can_convert_impl<This, T, Sequence, Size, true> : true_type {}; | |
62 | ||
63 | template <typename This, typename Sequence, typename T> | |
64 | struct can_convert_impl<This, Sequence, T, 1, true> | |
65 | : integral_constant< | |
66 | bool | |
67 | , !is_convertible< | |
68 | Sequence | |
69 | , typename fusion::extension::value_at_impl<vector_tag>:: | |
70 | template apply< This, mpl::int_<0> >::type | |
71 | >::value | |
72 | > | |
73 | {}; | |
74 | ||
75 | template <typename This, typename T, typename T_, std::size_t Size> | |
76 | struct can_convert | |
77 | : can_convert_impl< | |
78 | This, T, T_, Size, traits::is_sequence<T_>::value | |
79 | > | |
80 | {}; | |
81 | ||
82 | template <typename T, bool IsSeq, std::size_t Size> | |
83 | struct is_longer_sequence_impl : false_type {}; | |
84 | ||
85 | template <typename Sequence, std::size_t Size> | |
86 | struct is_longer_sequence_impl<Sequence, true, Size> | |
87 | : integral_constant< | |
88 | bool, (fusion::result_of::size<Sequence>::value >= Size) | |
89 | > | |
90 | {}; | |
91 | ||
92 | template<typename T, std::size_t Size> | |
93 | struct is_longer_sequence | |
94 | : is_longer_sequence_impl<T, traits::is_sequence<T>::value, Size> | |
95 | {}; | |
96 | ||
97 | // forward_at_c allows to access Nth element even if ForwardSequence | |
98 | // since fusion::at_c requires RandomAccessSequence. | |
99 | namespace result_of | |
100 | { | |
101 | template <typename Sequence, int N> | |
102 | struct forward_at_c | |
103 | : fusion::result_of::deref< | |
104 | typename fusion::result_of::advance_c< | |
105 | typename fusion::result_of::begin< | |
106 | typename remove_reference<Sequence>::type | |
107 | >::type | |
108 | , N | |
109 | >::type | |
110 | > | |
111 | {}; | |
112 | } | |
113 | ||
114 | template <int N, typename Sequence> | |
115 | BOOST_CONSTEXPR BOOST_FUSION_GPU_ENABLED | |
116 | inline typename result_of::forward_at_c<Sequence, N>::type | |
117 | forward_at_c(Sequence&& seq) | |
118 | { | |
119 | typedef typename | |
120 | result_of::forward_at_c<Sequence, N>::type | |
121 | result; | |
122 | return std::forward<result>(*advance_c<N>(begin(seq))); | |
123 | } | |
124 | ||
125 | // Object proxy since preserve object order | |
126 | template <std::size_t, typename T> | |
127 | struct store | |
128 | { | |
129 | BOOST_CONSTEXPR BOOST_FUSION_GPU_ENABLED | |
130 | store() | |
131 | : elem() // value-initialized explicitly | |
132 | {} | |
133 | ||
134 | BOOST_CONSTEXPR BOOST_FUSION_GPU_ENABLED | |
135 | store(store const& rhs) | |
136 | : elem(rhs.get()) | |
137 | {} | |
138 | ||
139 | BOOST_CXX14_CONSTEXPR BOOST_FUSION_GPU_ENABLED | |
140 | store& | |
141 | operator=(store const& rhs) | |
142 | { | |
143 | elem = rhs.get(); | |
144 | return *this; | |
145 | } | |
146 | ||
147 | BOOST_CONSTEXPR BOOST_FUSION_GPU_ENABLED | |
148 | store(store&& rhs) | |
149 | : elem(static_cast<T&&>(rhs.get())) | |
150 | {} | |
151 | ||
152 | BOOST_CXX14_CONSTEXPR BOOST_FUSION_GPU_ENABLED | |
153 | store& | |
154 | operator=(store&& rhs) | |
155 | { | |
156 | elem = static_cast<T&&>(rhs.get()); | |
157 | return *this; | |
158 | } | |
159 | ||
160 | template < | |
161 | typename U | |
162 | , typename = typename boost::disable_if< | |
163 | is_base_of<store, typename remove_reference<U>::type> | |
164 | >::type | |
165 | > | |
166 | BOOST_CONSTEXPR BOOST_FUSION_GPU_ENABLED | |
167 | store(U&& rhs) | |
168 | : elem(std::forward<U>(rhs)) | |
169 | {} | |
170 | ||
171 | BOOST_CXX14_CONSTEXPR BOOST_FUSION_GPU_ENABLED | |
172 | T & get() { return elem; } | |
173 | BOOST_CONSTEXPR BOOST_FUSION_GPU_ENABLED | |
174 | T const& get() const { return elem; } | |
175 | ||
176 | T elem; | |
177 | }; | |
178 | ||
179 | template <typename I, typename ...T> | |
180 | struct vector_data; | |
181 | ||
182 | template <std::size_t ...I, typename ...T> | |
183 | struct vector_data<detail::index_sequence<I...>, T...> | |
184 | : store<I, T>... | |
185 | , sequence_base<vector_data<detail::index_sequence<I...>, T...> > | |
186 | { | |
187 | typedef vector_tag fusion_tag; | |
188 | typedef fusion_sequence_tag tag; // this gets picked up by MPL | |
189 | typedef mpl::false_ is_view; | |
190 | typedef random_access_traversal_tag category; | |
191 | typedef mpl::int_<sizeof...(T)> size; | |
192 | typedef vector<T...> type_sequence; | |
193 | ||
194 | BOOST_CONSTEXPR BOOST_FUSION_GPU_ENABLED | |
195 | vector_data() | |
196 | {} | |
197 | ||
198 | template < | |
199 | typename Sequence | |
200 | , typename Sequence_ = typename remove_reference<Sequence>::type | |
201 | , typename = typename boost::enable_if< | |
202 | can_convert<vector_data, Sequence, Sequence_, sizeof...(I)> | |
203 | >::type | |
204 | > | |
205 | BOOST_CONSTEXPR BOOST_FUSION_GPU_ENABLED | |
206 | explicit | |
207 | vector_data(each_elem, Sequence&& rhs) | |
208 | : store<I, T>(forward_at_c<I>(std::forward<Sequence>(rhs)))... | |
209 | {} | |
210 | ||
211 | template <typename ...U> | |
212 | BOOST_CONSTEXPR BOOST_FUSION_GPU_ENABLED | |
213 | explicit | |
214 | vector_data(each_elem, U&&... var) | |
215 | : store<I, T>(std::forward<U>(var))... | |
216 | {} | |
217 | ||
218 | template <typename Sequence> | |
219 | BOOST_CXX14_CONSTEXPR BOOST_FUSION_GPU_ENABLED | |
220 | void | |
221 | assign_sequence(Sequence&& seq) | |
222 | { | |
223 | assign(std::forward<Sequence>(seq), detail::index_sequence<I...>()); | |
224 | } | |
225 | ||
226 | template <typename Sequence> | |
227 | BOOST_CXX14_CONSTEXPR BOOST_FUSION_GPU_ENABLED | |
228 | void | |
229 | assign(Sequence&&, detail::index_sequence<>) {} | |
230 | ||
231 | template <typename Sequence, std::size_t N, std::size_t ...M> | |
232 | BOOST_CXX14_CONSTEXPR BOOST_FUSION_GPU_ENABLED | |
233 | void | |
234 | assign(Sequence&& seq, detail::index_sequence<N, M...>) | |
235 | { | |
236 | at_impl(mpl::int_<N>()) = vector_detail::forward_at_c<N>(seq); | |
237 | assign(std::forward<Sequence>(seq), detail::index_sequence<M...>()); | |
238 | } | |
239 | ||
240 | template <std::size_t N, typename U> | |
241 | static BOOST_CXX14_CONSTEXPR BOOST_FUSION_GPU_ENABLED | |
242 | auto at_detail(store<N, U>* this_) -> decltype(this_->get()) | |
243 | { | |
244 | return this_->get(); | |
245 | } | |
246 | ||
247 | template <std::size_t N, typename U> | |
248 | static BOOST_CONSTEXPR BOOST_FUSION_GPU_ENABLED | |
249 | auto at_detail(store<N, U> const* this_) -> decltype(this_->get()) | |
250 | { | |
251 | return this_->get(); | |
252 | } | |
253 | ||
254 | template <typename J> | |
255 | BOOST_CXX14_CONSTEXPR BOOST_FUSION_GPU_ENABLED | |
256 | auto at_impl(J) -> decltype(at_detail<J::value>(this)) | |
257 | { | |
258 | return at_detail<J::value>(this); | |
259 | } | |
260 | ||
261 | template <typename J> | |
262 | BOOST_CONSTEXPR BOOST_FUSION_GPU_ENABLED | |
263 | auto at_impl(J) const -> decltype(at_detail<J::value>(this)) | |
264 | { | |
265 | return at_detail<J::value>(this); | |
266 | } | |
267 | ||
268 | template <std::size_t N, typename U> | |
269 | static BOOST_FUSION_GPU_ENABLED | |
270 | mpl::identity<U> value_at_impl(store<N, U>*); | |
271 | }; | |
272 | } // namespace boost::fusion::vector_detail | |
273 | ||
274 | template <typename... T> | |
275 | struct vector | |
276 | : vector_detail::vector_data< | |
277 | typename detail::make_index_sequence<sizeof...(T)>::type | |
278 | , T... | |
279 | > | |
280 | { | |
281 | typedef vector_detail::vector_data< | |
282 | typename detail::make_index_sequence<sizeof...(T)>::type | |
283 | , T... | |
284 | > base; | |
285 | ||
286 | BOOST_CONSTEXPR BOOST_FUSION_GPU_ENABLED | |
287 | vector() | |
288 | {} | |
289 | ||
290 | template < | |
291 | typename... U | |
292 | , typename = typename boost::enable_if_c<( | |
293 | sizeof...(U) >= 1 && | |
294 | fusion::detail::and_<is_convertible<U, T>...>::value && | |
295 | !fusion::detail::and_< | |
296 | is_base_of<vector, typename remove_reference<U>::type>... | |
297 | >::value | |
298 | )>::type | |
299 | > | |
300 | // XXX: constexpr become error due to pull-request #79, booooo!! | |
301 | // In the (near) future release, should be fixed. | |
302 | /* BOOST_CONSTEXPR */ BOOST_FUSION_GPU_ENABLED | |
303 | explicit vector(U&&... u) | |
304 | : base(vector_detail::each_elem(), std::forward<U>(u)...) | |
305 | {} | |
306 | ||
307 | template < | |
308 | typename Sequence | |
309 | , typename Sequence_ = typename remove_reference<Sequence>::type | |
310 | , typename = typename boost::enable_if_c<( | |
311 | !is_base_of<vector, Sequence_>::value && | |
312 | vector_detail::is_longer_sequence< | |
313 | Sequence_, sizeof...(T) | |
314 | >::value | |
315 | )>::type | |
316 | > | |
317 | BOOST_CONSTEXPR BOOST_FUSION_GPU_ENABLED | |
318 | vector(Sequence&& seq) | |
319 | : base(vector_detail::each_elem(), std::forward<Sequence>(seq)) | |
320 | {} | |
321 | ||
322 | template <typename Sequence> | |
323 | BOOST_CXX14_CONSTEXPR BOOST_FUSION_GPU_ENABLED | |
324 | vector& | |
325 | operator=(Sequence&& rhs) | |
326 | { | |
327 | base::assign_sequence(std::forward<Sequence>(rhs)); | |
328 | return *this; | |
329 | } | |
330 | }; | |
331 | }} | |
332 | ||
333 | #endif | |
334 | #endif | |
335 |