1 | // Copyright 2002 The Trustees of Indiana University. |
2 | |
3 | // Use, modification and distribution is subject to the Boost Software |
4 | // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at |
5 | // http://www.boost.org/LICENSE_1_0.txt) |
6 | |
7 | // Boost.MultiArray Library |
8 | // Authors: Ronald Garcia |
9 | // Jeremy Siek |
10 | // Andrew Lumsdaine |
11 | // See http://www.boost.org/libs/multi_array for documentation. |
12 | |
13 | #ifndef BOOST_MULTI_ARRAY_VIEW_HPP |
14 | #define BOOST_MULTI_ARRAY_VIEW_HPP |
15 | |
16 | // |
17 | // view.hpp - code for creating "views" of array data. |
18 | // |
19 | |
20 | #include "boost/multi_array/base.hpp" |
21 | #include "boost/multi_array/concept_checks.hpp" |
22 | #include "boost/multi_array/iterator.hpp" |
23 | #include "boost/multi_array/storage_order.hpp" |
24 | #include "boost/multi_array/subarray.hpp" |
25 | #include "boost/multi_array/algorithm.hpp" |
26 | #include "boost/type_traits/is_integral.hpp" |
27 | #include "boost/utility/enable_if.hpp" |
28 | #include "boost/array.hpp" |
29 | #include "boost/limits.hpp" |
30 | #include <algorithm> |
31 | #include <cstddef> |
32 | #include <functional> |
33 | #include <numeric> |
34 | |
35 | namespace boost { |
36 | namespace detail { |
37 | namespace multi_array { |
38 | |
39 | // TPtr = const T* defaulted in base.hpp |
40 | template <typename T, std::size_t NumDims, typename TPtr> |
41 | class const_multi_array_view : |
42 | public boost::detail::multi_array::multi_array_impl_base<T,NumDims> |
43 | { |
44 | typedef boost::detail::multi_array::multi_array_impl_base<T,NumDims> super_type; |
45 | public: |
46 | typedef typename super_type::value_type value_type; |
47 | typedef typename super_type::const_reference const_reference; |
48 | typedef typename super_type::const_iterator const_iterator; |
49 | typedef typename super_type::const_reverse_iterator const_reverse_iterator; |
50 | typedef typename super_type::element element; |
51 | typedef typename super_type::size_type size_type; |
52 | typedef typename super_type::difference_type difference_type; |
53 | typedef typename super_type::index index; |
54 | typedef typename super_type::extent_range extent_range; |
55 | |
56 | // template typedefs |
57 | template <std::size_t NDims> |
58 | struct const_array_view { |
59 | typedef boost::detail::multi_array::const_multi_array_view<T,NDims> type; |
60 | }; |
61 | |
62 | template <std::size_t NDims> |
63 | struct array_view { |
64 | typedef boost::detail::multi_array::multi_array_view<T,NDims> type; |
65 | }; |
66 | |
67 | template <typename OPtr> |
68 | const_multi_array_view(const |
69 | const_multi_array_view<T,NumDims,OPtr>& other) : |
70 | base_(other.base_), origin_offset_(other.origin_offset_), |
71 | num_elements_(other.num_elements_), extent_list_(other.extent_list_), |
72 | stride_list_(other.stride_list_), index_base_list_(other.index_base_list_) |
73 | { } |
74 | |
75 | |
76 | template <class BaseList> |
77 | #ifdef BOOST_NO_SFINAE |
78 | void |
79 | #else |
80 | typename |
81 | disable_if<typename boost::is_integral<BaseList>::type,void >::type |
82 | #endif |
83 | reindex(const BaseList& values) { |
84 | boost::function_requires< |
85 | CollectionConcept<BaseList> >(); |
86 | boost::detail::multi_array:: |
87 | copy_n(values.begin(),num_dimensions(),index_base_list_.begin()); |
88 | origin_offset_ = |
89 | this->calculate_indexing_offset(stride_list_,index_base_list_); |
90 | } |
91 | |
92 | void reindex(index value) { |
93 | index_base_list_.assign(value); |
94 | origin_offset_ = |
95 | this->calculate_indexing_offset(stride_list_,index_base_list_); |
96 | } |
97 | |
98 | size_type num_dimensions() const { return NumDims; } |
99 | |
100 | size_type size() const { return extent_list_.front(); } |
101 | size_type max_size() const { return num_elements(); } |
102 | bool empty() const { return size() == 0; } |
103 | |
104 | const size_type* shape() const { |
105 | return extent_list_.data(); |
106 | } |
107 | |
108 | const index* strides() const { |
109 | return stride_list_.data(); |
110 | } |
111 | |
112 | const T* origin() const { return base_+origin_offset_; } |
113 | |
114 | size_type num_elements() const { return num_elements_; } |
115 | |
116 | const index* index_bases() const { |
117 | return index_base_list_.data(); |
118 | } |
119 | |
120 | template <typename IndexList> |
121 | const element& operator()(IndexList indices) const { |
122 | boost::function_requires< |
123 | CollectionConcept<IndexList> >(); |
124 | return super_type::access_element(boost::type<const element&>(), |
125 | indices,origin(), |
126 | shape(),strides(),index_bases()); |
127 | } |
128 | |
129 | // Only allow const element access |
130 | const_reference operator[](index idx) const { |
131 | return super_type::access(boost::type<const_reference>(), |
132 | idx,origin(), |
133 | shape(),strides(), |
134 | index_bases()); |
135 | } |
136 | |
137 | // see generate_array_view in base.hpp |
138 | template <int NDims> |
139 | typename const_array_view<NDims>::type |
140 | operator[](const boost::detail::multi_array:: |
141 | index_gen<NumDims,NDims>& indices) |
142 | const { |
143 | typedef typename const_array_view<NDims>::type return_type; |
144 | return |
145 | super_type::generate_array_view(boost::type<return_type>(), |
146 | indices, |
147 | shape(), |
148 | strides(), |
149 | index_bases(), |
150 | origin()); |
151 | } |
152 | const_iterator begin() const { |
153 | return const_iterator(*index_bases(),origin(), |
154 | shape(),strides(),index_bases()); |
155 | } |
156 | |
157 | const_iterator end() const { |
158 | return const_iterator(*index_bases()+(index)*shape(),origin(), |
159 | shape(),strides(),index_bases()); |
160 | } |
161 | |
162 | const_reverse_iterator rbegin() const { |
163 | return const_reverse_iterator(end()); |
164 | } |
165 | |
166 | const_reverse_iterator rend() const { |
167 | return const_reverse_iterator(begin()); |
168 | } |
169 | |
170 | |
171 | template <typename OPtr> |
172 | bool operator==(const |
173 | const_multi_array_view<T,NumDims,OPtr>& rhs) |
174 | const { |
175 | if(std::equal(extent_list_.begin(), |
176 | extent_list_.end(), |
177 | rhs.extent_list_.begin())) |
178 | return std::equal(begin(),end(),rhs.begin()); |
179 | else return false; |
180 | } |
181 | |
182 | template <typename OPtr> |
183 | bool operator<(const |
184 | const_multi_array_view<T,NumDims,OPtr>& rhs) |
185 | const { |
186 | return std::lexicographical_compare(begin(),end(),rhs.begin(),rhs.end()); |
187 | } |
188 | |
189 | template <typename OPtr> |
190 | bool operator!=(const |
191 | const_multi_array_view<T,NumDims,OPtr>& rhs) |
192 | const { |
193 | return !(*this == rhs); |
194 | } |
195 | |
196 | template <typename OPtr> |
197 | bool operator>(const |
198 | const_multi_array_view<T,NumDims,OPtr>& rhs) |
199 | const { |
200 | return rhs < *this; |
201 | } |
202 | |
203 | template <typename OPtr> |
204 | bool operator<=(const |
205 | const_multi_array_view<T,NumDims,OPtr>& rhs) |
206 | const { |
207 | return !(*this > rhs); |
208 | } |
209 | |
210 | template <typename OPtr> |
211 | bool operator>=(const |
212 | const_multi_array_view<T,NumDims,OPtr>& rhs) |
213 | const { |
214 | return !(*this < rhs); |
215 | } |
216 | |
217 | |
218 | #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS |
219 | protected: |
220 | template <typename,std::size_t> friend class multi_array_impl_base; |
221 | template <typename,std::size_t,typename> friend class const_multi_array_view; |
222 | #else |
223 | public: // should be protected |
224 | #endif |
225 | |
226 | // This constructor is used by multi_array_impl_base::generate_array_view |
227 | // to create strides |
228 | template <typename ExtentList, typename Index> |
229 | explicit const_multi_array_view(TPtr base, |
230 | const ExtentList& extents, |
231 | const boost::array<Index,NumDims>& strides): |
232 | base_(base), origin_offset_(0) { |
233 | |
234 | index_base_list_.assign(0); |
235 | |
236 | // Get the extents and strides |
237 | boost::detail::multi_array:: |
238 | copy_n(extents.begin(),NumDims,extent_list_.begin()); |
239 | boost::detail::multi_array:: |
240 | copy_n(strides.begin(),NumDims,stride_list_.begin()); |
241 | |
242 | // Calculate the array size |
243 | num_elements_ = std::accumulate(extent_list_.begin(),extent_list_.end(), |
244 | size_type(1),std::multiplies<size_type>()); |
245 | } |
246 | |
247 | typedef boost::array<size_type,NumDims> size_list; |
248 | typedef boost::array<index,NumDims> index_list; |
249 | |
250 | TPtr base_; |
251 | index origin_offset_; |
252 | size_type num_elements_; |
253 | size_list extent_list_; |
254 | index_list stride_list_; |
255 | index_list index_base_list_; |
256 | |
257 | private: |
258 | // const_multi_array_view cannot be assigned to (no deep copies!) |
259 | const_multi_array_view& operator=(const const_multi_array_view& other); |
260 | }; |
261 | |
262 | |
263 | template <typename T, std::size_t NumDims> |
264 | class multi_array_view : |
265 | public const_multi_array_view<T,NumDims,T*> |
266 | { |
267 | typedef const_multi_array_view<T,NumDims,T*> super_type; |
268 | public: |
269 | typedef typename super_type::value_type value_type; |
270 | typedef typename super_type::reference reference; |
271 | typedef typename super_type::iterator iterator; |
272 | typedef typename super_type::reverse_iterator reverse_iterator; |
273 | typedef typename super_type::const_reference const_reference; |
274 | typedef typename super_type::const_iterator const_iterator; |
275 | typedef typename super_type::const_reverse_iterator const_reverse_iterator; |
276 | typedef typename super_type::element element; |
277 | typedef typename super_type::size_type size_type; |
278 | typedef typename super_type::difference_type difference_type; |
279 | typedef typename super_type::index index; |
280 | typedef typename super_type::extent_range extent_range; |
281 | |
282 | // template typedefs |
283 | template <std::size_t NDims> |
284 | struct const_array_view { |
285 | typedef boost::detail::multi_array::const_multi_array_view<T,NDims> type; |
286 | }; |
287 | |
288 | template <std::size_t NDims> |
289 | struct array_view { |
290 | typedef boost::detail::multi_array::multi_array_view<T,NDims> type; |
291 | }; |
292 | |
293 | // Assignment from other ConstMultiArray types. |
294 | template <typename ConstMultiArray> |
295 | multi_array_view& operator=(const ConstMultiArray& other) { |
296 | function_requires< |
297 | boost::multi_array_concepts:: |
298 | ConstMultiArrayConcept<ConstMultiArray,NumDims> >(); |
299 | |
300 | // make sure the dimensions agree |
301 | BOOST_ASSERT(other.num_dimensions() == this->num_dimensions()); |
302 | BOOST_ASSERT(std::equal(other.shape(),other.shape()+this->num_dimensions(), |
303 | this->shape())); |
304 | // iterator-based copy |
305 | std::copy(other.begin(),other.end(),begin()); |
306 | return *this; |
307 | } |
308 | |
309 | |
310 | multi_array_view& operator=(const multi_array_view& other) { |
311 | if (&other != this) { |
312 | // make sure the dimensions agree |
313 | BOOST_ASSERT(other.num_dimensions() == this->num_dimensions()); |
314 | BOOST_ASSERT(std::equal(other.shape(), |
315 | other.shape()+this->num_dimensions(), |
316 | this->shape())); |
317 | // iterator-based copy |
318 | std::copy(other.begin(),other.end(),begin()); |
319 | } |
320 | return *this; |
321 | } |
322 | |
323 | element* origin() { return this->base_+this->origin_offset_; } |
324 | |
325 | template <class IndexList> |
326 | element& operator()(const IndexList& indices) { |
327 | boost::function_requires< |
328 | CollectionConcept<IndexList> >(); |
329 | return super_type::access_element(boost::type<element&>(), |
330 | indices,origin(), |
331 | this->shape(),this->strides(), |
332 | this->index_bases()); |
333 | } |
334 | |
335 | |
336 | reference operator[](index idx) { |
337 | return super_type::access(boost::type<reference>(), |
338 | idx,origin(), |
339 | this->shape(),this->strides(), |
340 | this->index_bases()); |
341 | } |
342 | |
343 | |
344 | // see generate_array_view in base.hpp |
345 | template <int NDims> |
346 | typename array_view<NDims>::type |
347 | operator[](const boost::detail::multi_array:: |
348 | index_gen<NumDims,NDims>& indices) { |
349 | typedef typename array_view<NDims>::type return_type; |
350 | return |
351 | super_type::generate_array_view(boost::type<return_type>(), |
352 | indices, |
353 | this->shape(), |
354 | this->strides(), |
355 | this->index_bases(), |
356 | origin()); |
357 | } |
358 | |
359 | |
360 | iterator begin() { |
361 | return iterator(*this->index_bases(),origin(), |
362 | this->shape(),this->strides(), |
363 | this->index_bases()); |
364 | } |
365 | |
366 | iterator end() { |
367 | return iterator(*this->index_bases()+(index)*this->shape(),origin(), |
368 | this->shape(),this->strides(), |
369 | this->index_bases()); |
370 | } |
371 | |
372 | reverse_iterator rbegin() { |
373 | return reverse_iterator(end()); |
374 | } |
375 | |
376 | reverse_iterator rend() { |
377 | return reverse_iterator(begin()); |
378 | } |
379 | |
380 | // Using declarations don't seem to work for g++ |
381 | // These are the proxies to work around this. |
382 | |
383 | const element* origin() const { return super_type::origin(); } |
384 | |
385 | template <class IndexList> |
386 | const element& operator()(const IndexList& indices) const { |
387 | boost::function_requires< |
388 | CollectionConcept<IndexList> >(); |
389 | return super_type::operator()(indices); |
390 | } |
391 | |
392 | const_reference operator[](index idx) const { |
393 | return super_type::operator[](idx); |
394 | } |
395 | |
396 | // see generate_array_view in base.hpp |
397 | template <int NDims> |
398 | typename const_array_view<NDims>::type |
399 | operator[](const boost::detail::multi_array:: |
400 | index_gen<NumDims,NDims>& indices) |
401 | const { |
402 | return super_type::operator[](indices); |
403 | } |
404 | |
405 | const_iterator begin() const { |
406 | return super_type::begin(); |
407 | } |
408 | |
409 | const_iterator end() const { |
410 | return super_type::end(); |
411 | } |
412 | |
413 | const_reverse_iterator rbegin() const { |
414 | return super_type::rbegin(); |
415 | } |
416 | |
417 | const_reverse_iterator rend() const { |
418 | return super_type::rend(); |
419 | } |
420 | |
421 | #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS |
422 | private: |
423 | template <typename,std::size_t> friend class multi_array_impl_base; |
424 | #else |
425 | public: // should be private |
426 | #endif |
427 | |
428 | // constructor used by multi_array_impl_base::generate_array_view to |
429 | // generate array views |
430 | template <typename ExtentList, typename Index> |
431 | explicit multi_array_view(T* base, |
432 | const ExtentList& extents, |
433 | const boost::array<Index,NumDims>& strides) : |
434 | super_type(base,extents,strides) { } |
435 | |
436 | }; |
437 | |
438 | } // namespace multi_array |
439 | } // namespace detail |
440 | |
441 | // |
442 | // traits classes to get array_view types |
443 | // |
444 | template <typename Array, int N> |
445 | class array_view_gen { |
446 | typedef typename Array::element element; |
447 | public: |
448 | typedef boost::detail::multi_array::multi_array_view<element,N> type; |
449 | }; |
450 | |
451 | template <typename Array, int N> |
452 | class const_array_view_gen { |
453 | typedef typename Array::element element; |
454 | public: |
455 | typedef boost::detail::multi_array::const_multi_array_view<element,N> type; |
456 | }; |
457 | |
458 | } // namespace boost |
459 | |
460 | #endif |
461 | |