500 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			500 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // Copyright 2002 The Trustees of Indiana University.
 | |
| 
 | |
| // Use, modification and distribution is subject to the Boost Software 
 | |
| // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
 | |
| // http://www.boost.org/LICENSE_1_0.txt)
 | |
| 
 | |
| //  Boost.MultiArray Library
 | |
| //  Authors: Ronald Garcia
 | |
| //           Jeremy Siek
 | |
| //           Andrew Lumsdaine
 | |
| //  See http://www.boost.org/libs/multi_array for documentation.
 | |
| 
 | |
| #ifndef BOOST_MULTI_ARRAY_RG071801_HPP
 | |
| #define BOOST_MULTI_ARRAY_RG071801_HPP
 | |
| 
 | |
| //
 | |
| // multi_array.hpp - contains the multi_array class template
 | |
| // declaration and definition
 | |
| //
 | |
| 
 | |
| #include "boost/multi_array/base.hpp"
 | |
| #include "boost/multi_array/collection_concept.hpp"
 | |
| #include "boost/multi_array/copy_array.hpp"
 | |
| #include "boost/multi_array/iterator.hpp"
 | |
| #include "boost/multi_array/subarray.hpp"
 | |
| #include "boost/multi_array/multi_array_ref.hpp"
 | |
| #include "boost/multi_array/algorithm.hpp"
 | |
| #include "boost/array.hpp"
 | |
| #include "boost/mpl/if.hpp"
 | |
| #include "boost/type_traits.hpp"
 | |
| #include <algorithm>
 | |
| #include <cstddef>
 | |
| #include <functional>
 | |
| #include <numeric>
 | |
| #include <vector>
 | |
| 
 | |
| 
 | |
| 
 | |
