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_SUBARRAY_HPP |
14 | #define BOOST_MULTI_ARRAY_SUBARRAY_HPP |
15 | |
16 | // |
17 | // subarray.hpp - used to implement standard operator[] on |
18 | // multi_arrays |
19 | // |
20 | |
21 | #include "boost/multi_array/base.hpp" |
22 | #include "boost/multi_array/concept_checks.hpp" |
23 | #include "boost/limits.hpp" |
24 | #include "boost/type.hpp" |
25 | #include <algorithm> |
26 | #include <cstddef> |
27 | #include <functional> |
28 | |
29 | namespace boost { |
30 | namespace detail { |
31 | namespace multi_array { |
32 | |
33 | // |
34 | // const_sub_array |
35 | // multi_array's proxy class to allow multiple overloads of |
36 | // operator[] in order to provide a clean multi-dimensional array |
37 | // interface. |
38 | template <typename T, std::size_t NumDims, typename TPtr> |
39 | class const_sub_array : |
40 | public boost::detail::multi_array::multi_array_impl_base<T,NumDims> |
41 | { |
42 | typedef boost::detail::multi_array::multi_array_impl_base<T,NumDims> super_type; |
43 | public: |
44 | typedef typename super_type::value_type value_type; |
45 | typedef typename super_type::const_reference const_reference; |
46 | typedef typename super_type::const_iterator const_iterator; |
47 | typedef typename super_type::const_reverse_iterator const_reverse_iterator; |
48 | typedef typename super_type::element element; |
49 | typedef typename super_type::size_type size_type; |
50 | typedef typename super_type::difference_type difference_type; |
51 | typedef typename super_type::index index; |
52 | typedef typename super_type::extent_range extent_range; |
53 | |
54 | // template typedefs |
55 | template <std::size_t NDims> |
56 | struct const_array_view { |
57 | typedef boost::detail::multi_array::const_multi_array_view<T,NDims> type; |
58 | }; |
59 | |
60 | template <std::size_t NDims> |
61 | struct array_view { |
62 | typedef boost::detail::multi_array::multi_array_view<T,NDims> type; |
63 | }; |
64 | |
65 | // Allow default copy constructor as well. |
66 | |
67 | template <typename OPtr> |
68 | const_sub_array (const const_sub_array<T,NumDims,OPtr>& rhs) : |
69 | base_(rhs.base_), extents_(rhs.extents_), strides_(rhs.strides_), |
70 | index_base_(rhs.index_base_) { |
71 | } |
72 | |
73 | // const_sub_array always returns const types, regardless of its own |
74 | // constness. |
75 | const_reference operator[](index idx) const { |
76 | return super_type::access(boost::type<const_reference>(), |
77 | idx,base_,shape(),strides(),index_bases()); |
78 | } |
79 | |
80 | template <typename IndexList> |
81 | const element& operator()(const IndexList& indices) const { |
82 | boost::function_requires< |
83 | CollectionConcept<IndexList> >(); |
84 | return super_type::access_element(boost::type<const element&>(), |
85 | indices,origin(), |
86 | shape(),strides(),index_bases()); |
87 | } |
88 | |
89 | // see generate_array_view in base.hpp |
90 | template <int NDims> |
91 | typename const_array_view<NDims>::type |
92 | operator[](const boost::detail::multi_array:: |
93 | index_gen<NumDims,NDims>& indices) |
94 | const { |
95 | typedef typename const_array_view<NDims>::type return_type; |
96 | return |
97 | super_type::generate_array_view(boost::type<return_type>(), |
98 | indices, |
99 | shape(), |
100 | strides(), |
101 | index_bases(), |
102 | base_); |
103 | } |
104 | |
105 | template <typename OPtr> |
106 | bool operator<(const const_sub_array<T,NumDims,OPtr>& rhs) const { |
107 | return std::lexicographical_compare(begin(),end(),rhs.begin(),rhs.end()); |
108 | } |
109 | |
110 | template <typename OPtr> |
111 | bool operator==(const const_sub_array<T,NumDims,OPtr>& rhs) const { |
112 | if(std::equal(shape(),shape()+num_dimensions(),rhs.shape())) |
113 | return std::equal(begin(),end(),rhs.begin()); |
114 | else return false; |
115 | } |
116 | |
117 | template <typename OPtr> |
118 | bool operator!=(const const_sub_array<T,NumDims,OPtr>& rhs) const { |
119 | return !(*this == rhs); |
120 | } |
121 | |
122 | template <typename OPtr> |
123 | bool operator>(const const_sub_array<T,NumDims,OPtr>& rhs) const { |
124 | return rhs < *this; |
125 | } |
126 | |
127 | template <typename OPtr> |
128 | bool operator<=(const const_sub_array<T,NumDims,OPtr>& rhs) const { |
129 | return !(*this > rhs); |
130 | } |
131 | |
132 | template <typename OPtr> |
133 | bool operator>=(const const_sub_array<T,NumDims,OPtr>& rhs) const { |
134 | return !(*this < rhs); |
135 | } |
136 | |
137 | const_iterator begin() const { |
138 | return const_iterator(*index_bases(),origin(), |
139 | shape(),strides(),index_bases()); |
140 | } |
141 | |
142 | const_iterator end() const { |
143 | return const_iterator(*index_bases()+(index)*shape(),origin(), |
144 | shape(),strides(),index_bases()); |
145 | } |
146 | |
147 | const_reverse_iterator rbegin() const { |
148 | return const_reverse_iterator(end()); |
149 | } |
150 | |
151 | const_reverse_iterator rend() const { |
152 | return const_reverse_iterator(begin()); |
153 | } |
154 | |
155 | TPtr origin() const { return base_; } |
156 | size_type size() const { return extents_[0]; } |
157 | size_type max_size() const { return num_elements(); } |
158 | bool empty() const { return size() == 0; } |
159 | size_type num_dimensions() const { return NumDims; } |
160 | const size_type* shape() const { return extents_; } |
161 | const index* strides() const { return strides_; } |
162 | const index* index_bases() const { return index_base_; } |
163 | |
164 | size_type num_elements() const { |
165 | return std::accumulate(shape(),shape() + num_dimensions(), |
166 | size_type(1), std::multiplies<size_type>()); |
167 | } |
168 | |
169 | |
170 | #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS |
171 | protected: |
172 | template <typename,std::size_t> friend class value_accessor_n; |
173 | template <typename,std::size_t,typename> friend class const_sub_array; |
174 | #else |
175 | public: // Should be protected |
176 | #endif |
177 | |
178 | const_sub_array (TPtr base, |
179 | const size_type* extents, |
180 | const index* strides, |
181 | const index* index_base) : |
182 | base_(base), extents_(extents), strides_(strides), |
183 | index_base_(index_base) { |
184 | } |
185 | |
186 | TPtr base_; |
187 | const size_type* extents_; |
188 | const index* strides_; |
189 | const index* index_base_; |
190 | private: |
191 | // const_sub_array cannot be assigned to (no deep copies!) |
192 | const_sub_array& operator=(const const_sub_array&); |
193 | }; |
194 | |
195 | |
196 | // |
197 | // sub_array |
198 | // multi_array's proxy class to allow multiple overloads of |
199 | // operator[] in order to provide a clean multi-dimensional array |
200 | // interface. |
201 | template <typename T, std::size_t NumDims> |
202 | class sub_array : public const_sub_array<T,NumDims,T*> |
203 | { |
204 | typedef const_sub_array<T,NumDims,T*> super_type; |
205 | public: |
206 | typedef typename super_type::element element; |
207 | typedef typename super_type::reference reference; |
208 | typedef typename super_type::index index; |
209 | typedef typename super_type::size_type size_type; |
210 | typedef typename super_type::iterator iterator; |
211 | typedef typename super_type::reverse_iterator reverse_iterator; |
212 | typedef typename super_type::const_reference const_reference; |
213 | typedef typename super_type::const_iterator const_iterator; |
214 | typedef typename super_type::const_reverse_iterator const_reverse_iterator; |
215 | |
216 | // template typedefs |
217 | template <std::size_t NDims> |
218 | struct const_array_view { |
219 | typedef boost::detail::multi_array::const_multi_array_view<T,NDims> type; |
220 | }; |
221 | |
222 | template <std::size_t NDims> |
223 | struct array_view { |
224 | typedef boost::detail::multi_array::multi_array_view<T,NDims> type; |
225 | }; |
226 | |
227 | // Assignment from other ConstMultiArray types. |
228 | template <typename ConstMultiArray> |
229 | sub_array& operator=(const ConstMultiArray& other) { |
230 | function_requires< boost::multi_array_concepts::ConstMultiArrayConcept< |
231 | ConstMultiArray, NumDims> >(); |
232 | |
233 | // make sure the dimensions agree |
234 | BOOST_ASSERT(other.num_dimensions() == this->num_dimensions()); |
235 | BOOST_ASSERT(std::equal(other.shape(),other.shape()+this->num_dimensions(), |
236 | this->shape())); |
237 | // iterator-based copy |
238 | std::copy(other.begin(),other.end(),begin()); |
239 | return *this; |
240 | } |
241 | |
242 | |
243 | sub_array& operator=(const sub_array& other) { |
244 | if (&other != this) { |
245 | // make sure the dimensions agree |
246 | BOOST_ASSERT(other.num_dimensions() == this->num_dimensions()); |
247 | BOOST_ASSERT(std::equal(other.shape(), |
248 | other.shape()+this->num_dimensions(), |
249 | this->shape())); |
250 | // iterator-based copy |
251 | std::copy(other.begin(),other.end(),begin()); |
252 | } |
253 | return *this; |
254 | } |
255 | |
256 | T* origin() { return this->base_; } |
257 | const T* origin() const { return this->base_; } |
258 | |
259 | reference operator[](index idx) { |
260 | return super_type::access(boost::type<reference>(), |
261 | idx,this->base_,this->shape(),this->strides(), |
262 | this->index_bases()); |
263 | } |
264 | |
265 | // see generate_array_view in base.hpp |
266 | template <int NDims> |
267 | typename array_view<NDims>::type |
268 | operator[](const boost::detail::multi_array:: |
269 | index_gen<NumDims,NDims>& indices) { |
270 | typedef typename array_view<NDims>::type return_type; |
271 | return |
272 | super_type::generate_array_view(boost::type<return_type>(), |
273 | indices, |
274 | this->shape(), |
275 | this->strides(), |
276 | this->index_bases(), |
277 | origin()); |
278 | } |
279 | |
280 | template <class IndexList> |
281 | element& operator()(const IndexList& indices) { |
282 | boost::function_requires< |
283 | CollectionConcept<IndexList> >(); |
284 | return super_type::access_element(boost::type<element&>(), |
285 | indices,origin(), |
286 | this->shape(),this->strides(), |
287 | this->index_bases()); |
288 | } |
289 | |
290 | iterator begin() { |
291 | return iterator(*this->index_bases(),origin(), |
292 | this->shape(),this->strides(),this->index_bases()); |
293 | } |
294 | |
295 | iterator end() { |
296 | return iterator(*this->index_bases()+(index)*this->shape(),origin(), |
297 | this->shape(),this->strides(),this->index_bases()); |
298 | } |
299 | |
300 | // RG - rbegin() and rend() written naively to thwart MSVC ICE. |
301 | reverse_iterator rbegin() { |
302 | reverse_iterator ri(end()); |
303 | return ri; |
304 | } |
305 | |
306 | reverse_iterator rend() { |
307 | reverse_iterator ri(begin()); |
308 | return ri; |
309 | } |
310 | |
311 | // |
312 | // proxies |
313 | // |
314 | |
315 | template <class IndexList> |
316 | const element& operator()(const IndexList& indices) const { |
317 | boost::function_requires< |
318 | CollectionConcept<IndexList> >(); |
319 | return super_type::operator()(indices); |
320 | } |
321 | |
322 | const_reference operator[](index idx) const { |
323 | return super_type::operator[](idx); |
324 | } |
325 | |
326 | // see generate_array_view in base.hpp |
327 | template <int NDims> |
328 | typename const_array_view<NDims>::type |
329 | operator[](const boost::detail::multi_array:: |
330 | index_gen<NumDims,NDims>& indices) |
331 | const { |
332 | return super_type::operator[](indices); |
333 | } |
334 | |
335 | const_iterator begin() const { |
336 | return super_type::begin(); |
337 | } |
338 | |
339 | const_iterator end() const { |
340 | return super_type::end(); |
341 | } |
342 | |
343 | const_reverse_iterator rbegin() const { |
344 | return super_type::rbegin(); |
345 | } |
346 | |
347 | const_reverse_iterator rend() const { |
348 | return super_type::rend(); |
349 | } |
350 | |
351 | #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS |
352 | private: |
353 | template <typename,std::size_t> friend class value_accessor_n; |
354 | #else |
355 | public: // should be private |
356 | #endif |
357 | |
358 | sub_array (T* base, |
359 | const size_type* extents, |
360 | const index* strides, |
361 | const index* index_base) : |
362 | super_type(base,extents,strides,index_base) { |
363 | } |
364 | |
365 | }; |
366 | |
367 | } // namespace multi_array |
368 | } // namespace detail |
369 | // |
370 | // traits classes to get sub_array types |
371 | // |
372 | template <typename Array, int N> |
373 | class subarray_gen { |
374 | typedef typename Array::element element; |
375 | public: |
376 | typedef boost::detail::multi_array::sub_array<element,N> type; |
377 | }; |
378 | |
379 | template <typename Array, int N> |
380 | class const_subarray_gen { |
381 | typedef typename Array::element element; |
382 | public: |
383 | typedef boost::detail::multi_array::const_sub_array<element,N> type; |
384 | }; |
385 | } // namespace boost |
386 | |
387 | #endif |
388 | |