multi_array.hpp 18 KB

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