// 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 // #if defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 406) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wshadow" #endif #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 #include #include #include #include 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 char is_multi_array_impl_help(const_multi_array_view&); template char is_multi_array_impl_help(const_sub_array&); template char is_multi_array_impl_help(const_multi_array_ref&); char ( &is_multi_array_impl_help(...) )[2]; template struct is_multi_array_impl { static T x; BOOST_STATIC_CONSTANT(bool, value = sizeof((is_multi_array_impl_help)(x)) == 1); typedef mpl::bool_ type; }; template struct disable_multi_array_impl_impl { typedef int type; }; template <> struct disable_multi_array_impl_impl { // forming a pointer to a reference triggers SFINAE typedef int& type; }; template struct disable_multi_array_impl : disable_multi_array_impl_impl::value> { }; template <> struct disable_multi_array_impl { typedef int type; }; #endif } //namespace multi_array } // namespace detail template class multi_array : public multi_array_ref { typedef multi_array_ref 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 struct const_array_view { typedef boost::detail::multi_array::const_multi_array_view type; }; template struct array_view { typedef boost::detail::multi_array::multi_array_view type; }; explicit multi_array() : super_type((T*)initial_base_,c_storage_order(), /*index_bases=*/0, /*extents=*/0) { allocate_space(); } template explicit multi_array( ExtentList const& extents #ifdef BOOST_NO_FUNCTION_TEMPLATE_ORDERING , typename mpl::if_< detail::multi_array::is_multi_array_impl, int&,int>::type* = 0 #endif ) : super_type((T*)initial_base_,extents) { boost::function_requires< detail::multi_array::CollectionConcept >(); allocate_space(); } template explicit multi_array(ExtentList const& extents, const general_storage_order& so) : super_type((T*)initial_base_,extents,so) { boost::function_requires< detail::multi_array::CollectionConcept >(); allocate_space(); } template explicit multi_array(ExtentList const& extents, const general_storage_order& so, Allocator const& alloc) : super_type((T*)initial_base_,extents,so), allocator_(alloc) { boost::function_requires< detail::multi_array::CollectionConcept >(); allocate_space(); } explicit multi_array(const detail::multi_array ::extent_gen& ranges) : super_type((T*)initial_base_,ranges) { allocate_space(); } explicit multi_array(const detail::multi_array ::extent_gen& ranges, const general_storage_order& so) : super_type((T*)initial_base_,ranges,so) { allocate_space(); } explicit multi_array(const detail::multi_array ::extent_gen& ranges, const general_storage_order& 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 multi_array(const const_multi_array_ref& rhs, const general_storage_order& 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 multi_array(const detail::multi_array:: const_sub_array& rhs, const general_storage_order& so = c_storage_order()) : super_type(0,so,rhs.index_bases(),rhs.shape()) { allocate_space(); std::copy(rhs.begin(),rhs.end(),this->begin()); } template multi_array(const detail::multi_array:: const_multi_array_view& rhs, const general_storage_order& 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& 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& rhs, const general_storage_order& 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& 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& rhs, const general_storage_order& 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& 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& rhs, const general_storage_order& 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& 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& rhs, const general_storage_order& 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& 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& rhs, const general_storage_order& 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& 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& rhs, const general_storage_order& 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 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 multi_array& resize(const ExtentList& extents) { boost::function_requires< detail::multi_array::CollectionConcept >(); typedef detail::multi_array::extent_gen 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& 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 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_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 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::type view_old = (*this)[old_idxes]; typename multi_array::BOOST_NESTED_TEMPLATE array_view::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_list; typedef boost::array index_list; Allocator allocator_; T* base_; size_type allocated_elements_; enum {initial_base_ = 0}; }; } // namespace boost #if defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 406) # pragma GCC diagnostic pop #endif #endif // BOOST_MULTI_ARRAY_RG071801_HPP