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