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