sl@0: // Copyright 2002 The Trustees of Indiana University. sl@0: sl@0: // Use, modification and distribution is subject to the Boost Software sl@0: // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at sl@0: // http://www.boost.org/LICENSE_1_0.txt) sl@0: sl@0: // Boost.MultiArray Library sl@0: // Authors: Ronald Garcia sl@0: // Jeremy Siek sl@0: // Andrew Lumsdaine sl@0: // See http://www.boost.org/libs/multi_array for documentation. sl@0: sl@0: #ifndef BASE_RG071801_HPP sl@0: #define BASE_RG071801_HPP sl@0: sl@0: // sl@0: // base.hpp - some implementation base classes for from which sl@0: // functionality is acquired sl@0: // sl@0: sl@0: #include "boost/multi_array/extent_range.hpp" sl@0: #include "boost/multi_array/extent_gen.hpp" sl@0: #include "boost/multi_array/index_range.hpp" sl@0: #include "boost/multi_array/index_gen.hpp" sl@0: #include "boost/multi_array/storage_order.hpp" sl@0: #include "boost/multi_array/types.hpp" sl@0: #include "boost/config.hpp" sl@0: #include "boost/multi_array/concept_checks.hpp" //for ignore_unused_... sl@0: #include "boost/mpl/eval_if.hpp" sl@0: #include "boost/mpl/if.hpp" sl@0: #include "boost/mpl/size_t.hpp" sl@0: #include "boost/mpl/aux_/msvc_eti_base.hpp" sl@0: #include "boost/iterator/reverse_iterator.hpp" sl@0: #include "boost/static_assert.hpp" sl@0: #include "boost/type.hpp" sl@0: #include "boost/assert.hpp" sl@0: #include sl@0: #include sl@0: sl@0: namespace boost { sl@0: sl@0: ///////////////////////////////////////////////////////////////////////// sl@0: // class declarations sl@0: ///////////////////////////////////////////////////////////////////////// sl@0: sl@0: template > sl@0: class multi_array; sl@0: sl@0: // This is a public interface for use by end users! sl@0: namespace multi_array_types { sl@0: typedef boost::detail::multi_array::size_type size_type; sl@0: typedef std::ptrdiff_t difference_type; sl@0: typedef boost::detail::multi_array::index index; sl@0: typedef detail::multi_array::index_range index_range; sl@0: typedef detail::multi_array::extent_range extent_range; sl@0: typedef detail::multi_array::index_gen<0,0> index_gen; sl@0: typedef detail::multi_array::extent_gen<0> extent_gen; sl@0: } sl@0: sl@0: sl@0: // boost::extents and boost::indices are now a part of the public sl@0: // interface. That way users don't necessarily have to create their sl@0: // own objects. On the other hand, one may not want the overhead of sl@0: // object creation in small-memory environments. Thus, the objects sl@0: // can be left undefined by defining BOOST_MULTI_ARRAY_NO_GENERATORS sl@0: // before loading multi_array.hpp. sl@0: #if !BOOST_MULTI_ARRAY_NO_GENERATORS sl@0: namespace { sl@0: multi_array_types::extent_gen extents; sl@0: multi_array_types::index_gen indices; sl@0: } sl@0: #endif // BOOST_MULTI_ARRAY_NO_GENERATORS sl@0: sl@0: namespace detail { sl@0: namespace multi_array { sl@0: sl@0: template sl@0: class sub_array; sl@0: sl@0: template sl@0: class const_sub_array; sl@0: sl@0: template sl@0: class array_iterator; sl@0: sl@0: template sl@0: class const_multi_array_view; sl@0: sl@0: template sl@0: class multi_array_view; sl@0: sl@0: ///////////////////////////////////////////////////////////////////////// sl@0: // class interfaces sl@0: ///////////////////////////////////////////////////////////////////////// sl@0: sl@0: class multi_array_base { sl@0: public: sl@0: typedef multi_array_types::size_type size_type; sl@0: typedef multi_array_types::difference_type difference_type; sl@0: typedef multi_array_types::index index; sl@0: typedef multi_array_types::index_range index_range; sl@0: typedef multi_array_types::extent_range extent_range; sl@0: typedef multi_array_types::index_gen index_gen; sl@0: typedef multi_array_types::extent_gen extent_gen; sl@0: }; sl@0: sl@0: // sl@0: // value_accessor_n sl@0: // contains the routines for accessing elements from sl@0: // N-dimensional views. sl@0: // sl@0: template sl@0: class value_accessor_n : public multi_array_base { sl@0: typedef multi_array_base super_type; sl@0: public: sl@0: typedef typename super_type::index index; sl@0: sl@0: // sl@0: // public typedefs used by classes that inherit from this base sl@0: // sl@0: typedef T element; sl@0: typedef boost::multi_array value_type; sl@0: typedef sub_array reference; sl@0: typedef const_sub_array const_reference; sl@0: sl@0: protected: sl@0: // used by array operator[] and iterators to get reference types. sl@0: template sl@0: Reference access(boost::type,index idx,TPtr base, sl@0: const size_type* extents, sl@0: const index* strides, sl@0: const index* index_bases) const { sl@0: sl@0: BOOST_ASSERT(idx - index_bases[0] >= 0); sl@0: BOOST_ASSERT(size_type(idx - index_bases[0]) < extents[0]); sl@0: // return a sub_array proxy object sl@0: TPtr newbase = base + idx * strides[0]; sl@0: return Reference(newbase,extents+1,strides+1,index_bases+1); sl@0: sl@0: } sl@0: sl@0: value_accessor_n() { } sl@0: ~value_accessor_n() { } sl@0: }; sl@0: sl@0: sl@0: sl@0: // sl@0: // value_accessor_one sl@0: // contains the routines for accessing reference elements from sl@0: // 1-dimensional views. sl@0: // sl@0: template sl@0: class value_accessor_one : public multi_array_base { sl@0: typedef multi_array_base super_type; sl@0: public: sl@0: typedef typename super_type::index index; sl@0: // sl@0: // public typedefs for use by classes that inherit it. sl@0: // sl@0: typedef T element; sl@0: typedef T value_type; sl@0: typedef T& reference; sl@0: typedef T const& const_reference; sl@0: sl@0: protected: sl@0: // used by array operator[] and iterators to get reference types. sl@0: template sl@0: Reference access(boost::type,index idx,TPtr base, sl@0: const size_type* extents, sl@0: const index* strides, sl@0: const index* index_bases) const { sl@0: sl@0: ignore_unused_variable_warning(index_bases); sl@0: ignore_unused_variable_warning(extents); sl@0: BOOST_ASSERT(idx - index_bases[0] >= 0); sl@0: BOOST_ASSERT(size_type(idx - index_bases[0]) < extents[0]); sl@0: return *(base + idx * strides[0]); sl@0: } sl@0: sl@0: value_accessor_one() { } sl@0: ~value_accessor_one() { } sl@0: }; sl@0: sl@0: sl@0: ///////////////////////////////////////////////////////////////////////// sl@0: // choose value accessor begins sl@0: // sl@0: sl@0: template sl@0: struct choose_value_accessor_n { sl@0: typedef value_accessor_n type; sl@0: }; sl@0: sl@0: template sl@0: struct choose_value_accessor_one { sl@0: typedef value_accessor_one type; sl@0: }; sl@0: sl@0: template sl@0: struct value_accessor_generator { sl@0: BOOST_STATIC_CONSTANT(std::size_t, dimensionality = NumDims::value); sl@0: sl@0: typedef typename sl@0: mpl::eval_if_c<(dimensionality == 1), sl@0: choose_value_accessor_one, sl@0: choose_value_accessor_n sl@0: >::type type; sl@0: }; sl@0: sl@0: #if BOOST_WORKAROUND(BOOST_MSVC, < 1300) sl@0: sl@0: struct eti_value_accessor sl@0: { sl@0: typedef int index; sl@0: typedef int size_type; sl@0: typedef int element; sl@0: typedef int index_range; sl@0: typedef int value_type; sl@0: typedef int reference; sl@0: typedef int const_reference; sl@0: }; sl@0: sl@0: template <> sl@0: struct value_accessor_generator sl@0: { sl@0: typedef eti_value_accessor type; sl@0: }; sl@0: sl@0: template sl@0: struct associated_types sl@0: : mpl::aux::msvc_eti_base< sl@0: typename value_accessor_generator::type sl@0: >::type sl@0: {}; sl@0: sl@0: template <> sl@0: struct associated_types : eti_value_accessor {}; sl@0: sl@0: #else sl@0: sl@0: template sl@0: struct associated_types sl@0: : value_accessor_generator::type sl@0: {}; sl@0: sl@0: #endif sl@0: sl@0: // sl@0: // choose value accessor ends sl@0: ///////////////////////////////////////////////////////////////////////// sl@0: sl@0: sl@0: sl@0: //////////////////////////////////////////////////////////////////////// sl@0: // multi_array_base sl@0: //////////////////////////////////////////////////////////////////////// sl@0: template sl@0: class multi_array_impl_base sl@0: : sl@0: #if BOOST_WORKAROUND(BOOST_MSVC, < 1300) sl@0: public mpl::aux::msvc_eti_base< sl@0: typename value_accessor_generator >::type sl@0: >::type sl@0: #else sl@0: public value_accessor_generator >::type sl@0: #endif sl@0: { sl@0: typedef associated_types > types; sl@0: public: sl@0: typedef typename types::index index; sl@0: typedef typename types::size_type size_type; sl@0: typedef typename types::element element; sl@0: typedef typename types::index_range index_range; sl@0: typedef typename types::value_type value_type; sl@0: typedef typename types::reference reference; sl@0: typedef typename types::const_reference const_reference; sl@0: sl@0: template sl@0: struct subarray { sl@0: typedef boost::detail::multi_array::sub_array type; sl@0: }; sl@0: sl@0: template sl@0: struct const_subarray { sl@0: typedef boost::detail::multi_array::const_sub_array type; sl@0: }; sl@0: sl@0: template sl@0: struct array_view { sl@0: typedef boost::detail::multi_array::multi_array_view type; sl@0: }; sl@0: sl@0: template sl@0: struct const_array_view { sl@0: public: sl@0: typedef boost::detail::multi_array::const_multi_array_view type; sl@0: }; sl@0: sl@0: // sl@0: // iterator support sl@0: // sl@0: typedef array_iterator,reference> iterator; sl@0: typedef array_iterator,const_reference> const_iterator; sl@0: sl@0: typedef ::boost::reverse_iterator reverse_iterator; sl@0: typedef ::boost::reverse_iterator const_reverse_iterator; sl@0: sl@0: BOOST_STATIC_CONSTANT(std::size_t, dimensionality = NumDims); sl@0: protected: sl@0: sl@0: multi_array_impl_base() { } sl@0: ~multi_array_impl_base() { } sl@0: sl@0: // Used by operator() in our array classes sl@0: template sl@0: Reference access_element(boost::type, sl@0: const IndexList& indices, sl@0: TPtr base, sl@0: const size_type* extents, sl@0: const index* strides, sl@0: const index* index_bases) const { sl@0: sl@0: ignore_unused_variable_warning(index_bases); sl@0: ignore_unused_variable_warning(extents); sl@0: #if !defined(NDEBUG) && !defined(BOOST_DISABLE_ASSERTS) sl@0: for (size_type i = 0; i != NumDims; ++i) { sl@0: BOOST_ASSERT(indices[i] - index_bases[i] >= 0); sl@0: BOOST_ASSERT(size_type(indices[i] - index_bases[i]) < extents[i]); sl@0: } sl@0: #endif sl@0: sl@0: index offset = 0; sl@0: for (size_type n = 0; n != NumDims; ++n) sl@0: offset += indices[n] * strides[n]; sl@0: sl@0: return base[offset]; sl@0: } sl@0: sl@0: template sl@0: void compute_strides(StrideList& stride_list, ExtentList& extent_list, sl@0: const general_storage_order& storage) sl@0: { sl@0: // invariant: stride = the stride for dimension n sl@0: index stride = 1; sl@0: for (size_type n = 0; n != NumDims; ++n) { sl@0: index stride_sign = +1; sl@0: sl@0: if (!storage.ascending(storage.ordering(n))) sl@0: stride_sign = -1; sl@0: sl@0: // The stride for this dimension is the product of the sl@0: // lengths of the ranks minor to it. sl@0: stride_list[storage.ordering(n)] = stride * stride_sign; sl@0: sl@0: stride *= extent_list[storage.ordering(n)]; sl@0: } sl@0: } sl@0: sl@0: // This calculates the offset to the array base pointer due to: sl@0: // 1. dimensions stored in descending order sl@0: // 2. non-zero dimension index bases sl@0: template sl@0: index sl@0: calculate_origin_offset(const StrideList& stride_list, sl@0: const ExtentList& extent_list, sl@0: const general_storage_order& storage, sl@0: const BaseList& index_base_list) sl@0: { sl@0: return sl@0: calculate_descending_dimension_offset(stride_list,extent_list, sl@0: storage) + sl@0: calculate_indexing_offset(stride_list,index_base_list); sl@0: } sl@0: sl@0: // This calculates the offset added to the base pointer that are sl@0: // caused by descending dimensions sl@0: template sl@0: index sl@0: calculate_descending_dimension_offset(const StrideList& stride_list, sl@0: const ExtentList& extent_list, sl@0: const general_storage_order& storage) sl@0: { sl@0: index offset = 0; sl@0: if (!storage.all_dims_ascending()) sl@0: for (size_type n = 0; n != NumDims; ++n) sl@0: if (!storage.ascending(n)) sl@0: offset -= (extent_list[n] - 1) * stride_list[n]; sl@0: sl@0: return offset; sl@0: } sl@0: sl@0: // This is used to reindex array_views, which are no longer sl@0: // concerned about storage order (specifically, whether dimensions sl@0: // are ascending or descending) since the viewed array handled it. sl@0: sl@0: template sl@0: index sl@0: calculate_indexing_offset(const StrideList& stride_list, sl@0: const BaseList& index_base_list) sl@0: { sl@0: index offset = 0; sl@0: for (size_type n = 0; n != NumDims; ++n) sl@0: offset -= stride_list[n] * index_base_list[n]; sl@0: return offset; sl@0: } sl@0: sl@0: // Slicing using an index_gen. sl@0: // Note that populating an index_gen creates a type that encodes sl@0: // both the number of dimensions in the current Array (NumDims), and sl@0: // the Number of dimensions for the resulting view. This allows the sl@0: // compiler to fail if the dimensions aren't completely accounted sl@0: // for. For reasons unbeknownst to me, a BOOST_STATIC_ASSERT sl@0: // within the member function template does not work. I should add a sl@0: // note to the documentation specifying that you get a damn ugly sl@0: // error message if you screw up in your slicing code. sl@0: template sl@0: ArrayRef sl@0: generate_array_view(boost::type, sl@0: const boost::detail::multi_array:: sl@0: index_gen& indices, sl@0: const size_type* extents, sl@0: const index* strides, sl@0: const index* index_bases, sl@0: TPtr base) const { sl@0: sl@0: boost::array new_strides; sl@0: boost::array new_extents; sl@0: sl@0: index offset = 0; sl@0: size_type dim = 0; sl@0: for (size_type n = 0; n != NumDims; ++n) { sl@0: const index default_start = index_bases[n]; sl@0: const index default_finish = default_start+extents[n]; sl@0: const index_range& current_range = indices.ranges_[n]; sl@0: index start = current_range.get_start(default_start); sl@0: index finish = current_range.get_finish(default_finish); sl@0: index index_factor = current_range.stride(); sl@0: index len = (finish - start + (index_factor - 1)) / index_factor; sl@0: sl@0: BOOST_ASSERT(index_bases[n] <= start && sl@0: start <= index_bases[n]+index(extents[n])); sl@0: BOOST_ASSERT(index_bases[n] <= finish && sl@0: finish <= index_bases[n]+index(extents[n])); sl@0: BOOST_ASSERT(index_factor > 0); sl@0: sl@0: // the array data pointer is modified to account for non-zero sl@0: // bases during slicing (see [Garcia] for the math involved) sl@0: offset += start * strides[n]; sl@0: sl@0: if (!current_range.is_degenerate()) { sl@0: sl@0: // The index_factor for each dimension is included into the sl@0: // strides for the array_view (see [Garcia] for the math involved). sl@0: new_strides[dim] = index_factor * strides[n]; sl@0: sl@0: // calculate new extents sl@0: new_extents[dim] = len; sl@0: ++dim; sl@0: } sl@0: } sl@0: BOOST_ASSERT(dim == NDims); sl@0: sl@0: return sl@0: ArrayRef(base+offset, sl@0: new_extents, sl@0: new_strides); sl@0: } sl@0: sl@0: sl@0: }; sl@0: sl@0: } // namespace multi_array sl@0: } // namespace detail sl@0: sl@0: } // namespace boost sl@0: sl@0: #endif // BASE_RG071801_HPP