| namespace boost {
 | |
|   namespace detail {
 | |
|     namespace multi_array {
 | |
| 
 | |
|       struct populate_index_ranges {
 | |
|         multi_array_types::index_range
 | |
|         // RG: underscore on extent_ to stifle strange MSVC warning.
 | |
|         operator()(multi_array_types::index base,
 | |
|                    multi_array_types::size_type extent_) {
 | |
|           return multi_array_types::index_range(base,base+extent_);
 | |
|         }
 | |
|       };
 | |
| 
 | |
| #ifdef BOOST_NO_FUNCTION_TEMPLATE_ORDERING
 | |
| //
 | |
| // Compilers that don't support partial ordering may need help to
 | |
| // disambiguate multi_array's templated constructors.  Even vc6/7 are
 | |
| // capable of some limited SFINAE, so we take the most-general version
 | |
| // out of the overload set with disable_multi_array_impl.
 | |
| //
 | |
| template <typename T, std::size_t NumDims, typename TPtr>
 | |
| char is_multi_array_impl_help(const_multi_array_view<T,NumDims,TPtr>&);
 | |
| template <typename T, std::size_t NumDims, typename TPtr>
 | |
| char is_multi_array_impl_help(const_sub_array<T,NumDims,TPtr>&);
 | |
| template <typename T, std::size_t NumDims, typename TPtr>
 | |
| char is_multi_array_impl_help(const_multi_array_ref<T,NumDims,TPtr>&);
 | |
| 
 | |
| char ( &is_multi_array_impl_help(...) )[2];
 | |
| 
 | |
| template <class T>
 | |
| struct is_multi_array_impl
 | |
| {
 | |
|     static T x;
 | |
|     BOOST_STATIC_CONSTANT(bool, value = sizeof((is_multi_array_impl_help)(x)) == 1);
 | |
| 
 | |
|   typedef mpl::bool_<value> type;
 | |
| };
 | |
| 
 | |
| template <bool multi_array = false>
 | |
| struct disable_multi_array_impl_impl
 | |
| {
 | |
|     typedef int type;
 | |
| };
 | |
| 
 | |
| template <>
 | |
| struct disable_multi_array_impl_impl<true>
 | |
| {
 | |
|     // forming a pointer to a reference triggers SFINAE
 | |
|     typedef int& type; 
 | |
| };
 | |
| 
 | |
| 
 | |
| template <class T>
 | |
| struct disable_multi_array_impl :
 | |
|   disable_multi_array_impl_impl<is_multi_array_impl<T>::value>
 | |
| { };
 | |
| 
 | |
| 
 | |
| template <>
 | |
| struct disable_multi_array_impl<int>
 | |
| {
 | |
|   typedef int type;
 | |
| };
 | |
| 
 | |
| 
 | |
| #endif
 | |
| 
 | |
|     } //namespace multi_array
 | |
|   } // namespace detail
 | |
| 
 | |
| template<typename T, std::size_t NumDims,
 | |
|   typename Allocator>
 | |
| class multi_array :
 | |
|   public multi_array_ref<T,NumDims>
 | |
| {
 | |
|   typedef multi_array_ref<T,NumDims> super_type;
 | |
| public:
 | |
|   typedef typename super_type::value_type value_type;
 | |
|   typedef typename super_type::reference reference;
 | |
|   typedef typename super_type::const_reference const_reference;
 | |
|   typedef typename super_type::iterator iterator;
 | |
|   typedef typename super_type::const_iterator const_iterator;
 | |
|   typedef typename super_type::reverse_iterator reverse_iterator;
 | |
|   typedef typename super_type::const_reverse_iterator const_reverse_iterator;
 | |
|   typedef typename super_type::element element;
 | |
|   typedef typename super_type::size_type size_type;
 | |
|   typedef typename super_type::difference_type difference_type;
 | |
|   typedef typename super_type::index index;
 | |
|   typedef typename super_type::extent_range extent_range;
 | |
| 
 | |
| 
 | |
|   template <std::size_t NDims>
 | |
|   struct const_array_view {
 | |
|     typedef boost::detail::multi_array::const_multi_array_view<T,NDims> type;
 | |
|   };
 | |
| 
 | |
|   template <std::size_t NDims>
 | |
|   struct array_view {
 | |
|     typedef boost::detail::multi_array::multi_array_view<T,NDims> type;
 | |
|   };
 | |
| 
 | |
|   explicit multi_array() :
 | |
|     super_type((T*)initial_base_,c_storage_order(),
 | |
|                /*index_bases=*/0, /*extents=*/0) {
 | |
|     allocate_space(); 
 | |
|   }
 | |
| 
 | |
|   template <class ExtentList>
 | |
|   explicit multi_array(
 | |
|       ExtentList const& extents
 | |
| #ifdef BOOST_NO_FUNCTION_TEMPLATE_ORDERING
 | |
|       , typename mpl::if_<
 | |
|       detail::multi_array::is_multi_array_impl<ExtentList>,
 | |
|       int&,int>::type* = 0
 | |
| #endif
 | |
|       ) :
 | |
|     super_type((T*)initial_base_,extents) {
 | |
|     boost::function_requires<
 | |
|       detail::multi_array::CollectionConcept<ExtentList> >();
 | |
|     allocate_space();
 | |
|   }
 | |
| 
 | |
|     
 | |
|   template <class ExtentList>
 | |
|   explicit multi_array(ExtentList const& extents,
 | |
|                        const general_storage_order<NumDims>& so) :
 | |
|     super_type((T*)initial_base_,extents,so) {
 | |
|     boost::function_requires<
 | |
|       detail::multi_array::CollectionConcept<ExtentList> >();
 | |
|     allocate_space();
 | |
|   }
 | |
| 
 | |
|   template <class ExtentList>
 | |
|   explicit multi_array(ExtentList const& extents,
 | |
|                        const general_storage_order<NumDims>& so,
 | |
|                        Allocator const& alloc) :
 | |
|     super_type((T*)initial_base_,extents,so), allocator_(alloc) {
 | |
|     boost::function_requires<
 | |
|       detail::multi_array::CollectionConcept<ExtentList> >();
 | |
|     allocate_space();
 | |
|   }
 | |
| 
 | |
| 
 | |
|   explicit multi_array(const detail::multi_array
 | |
|                        ::extent_gen<NumDims>& ranges) :
 | |
|     super_type((T*)initial_base_,ranges) {
 | |
| 
 | |
|     allocate_space();
 | |
|   }
 | |
| 
 | |
| 
 | |
|   explicit multi_array(const detail::multi_array
 | |
|                        ::extent_gen<NumDims>& ranges,
 | |
|                        const general_storage_order<NumDims>& so) :
 | |
|     super_type((T*)initial_base_,ranges,so) {
 | |
| 
 | |
|     allocate_space();
 | |
|   }
 | |
| 
 | |
| 
 | |
|   explicit multi_array(const detail::multi_array
 | |
|                        ::extent_gen<NumDims>& ranges,
 | |
|                        const general_storage_order<NumDims>& so,
 | |
|                        Allocator const& alloc) :
 | |
|     super_type((T*)initial_base_,ranges,so), allocator_(alloc) {
 | |
| 
 | |
|     allocate_space();
 | |
|   }
 | |
| 
 | |
|   multi_array(const multi_array& rhs) :
 | |
|   super_type(rhs), allocator_(rhs.allocator_) {
 | |
|     allocate_space();
 | |
|     boost::detail::multi_array::copy_n(rhs.base_,rhs.num_elements(),base_);
 | |
|   }
 | |
| 
 | |
| 
 | |
|   //
 | |
|   // A multi_array is constructible from any multi_array_ref, subarray, or
 | |
|   // array_view object.  The following constructors ensure that.
 | |
|   //
 | |
| 
 | |
|   // Due to limited support for partial template ordering, 
 | |
|   // MSVC 6&7 confuse the following with the most basic ExtentList 
 | |
|   // constructor.
 | |
| #ifndef BOOST_NO_FUNCTION_TEMPLATE_ORDERING
 | |
|   template <typename OPtr>
 | |
|   multi_array(const const_multi_array_ref<T,NumDims,OPtr>& rhs,
 | |
|               const general_storage_order<NumDims>& so = c_storage_order())
 | |
|     : super_type(0,so,rhs.index_bases(),rhs.shape()) 
 | |
|   {
 | |
|     allocate_space();
 | |
|     // Warning! storage order may change, hence the following copy technique.
 | |
|     std::copy(rhs.begin(),rhs.end(),this->begin());
 | |
|   }
 | |
| 
 | |
|   template <typename OPtr>
 | |
|   multi_array(const detail::multi_array::
 | |
|               const_sub_array<T,NumDims,OPtr>& rhs,
 | |
|               const general_storage_order<NumDims>& so = c_storage_order())
 | |
|     : super_type(0,so,rhs.index_bases(),rhs.shape()) 
 | |
|   {
 | |
|     allocate_space();
 | |
|     std::copy(rhs.begin(),rhs.end(),this->begin());
 | |
|   }
 | |
| 
 | |
| 
 | |
|   template <typename OPtr>
 | |
|   multi_array(const detail::multi_array::
 | |
|               const_multi_array_view<T,NumDims,OPtr>& rhs,
 | |
|               const general_storage_order<NumDims>& so = c_storage_order())
 | |
|     : super_type(0,so,rhs.index_bases(),rhs.shape()) 
 | |
|   {
 | |
|     allocate_space();
 | |
|     std::copy(rhs.begin(),rhs.end(),this->begin());
 | |
|   }
 | |
| 
 | |
| #else // BOOST_NO_FUNCTION_TEMPLATE_ORDERING
 | |
|   // More limited support for MSVC
 | |
| 
 | |
| 
 | |
|   multi_array(const const_multi_array_ref<T,NumDims>& rhs)
 | |
|     : super_type(0,c_storage_order(),rhs.index_bases(),rhs.shape()) 
 | |
|   {
 | |
|     allocate_space();
 | |
|     // Warning! storage order may change, hence the following copy technique.
 | |
|     std::copy(rhs.begin(),rhs.end(),this->begin());
 | |
|   }
 | |
| 
 | |
|   multi_array(const const_multi_array_ref<T,NumDims>& rhs,
 | |
|               const general_storage_order<NumDims>& so)
 | |
|     : super_type(0,so,rhs.index_bases(),rhs.shape()) 
 | |
|   {
 | |
|     allocate_space();
 | |
|     // Warning! storage order may change, hence the following copy technique.
 | |
|     std::copy(rhs.begin(),rhs.end(),this->begin());
 | |
|   }
 | |
| 
 | |
|   multi_array(const detail::multi_array::
 | |
|               const_sub_array<T,NumDims>& rhs)
 | |
|     : super_type(0,c_storage_order(),rhs.index_bases(),rhs.shape()) 
 | |
|   {
 | |
|     allocate_space();
 | |
|     std::copy(rhs.begin(),rhs.end(),this->begin());
 | |
|   }
 | |
| 
 | |
|   multi_array(const detail::multi_array::
 | |
|               const_sub_array<T,NumDims>& rhs,
 | |
|               const general_storage_order<NumDims>& so)
 | |
|     : super_type(0,so,rhs.index_bases(),rhs.shape()) 
 | |
|   {
 | |
|     allocate_space();
 | |
|     std::copy(rhs.begin(),rhs.end(),this->begin());
 | |
|   }
 | |
| 
 | |
| 
 | |
|   multi_array(const detail::multi_array::
 | |
|               const_multi_array_view<T,NumDims>& rhs)
 | |
|     : super_type(0,c_storage_order(),rhs.index_bases(),rhs.shape()) 
 | |
|   {
 | |
|     allocate_space();
 | |
|     std::copy(rhs.begin(),rhs.end(),this->begin());
 | |
|   }
 | |
| 
 | |
|   multi_array(const detail::multi_array::
 | |
|               const_multi_array_view<T,NumDims>& rhs,
 | |
|               const general_storage_order<NumDims>& so)
 | |
|     : super_type(0,so,rhs.index_bases(),rhs.shape()) 
 | |
|   {
 | |
|     allocate_space();
 | |
|     std::copy(rhs.begin(),rhs.end(),this->begin());
 | |
|   }
 | |
| 
 | |
| #endif // !BOOST_NO_FUNCTION_TEMPLATE_ORDERING
 | |
| 
 | |
|   // Thes constructors are necessary because of more exact template matches.
 | |
|   multi_array(const multi_array_ref<T,NumDims>& rhs)
 | |
|     : super_type(0,c_storage_order(),rhs.index_bases(),rhs.shape()) 
 | |
|   {
 | |
|     allocate_space();
 | |
|     // Warning! storage order may change, hence the following copy technique.
 | |
|     std::copy(rhs.begin(),rhs.end(),this->begin());
 | |
|   }
 | |
| 
 | |
|   multi_array(const multi_array_ref<T,NumDims>& rhs,
 | |
|               const general_storage_order<NumDims>& so)
 | |
|     : super_type(0,so,rhs.index_bases(),rhs.shape()) 
 | |
|   {
 | |
|     allocate_space();
 | |
|     // Warning! storage order may change, hence the following copy technique.
 | |
|     std::copy(rhs.begin(),rhs.end(),this->begin());
 | |
|   }
 | |
| 
 | |
| 
 | |
|   multi_array(const detail::multi_array::
 | |
|               sub_array<T,NumDims>& rhs)
 | |
|     : super_type(0,c_storage_order(),rhs.index_bases(),rhs.shape()) 
 | |
|   {
 | |
|     allocate_space();
 | |
|     std::copy(rhs.begin(),rhs.end(),this->begin());
 | |
|   }
 | |
| 
 | |
|   multi_array(const detail::multi_array::
 | |
|               sub_array<T,NumDims>& rhs,
 | |
|               const general_storage_order<NumDims>& so)
 | |
|     : super_type(0,so,rhs.index_bases(),rhs.shape()) 
 | |
|   {
 | |
|     allocate_space();
 | |
|     std::copy(rhs.begin(),rhs.end(),this->begin());
 | |
|   }
 | |
| 
 | |
| 
 | |
|   multi_array(const detail::multi_array::
 | |
|               multi_array_view<T,NumDims>& rhs)
 | |
|     : super_type(0,c_storage_order(),rhs.index_bases(),rhs.shape()) 
 | |
|   {
 | |
|     allocate_space();
 | |
|     std::copy(rhs.begin(),rhs.end(),this->begin());
 | |
|   }
 | |
|     
 | |
|   multi_array(const detail::multi_array::
 | |
|               multi_array_view<T,NumDims>& rhs,
 | |
|               const general_storage_order<NumDims>& so)
 | |
|     : super_type(0,so,rhs.index_bases(),rhs.shape()) 
 | |
|   {
 | |
|     allocate_space();
 | |
|     std::copy(rhs.begin(),rhs.end(),this->begin());
 | |
|   }
 | |
|     
 | |
|   // Since assignment is a deep copy, multi_array_ref
 | |
|   // contains all the necessary code.
 | |
|   template <typename ConstMultiArray>
 | |
|   multi_array& operator=(const ConstMultiArray& other) {
 | |
|     super_type::operator=(other);
 | |
|     return *this;
 | |
|   }
 | |
| 
 | |
|   multi_array& operator=(const multi_array& other) {
 | |
|     if (&other != this) {
 | |
|       super_type::operator=(other);
 | |
|     }
 | |
|     return *this;
 | |
|   }
 | |
| 
 | |
| 
 | |
|   template <typename ExtentList>
 | |
|   multi_array& resize(const ExtentList& extents) {
 | |
|     boost::function_requires<
 | |
|       detail::multi_array::CollectionConcept<ExtentList> >();
 | |
| 
 | |
|     typedef detail::multi_array::extent_gen<NumDims> gen_type;
 | |
|     gen_type ranges;
 | |
| 
 | |
|     for (int i=0; i != NumDims; ++i) {
 | |
|       typedef typename gen_type::range range_type;
 | |
|       ranges.ranges_[i] = range_type(0,extents[i]);
 | |
|     }
 | |
|     
 | |
|     return this->resize(ranges);
 | |
|   }
 | |
| 
 | |
| 
 | |
| 
 | |
|   multi_array& resize(const detail::multi_array
 | |
|                       ::extent_gen<NumDims>& ranges) {
 | |
| 
 | |
| 
 | |
|     // build a multi_array with the specs given
 | |
|     multi_array new_array(ranges,this->storage_order());
 | |
| 
 | |
| 
 | |
|     // build a view of tmp with the minimum extents
 | |
| 
 | |
|     // Get the minimum extents of the arrays.
 | |
|     boost::array<size_type,NumDims> min_extents;
 | |
| 
 | |
|     const size_type& (*min)(const size_type&, const size_type&) =
 | |
|       std::min;
 | |
|     std::transform(new_array.extent_list_.begin(),new_array.extent_list_.end(),
 | |
|                    this->extent_list_.begin(),
 | |
|                    min_extents.begin(),
 | |
|                    min);
 | |
| 
 | |
| 
 | |
|     // typedef boost::array<index,NumDims> index_list;
 | |
|     // Build index_gen objects to create views with the same shape
 | |
| 
 | |
|     // these need to be separate to handle non-zero index bases
 | |
|     typedef detail::multi_array::index_gen<NumDims,NumDims> index_gen;
 | |
|     index_gen old_idxes;
 | |
|     index_gen new_idxes;
 | |
| 
 | |
|     std::transform(new_array.index_base_list_.begin(),
 | |
|                    new_array.index_base_list_.end(),
 | |
|                    min_extents.begin(),new_idxes.ranges_.begin(),
 | |
|                    detail::multi_array::populate_index_ranges());
 | |
| 
 | |
|     std::transform(this->index_base_list_.begin(),
 | |
|                    this->index_base_list_.end(),
 | |
|                    min_extents.begin(),old_idxes.ranges_.begin(),
 | |
|                    detail::multi_array::populate_index_ranges());
 | |
| 
 | |
|     // Build same-shape views of the two arrays
 | |
|     typename
 | |
|       multi_array::BOOST_NESTED_TEMPLATE array_view<NumDims>::type view_old = (*this)[old_idxes];
 | |
|     typename
 | |
|       multi_array::BOOST_NESTED_TEMPLATE array_view<NumDims>::type view_new = new_array[new_idxes];
 | |
| 
 | |
|     // Set the right portion of the new array
 | |
|     view_new = view_old;
 | |
| 
 | |
|     using std::swap;
 | |
|     // Swap the internals of these arrays.
 | |
|     swap(this->super_type::base_,new_array.super_type::base_);
 | |
|     swap(this->storage_,new_array.storage_);
 | |
|     swap(this->extent_list_,new_array.extent_list_);
 | |
|     swap(this->stride_list_,new_array.stride_list_);
 | |
|     swap(this->index_base_list_,new_array.index_base_list_);
 | |
|     swap(this->origin_offset_,new_array.origin_offset_);
 | |
|     swap(this->directional_offset_,new_array.directional_offset_);
 | |
|     swap(this->num_elements_,new_array.num_elements_);
 | |
|     swap(this->allocator_,new_array.allocator_);
 | |
|     swap(this->base_,new_array.base_);
 | |
|     swap(this->allocated_elements_,new_array.allocated_elements_);
 | |
| 
 | |
|     return *this;
 | |
|   }
 | |
| 
 | |
| 
 | |
|   ~multi_array() {
 | |
|     deallocate_space();
 | |
|   }
 | |
| 
 | |
| private:
 | |
|   void allocate_space() {
 | |
|     typename Allocator::const_pointer no_hint=0;
 | |
|     base_ = allocator_.allocate(this->num_elements(),no_hint);
 | |
|     this->set_base_ptr(base_);
 | |
|     allocated_elements_ = this->num_elements();
 | |
|     std::uninitialized_fill_n(base_,allocated_elements_,T());
 | |
|   }
 | |
| 
 | |
|   void deallocate_space() {
 | |
|     if(base_) {
 | |
|       for(T* i = base_; i != base_+allocated_elements_; ++i)
 | |
|         allocator_.destroy(i);
 | |
|       allocator_.deallocate(base_,allocated_elements_);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   typedef boost::array<size_type,NumDims> size_list;
 | |
|   typedef boost::array<index,NumDims> index_list;
 | |
| 
 | |
|   Allocator allocator_;
 | |
|   T* base_;
 | |
|   size_type allocated_elements_;
 | |
|   enum {initial_base_ = 0};
 | |
| };
 | |
| 
 | |
| } // namespace boost
 | |
| 
 | |
| #endif // BOOST_MULTI_ARRAY_RG071801_HPP
 | 
