multi_array.hpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  1. // Copyright 2002 The Trustees of Indiana University.
  2. // Use, modification and distribution is subject to the Boost Software
  3. // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  4. // http://www.boost.org/LICENSE_1_0.txt)
  5. // Boost.MultiArray Library
  6. // Authors: Ronald Garcia
  7. // Jeremy Siek
  8. // Andrew Lumsdaine
  9. // See http://www.boost.org/libs/multi_array for documentation.
  10. #ifndef BOOST_MULTI_ARRAY_RG071801_HPP
  11. #define BOOST_MULTI_ARRAY_RG071801_HPP
  12. //
  13. // multi_array.hpp - contains the multi_array class template
  14. // declaration and definition
  15. //
  16. #if defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 406)
  17. # pragma GCC diagnostic push
  18. # pragma GCC diagnostic ignored "-Wshadow"
  19. #endif
  20. #include "boost/multi_array/base.hpp"
  21. #include "boost/multi_array/collection_concept.hpp"
  22. #include "boost/multi_array/copy_array.hpp"
  23. #include "boost/multi_array/iterator.hpp"
  24. #include "boost/multi_array/subarray.hpp"
  25. #include "boost/multi_array/multi_array_ref.hpp"
  26. #include "boost/multi_array/algorithm.hpp"
  27. #include "boost/array.hpp"
  28. #include "boost/mpl/if.hpp"
  29. #include "boost/type_traits.hpp"
  30. #include <algorithm>
  31. #include <cstddef>
  32. #include <functional>
  33. #include <numeric>
  34. #include <vector>
  35. namespace boost {
  36. namespace detail {
  37. namespace multi_array {
  38. struct populate_index_ranges {
  39. multi_array_types::index_range
  40. // RG: underscore on extent_ to stifle strange MSVC warning.
  41. operator()(multi_array_types::index base,
  42. multi_array_types::size_type extent_) {
  43. return multi_array_types::index_range(base,base+extent_);
  44. }
  45. };
  46. #ifdef BOOST_NO_FUNCTION_TEMPLATE_ORDERING
  47. //
  48. // Compilers that don't support partial ordering may need help to
  49. // disambiguate multi_array's templated constructors. Even vc6/7 are
  50. // capable of some limited SFINAE, so we take the most-general version
  51. // out of the overload set with disable_multi_array_impl.
  52. //
  53. template <typename T, std::size_t NumDims, typename TPtr>
  54. char is_multi_array_impl_help(const_multi_array_view<T,NumDims,TPtr>&);
  55. template <typename T, std::size_t NumDims, typename TPtr>
  56. char is_multi_array_impl_help(const_sub_array<T,NumDims,TPtr>&);
  57. template <typename T, std::size_t NumDims, typename TPtr>
  58. char is_multi_array_impl_help(const_multi_array_ref<T,NumDims,TPtr>&);
  59. char ( &is_multi_array_impl_help(...) )[2];
  60. template <class T>
  61. struct is_multi_array_impl
  62. {
  63. static T x;
  64. BOOST_STATIC_CONSTANT(bool, value = sizeof((is_multi_array_impl_help)(x)) == 1);
  65. typedef mpl::bool_<value> type;
  66. };
  67. template <bool multi_array = false>
  68. struct disable_multi_array_impl_impl
  69. {
  70. typedef int type;
  71. };
  72. template <>
  73. struct disable_multi_array_impl_impl<true>
  74. {
  75. // forming a pointer to a reference triggers SFINAE
  76. typedef int& type;
  77. };
  78. template <class T>
  79. struct disable_multi_array_impl :
  80. disable_multi_array_impl_impl<is_multi_array_impl<T>::value>
  81. { };
  82. template <>
  83. struct disable_multi_array_impl<int>
  84. {
  85. typedef int type;
  86. };
  87. #endif
  88. } //namespace multi_array
  89. } // namespace detail
  90. template<typename T, std::size_t NumDims,
  91. typename Allocator>
  92. class multi_array :
  93. public multi_array_ref<T,NumDims>
  94. {
  95. typedef multi_array_ref<T,NumDims> super_type;
  96. public:
  97. typedef typename super_type::value_type value_type;
  98. typedef typename super_type::reference reference;
  99. typedef typename super_type::const_reference const_reference;
  100. typedef typename super_type::iterator iterator;
  101. typedef typename super_type::const_iterator const_iterator;
  102. typedef typename super_type::reverse_iterator reverse_iterator;
  103. typedef typename super_type::const_reverse_iterator const_reverse_iterator;
  104. typedef typename super_type::element element;
  105. typedef typename super_type::size_type size_type;
  106. typedef typename super_type::difference_type difference_type;
  107. typedef typename super_type::index index;
  108. typedef typename super_type::extent_range extent_range;
  109. template <std::size_t NDims>
  110. struct const_array_view {
  111. typedef boost::detail::multi_array::const_multi_array_view<T,NDims> type;
  112. };
  113. template <std::size_t NDims>
  114. struct array_view {
  115. typedef boost::detail::multi_array::multi_array_view<T,NDims> type;
  116. };
  117. explicit multi_array() :
  118. super_type((T*)initial_base_,c_storage_order(),
  119. /*index_bases=*/0, /*extents=*/0) {
  120. allocate_space();
  121. }
  122. template <class ExtentList>
  123. explicit multi_array(
  124. ExtentList const& extents
  125. #ifdef BOOST_NO_FUNCTION_TEMPLATE_ORDERING
  126. , typename mpl::if_<
  127. detail::multi_array::is_multi_array_impl<ExtentList>,
  128. int&,int>::type* = 0
  129. #endif
  130. ) :
  131. super_type((T*)initial_base_,extents) {
  132. boost::function_requires<
  133. detail::multi_array::CollectionConcept<ExtentList> >();
  134. allocate_space();
  135. }
  136. template <class ExtentList>
  137. explicit multi_array(ExtentList const& extents,
  138. const general_storage_order<NumDims>& so) :
  139. super_type((T*)initial_base_,extents,so) {
  140. boost::function_requires<
  141. detail::multi_array::CollectionConcept<ExtentList> >();
  142. allocate_space();
  143. }
  144. template <class ExtentList>
  145. explicit multi_array(ExtentList const& extents,
  146. const general_storage_order<NumDims>& so,
  147. Allocator const& alloc) :
  148. super_type((T*)initial_base_,extents,so), allocator_(alloc) {
  149. boost::function_requires<
  150. detail::multi_array::CollectionConcept<ExtentList> >();
  151. allocate_space();
  152. }
  153. explicit multi_array(const detail::multi_array
  154. ::extent_gen<NumDims>& ranges) :
  155. super_type((T*)initial_base_,ranges) {
  156. allocate_space();
  157. }
  158. explicit multi_array(const detail::multi_array
  159. ::extent_gen<NumDims>& ranges,
  160. const general_storage_order<NumDims>& so) :
  161. super_type((T*)initial_base_,ranges,so) {
  162. allocate_space();
  163. }
  164. explicit multi_array(const detail::multi_array
  165. ::extent_gen<NumDims>& ranges,
  166. const general_storage_order<NumDims>& so,
  167. Allocator const& alloc) :
  168. super_type((T*)initial_base_,ranges,so), allocator_(alloc) {
  169. allocate_space();
  170. }
  171. multi_array(const multi_array& rhs) :
  172. super_type(rhs), allocator_(rhs.allocator_) {
  173. allocate_space();
  174. boost::detail::multi_array::copy_n(rhs.base_,rhs.num_elements(),base_);
  175. }
  176. //
  177. // A multi_array is constructible from any multi_array_ref, subarray, or
  178. // array_view object. The following constructors ensure that.
  179. //
  180. // Due to limited support for partial template ordering,
  181. // MSVC 6&7 confuse the following with the most basic ExtentList
  182. // constructor.
  183. #ifndef BOOST_NO_FUNCTION_TEMPLATE_ORDERING
  184. template <typename OPtr>
  185. multi_array(const const_multi_array_ref<T,NumDims,OPtr>& rhs,
  186. const general_storage_order<NumDims>& so = c_storage_order())
  187. : super_type(0,so,rhs.index_bases(),rhs.shape())
  188. {
  189. allocate_space();
  190. // Warning! storage order may change, hence the following copy technique.
  191. std::copy(rhs.begin(),rhs.end(),this->begin());
  192. }
  193. template <typename OPtr>
  194. multi_array(const detail::multi_array::
  195. const_sub_array<T,NumDims,OPtr>& rhs,
  196. const general_storage_order<NumDims>& so = c_storage_order())
  197. : super_type(0,so,rhs.index_bases(),rhs.shape())
  198. {
  199. allocate_space();
  200. std::copy(rhs.begin(),rhs.end(),this->begin());
  201. }
  202. template <typename OPtr>
  203. multi_array(const detail::multi_array::
  204. const_multi_array_view<T,NumDims,OPtr>& rhs,
  205. const general_storage_order<NumDims>& so = c_storage_order())
  206. : super_type(0,so,rhs.index_bases(),rhs.shape())
  207. {
  208. allocate_space();
  209. std::copy(rhs.begin(),rhs.end(),this->begin());
  210. }
  211. #else // BOOST_NO_FUNCTION_TEMPLATE_ORDERING
  212. // More limited support for MSVC
  213. multi_array(const const_multi_array_ref<T,NumDims>& rhs)
  214. : super_type(0,c_storage_order(),rhs.index_bases(),rhs.shape())
  215. {
  216. allocate_space();
  217. // Warning! storage order may change, hence the following copy technique.
  218. std::copy(rhs.begin(),rhs.end(),this->begin());
  219. }
  220. multi_array(const const_multi_array_ref<T,NumDims>& rhs,
  221. const general_storage_order<NumDims>& so)
  222. : super_type(0,so,rhs.index_bases(),rhs.shape())
  223. {
  224. allocate_space();
  225. // Warning! storage order may change, hence the following copy technique.
  226. std::copy(rhs.begin(),rhs.end(),this->begin());
  227. }
  228. multi_array(const detail::multi_array::
  229. const_sub_array<T,NumDims>& rhs)
  230. : super_type(0,c_storage_order(),rhs.index_bases(),rhs.shape())
  231. {
  232. allocate_space();
  233. std::copy(rhs.begin(),rhs.end(),this->begin());
  234. }
  235. multi_array(const detail::multi_array::
  236. const_sub_array<T,NumDims>& rhs,
  237. const general_storage_order<NumDims>& so)
  238. : super_type(0,so,rhs.index_bases(),rhs.shape())
  239. {
  240. allocate_space();
  241. std::copy(rhs.begin(),rhs.end(),this->begin());
  242. }
  243. multi_array(const detail::multi_array::
  244. const_multi_array_view<T,NumDims>& rhs)
  245. : super_type(0,c_storage_order(),rhs.index_bases(),rhs.shape())
  246. {
  247. allocate_space();
  248. std::copy(rhs.begin(),rhs.end(),this->begin());
  249. }
  250. multi_array(const detail::multi_array::
  251. const_multi_array_view<T,NumDims>& rhs,
  252. const general_storage_order<NumDims>& so)
  253. : super_type(0,so,rhs.index_bases(),rhs.shape())
  254. {
  255. allocate_space();
  256. std::copy(rhs.begin(),rhs.end(),this->begin());
  257. }
  258. #endif // !BOOST_NO_FUNCTION_TEMPLATE_ORDERING
  259. // Thes constructors are necessary because of more exact template matches.
  260. multi_array(const multi_array_ref<T,NumDims>& rhs)
  261. : super_type(0,c_storage_order(),rhs.index_bases(),rhs.shape())
  262. {
  263. allocate_space();
  264. // Warning! storage order may change, hence the following copy technique.
  265. std::copy(rhs.begin(),rhs.end(),this->begin());
  266. }
  267. multi_array(const multi_array_ref<T,NumDims>& rhs,
  268. const general_storage_order<NumDims>& so)
  269. : super_type(0,so,rhs.index_bases(),rhs.shape())
  270. {
  271. allocate_space();
  272. // Warning! storage order may change, hence the following copy technique.
  273. std::copy(rhs.begin(),rhs.end(),this->begin());
  274. }
  275. multi_array(const detail::multi_array::
  276. sub_array<T,NumDims>& rhs)
  277. : super_type(0,c_storage_order(),rhs.index_bases(),rhs.shape())
  278. {
  279. allocate_space();
  280. std::copy(rhs.begin(),rhs.end(),this->begin());
  281. }
  282. multi_array(const detail::multi_array::
  283. sub_array<T,NumDims>& rhs,
  284. const general_storage_order<NumDims>& so)
  285. : super_type(0,so,rhs.index_bases(),rhs.shape())
  286. {
  287. allocate_space();
  288. std::copy(rhs.begin(),rhs.end(),this->begin());
  289. }
  290. multi_array(const detail::multi_array::
  291. multi_array_view<T,NumDims>& rhs)
  292. : super_type(0,c_storage_order(),rhs.index_bases(),rhs.shape())
  293. {
  294. allocate_space();
  295. std::copy(rhs.begin(),rhs.end(),this->begin());
  296. }
  297. multi_array(const detail::multi_array::
  298. multi_array_view<T,NumDims>& rhs,
  299. const general_storage_order<NumDims>& so)
  300. : super_type(0,so,rhs.index_bases(),rhs.shape())
  301. {
  302. allocate_space();
  303. std::copy(rhs.begin(),rhs.end(),this->begin());
  304. }
  305. // Since assignment is a deep copy, multi_array_ref
  306. // contains all the necessary code.
  307. template <typename ConstMultiArray>
  308. multi_array& operator=(const ConstMultiArray& other) {
  309. super_type::operator=(other);
  310. return *this;
  311. }
  312. multi_array& operator=(const multi_array& other) {
  313. if (&other != this) {
  314. super_type::operator=(other);
  315. }
  316. return *this;
  317. }
  318. template <typename ExtentList>
  319. multi_array& resize(const ExtentList& extents) {
  320. boost::function_requires<
  321. detail::multi_array::CollectionConcept<ExtentList> >();
  322. typedef detail::multi_array::extent_gen<NumDims> gen_type;
  323. gen_type ranges;
  324. for (int i=0; i != NumDims; ++i) {
  325. typedef typename gen_type::range range_type;
  326. ranges.ranges_[i] = range_type(0,extents[i]);
  327. }
  328. return this->resize(ranges);
  329. }
  330. multi_array& resize(const detail::multi_array
  331. ::extent_gen<NumDims>& ranges) {
  332. // build a multi_array with the specs given
  333. multi_array new_array(ranges,this->storage_order());
  334. // build a view of tmp with the minimum extents
  335. // Get the minimum extents of the arrays.
  336. boost::array<size_type,NumDims> min_extents;
  337. const size_type& (*min)(const size_type&, const size_type&) =
  338. std::min;
  339. std::transform(new_array.extent_list_.begin(),new_array.extent_list_.end(),
  340. this->extent_list_.begin(),
  341. min_extents.begin(),
  342. min);
  343. // typedef boost::array<index,NumDims> index_list;
  344. // Build index_gen objects to create views with the same shape
  345. // these need to be separate to handle non-zero index bases
  346. typedef detail::multi_array::index_gen<NumDims,NumDims> index_gen;
  347. index_gen old_idxes;
  348. index_gen new_idxes;
  349. std::transform(new_array.index_base_list_.begin(),
  350. new_array.index_base_list_.end(),
  351. min_extents.begin(),new_idxes.ranges_.begin(),
  352. detail::multi_array::populate_index_ranges());
  353. std::transform(this->index_base_list_.begin(),
  354. this->index_base_list_.end(),
  355. min_extents.begin(),old_idxes.ranges_.begin(),
  356. detail::multi_array::populate_index_ranges());
  357. // Build same-shape views of the two arrays
  358. typename
  359. multi_array::BOOST_NESTED_TEMPLATE array_view<NumDims>::type view_old = (*this)[old_idxes];
  360. typename
  361. multi_array::BOOST_NESTED_TEMPLATE array_view<NumDims>::type view_new = new_array[new_idxes];
  362. // Set the right portion of the new array
  363. view_new = view_old;
  364. using std::swap;
  365. // Swap the internals of these arrays.
  366. swap(this->super_type::base_,new_array.super_type::base_);
  367. swap(this->storage_,new_array.storage_);
  368. swap(this->extent_list_,new_array.extent_list_);
  369. swap(this->stride_list_,new_array.stride_list_);
  370. swap(this->index_base_list_,new_array.index_base_list_);
  371. swap(this->origin_offset_,new_array.origin_offset_);
  372. swap(this->directional_offset_,new_array.directional_offset_);
  373. swap(this->num_elements_,new_array.num_elements_);
  374. swap(this->allocator_,new_array.allocator_);
  375. swap(this->base_,new_array.base_);
  376. swap(this->allocated_elements_,new_array.allocated_elements_);
  377. return *this;
  378. }
  379. ~multi_array() {
  380. deallocate_space();
  381. }
  382. private:
  383. void allocate_space() {
  384. typename Allocator::const_pointer no_hint=0;
  385. base_ = allocator_.allocate(this->num_elements(),no_hint);
  386. this->set_base_ptr(base_);
  387. allocated_elements_ = this->num_elements();
  388. std::uninitialized_fill_n(base_,allocated_elements_,T());
  389. }
  390. void deallocate_space() {
  391. if(base_) {
  392. for(T* i = base_; i != base_+allocated_elements_; ++i)
  393. allocator_.destroy(i);
  394. allocator_.deallocate(base_,allocated_elements_);
  395. }
  396. }
  397. typedef boost::array<size_type,NumDims> size_list;
  398. typedef boost::array<index,NumDims> index_list;
  399. Allocator allocator_;
  400. T* base_;
  401. size_type allocated_elements_;
  402. enum {initial_base_ = 0};
  403. };
  404. } // namespace boost
  405. #if defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 406)
  406. # pragma GCC diagnostic pop
  407. #endif
  408. #endif // BOOST_MULTI_ARRAY_RG071801_HPP