multi_array_ref.hpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622
  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_MULTI_ARRAY_REF_HPP
  11. #define BOOST_MULTI_ARRAY_MULTI_ARRAY_REF_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. template <int NDims>
  189. typename const_array_view<NDims>::type
  190. operator[](const detail::multi_array::
  191. index_gen<NumDims,NDims>& indices)
  192. const {
  193. typedef typename const_array_view<NDims>::type return_type;
  194. return
  195. super_type::generate_array_view(boost::type<return_type>(),
  196. indices,
  197. shape(),
  198. strides(),
  199. index_bases(),
  200. origin());
  201. }
  202. const_iterator begin() const {
  203. return const_iterator(*index_bases(),origin(),
  204. shape(),strides(),index_bases());
  205. }
  206. const_iterator end() const {
  207. return const_iterator(*index_bases()+(index)*shape(),origin(),
  208. shape(),strides(),index_bases());
  209. }
  210. const_reverse_iterator rbegin() const {
  211. return const_reverse_iterator(end());
  212. }
  213. const_reverse_iterator rend() const {
  214. return const_reverse_iterator(begin());
  215. }
  216. template <typename OPtr>
  217. bool operator==(const
  218. const_multi_array_ref<T,NumDims,OPtr>& rhs)
  219. const {
  220. if(std::equal(extent_list_.begin(),
  221. extent_list_.end(),
  222. rhs.extent_list_.begin()))
  223. return std::equal(begin(),end(),rhs.begin());
  224. else return false;
  225. }
  226. template <typename OPtr>
  227. bool operator<(const
  228. const_multi_array_ref<T,NumDims,OPtr>& rhs)
  229. const {
  230. return std::lexicographical_compare(begin(),end(),rhs.begin(),rhs.end());
  231. }
  232. template <typename OPtr>
  233. bool operator!=(const
  234. const_multi_array_ref<T,NumDims,OPtr>& rhs)
  235. const {
  236. return !(*this == rhs);
  237. }
  238. template <typename OPtr>
  239. bool operator>(const
  240. const_multi_array_ref<T,NumDims,OPtr>& rhs)
  241. const {
  242. return rhs < *this;
  243. }
  244. template <typename OPtr>
  245. bool operator<=(const
  246. const_multi_array_ref<T,NumDims,OPtr>& rhs)
  247. const {
  248. return !(*this > rhs);
  249. }
  250. template <typename OPtr>
  251. bool operator>=(const
  252. const_multi_array_ref<T,NumDims,OPtr>& rhs)
  253. const {
  254. return !(*this < rhs);
  255. }
  256. #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
  257. protected:
  258. #else
  259. public:
  260. #endif
  261. typedef boost::array<size_type,NumDims> size_list;
  262. typedef boost::array<index,NumDims> index_list;
  263. // This is used by multi_array, which is a subclass of this
  264. void set_base_ptr(TPtr new_base) { base_ = new_base; }
  265. // This constructor supports multi_array's default constructor
  266. // and constructors from multi_array_ref, subarray, and array_view
  267. explicit
  268. const_multi_array_ref(TPtr base,
  269. const storage_order_type& so,
  270. const index * index_bases,
  271. const size_type* extents) :
  272. base_(base), storage_(so), origin_offset_(0), directional_offset_(0)
  273. {
  274. // If index_bases or extents is null, then initialize the corresponding
  275. // private data to zeroed lists.
  276. if(index_bases) {
  277. boost::detail::multi_array::
  278. copy_n(index_bases,NumDims,index_base_list_.begin());
  279. } else {
  280. std::fill_n(index_base_list_.begin(),NumDims,0);
  281. }
  282. if(extents) {
  283. init_multi_array_ref(extents);
  284. } else {
  285. boost::array<index,NumDims> extent_list;
  286. extent_list.assign(0);
  287. init_multi_array_ref(extent_list.begin());
  288. }
  289. }
  290. TPtr base_;
  291. storage_order_type storage_;
  292. size_list extent_list_;
  293. index_list stride_list_;
  294. index_list index_base_list_;
  295. index origin_offset_;
  296. index directional_offset_;
  297. size_type num_elements_;
  298. private:
  299. // const_multi_array_ref cannot be assigned to (no deep copies!)
  300. const_multi_array_ref& operator=(const const_multi_array_ref& other);
  301. void init_from_extent_gen(const
  302. detail::multi_array::
  303. extent_gen<NumDims>& ranges) {
  304. typedef boost::array<index,NumDims> extent_list;
  305. // get the index_base values
  306. std::transform(ranges.ranges_.begin(),ranges.ranges_.end(),
  307. index_base_list_.begin(),
  308. boost::mem_fun_ref(&extent_range::start));
  309. // calculate the extents
  310. extent_list extents;
  311. std::transform(ranges.ranges_.begin(),ranges.ranges_.end(),
  312. extents.begin(),
  313. boost::mem_fun_ref(&extent_range::size));
  314. init_multi_array_ref(extents.begin());
  315. }
  316. #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
  317. protected:
  318. #else
  319. public:
  320. #endif
  321. // RG - move me!
  322. template <class InputIterator>
  323. void init_multi_array_ref(InputIterator extents_iter) {
  324. boost::function_requires<InputIteratorConcept<InputIterator> >();
  325. boost::detail::multi_array::
  326. copy_n(extents_iter,num_dimensions(),extent_list_.begin());
  327. // Calculate the array size
  328. num_elements_ = std::accumulate(extent_list_.begin(),extent_list_.end(),
  329. size_type(1),std::multiplies<size_type>());
  330. this->compute_strides(stride_list_,extent_list_,storage_);
  331. origin_offset_ =
  332. this->calculate_origin_offset(stride_list_,extent_list_,
  333. storage_,index_base_list_);
  334. directional_offset_ =
  335. this->calculate_descending_dimension_offset(stride_list_,extent_list_,
  336. storage_);
  337. }
  338. };
  339. template <typename T, std::size_t NumDims>
  340. class multi_array_ref :
  341. public const_multi_array_ref<T,NumDims,T*>
  342. {
  343. typedef const_multi_array_ref<T,NumDims,T*> super_type;
  344. public:
  345. typedef typename super_type::value_type value_type;
  346. typedef typename super_type::reference reference;
  347. typedef typename super_type::iterator iterator;
  348. typedef typename super_type::reverse_iterator reverse_iterator;
  349. typedef typename super_type::const_reference const_reference;
  350. typedef typename super_type::const_iterator const_iterator;
  351. typedef typename super_type::const_reverse_iterator const_reverse_iterator;
  352. typedef typename super_type::element element;
  353. typedef typename super_type::size_type size_type;
  354. typedef typename super_type::difference_type difference_type;
  355. typedef typename super_type::index index;
  356. typedef typename super_type::extent_range extent_range;
  357. typedef typename super_type::storage_order_type storage_order_type;
  358. typedef typename super_type::index_list index_list;
  359. typedef typename super_type::size_list size_list;
  360. template <std::size_t NDims>
  361. struct const_array_view {
  362. typedef boost::detail::multi_array::const_multi_array_view<T,NDims> type;
  363. };
  364. template <std::size_t NDims>
  365. struct array_view {
  366. typedef boost::detail::multi_array::multi_array_view<T,NDims> type;
  367. };
  368. template <class ExtentList>
  369. explicit multi_array_ref(T* base, const ExtentList& extents) :
  370. super_type(base,extents) {
  371. boost::function_requires<
  372. CollectionConcept<ExtentList> >();
  373. }
  374. template <class ExtentList>
  375. explicit multi_array_ref(T* base, const ExtentList& extents,
  376. const general_storage_order<NumDims>& so) :
  377. super_type(base,extents,so) {
  378. boost::function_requires<
  379. CollectionConcept<ExtentList> >();
  380. }
  381. explicit multi_array_ref(T* base,
  382. const detail::multi_array::
  383. extent_gen<NumDims>& ranges) :
  384. super_type(base,ranges) { }
  385. explicit multi_array_ref(T* base,
  386. const detail::multi_array::
  387. extent_gen<NumDims>&
  388. ranges,
  389. const general_storage_order<NumDims>& so) :
  390. super_type(base,ranges,so) { }
  391. // Assignment from other ConstMultiArray types.
  392. template <typename ConstMultiArray>
  393. multi_array_ref& operator=(const ConstMultiArray& other) {
  394. function_requires<
  395. multi_array_concepts::
  396. ConstMultiArrayConcept<ConstMultiArray,NumDims> >();
  397. // make sure the dimensions agree
  398. BOOST_ASSERT(other.num_dimensions() == this->num_dimensions());
  399. BOOST_ASSERT(std::equal(other.shape(),other.shape()+this->num_dimensions(),
  400. this->shape()));
  401. // iterator-based copy
  402. std::copy(other.begin(),other.end(),this->begin());
  403. return *this;
  404. }
  405. multi_array_ref& operator=(const multi_array_ref& other) {
  406. if (&other != this) {
  407. // make sure the dimensions agree
  408. BOOST_ASSERT(other.num_dimensions() == this->num_dimensions());
  409. BOOST_ASSERT(std::equal(other.shape(),
  410. other.shape()+this->num_dimensions(),
  411. this->shape()));
  412. // iterator-based copy
  413. std::copy(other.begin(),other.end(),this->begin());
  414. }
  415. return *this;
  416. }
  417. element* origin() { return super_type::base_+super_type::origin_offset_; }
  418. element* data() { return super_type::base_; }
  419. template <class IndexList>
  420. element& operator()(const IndexList& indices) {
  421. boost::function_requires<
  422. CollectionConcept<IndexList> >();
  423. return super_type::access_element(boost::type<element&>(),
  424. indices,origin(),
  425. this->shape(),this->strides(),
  426. this->index_bases());
  427. }
  428. reference operator[](index idx) {
  429. return super_type::access(boost::type<reference>(),
  430. idx,origin(),
  431. this->shape(),this->strides(),
  432. this->index_bases());
  433. }
  434. // See note attached to generate_array_view in base.hpp
  435. template <int NDims>
  436. typename array_view<NDims>::type
  437. operator[](const detail::multi_array::
  438. index_gen<NumDims,NDims>& indices) {
  439. typedef typename array_view<NDims>::type return_type;
  440. return
  441. super_type::generate_array_view(boost::type<return_type>(),
  442. indices,
  443. this->shape(),
  444. this->strides(),
  445. this->index_bases(),
  446. origin());
  447. }
  448. iterator begin() {
  449. return iterator(*this->index_bases(),origin(),this->shape(),
  450. this->strides(),this->index_bases());
  451. }
  452. iterator end() {
  453. return iterator(*this->index_bases()+(index)*this->shape(),origin(),
  454. this->shape(),this->strides(),
  455. this->index_bases());
  456. }
  457. // rbegin() and rend() written naively to thwart MSVC ICE.
  458. reverse_iterator rbegin() {
  459. reverse_iterator ri(end());
  460. return ri;
  461. }
  462. reverse_iterator rend() {
  463. reverse_iterator ri(begin());
  464. return ri;
  465. }
  466. // Using declarations don't seem to work for g++
  467. // These are the proxies to work around this.
  468. const element* origin() const { return super_type::origin(); }
  469. const element* data() const { return super_type::data(); }
  470. template <class IndexList>
  471. const element& operator()(const IndexList& indices) const {
  472. boost::function_requires<
  473. CollectionConcept<IndexList> >();
  474. return super_type::operator()(indices);
  475. }
  476. const_reference operator[](index idx) const {
  477. return super_type::access(boost::type<const_reference>(),
  478. idx,origin(),
  479. this->shape(),this->strides(),
  480. this->index_bases());
  481. }
  482. // See note attached to generate_array_view in base.hpp
  483. template <int NDims>
  484. typename const_array_view<NDims>::type
  485. operator[](const detail::multi_array::
  486. index_gen<NumDims,NDims>& indices)
  487. const {
  488. return super_type::operator[](indices);
  489. }
  490. const_iterator begin() const {
  491. return super_type::begin();
  492. }
  493. const_iterator end() const {
  494. return super_type::end();
  495. }
  496. const_reverse_iterator rbegin() const {
  497. return super_type::rbegin();
  498. }
  499. const_reverse_iterator rend() const {
  500. return super_type::rend();
  501. }
  502. protected:
  503. // This is only supplied to support multi_array's default constructor
  504. explicit multi_array_ref(T* base,
  505. const storage_order_type& so,
  506. const index* index_bases,
  507. const size_type* extents) :
  508. super_type(base,so,index_bases,extents) { }
  509. };
  510. } // namespace boost
  511. #endif