500 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
		
		
			
		
	
	
			500 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
|   | // 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 |