123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572 |
- // Copyright 2002 The Trustees of Indiana University.
- // Copyright 2018 Glen Joseph Fernandes
- // (glenjofe@gmail.com)
- // 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_HPP
- #define BOOST_MULTI_ARRAY_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/core/alloc_construct.hpp"
- #include "boost/core/empty_value.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>,
- private boost::empty_value<Allocator>
- {
- typedef boost::empty_value<Allocator> alloc_base;
- 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(const Allocator& alloc = Allocator()) :
- super_type((T*)initial_base_,c_storage_order(),
- /*index_bases=*/0, /*extents=*/0),
- alloc_base(boost::empty_init_t(),alloc) {
- allocate_space();
- }
- template <class ExtentList>
- explicit multi_array(
- ExtentList const& extents,
- const Allocator& alloc = Allocator()
- #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),
- alloc_base(boost::empty_init_t(),alloc) {
- 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),
- alloc_base(boost::empty_init_t()) {
- 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),
- alloc_base(boost::empty_init_t(),alloc) {
- boost::function_requires<
- detail::multi_array::CollectionConcept<ExtentList> >();
- allocate_space();
- }
- explicit multi_array(const detail::multi_array
- ::extent_gen<NumDims>& ranges,
- const Allocator& alloc = Allocator()) :
- super_type((T*)initial_base_,ranges),
- alloc_base(boost::empty_init_t(),alloc) {
- 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),
- alloc_base(boost::empty_init_t()) {
- 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),
- alloc_base(boost::empty_init_t(),alloc) {
- allocate_space();
- }
- multi_array(const multi_array& rhs) :
- super_type(rhs),
- alloc_base(static_cast<const alloc_base&>(rhs)) {
- 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(),
- const Allocator& alloc = Allocator())
- : super_type(0,so,rhs.index_bases(),rhs.shape()),
- alloc_base(boost::empty_init_t(),alloc)
- {
- 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(),
- const Allocator& alloc = Allocator())
- : super_type(0,so,rhs.index_bases(),rhs.shape()),
- alloc_base(boost::empty_init_t(),alloc)
- {
- 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(),
- const Allocator& alloc = Allocator())
- : super_type(0,so,rhs.index_bases(),rhs.shape()),
- alloc_base(boost::empty_init_t(),alloc)
- {
- 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,
- const Allocator& alloc = Allocator())
- : super_type(0,c_storage_order(),rhs.index_bases(),rhs.shape()),
- alloc_base(boost::empty_init_t(),alloc)
- {
- 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,
- const Allocator& alloc = Allocator())
- : super_type(0,so,rhs.index_bases(),rhs.shape()),
- alloc_base(boost::empty_init_t(),alloc)
- {
- 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,
- const Allocator& alloc = Allocator())
- : super_type(0,c_storage_order(),rhs.index_bases(),rhs.shape()),
- alloc_base(boost::empty_init_t(),alloc)
- {
- 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,
- const Allocator& alloc = Allocator())
- : super_type(0,so,rhs.index_bases(),rhs.shape()),
- alloc_base(boost::empty_init_t(),alloc)
- {
- allocate_space();
- std::copy(rhs.begin(),rhs.end(),this->begin());
- }
- multi_array(const detail::multi_array::
- const_multi_array_view<T,NumDims>& rhs,
- const Allocator& alloc = Allocator())
- : super_type(0,c_storage_order(),rhs.index_bases(),rhs.shape()),
- alloc_base(boost::empty_init_t(),alloc)
- {
- 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,
- const Allocator& alloc = Allocator())
- : super_type(0,so,rhs.index_bases(),rhs.shape()),
- alloc_base(boost::empty_init_t(),alloc)
- {
- 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,
- const Allocator& alloc = Allocator())
- : super_type(0,c_storage_order(),rhs.index_bases(),rhs.shape()),
- alloc_base(boost::empty_init_t(),alloc)
- {
- 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,
- const Allocator& alloc = Allocator())
- : super_type(0,so,rhs.index_bases(),rhs.shape()),
- alloc_base(boost::empty_init_t(),alloc)
- {
- 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,
- const Allocator& alloc = Allocator())
- : super_type(0,c_storage_order(),rhs.index_bases(),rhs.shape()),
- alloc_base(boost::empty_init_t(),alloc)
- {
- 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,
- const Allocator& alloc = Allocator())
- : super_type(0,so,rhs.index_bases(),rhs.shape()),
- alloc_base(boost::empty_init_t(),alloc)
- {
- allocate_space();
- std::copy(rhs.begin(),rhs.end(),this->begin());
- }
- multi_array(const detail::multi_array::
- multi_array_view<T,NumDims>& rhs,
- const Allocator& alloc = Allocator())
- : super_type(0,c_storage_order(),rhs.index_bases(),rhs.shape()),
- alloc_base(boost::empty_init_t(),alloc)
- {
- 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,
- const Allocator& alloc = Allocator())
- : super_type(0,so,rhs.index_bases(),rhs.shape()),
- alloc_base(boost::empty_init_t(),alloc)
- {
- 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(),allocator());
- // 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->allocator(),new_array.allocator());
- 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->base_,new_array.base_);
- swap(this->allocated_elements_,new_array.allocated_elements_);
- return *this;
- }
- ~multi_array() {
- deallocate_space();
- }
- private:
- friend inline bool operator==(const multi_array& a, const multi_array& b) {
- return a.base() == b.base();
- }
- friend inline bool operator!=(const multi_array& a, const multi_array& b) {
- return !(a == b);
- }
- const super_type& base() const {
- return *this;
- }
- const Allocator& allocator() const {
- return alloc_base::get();
- }
- Allocator& allocator() {
- return alloc_base::get();
- }
- void allocate_space() {
- base_ = allocator().allocate(this->num_elements());
- this->set_base_ptr(base_);
- allocated_elements_ = this->num_elements();
- boost::alloc_construct_n(allocator(),base_,allocated_elements_);
- }
- void deallocate_space() {
- if(base_) {
- boost::alloc_destroy_n(allocator(),base_,allocated_elements_);
- allocator().deallocate(base_,allocated_elements_);
- }
- }
- typedef boost::array<size_type,NumDims> size_list;
- typedef boost::array<index,NumDims> index_list;
- 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
|