| // 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 |