multi_array_ref.hpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634
  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_REF_RG071801_HPP
  11. #define BOOST_MULTI_ARRAY_REF_RG071801_HPP
  12. //
  13. // multi_array_ref.hpp - code for creating "views" of array data.
  14. //
  15. #include "boost/multi_array/base.hpp"
  16. #include "boost/multi_array/collection_concept.hpp"
  17. #include "boost/multi_array/concept_checks.hpp"
  18. #include "boost/multi_array/iterator.hpp"
  19. #include "boost/multi_array/storage_order.hpp"
  20. #include "boost/multi_array/subarray.hpp"
  21. #include "boost/multi_array/view.hpp"
  22. #include "boost/multi_array/algorithm.hpp"
  23. #include "boost/type_traits/is_integral.hpp"
  24. #include "boost/utility/enable_if.hpp"
  25. #include "boost/array.hpp"
  26. #include "boost/concept_check.hpp"
  27. #include "boost/functional.hpp"
  28. #include "boost/limits.hpp"
  29. #include <algorithm>
  30. #include <cstddef>
  31. #include <functional>
  32. #include <numeric>
  33. namespace boost {
  34. template <typename T, std::size_t NumDims,
  35. typename TPtr = const T*
  36. >
  37. class const_multi_array_ref :
  38. public detail::multi_array::multi_array_impl_base<T,NumDims>
  39. {
  40. typedef detail::multi_array::multi_array_impl_base<T,NumDims> super_type;
  41. public:
  42. typedef typename super_type::value_type value_type;
  43. typedef typename super_type::const_reference const_reference;
  44. typedef typename super_type::const_iterator const_iterator;
  45. typedef typename super_type::const_reverse_iterator const_reverse_iterator;
  46. typedef typename super_type::element element;
  47. typedef typename super_type::size_type size_type;
  48. typedef typename super_type::difference_type difference_type;
  49. typedef typename super_type::index index;
  50. typedef typename super_type::extent_range extent_range;
  51. typedef general_storage_order<NumDims> storage_order_type;
  52. // template typedefs
  53. template <std::size_t NDims>
  54. struct const_array_view {
  55. typedef boost::detail::multi_array::const_multi_array_view<T,NDims> type;
  56. };
  57. template <std::size_t NDims>
  58. struct array_view {
  59. typedef boost::detail::multi_array::multi_array_view<T,NDims> type;
  60. };
  61. #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
  62. // make const_multi_array_ref a friend of itself
  63. template <typename,std::size_t,typename>
  64. friend class const_multi_array_ref;
  65. #endif
  66. // This ensures that const_multi_array_ref types with different TPtr
  67. // types can convert to each other
  68. template <typename OPtr>
  69. const_multi_array_ref(const const_multi_array_ref<T,NumDims,OPtr>& other)
  70. : base_(other.base_), storage_(other.storage_),
  71. extent_list_(other.extent_list_),
  72. stride_list_(other.stride_list_),
  73. index_base_list_(other.index_base_list_),
  74. origin_offset_(other.origin_offset_),
  75. directional_offset_(other.directional_offset_),
  76. num_elements_(other.num_elements_) { }
  77. template <typename ExtentList>
  78. explicit const_multi_array_ref(TPtr base, const ExtentList& extents) :
  79. base_(base), storage_(c_storage_order()) {
  80. boost::function_requires<
  81. CollectionConcept<ExtentList> >();
  82. index_base_list_.assign(0);
  83. init_multi_array_ref(extents.begin());
  84. }
  85. template <typename ExtentList>
  86. explicit const_multi_array_ref(TPtr base, const ExtentList& extents,
  87. const general_storage_order<NumDims>& so) :
  88. base_(base), storage_(so) {
  89. boost::function_requires<
  90. CollectionConcept<ExtentList> >();
  91. index_base_list_.assign(0);
  92. init_multi_array_ref(extents.begin());
  93. }
  94. explicit const_multi_array_ref(TPtr base,
  95. const detail::multi_array::
  96. extent_gen<NumDims>& ranges) :
  97. base_(base), storage_(c_storage_order()) {
  98. init_from_extent_gen(ranges);
  99. }
  100. explicit const_multi_array_ref(TPtr base,
  101. const detail::multi_array::
  102. extent_gen<NumDims>& ranges,
  103. const general_storage_order<NumDims>& so) :
  104. base_(base), storage_(so) {
  105. init_from_extent_gen(ranges);
  106. }
  107. template <class InputIterator>
  108. void assign(InputIterator begin, InputIterator end) {
  109. boost::function_requires<InputIteratorConcept<InputIterator> >();
  110. InputIterator in_iter = begin;
  111. T* out_iter = base_;
  112. std::size_t copy_count=0;
  113. while (in_iter != end && copy_count < num_elements_) {
  114. *out_iter++ = *in_iter++;
  115. copy_count++;
  116. }
  117. }
  118. template <class BaseList>
  119. #ifdef BOOST_NO_SFINAE
  120. void
  121. #else
  122. typename
  123. disable_if<typename boost::is_integral<BaseList>::type,void >::type
  124. #endif // BOOST_NO_SFINAE
  125. reindex(const BaseList& values) {
  126. boost::function_requires<
  127. CollectionConcept<BaseList> >();
  128. boost::detail::multi_array::
  129. copy_n(values.begin(),num_dimensions(),index_base_list_.begin());
  130. origin_offset_ =
  131. this->calculate_origin_offset(stride_list_,extent_list_,
  132. storage_,index_base_list_);
  133. }
  134. void reindex(index value) {
  135. index_base_list_.assign(value);
  136. origin_offset_ =
  137. this->calculate_origin_offset(stride_list_,extent_list_,
  138. storage_,index_base_list_);
  139. }
  140. template <typename SizeList>
  141. void reshape(const SizeList& extents) {
  142. boost::function_requires<
  143. CollectionConcept<SizeList> >();
  144. BOOST_ASSERT(num_elements_ ==
  145. std::accumulate(extents.begin(),extents.end(),
  146. size_type(1),std::multiplies<size_type>()));
  147. std::copy(extents.begin(),extents.end(),extent_list_.begin());
  148. this->compute_strides(stride_list_,extent_list_,storage_);
  149. origin_offset_ =
  150. this->calculate_origin_offset(stride_list_,extent_list_,
  151. storage_,index_base_list_);
  152. }
  153. size_type num_dimensions() const { return NumDims; }
  154. size_type size() const { return extent_list_.front(); }
  155. // given reshaping functionality, this is the max possible size.
  156. size_type max_size() const { return num_elements(); }
  157. bool empty() const { return size() == 0; }
  158. const size_type* shape() const {
  159. return extent_list_.data();
  160. }
  161. const index* strides() const {
  162. return stride_list_.data();
  163. }
  164. const element* origin() const { return base_+origin_offset_; }
  165. const element* data() const { return base_; }
  166. size_type num_elements() const { return num_elements_; }
  167. const index* index_bases() const {
  168. return index_base_list_.data();
  169. }
  170. const storage_order_type& storage_order() const {
  171. return storage_;
  172. }
  173. template <typename IndexList>
  174. const element& operator()(IndexList indices) const {
  175. boost::function_requires<
  176. CollectionConcept<IndexList> >();
  177. return super_type::access_element(boost::type<const element&>(),
  178. indices,origin(),
  179. shape(),strides(),index_bases());
  180. }
  181. // Only allow const element access
  182. const_reference operator[](index idx) const {
  183. return super_type::access(boost::type<const_reference>(),
  184. idx,origin(),
  185. shape(),strides(),index_bases());
  186. }
  187. // see generate_array_view in base.hpp
  188. #if !defined(BOOST_MSVC) || BOOST_MSVC > 1300
  189. template <int NDims>
  190. #else
  191. template <int NumDims, int NDims> // else ICE
  192. #endif // BOOST_MSVC
  193. typename const_array_view<NDims>::type
  194. operator[](const detail::multi_array::
  195. index_gen<NumDims,NDims>& indices)
  196. const {
  197. typedef typename const_array_view<NDims>::type return_type;
  198. return
  199. super_type::generate_array_view(boost::type<return_type>(),
  200. indices,
  201. shape(),
  202. strides(),
  203. index_bases(),
  204. origin());
  205. }
  206. const_iterator begin() const {
  207. return const_iterator(*index_bases(),origin(),
  208. shape(),strides(),index_bases());
  209. }
  210. const_iterator end() const {
  211. return const_iterator(*index_bases()+(index)*shape(),origin(),
  212. shape(),strides(),index_bases());
  213. }
  214. const_reverse_iterator rbegin() const {
  215. return const_reverse_iterator(end());
  216. }
  217. const_reverse_iterator rend() const {
  218. return const_reverse_iterator(begin());
  219. }
  220. template <typename OPtr>
  221. bool operator==(const
  222. const_multi_array_ref<T,NumDims,OPtr>& rhs)
  223. const {
  224. if(std::equal(extent_list_.begin(),
  225. extent_list_.end(),
  226. rhs.extent_list_.begin()))
  227. return std::equal(begin(),end(),rhs.begin());
  228. else return false;
  229. }
  230. template <typename OPtr>
  231. bool operator<(const
  232. const_multi_array_ref<T,NumDims,OPtr>& rhs)
  233. const {
  234. return std::lexicographical_compare(begin(),end(),rhs.begin(),rhs.end());
  235. }
  236. template <typename OPtr>
  237. bool operator!=(const
  238. const_multi_array_ref<T,NumDims,OPtr>& rhs)
  239. const {
  240. return !(*this == rhs);
  241. }
  242. template <typename OPtr>
  243. bool operator>(const
  244. const_multi_array_ref<T,NumDims,OPtr>& rhs)
  245. const {
  246. return rhs < *this;
  247. }
  248. template <typename OPtr>
  249. bool operator<=(const
  250. const_multi_array_ref<T,NumDims,OPtr>& rhs)
  251. const {
  252. return !(*this > rhs);
  253. }
  254. template <typename OPtr>
  255. bool operator>=(const
  256. const_multi_array_ref<T,NumDims,OPtr>& rhs)
  257. const {
  258. return !(*this < rhs);
  259. }
  260. #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
  261. protected:
  262. #else
  263. public:
  264. #endif
  265. typedef boost::array<size_type,NumDims> size_list;
  266. typedef boost::array<index,NumDims> index_list;
  267. // This is used by multi_array, which is a subclass of this
  268. void set_base_ptr(TPtr new_base) { base_ = new_base; }
  269. // This constructor supports multi_array's default constructor
  270. // and constructors from multi_array_ref, subarray, and array_view
  271. explicit
  272. const_multi_array_ref(TPtr base,
  273. const storage_order_type& so,
  274. const index * index_bases,
  275. const size_type* extents) :
  276. base_(base), storage_(so), origin_offset_(0), directional_offset_(0)
  277. {
  278. // If index_bases or extents is null, then initialize the corresponding
  279. // private data to zeroed lists.
  280. if(index_bases) {
  281. boost::detail::multi_array::
  282. copy_n(index_bases,NumDims,index_base_list_.begin());
  283. } else {
  284. std::fill_n(index_base_list_.begin(),NumDims,0);
  285. }
  286. if(extents) {
  287. init_multi_array_ref(extents);
  288. } else {
  289. boost::array<index,NumDims> extent_list;
  290. extent_list.assign(0);
  291. init_multi_array_ref(extent_list.begin());
  292. }
  293. }
  294. TPtr base_;
  295. storage_order_type storage_;
  296. size_list extent_list_;
  297. index_list stride_list_;
  298. index_list index_base_list_;
  299. index origin_offset_;
  300. index directional_offset_;
  301. size_type num_elements_;
  302. private:
  303. // const_multi_array_ref cannot be assigned to (no deep copies!)
  304. const_multi_array_ref& operator=(const const_multi_array_ref& other);
  305. void init_from_extent_gen(const
  306. detail::multi_array::
  307. extent_gen<NumDims>& ranges) {
  308. typedef boost::array<index,NumDims> extent_list;
  309. // get the index_base values
  310. std::transform(ranges.ranges_.begin(),ranges.ranges_.end(),
  311. index_base_list_.begin(),
  312. boost::mem_fun_ref(&extent_range::start));
  313. // calculate the extents
  314. extent_list extents;
  315. std::transform(ranges.ranges_.begin(),ranges.ranges_.end(),
  316. extents.begin(),
  317. boost::mem_fun_ref(&extent_range::size));
  318. init_multi_array_ref(extents.begin());
  319. }
  320. #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
  321. protected:
  322. #else
  323. public:
  324. #endif
  325. // RG - move me!
  326. template <class InputIterator>
  327. void init_multi_array_ref(InputIterator extents_iter) {
  328. boost::function_requires<InputIteratorConcept<InputIterator> >();
  329. boost::detail::multi_array::
  330. copy_n(extents_iter,num_dimensions(),extent_list_.begin());
  331. // Calculate the array size
  332. num_elements_ = std::accumulate(extent_list_.begin(),extent_list_.end(),
  333. size_type(1),std::multiplies<size_type>());
  334. this->compute_strides(stride_list_,extent_list_,storage_);
  335. origin_offset_ =
  336. this->calculate_origin_offset(stride_list_,extent_list_,
  337. storage_,index_base_list_);
  338. directional_offset_ =
  339. this->calculate_descending_dimension_offset(stride_list_,extent_list_,
  340. storage_);
  341. }
  342. };
  343. template <typename T, std::size_t NumDims>
  344. class multi_array_ref :
  345. public const_multi_array_ref<T,NumDims,T*>
  346. {
  347. typedef const_multi_array_ref<T,NumDims,T*> super_type;
  348. public:
  349. typedef typename super_type::value_type value_type;
  350. typedef typename super_type::reference reference;
  351. typedef typename super_type::iterator iterator;
  352. typedef typename super_type::reverse_iterator reverse_iterator;
  353. typedef typename super_type::const_reference const_reference;
  354. typedef typename super_type::const_iterator const_iterator;
  355. typedef typename super_type::const_reverse_iterator const_reverse_iterator;
  356. typedef typename super_type::element element;
  357. typedef typename super_type::size_type size_type;
  358. typedef typename super_type::difference_type difference_type;
  359. typedef typename super_type::index index;
  360. typedef typename super_type::extent_range extent_range;
  361. typedef typename super_type::storage_order_type storage_order_type;
  362. typedef typename super_type::index_list index_list;
  363. typedef typename super_type::size_list size_list;
  364. template <std::size_t NDims>
  365. struct const_array_view {
  366. typedef boost::detail::multi_array::const_multi_array_view<T,NDims> type;
  367. };
  368. template <std::size_t NDims>
  369. struct array_view {
  370. typedef boost::detail::multi_array::multi_array_view<T,NDims> type;
  371. };
  372. template <class ExtentList>
  373. explicit multi_array_ref(T* base, const ExtentList& extents) :
  374. super_type(base,extents) {
  375. boost::function_requires<
  376. CollectionConcept<ExtentList> >();
  377. }
  378. template <class ExtentList>
  379. explicit multi_array_ref(T* base, const ExtentList& extents,
  380. const general_storage_order<NumDims>& so) :
  381. super_type(base,extents,so) {
  382. boost::function_requires<
  383. CollectionConcept<ExtentList> >();
  384. }
  385. explicit multi_array_ref(T* base,
  386. const detail::multi_array::
  387. extent_gen<NumDims>& ranges) :
  388. super_type(base,ranges) { }
  389. explicit multi_array_ref(T* base,
  390. const detail::multi_array::
  391. extent_gen<NumDims>&
  392. ranges,
  393. const general_storage_order<NumDims>& so) :
  394. super_type(base,ranges,so) { }
  395. // Assignment from other ConstMultiArray types.
  396. template <typename ConstMultiArray>
  397. multi_array_ref& operator=(const ConstMultiArray& other) {
  398. function_requires<
  399. multi_array_concepts::
  400. ConstMultiArrayConcept<ConstMultiArray,NumDims> >();
  401. // make sure the dimensions agree
  402. BOOST_ASSERT(other.num_dimensions() == this->num_dimensions());
  403. BOOST_ASSERT(std::equal(other.shape(),other.shape()+this->num_dimensions(),
  404. this->shape()));
  405. // iterator-based copy
  406. std::copy(other.begin(),other.end(),this->begin());
  407. return *this;
  408. }
  409. multi_array_ref& operator=(const multi_array_ref& other) {
  410. if (&other != this) {
  411. // make sure the dimensions agree
  412. BOOST_ASSERT(other.num_dimensions() == this->num_dimensions());
  413. BOOST_ASSERT(std::equal(other.shape(),
  414. other.shape()+this->num_dimensions(),
  415. this->shape()));
  416. // iterator-based copy
  417. std::copy(other.begin(),other.end(),this->begin());
  418. }
  419. return *this;
  420. }
  421. element* origin() { return super_type::base_+super_type::origin_offset_; }
  422. element* data() { return super_type::base_; }
  423. template <class IndexList>
  424. element& operator()(const IndexList& indices) {
  425. boost::function_requires<
  426. CollectionConcept<IndexList> >();
  427. return super_type::access_element(boost::type<element&>(),
  428. indices,origin(),
  429. this->shape(),this->strides(),
  430. this->index_bases());
  431. }
  432. reference operator[](index idx) {
  433. return super_type::access(boost::type<reference>(),
  434. idx,origin(),
  435. this->shape(),this->strides(),
  436. this->index_bases());
  437. }
  438. // See note attached to generate_array_view in base.hpp
  439. #if !defined(BOOST_MSVC) || BOOST_MSVC > 1300
  440. template <int NDims>
  441. #else
  442. template <int NumDims, int NDims> // else ICE
  443. #endif // BOOST_MSVC
  444. typename array_view<NDims>::type
  445. operator[](const detail::multi_array::
  446. index_gen<NumDims,NDims>& indices) {
  447. typedef typename array_view<NDims>::type return_type;
  448. return
  449. super_type::generate_array_view(boost::type<return_type>(),
  450. indices,
  451. this->shape(),
  452. this->strides(),
  453. this->index_bases(),
  454. origin());
  455. }
  456. iterator begin() {
  457. return iterator(*this->index_bases(),origin(),this->shape(),
  458. this->strides(),this->index_bases());
  459. }
  460. iterator end() {
  461. return iterator(*this->index_bases()+(index)*this->shape(),origin(),
  462. this->shape(),this->strides(),
  463. this->index_bases());
  464. }
  465. // rbegin() and rend() written naively to thwart MSVC ICE.
  466. reverse_iterator rbegin() {
  467. reverse_iterator ri(end());
  468. return ri;
  469. }
  470. reverse_iterator rend() {
  471. reverse_iterator ri(begin());
  472. return ri;
  473. }
  474. // Using declarations don't seem to work for g++
  475. // These are the proxies to work around this.
  476. const element* origin() const { return super_type::origin(); }
  477. const element* data() const { return super_type::data(); }
  478. template <class IndexList>
  479. const element& operator()(const IndexList& indices) const {
  480. boost::function_requires<
  481. CollectionConcept<IndexList> >();
  482. return super_type::operator()(indices);
  483. }
  484. const_reference operator[](index idx) const {
  485. return super_type::access(boost::type<const_reference>(),
  486. idx,origin(),
  487. this->shape(),this->strides(),
  488. this->index_bases());
  489. }
  490. // See note attached to generate_array_view in base.hpp
  491. #if !defined(BOOST_MSVC) || BOOST_MSVC > 1300
  492. template <int NDims>
  493. #else
  494. template <int NumDims, int NDims> // else ICE
  495. #endif // BOOST_MSVC
  496. typename const_array_view<NDims>::type
  497. operator[](const detail::multi_array::
  498. index_gen<NumDims,NDims>& indices)
  499. const {
  500. return super_type::operator[](indices);
  501. }
  502. const_iterator begin() const {
  503. return super_type::begin();
  504. }
  505. const_iterator end() const {
  506. return super_type::end();
  507. }
  508. const_reverse_iterator rbegin() const {
  509. return super_type::rbegin();
  510. }
  511. const_reverse_iterator rend() const {
  512. return super_type::rend();
  513. }
  514. protected:
  515. // This is only supplied to support multi_array's default constructor
  516. explicit multi_array_ref(T* base,
  517. const storage_order_type& so,
  518. const index* index_bases,
  519. const size_type* extents) :
  520. super_type(base,so,index_bases,extents) { }
  521. };
  522. } // namespace boost
  523. #endif // BOOST_MULTI_ARRAY_REF_RG071801_HPP