diff --git a/doc/user.html b/doc/user.html index 5721128..57d73a3 100644 --- a/doc/user.html +++ b/doc/user.html @@ -661,6 +661,11 @@ arrays, as boost::array does for C one-dimensional arrays.
  • Beman Dawes helped immensely with porting the library to Microsoft Windows compilers. + +
  • Glen Fernandes + implemented support for the C++11 allocator model, including + support for stateful allocators, minimal allocators, and + optimized storage for stateless allocators.
    diff --git a/doc/xml/multi_array.xml b/doc/xml/multi_array.xml index db42882..01e2d8d 100644 --- a/doc/xml/multi_array.xml +++ b/doc/xml/multi_array.xml @@ -65,7 +65,7 @@ public: // constructors and destructors - multi_array(); + multi_array(const Allocator& alloc = Allocator()); template explicit multi_array(const ExtentList& sizes, @@ -75,13 +75,19 @@ public: const storage_order_type& store = c_storage_order(), const Allocator& alloc = Allocator()); multi_array(const multi_array& x); - multi_array(const const_multi_array_ref& x); - multi_array(const const_subarray::type& x); - multi_array(const const_array_view::type& x); + multi_array(const const_multi_array_ref& x, + const Allocator& alloc = Allocator()); + multi_array(const const_subarray::type& x, + const Allocator& alloc = Allocator()); + multi_array(const const_array_view::type& x, + const Allocator& alloc = Allocator()); - multi_array(const multi_array_ref& x); - multi_array(const subarray::type& x); - multi_array(const array_view::type& x); + multi_array(const multi_array_ref& x, + const Allocator& alloc = Allocator()); + multi_array(const subarray::type& x, + const Allocator& alloc = Allocator()); + multi_array(const array_view::type& x, + const Allocator& alloc = Allocator()); ~multi_array(); @@ -207,12 +213,18 @@ elements. & x); -multi_array(const const_subarray::type& x); -multi_array(const const_array_view::type& x); -multi_array(const multi_array_ref& x); -multi_array(const subarray::type& x); -multi_array(const array_view::type& x);]]> +multi_array(const const_multi_array_ref& x, + const Allocator& alloc = Allocator()); +multi_array(const const_subarray::type& x, + const Allocator& alloc = Allocator()); +multi_array(const const_array_view::type& x, + const Allocator& alloc = Allocator()); +multi_array(const multi_array_ref& x, + const Allocator& alloc = Allocator()); +multi_array(const subarray::type& x, + const Allocator& alloc = Allocator()); +multi_array(const array_view::type& x, + const Allocator& alloc = Allocator());]]> These constructors all constructs a multi_array and diff --git a/include/boost/multi_array.hpp b/include/boost/multi_array.hpp index a134abb..46979ac 100644 --- a/include/boost/multi_array.hpp +++ b/include/boost/multi_array.hpp @@ -1,5 +1,8 @@ // 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) @@ -30,6 +33,8 @@ #include "boost/multi_array/subarray.hpp" #include "boost/multi_array/multi_array_ref.hpp" #include "boost/multi_array/algorithm.hpp" +#include "boost/multi_array/allocators.hpp" +#include "boost/core/empty_value.hpp" #include "boost/array.hpp" #include "boost/mpl/if.hpp" #include "boost/type_traits.hpp" @@ -114,8 +119,10 @@ struct disable_multi_array_impl template class multi_array : - public multi_array_ref + public multi_array_ref, + private boost::empty_value { + typedef boost::empty_value alloc_base; typedef multi_array_ref super_type; public: typedef typename super_type::value_type value_type; @@ -142,22 +149,25 @@ public: typedef boost::detail::multi_array::multi_array_view type; }; - explicit multi_array() : + explicit multi_array(const Allocator& alloc = Allocator()) : super_type((T*)initial_base_,c_storage_order(), - /*index_bases=*/0, /*extents=*/0) { + /*index_bases=*/0, /*extents=*/0), + alloc_base(boost::empty_init_t(),alloc) { allocate_space(); } template explicit multi_array( - ExtentList const& extents + ExtentList const& extents, + const Allocator& alloc = Allocator() #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) { + super_type((T*)initial_base_,extents), + alloc_base(boost::empty_init_t(),alloc) { boost::function_requires< detail::multi_array::CollectionConcept >(); allocate_space(); @@ -167,7 +177,8 @@ public: template explicit multi_array(ExtentList const& extents, const general_storage_order& so) : - super_type((T*)initial_base_,extents,so) { + super_type((T*)initial_base_,extents,so), + alloc_base(boost::empty_init_t()) { boost::function_requires< detail::multi_array::CollectionConcept >(); allocate_space(); @@ -177,7 +188,8 @@ public: explicit multi_array(ExtentList const& extents, const general_storage_order& so, Allocator const& alloc) : - super_type((T*)initial_base_,extents,so), allocator_(alloc) { + super_type((T*)initial_base_,extents,so), + alloc_base(boost::empty_init_t(),alloc) { boost::function_requires< detail::multi_array::CollectionConcept >(); allocate_space(); @@ -185,8 +197,10 @@ public: explicit multi_array(const detail::multi_array - ::extent_gen& ranges) : - super_type((T*)initial_base_,ranges) { + ::extent_gen& ranges, + const Allocator& alloc = Allocator()) : + super_type((T*)initial_base_,ranges), + alloc_base(boost::empty_init_t(),alloc) { allocate_space(); } @@ -195,7 +209,8 @@ public: explicit multi_array(const detail::multi_array ::extent_gen& ranges, const general_storage_order& so) : - super_type((T*)initial_base_,ranges,so) { + super_type((T*)initial_base_,ranges,so), + alloc_base(boost::empty_init_t()) { allocate_space(); } @@ -205,13 +220,15 @@ public: ::extent_gen& ranges, const general_storage_order& so, Allocator const& alloc) : - super_type((T*)initial_base_,ranges,so), allocator_(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), allocator_(rhs.allocator_) { + super_type(rhs), + alloc_base(static_cast(rhs)) { allocate_space(); boost::detail::multi_array::copy_n(rhs.base_,rhs.num_elements(),base_); } @@ -228,8 +245,10 @@ public: #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()) + const general_storage_order& 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. @@ -239,8 +258,10 @@ public: 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()) + const general_storage_order& 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()); @@ -250,8 +271,10 @@ public: 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()) + const general_storage_order& 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()); @@ -261,8 +284,10 @@ public: // More limited support for MSVC - multi_array(const const_multi_array_ref& rhs) - : super_type(0,c_storage_order(),rhs.index_bases(),rhs.shape()) + multi_array(const const_multi_array_ref& 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. @@ -270,8 +295,10 @@ public: } multi_array(const const_multi_array_ref& rhs, - const general_storage_order& so) - : super_type(0,so,rhs.index_bases(),rhs.shape()) + const general_storage_order& 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. @@ -279,8 +306,10 @@ public: } multi_array(const detail::multi_array:: - const_sub_array& rhs) - : super_type(0,c_storage_order(),rhs.index_bases(),rhs.shape()) + const_sub_array& 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()); @@ -288,8 +317,10 @@ public: multi_array(const detail::multi_array:: const_sub_array& rhs, - const general_storage_order& so) - : super_type(0,so,rhs.index_bases(),rhs.shape()) + const general_storage_order& 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()); @@ -297,8 +328,10 @@ public: multi_array(const detail::multi_array:: - const_multi_array_view& rhs) - : super_type(0,c_storage_order(),rhs.index_bases(),rhs.shape()) + const_multi_array_view& 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()); @@ -306,8 +339,10 @@ public: 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()) + const general_storage_order& 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()); @@ -316,8 +351,10 @@ public: #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()) + multi_array(const multi_array_ref& 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. @@ -325,8 +362,10 @@ public: } multi_array(const multi_array_ref& rhs, - const general_storage_order& so) - : super_type(0,so,rhs.index_bases(),rhs.shape()) + const general_storage_order& 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. @@ -335,8 +374,10 @@ public: multi_array(const detail::multi_array:: - sub_array& rhs) - : super_type(0,c_storage_order(),rhs.index_bases(),rhs.shape()) + sub_array& 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()); @@ -344,8 +385,10 @@ public: multi_array(const detail::multi_array:: sub_array& rhs, - const general_storage_order& so) - : super_type(0,so,rhs.index_bases(),rhs.shape()) + const general_storage_order& 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()); @@ -353,8 +396,10 @@ public: multi_array(const detail::multi_array:: - multi_array_view& rhs) - : super_type(0,c_storage_order(),rhs.index_bases(),rhs.shape()) + multi_array_view& 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()); @@ -362,8 +407,10 @@ public: multi_array(const detail::multi_array:: multi_array_view& rhs, - const general_storage_order& so) - : super_type(0,so,rhs.index_bases(),rhs.shape()) + const general_storage_order& 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()); @@ -408,7 +455,7 @@ public: // build a multi_array with the specs given - multi_array new_array(ranges,this->storage_order()); + multi_array new_array(ranges,this->storage_order(),allocator()); // build a view of tmp with the minimum extents @@ -454,6 +501,7 @@ public: 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_); @@ -461,7 +509,6 @@ public: 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_); @@ -474,26 +521,43 @@ public: } 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() { - typename Allocator::const_pointer no_hint=0; - base_ = allocator_.allocate(this->num_elements(),no_hint); + base_ = allocator().allocate(this->num_elements()); this->set_base_ptr(base_); allocated_elements_ = this->num_elements(); - std::uninitialized_fill_n(base_,allocated_elements_,T()); + detail::multi_array::construct(allocator(),base_,base_+allocated_elements_); } void deallocate_space() { if(base_) { - for(T* i = base_; i != base_+allocated_elements_; ++i) - allocator_.destroy(i); - allocator_.deallocate(base_,allocated_elements_); + detail::multi_array::destroy(allocator(),base_,base_+allocated_elements_); + 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}; diff --git a/include/boost/multi_array/allocators.hpp b/include/boost/multi_array/allocators.hpp new file mode 100644 index 0000000..4691464 --- /dev/null +++ b/include/boost/multi_array/allocators.hpp @@ -0,0 +1,72 @@ +// Copyright 2018 Glen Joseph Fernandes +// (glenjofe@gmail.com) +// +// Distributed under 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) + +#ifndef BOOST_MULTI_ARRAY_ALLOCATORS_HPP +#define BOOST_MULTI_ARRAY_ALLOCATORS_HPP + +#include +#if !defined(BOOST_NO_CXX11_ALLOCATOR) +#include +#else +#include +#endif + +namespace boost { +namespace detail { +namespace multi_array { + +template +inline void destroy(A& allocator, T* ptr, T* end) +{ + for (; ptr != end; ++ptr) { +#if !defined(BOOST_NO_CXX11_ALLOCATOR) + std::allocator_traits::destroy(allocator,ptr); +#else + ptr->~T(); +#endif + } +} + +template +inline void construct(A& allocator, T* ptr) +{ +#if !defined(BOOST_NO_CXX11_ALLOCATOR) + std::allocator_traits::construct(allocator,ptr); +#else + ::new(static_cast(ptr)) T(); +#endif +} + +#if !defined(BOOST_NO_EXCEPTIONS) +template +inline void construct(A& allocator, T* ptr, T* end) +{ + T* start = ptr; + try { + for (; ptr != end; ++ptr) { + boost::detail::multi_array::construct(allocator,ptr); + } + } catch (...) { + boost::detail::multi_array::destroy(allocator,start,ptr); + throw; + } +} +#else +template +inline void construct(A& allocator, T* ptr, T* end) +{ + for (; ptr != end; ++ptr) { + boost::detail::multi_array::construct(allocator,ptr); + } +} +#endif + +} // multi_array +} // detail +} // boost + +#endif