1 // Copyright 2002 The Trustees of Indiana University.
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)
7 // Boost.MultiArray Library
8 // Authors: Ronald Garcia
11 // See http://www.boost.org/libs/multi_array for documentation.
13 #ifndef SUBARRAY_RG071801_HPP
14 #define SUBARRAY_RG071801_HPP
17 // subarray.hpp - used to implement standard operator[] on
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"
31 namespace multi_array {
35 // multi_array's proxy class to allow multiple overloads of
36 // operator[] in order to provide a clean multi-dimensional array
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>
42 typedef boost::detail::multi_array::multi_array_impl_base<T,NumDims> super_type;
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;
55 template <std::size_t NDims>
56 struct const_array_view {
57 typedef boost::detail::multi_array::const_multi_array_view<T,NDims> type;
60 template <std::size_t NDims>
62 typedef boost::detail::multi_array::multi_array_view<T,NDims> type;
65 // Allow default copy constructor as well.
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_) {
73 // const_sub_array always returns const types, regardless of its own
75 const_reference operator[](index idx) const {
76 return super_type::access(boost::type<const_reference>(),
77 idx,base_,shape(),strides(),index_bases());
80 template <typename IndexList>
81 const element& operator()(const IndexList& indices) const {
82 return super_type::access_element(boost::type<const element&>(),
87 // see generate_array_view in base.hpp
88 #if !defined(BOOST_MSVC) || BOOST_MSVC > 1300
91 template <int NumDims, int NDims> // else ICE
93 typename const_array_view<NDims>::type
94 operator[](const boost::detail::multi_array::
95 index_gen<NumDims,NDims>& indices)
97 typedef typename const_array_view<NDims>::type return_type;
99 super_type::generate_array_view(boost::type<return_type>(),
107 template <typename OPtr>
108 bool operator<(const const_sub_array<T,NumDims,OPtr>& rhs) const {
109 return std::lexicographical_compare(begin(),end(),rhs.begin(),rhs.end());
112 template <typename OPtr>
113 bool operator==(const const_sub_array<T,NumDims,OPtr>& rhs) const {
114 if(std::equal(shape(),shape()+num_dimensions(),rhs.shape()))
115 return std::equal(begin(),end(),rhs.begin());
119 template <typename OPtr>
120 bool operator!=(const const_sub_array<T,NumDims,OPtr>& rhs) const {
121 return !(*this == rhs);
124 template <typename OPtr>
125 bool operator>(const const_sub_array<T,NumDims,OPtr>& rhs) const {
129 template <typename OPtr>
130 bool operator<=(const const_sub_array<T,NumDims,OPtr>& rhs) const {
131 return !(*this > rhs);
134 template <typename OPtr>
135 bool operator>=(const const_sub_array<T,NumDims,OPtr>& rhs) const {
136 return !(*this < rhs);
139 const_iterator begin() const {
140 return const_iterator(*index_bases(),origin(),
141 shape(),strides(),index_bases());
144 const_iterator end() const {
145 return const_iterator(*index_bases()+*shape(),origin(),
146 shape(),strides(),index_bases());
149 const_reverse_iterator rbegin() const {
150 return const_reverse_iterator(end());
153 const_reverse_iterator rend() const {
154 return const_reverse_iterator(begin());
157 TPtr origin() const { return base_; }
158 size_type size() const { return extents_[0]; }
159 size_type max_size() const { return num_elements(); }
160 bool empty() const { return size() == 0; }
161 size_type num_dimensions() const { return NumDims; }
162 const size_type* shape() const { return extents_; }
163 const index* strides() const { return strides_; }
164 const index* index_bases() const { return index_base_; }
166 size_type num_elements() const {
167 return std::accumulate(shape(),shape() + num_dimensions(),
168 size_type(1), std::multiplies<size_type>());
172 #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
174 template <typename,std::size_t> friend class value_accessor_n;
175 template <typename,std::size_t,typename> friend class const_sub_array;
177 public: // Should be protected
180 const_sub_array (TPtr base,
181 const size_type* extents,
182 const index* strides,
183 const index* index_base) :
184 base_(base), extents_(extents), strides_(strides),
185 index_base_(index_base) {
189 const size_type* extents_;
190 const index* strides_;
191 const index* index_base_;
193 // const_sub_array cannot be assigned to (no deep copies!)
194 const_sub_array& operator=(const const_sub_array&);
197 #ifdef BOOST_NO_FUNCTION_TEMPLATE_ORDERING
199 // Compilers that don't support partial ordering may need help to
200 // disambiguate multi_array's templated constructors. Even vc6/7 are
201 // capable of some limited SFINAE, so we take the most-general version
202 // out of the overload set with disable_non_sub_array.
204 template <typename T, std::size_t NumDims, typename TPtr>
205 char is_sub_array_help(const_sub_array<T,NumDims,TPtr>&);
207 char ( &is_sub_array_help(...) )[2];
213 BOOST_STATIC_CONSTANT(bool, value = sizeof((is_sub_array_help)(x)) == 1);
216 template <bool sub_array = false>
217 struct disable_non_sub_array_impl
219 // forming a pointer to a reference triggers SFINAE
224 struct disable_non_sub_array_impl<true>
230 struct disable_non_sub_array
232 typedef typename disable_non_sub_array_impl<is_sub_array<T>::value>::type type;
238 // multi_array's proxy class to allow multiple overloads of
239 // operator[] in order to provide a clean multi-dimensional array
241 template <typename T, std::size_t NumDims>
242 class sub_array : public const_sub_array<T,NumDims,T*>
244 typedef const_sub_array<T,NumDims,T*> super_type;
246 typedef typename super_type::element element;
247 typedef typename super_type::reference reference;
248 typedef typename super_type::index index;
249 typedef typename super_type::size_type size_type;
250 typedef typename super_type::iterator iterator;
251 typedef typename super_type::reverse_iterator reverse_iterator;
252 typedef typename super_type::const_reference const_reference;
253 typedef typename super_type::const_iterator const_iterator;
254 typedef typename super_type::const_reverse_iterator const_reverse_iterator;
257 template <std::size_t NDims>
258 struct const_array_view {
259 typedef boost::detail::multi_array::const_multi_array_view<T,NDims> type;
262 template <std::size_t NDims>
264 typedef boost::detail::multi_array::multi_array_view<T,NDims> type;
267 // Assignment from other ConstMultiArray types.
268 template <typename ConstMultiArray>
269 sub_array& operator=(const ConstMultiArray& other) {
270 function_requires< boost::detail::multi_array::ConstMultiArrayConcept<
271 ConstMultiArray, NumDims> >();
273 // make sure the dimensions agree
274 assert(other.num_dimensions() == this->num_dimensions());
275 assert(std::equal(other.shape(),other.shape()+this->num_dimensions(),
277 // iterator-based copy
278 std::copy(other.begin(),other.end(),begin());
283 sub_array& operator=(const sub_array& other) {
284 if (&other != this) {
285 // make sure the dimensions agree
286 assert(other.num_dimensions() == this->num_dimensions());
287 assert(std::equal(other.shape(),other.shape()+this->num_dimensions(),
289 // iterator-based copy
290 std::copy(other.begin(),other.end(),begin());
295 T* origin() { return this->base_; }
296 const T* origin() const { return this->base_; }
298 reference operator[](index idx) {
299 return super_type::access(boost::type<reference>(),
300 idx,this->base_,this->shape(),this->strides(),
301 this->index_bases());
304 // see generate_array_view in base.hpp
305 #if !defined(BOOST_MSVC) || BOOST_MSVC > 1300
308 template <int NumDims, int NDims> // else ICE
310 typename array_view<NDims>::type
311 operator[](const boost::detail::multi_array::
312 index_gen<NumDims,NDims>& indices) {
313 typedef typename array_view<NDims>::type return_type;
315 super_type::generate_array_view(boost::type<return_type>(),
323 template <class IndexList>
324 element& operator()(const IndexList& indices) {
325 return super_type::access_element(boost::type<element&>(),
327 indices,this->strides());
331 return iterator(*this->index_bases(),origin(),
332 this->shape(),this->strides(),this->index_bases());
336 return iterator(*this->index_bases()+*this->shape(),origin(),
337 this->shape(),this->strides(),this->index_bases());
340 // RG - rbegin() and rend() written naively to thwart MSVC ICE.
341 reverse_iterator rbegin() {
342 reverse_iterator ri(end());
346 reverse_iterator rend() {
347 reverse_iterator ri(begin());
355 template <class IndexList>
356 const element& operator()(const IndexList& indices) const {
357 return super_type::operator()(indices);
360 const_reference operator[](index idx) const {
361 return super_type::operator[](idx);
364 // see generate_array_view in base.hpp
365 #if !defined(BOOST_MSVC) || BOOST_MSVC > 1300
368 template <int NumDims, int NDims> // else ICE
370 typename const_array_view<NDims>::type
371 operator[](const boost::detail::multi_array::
372 index_gen<NumDims,NDims>& indices)
374 return super_type::operator[](indices);
377 const_iterator begin() const {
378 return super_type::begin();
381 const_iterator end() const {
382 return super_type::end();
385 const_reverse_iterator rbegin() const {
386 return super_type::rbegin();
389 const_reverse_iterator rend() const {
390 return super_type::rend();
393 #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
395 template <typename,std::size_t> friend class value_accessor_n;
397 public: // should be private
401 const size_type* extents,
402 const index* strides,
403 const index* index_base) :
404 super_type(base,extents,strides,index_base) {
409 } // namespace multi_array
410 } // namespace detail
412 // traits classes to get sub_array types
414 template <typename Array, int N>
416 typedef typename Array::element element;
418 typedef boost::detail::multi_array::sub_array<element,N> type;
421 template <typename Array, int N>
422 class const_subarray_gen {
423 typedef typename Array::element element;
425 typedef boost::detail::multi_array::const_sub_array<element,N> type;
429 #endif // SUBARRAY_RG071801_HPP