1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/epoc32/include/stdapis/boost/multi_array/multi_array_ref.hpp Tue Mar 16 16:12:26 2010 +0000
1.3 @@ -0,0 +1,633 @@
1.4 +// Copyright 2002 The Trustees of Indiana University.
1.5 +
1.6 +// Use, modification and distribution is subject to the Boost Software
1.7 +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
1.8 +// http://www.boost.org/LICENSE_1_0.txt)
1.9 +
1.10 +// Boost.MultiArray Library
1.11 +// Authors: Ronald Garcia
1.12 +// Jeremy Siek
1.13 +// Andrew Lumsdaine
1.14 +// See http://www.boost.org/libs/multi_array for documentation.
1.15 +
1.16 +#ifndef BOOST_MULTI_ARRAY_REF_RG071801_HPP
1.17 +#define BOOST_MULTI_ARRAY_REF_RG071801_HPP
1.18 +
1.19 +//
1.20 +// multi_array_ref.hpp - code for creating "views" of array data.
1.21 +//
1.22 +
1.23 +#include "boost/multi_array/base.hpp"
1.24 +#include "boost/multi_array/collection_concept.hpp"
1.25 +#include "boost/multi_array/concept_checks.hpp"
1.26 +#include "boost/multi_array/iterator.hpp"
1.27 +#include "boost/multi_array/storage_order.hpp"
1.28 +#include "boost/multi_array/subarray.hpp"
1.29 +#include "boost/multi_array/view.hpp"
1.30 +#include "boost/multi_array/algorithm.hpp"
1.31 +#include "boost/type_traits/is_integral.hpp"
1.32 +#include "boost/array.hpp"
1.33 +#include "boost/concept_check.hpp"
1.34 +#include "boost/functional.hpp"
1.35 +#include "boost/limits.hpp"
1.36 +#include <algorithm>
1.37 +#include <cassert>
1.38 +#include <cstddef>
1.39 +#include <functional>
1.40 +#include <numeric>
1.41 +
1.42 +namespace boost {
1.43 +
1.44 +template <typename T, std::size_t NumDims,
1.45 + typename TPtr = const T*
1.46 +>
1.47 +class const_multi_array_ref :
1.48 + public detail::multi_array::multi_array_impl_base<T,NumDims>
1.49 +{
1.50 + typedef detail::multi_array::multi_array_impl_base<T,NumDims> super_type;
1.51 +public:
1.52 + typedef typename super_type::value_type value_type;
1.53 + typedef typename super_type::const_reference const_reference;
1.54 + typedef typename super_type::const_iterator const_iterator;
1.55 + typedef typename super_type::const_reverse_iterator const_reverse_iterator;
1.56 + typedef typename super_type::element element;
1.57 + typedef typename super_type::size_type size_type;
1.58 + typedef typename super_type::difference_type difference_type;
1.59 + typedef typename super_type::index index;
1.60 + typedef typename super_type::extent_range extent_range;
1.61 + typedef general_storage_order<NumDims> storage_order_type;
1.62 +
1.63 + // template typedefs
1.64 + template <std::size_t NDims>
1.65 + struct const_array_view {
1.66 + typedef boost::detail::multi_array::const_multi_array_view<T,NDims> type;
1.67 + };
1.68 +
1.69 + template <std::size_t NDims>
1.70 + struct array_view {
1.71 + typedef boost::detail::multi_array::multi_array_view<T,NDims> type;
1.72 + };
1.73 +
1.74 +#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
1.75 + // make const_multi_array_ref a friend of itself
1.76 + template <typename,std::size_t,typename>
1.77 + friend class const_multi_array_ref;
1.78 +#endif
1.79 +
1.80 + // This ensures that const_multi_array_ref types with different TPtr
1.81 + // types can convert to each other
1.82 + template <typename OPtr>
1.83 + const_multi_array_ref(const const_multi_array_ref<T,NumDims,OPtr>& other)
1.84 + : base_(other.base_), storage_(other.storage_),
1.85 + extent_list_(other.extent_list_),
1.86 + stride_list_(other.stride_list_),
1.87 + index_base_list_(other.index_base_list_),
1.88 + origin_offset_(other.origin_offset_),
1.89 + directional_offset_(other.directional_offset_),
1.90 + num_elements_(other.num_elements_) { }
1.91 +
1.92 + template <typename ExtentList>
1.93 + explicit const_multi_array_ref(TPtr base, const ExtentList& extents) :
1.94 + base_(base), storage_(c_storage_order()) {
1.95 + boost::function_requires<
1.96 + detail::multi_array::CollectionConcept<ExtentList> >();
1.97 +
1.98 + index_base_list_.assign(0);
1.99 + init_multi_array_ref(extents.begin());
1.100 + }
1.101 +
1.102 + template <typename ExtentList>
1.103 + explicit const_multi_array_ref(TPtr base, const ExtentList& extents,
1.104 + const general_storage_order<NumDims>& so) :
1.105 + base_(base), storage_(so) {
1.106 + boost::function_requires<
1.107 + detail::multi_array::CollectionConcept<ExtentList> >();
1.108 +
1.109 + index_base_list_.assign(0);
1.110 + init_multi_array_ref(extents.begin());
1.111 + }
1.112 +
1.113 + explicit const_multi_array_ref(TPtr base,
1.114 + const detail::multi_array::
1.115 + extent_gen<NumDims>& ranges) :
1.116 + base_(base), storage_(c_storage_order()) {
1.117 +
1.118 + init_from_extent_gen(ranges);
1.119 + }
1.120 +
1.121 + explicit const_multi_array_ref(TPtr base,
1.122 + const detail::multi_array::
1.123 + extent_gen<NumDims>& ranges,
1.124 + const general_storage_order<NumDims>& so) :
1.125 + base_(base), storage_(so) {
1.126 +
1.127 + init_from_extent_gen(ranges);
1.128 + }
1.129 +
1.130 + template <class InputIterator>
1.131 + void assign(InputIterator begin, InputIterator end) {
1.132 + boost::function_requires<InputIteratorConcept<InputIterator> >();
1.133 +
1.134 + InputIterator in_iter = begin;
1.135 + T* out_iter = base_;
1.136 + std::size_t copy_count=0;
1.137 + while (in_iter != end && copy_count < num_elements_) {
1.138 + *out_iter++ = *in_iter++;
1.139 + copy_count++;
1.140 + }
1.141 + }
1.142 +
1.143 + template <class BaseList>
1.144 +#ifdef BOOST_NO_SFINAE
1.145 + void
1.146 +#else
1.147 + typename
1.148 + disable_if<typename boost::is_integral<BaseList>::type,void >::type
1.149 +#endif // BOOST_NO_SFINAE
1.150 + reindex(const BaseList& values) {
1.151 + boost::function_requires<
1.152 + detail::multi_array::CollectionConcept<BaseList> >();
1.153 + boost::detail::multi_array::
1.154 + copy_n(values.begin(),num_dimensions(),index_base_list_.begin());
1.155 + origin_offset_ =
1.156 + this->calculate_origin_offset(stride_list_,extent_list_,
1.157 + storage_,index_base_list_);
1.158 + }
1.159 +
1.160 + void reindex(index value) {
1.161 + index_base_list_.assign(value);
1.162 + origin_offset_ =
1.163 + this->calculate_origin_offset(stride_list_,extent_list_,
1.164 + storage_,index_base_list_);
1.165 + }
1.166 +
1.167 + template <typename SizeList>
1.168 + void reshape(const SizeList& extents) {
1.169 + boost::function_requires<
1.170 + detail::multi_array::CollectionConcept<SizeList> >();
1.171 + assert(num_elements_ ==
1.172 + std::accumulate(extents.begin(),extents.end(),
1.173 + size_type(1),std::multiplies<size_type>()));
1.174 +
1.175 + std::copy(extents.begin(),extents.end(),extent_list_.begin());
1.176 + this->compute_strides(stride_list_,extent_list_,storage_);
1.177 +
1.178 + origin_offset_ =
1.179 + this->calculate_origin_offset(stride_list_,extent_list_,
1.180 + storage_,index_base_list_);
1.181 + }
1.182 +
1.183 + size_type num_dimensions() const { return NumDims; }
1.184 +
1.185 + size_type size() const { return extent_list_.front(); }
1.186 +
1.187 + // given reshaping functionality, this is the max possible size.
1.188 + size_type max_size() const { return num_elements(); }
1.189 +
1.190 + bool empty() const { return size() == 0; }
1.191 +
1.192 + const size_type* shape() const {
1.193 + return extent_list_.data();
1.194 + }
1.195 +
1.196 + const index* strides() const {
1.197 + return stride_list_.data();
1.198 + }
1.199 +
1.200 + const element* origin() const { return base_+origin_offset_; }
1.201 + const element* data() const { return base_; }
1.202 +
1.203 + size_type num_elements() const { return num_elements_; }
1.204 +
1.205 + const index* index_bases() const {
1.206 + return index_base_list_.data();
1.207 + }
1.208 +
1.209 +
1.210 + const storage_order_type& storage_order() const {
1.211 + return storage_;
1.212 + }
1.213 +
1.214 + template <typename IndexList>
1.215 + const element& operator()(IndexList indices) const {
1.216 + boost::function_requires<
1.217 + detail::multi_array::CollectionConcept<IndexList> >();
1.218 + return super_type::access_element(boost::type<const element&>(),
1.219 + indices,origin(),
1.220 + shape(),strides(),index_bases());
1.221 + }
1.222 +
1.223 + // Only allow const element access
1.224 + const_reference operator[](index idx) const {
1.225 + return super_type::access(boost::type<const_reference>(),
1.226 + idx,origin(),
1.227 + shape(),strides(),index_bases());
1.228 + }
1.229 +
1.230 + // see generate_array_view in base.hpp
1.231 +#if !defined(BOOST_MSVC) || BOOST_MSVC > 1300
1.232 + template <int NDims>
1.233 +#else
1.234 + template <int NumDims, int NDims> // else ICE
1.235 +#endif // BOOST_MSVC
1.236 + typename const_array_view<NDims>::type
1.237 + operator[](const detail::multi_array::
1.238 + index_gen<NumDims,NDims>& indices)
1.239 + const {
1.240 + typedef typename const_array_view<NDims>::type return_type;
1.241 + return
1.242 + super_type::generate_array_view(boost::type<return_type>(),
1.243 + indices,
1.244 + shape(),
1.245 + strides(),
1.246 + index_bases(),
1.247 + origin());
1.248 + }
1.249 +
1.250 + const_iterator begin() const {
1.251 + return const_iterator(*index_bases(),origin(),
1.252 + shape(),strides(),index_bases());
1.253 + }
1.254 +
1.255 + const_iterator end() const {
1.256 + return const_iterator(*index_bases()+(index)*shape(),origin(),
1.257 + shape(),strides(),index_bases());
1.258 + }
1.259 +
1.260 + const_reverse_iterator rbegin() const {
1.261 + return const_reverse_iterator(end());
1.262 + }
1.263 +
1.264 + const_reverse_iterator rend() const {
1.265 + return const_reverse_iterator(begin());
1.266 + }
1.267 +
1.268 +
1.269 + template <typename OPtr>
1.270 + bool operator==(const
1.271 + const_multi_array_ref<T,NumDims,OPtr>& rhs)
1.272 + const {
1.273 + if(std::equal(extent_list_.begin(),
1.274 + extent_list_.end(),
1.275 + rhs.extent_list_.begin()))
1.276 + return std::equal(begin(),end(),rhs.begin());
1.277 + else return false;
1.278 + }
1.279 +
1.280 + template <typename OPtr>
1.281 + bool operator<(const
1.282 + const_multi_array_ref<T,NumDims,OPtr>& rhs)
1.283 + const {
1.284 + return std::lexicographical_compare(begin(),end(),rhs.begin(),rhs.end());
1.285 + }
1.286 +
1.287 + template <typename OPtr>
1.288 + bool operator!=(const
1.289 + const_multi_array_ref<T,NumDims,OPtr>& rhs)
1.290 + const {
1.291 + return !(*this == rhs);
1.292 + }
1.293 +
1.294 + template <typename OPtr>
1.295 + bool operator>(const
1.296 + const_multi_array_ref<T,NumDims,OPtr>& rhs)
1.297 + const {
1.298 + return rhs < *this;
1.299 + }
1.300 +
1.301 + template <typename OPtr>
1.302 + bool operator<=(const
1.303 + const_multi_array_ref<T,NumDims,OPtr>& rhs)
1.304 + const {
1.305 + return !(*this > rhs);
1.306 + }
1.307 +
1.308 + template <typename OPtr>
1.309 + bool operator>=(const
1.310 + const_multi_array_ref<T,NumDims,OPtr>& rhs)
1.311 + const {
1.312 + return !(*this < rhs);
1.313 + }
1.314 +
1.315 +
1.316 +#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
1.317 +protected:
1.318 +#else
1.319 +public:
1.320 +#endif
1.321 +
1.322 + typedef boost::array<size_type,NumDims> size_list;
1.323 + typedef boost::array<index,NumDims> index_list;
1.324 +
1.325 + // This is used by multi_array, which is a subclass of this
1.326 + void set_base_ptr(TPtr new_base) { base_ = new_base; }
1.327 +
1.328 +
1.329 + // This constructor supports multi_array's default constructor
1.330 + // and constructors from multi_array_ref, subarray, and array_view
1.331 + explicit
1.332 + const_multi_array_ref(TPtr base,
1.333 + const storage_order_type& so,
1.334 + const index * index_bases,
1.335 + const size_type* extents) :
1.336 + base_(base), storage_(so), origin_offset_(0), directional_offset_(0)
1.337 + {
1.338 + // If index_bases or extents is null, then initialize the corresponding
1.339 + // private data to zeroed lists.
1.340 + if(index_bases) {
1.341 + boost::detail::multi_array::
1.342 + copy_n(index_bases,NumDims,index_base_list_.begin());
1.343 + } else {
1.344 + std::fill_n(index_base_list_.begin(),NumDims,0);
1.345 + }
1.346 + if(extents) {
1.347 + init_multi_array_ref(extents);
1.348 + } else {
1.349 + boost::array<index,NumDims> extent_list;
1.350 + extent_list.assign(0);
1.351 + init_multi_array_ref(extent_list.begin());
1.352 + }
1.353 + }
1.354 +
1.355 +
1.356 + TPtr base_;
1.357 + storage_order_type storage_;
1.358 + size_list extent_list_;
1.359 + index_list stride_list_;
1.360 + index_list index_base_list_;
1.361 + index origin_offset_;
1.362 + index directional_offset_;
1.363 + size_type num_elements_;
1.364 +
1.365 +private:
1.366 + // const_multi_array_ref cannot be assigned to (no deep copies!)
1.367 + const_multi_array_ref& operator=(const const_multi_array_ref& other);
1.368 +
1.369 + void init_from_extent_gen(const
1.370 + detail::multi_array::
1.371 + extent_gen<NumDims>& ranges) {
1.372 +
1.373 + typedef boost::array<index,NumDims> extent_list;
1.374 +
1.375 + // get the index_base values
1.376 + std::transform(ranges.ranges_.begin(),ranges.ranges_.end(),
1.377 + index_base_list_.begin(),
1.378 + boost::mem_fun_ref(&extent_range::start));
1.379 +
1.380 + // calculate the extents
1.381 + extent_list extents;
1.382 + std::transform(ranges.ranges_.begin(),ranges.ranges_.end(),
1.383 + extents.begin(),
1.384 + boost::mem_fun_ref(&extent_range::size));
1.385 +
1.386 + init_multi_array_ref(extents.begin());
1.387 + }
1.388 +
1.389 +
1.390 +#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
1.391 +protected:
1.392 +#else
1.393 +public:
1.394 +#endif
1.395 + // RG - move me!
1.396 + template <class InputIterator>
1.397 + void init_multi_array_ref(InputIterator extents_iter) {
1.398 + boost::function_requires<InputIteratorConcept<InputIterator> >();
1.399 +
1.400 + boost::detail::multi_array::
1.401 + copy_n(extents_iter,num_dimensions(),extent_list_.begin());
1.402 +
1.403 + // Calculate the array size
1.404 + num_elements_ = std::accumulate(extent_list_.begin(),extent_list_.end(),
1.405 + size_type(1),std::multiplies<size_type>());
1.406 +
1.407 + this->compute_strides(stride_list_,extent_list_,storage_);
1.408 +
1.409 + origin_offset_ =
1.410 + this->calculate_origin_offset(stride_list_,extent_list_,
1.411 + storage_,index_base_list_);
1.412 + directional_offset_ =
1.413 + this->calculate_descending_dimension_offset(stride_list_,extent_list_,
1.414 + storage_);
1.415 + }
1.416 +};
1.417 +
1.418 +template <typename T, std::size_t NumDims>
1.419 +class multi_array_ref :
1.420 + public const_multi_array_ref<T,NumDims,T*>
1.421 +{
1.422 + typedef const_multi_array_ref<T,NumDims,T*> super_type;
1.423 +public:
1.424 + typedef typename super_type::value_type value_type;
1.425 + typedef typename super_type::reference reference;
1.426 + typedef typename super_type::iterator iterator;
1.427 + typedef typename super_type::reverse_iterator reverse_iterator;
1.428 + typedef typename super_type::const_reference const_reference;
1.429 + typedef typename super_type::const_iterator const_iterator;
1.430 + typedef typename super_type::const_reverse_iterator const_reverse_iterator;
1.431 + typedef typename super_type::element element;
1.432 + typedef typename super_type::size_type size_type;
1.433 + typedef typename super_type::difference_type difference_type;
1.434 + typedef typename super_type::index index;
1.435 + typedef typename super_type::extent_range extent_range;
1.436 +
1.437 + typedef typename super_type::storage_order_type storage_order_type;
1.438 + typedef typename super_type::index_list index_list;
1.439 + typedef typename super_type::size_list size_list;
1.440 +
1.441 + template <std::size_t NDims>
1.442 + struct const_array_view {
1.443 + typedef boost::detail::multi_array::const_multi_array_view<T,NDims> type;
1.444 + };
1.445 +
1.446 + template <std::size_t NDims>
1.447 + struct array_view {
1.448 + typedef boost::detail::multi_array::multi_array_view<T,NDims> type;
1.449 + };
1.450 +
1.451 + template <class ExtentList>
1.452 + explicit multi_array_ref(T* base, const ExtentList& extents) :
1.453 + super_type(base,extents) {
1.454 + boost::function_requires<
1.455 + detail::multi_array::CollectionConcept<ExtentList> >();
1.456 + }
1.457 +
1.458 + template <class ExtentList>
1.459 + explicit multi_array_ref(T* base, const ExtentList& extents,
1.460 + const general_storage_order<NumDims>& so) :
1.461 + super_type(base,extents,so) {
1.462 + boost::function_requires<
1.463 + detail::multi_array::CollectionConcept<ExtentList> >();
1.464 + }
1.465 +
1.466 +
1.467 + explicit multi_array_ref(T* base,
1.468 + const detail::multi_array::
1.469 + extent_gen<NumDims>& ranges) :
1.470 + super_type(base,ranges) { }
1.471 +
1.472 +
1.473 + explicit multi_array_ref(T* base,
1.474 + const detail::multi_array::
1.475 + extent_gen<NumDims>&
1.476 + ranges,
1.477 + const general_storage_order<NumDims>& so) :
1.478 + super_type(base,ranges,so) { }
1.479 +
1.480 +
1.481 + // Assignment from other ConstMultiArray types.
1.482 + template <typename ConstMultiArray>
1.483 + multi_array_ref& operator=(const ConstMultiArray& other) {
1.484 + function_requires<
1.485 + detail::multi_array::
1.486 + ConstMultiArrayConcept<ConstMultiArray,NumDims> >();
1.487 +
1.488 + // make sure the dimensions agree
1.489 + assert(other.num_dimensions() == this->num_dimensions());
1.490 + assert(std::equal(other.shape(),other.shape()+this->num_dimensions(),
1.491 + this->shape()));
1.492 + // iterator-based copy
1.493 + std::copy(other.begin(),other.end(),this->begin());
1.494 + return *this;
1.495 + }
1.496 +
1.497 + multi_array_ref& operator=(const multi_array_ref& other) {
1.498 + if (&other != this) {
1.499 + // make sure the dimensions agree
1.500 +
1.501 + assert(other.num_dimensions() == this->num_dimensions());
1.502 + assert(std::equal(other.shape(),other.shape()+this->num_dimensions(),
1.503 + this->shape()));
1.504 + // iterator-based copy
1.505 + std::copy(other.begin(),other.end(),this->begin());
1.506 + }
1.507 + return *this;
1.508 + }
1.509 +
1.510 + element* origin() { return super_type::base_+super_type::origin_offset_; }
1.511 +
1.512 + element* data() { return super_type::base_; }
1.513 +
1.514 + template <class IndexList>
1.515 + element& operator()(const IndexList& indices) {
1.516 + boost::function_requires<
1.517 + detail::multi_array::CollectionConcept<IndexList> >();
1.518 + return super_type::access_element(boost::type<element&>(),
1.519 + indices,origin(),
1.520 + this->shape(),this->strides(),
1.521 + this->index_bases());
1.522 + }
1.523 +
1.524 +
1.525 + reference operator[](index idx) {
1.526 + return super_type::access(boost::type<reference>(),
1.527 + idx,origin(),
1.528 + this->shape(),this->strides(),
1.529 + this->index_bases());
1.530 + }
1.531 +
1.532 +
1.533 + // See note attached to generate_array_view in base.hpp
1.534 +#if !defined(BOOST_MSVC) || BOOST_MSVC > 1300
1.535 + template <int NDims>
1.536 +#else
1.537 + template <int NumDims, int NDims> // else ICE
1.538 +#endif // BOOST_MSVC
1.539 + typename array_view<NDims>::type
1.540 + operator[](const detail::multi_array::
1.541 + index_gen<NumDims,NDims>& indices) {
1.542 + typedef typename array_view<NDims>::type return_type;
1.543 + return
1.544 + super_type::generate_array_view(boost::type<return_type>(),
1.545 + indices,
1.546 + this->shape(),
1.547 + this->strides(),
1.548 + this->index_bases(),
1.549 + origin());
1.550 + }
1.551 +
1.552 +
1.553 + iterator begin() {
1.554 + return iterator(*this->index_bases(),origin(),this->shape(),
1.555 + this->strides(),this->index_bases());
1.556 + }
1.557 +
1.558 + iterator end() {
1.559 + return iterator(*this->index_bases()+(index)*this->shape(),origin(),
1.560 + this->shape(),this->strides(),
1.561 + this->index_bases());
1.562 + }
1.563 +
1.564 + // rbegin() and rend() written naively to thwart MSVC ICE.
1.565 + reverse_iterator rbegin() {
1.566 + reverse_iterator ri(end());
1.567 + return ri;
1.568 + }
1.569 +
1.570 + reverse_iterator rend() {
1.571 + reverse_iterator ri(begin());
1.572 + return ri;
1.573 + }
1.574 +
1.575 + // Using declarations don't seem to work for g++
1.576 + // These are the proxies to work around this.
1.577 +
1.578 + const element* origin() const { return super_type::origin(); }
1.579 + const element* data() const { return super_type::data(); }
1.580 +
1.581 + template <class IndexList>
1.582 + const element& operator()(const IndexList& indices) const {
1.583 + boost::function_requires<
1.584 + detail::multi_array::CollectionConcept<IndexList> >();
1.585 + return super_type::operator()(indices);
1.586 + }
1.587 +
1.588 + const_reference operator[](index idx) const {
1.589 + return super_type::access(boost::type<const_reference>(),
1.590 + idx,origin(),
1.591 + this->shape(),this->strides(),
1.592 + this->index_bases());
1.593 + }
1.594 +
1.595 + // See note attached to generate_array_view in base.hpp
1.596 +#if !defined(BOOST_MSVC) || BOOST_MSVC > 1300
1.597 + template <int NDims>
1.598 +#else
1.599 + template <int NumDims, int NDims> // else ICE
1.600 +#endif // BOOST_MSVC
1.601 + typename const_array_view<NDims>::type
1.602 + operator[](const detail::multi_array::
1.603 + index_gen<NumDims,NDims>& indices)
1.604 + const {
1.605 + return super_type::operator[](indices);
1.606 + }
1.607 +
1.608 + const_iterator begin() const {
1.609 + return super_type::begin();
1.610 + }
1.611 +
1.612 + const_iterator end() const {
1.613 + return super_type::end();
1.614 + }
1.615 +
1.616 + const_reverse_iterator rbegin() const {
1.617 + return super_type::rbegin();
1.618 + }
1.619 +
1.620 + const_reverse_iterator rend() const {
1.621 + return super_type::rend();
1.622 + }
1.623 +
1.624 +protected:
1.625 + // This is only supplied to support multi_array's default constructor
1.626 + explicit multi_array_ref(T* base,
1.627 + const storage_order_type& so,
1.628 + const index* index_bases,
1.629 + const size_type* extents) :
1.630 + super_type(base,so,index_bases,extents) { }
1.631 +
1.632 +};
1.633 +
1.634 +} // namespace boost
1.635 +
1.636 +#endif // BOOST_MULTI_ARRAY_REF_RG071801_HPP