2 // Copyright (c) 2000-2002
3 // Joerg Walter, Mathias Koch
5 // Distributed under the Boost Software License, Version 1.0. (See
6 // accompanying file LICENSE_1_0.txt or copy at
7 // http://www.boost.org/LICENSE_1_0.txt)
9 // The authors gratefully acknowledge the support of
10 // GeNeSys mbH & Co. KG in producing this work.
13 #ifndef _BOOST_UBLAS_VECTOR_PROXY_
14 #define _BOOST_UBLAS_VECTOR_PROXY_
16 #include <boost/numeric/ublas/vector_expression.hpp>
17 #include <boost/numeric/ublas/detail/vector_assign.hpp>
18 #include <boost/numeric/ublas/detail/temporary.hpp>
20 // Iterators based on ideas of Jeremy Siek
22 namespace boost { namespace numeric { namespace ublas {
24 /** \brief A vector referencing a continuous subvector of elements of vector \c v containing all elements specified by \c range.
26 * A vector range can be used as a normal vector in any expression.
27 * If the specified range falls outside that of the index range of the vector, then
28 * the \c vector_range is not a well formed \i Vector \i Expression and access to an
29 * element outside of index range of the vector is \b undefined.
31 * \tparam V the type of vector referenced (for example \c vector<double>)
35 public vector_expression<vector_range<V> > {
37 typedef vector_range<V> self_type;
39 #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS
40 using vector_expression<self_type>::operator ();
42 typedef const V const_vector_type;
43 typedef V vector_type;
44 typedef typename V::size_type size_type;
45 typedef typename V::difference_type difference_type;
46 typedef typename V::value_type value_type;
47 typedef typename V::const_reference const_reference;
48 typedef typename boost::mpl::if_<boost::is_const<V>,
49 typename V::const_reference,
50 typename V::reference>::type reference;
51 typedef typename boost::mpl::if_<boost::is_const<V>,
52 typename V::const_closure_type,
53 typename V::closure_type>::type vector_closure_type;
54 typedef basic_range<size_type, difference_type> range_type;
55 typedef const self_type const_closure_type;
56 typedef self_type closure_type;
57 typedef typename storage_restrict_traits<typename V::storage_category,
58 dense_proxy_tag>::storage_category storage_category;
60 // Construction and destruction
62 vector_range (vector_type &data, const range_type &r):
63 data_ (data), r_ (r.preprocess (data.size ())) {
64 // Early checking of preconditions here.
65 // BOOST_UBLAS_CHECK (r_.start () <= data_.size () &&
66 // r_.start () + r_.size () <= data_.size (), bad_index ());
69 vector_range (const vector_closure_type &data, const range_type &r, bool):
70 data_ (data), r_ (r.preprocess (data.size ())) {
71 // Early checking of preconditions here.
72 // BOOST_UBLAS_CHECK (r_.start () <= data_.size () &&
73 // r_.start () + r_.size () <= data_.size (), bad_index ());
78 size_type start () const {
82 size_type size () const {
88 const vector_closure_type &data () const {
92 vector_closure_type &data () {
97 #ifndef BOOST_UBLAS_PROXY_CONST_MEMBER
99 const_reference operator () (size_type i) const {
100 return data_ (r_ (i));
103 reference operator () (size_type i) {
104 return data_ (r_ (i));
108 const_reference operator [] (size_type i) const {
112 reference operator [] (size_type i) {
117 reference operator () (size_type i) const {
118 return data_ (r_ (i));
122 reference operator [] (size_type i) const {
127 // ISSUE can this be done in free project function?
128 // Although a const function can create a non-const proxy to a non-const object
129 // Critical is that vector_type and data_ (vector_closure_type) are const correct
131 vector_range<vector_type> project (const range_type &r) const {
132 return vector_range<vector_type> (data_, r_.compose (r.preprocess (data_.size ())), false);
137 vector_range &operator = (const vector_range &vr) {
138 // ISSUE need a temporary, proxy can be overlaping alias
139 vector_assign<scalar_assign> (*this, typename vector_temporary_traits<V>::type (vr));
143 vector_range &assign_temporary (vector_range &vr) {
144 // assign elements, proxied container remains the same
145 vector_assign<scalar_assign> (*this, vr);
150 vector_range &operator = (const vector_expression<AE> &ae) {
151 vector_assign<scalar_assign> (*this, typename vector_temporary_traits<V>::type (ae));
156 vector_range &assign (const vector_expression<AE> &ae) {
157 vector_assign<scalar_assign> (*this, ae);
162 vector_range &operator += (const vector_expression<AE> &ae) {
163 vector_assign<scalar_assign> (*this, typename vector_temporary_traits<V>::type (*this + ae));
168 vector_range &plus_assign (const vector_expression<AE> &ae) {
169 vector_assign<scalar_plus_assign> (*this, ae);
174 vector_range &operator -= (const vector_expression<AE> &ae) {
175 vector_assign<scalar_assign> (*this, typename vector_temporary_traits<V>::type (*this - ae));
180 vector_range &minus_assign (const vector_expression<AE> &ae) {
181 vector_assign<scalar_minus_assign> (*this, ae);
186 vector_range &operator *= (const AT &at) {
187 vector_assign_scalar<scalar_multiplies_assign> (*this, at);
192 vector_range &operator /= (const AT &at) {
193 vector_assign_scalar<scalar_divides_assign> (*this, at);
197 // Closure comparison
199 bool same_closure (const vector_range &vr) const {
200 return (*this).data_.same_closure (vr.data_);
205 bool operator == (const vector_range &vr) const {
206 return (*this).data_ == vr.data_ && r_ == vr.r_;
211 void swap (vector_range vr) {
213 BOOST_UBLAS_CHECK (size () == vr.size (), bad_size ());
214 // Sparse ranges may be nonconformant now.
215 // std::swap_ranges (begin (), end (), vr.begin ());
216 vector_swap<scalar_swap> (*this, vr);
220 friend void swap (vector_range vr1, vector_range vr2) {
226 typedef typename V::const_iterator const_subiterator_type;
227 typedef typename boost::mpl::if_<boost::is_const<V>,
228 typename V::const_iterator,
229 typename V::iterator>::type subiterator_type;
232 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
233 typedef indexed_iterator<vector_range<vector_type>,
234 typename subiterator_type::iterator_category> iterator;
235 typedef indexed_const_iterator<vector_range<vector_type>,
236 typename const_subiterator_type::iterator_category> const_iterator;
238 class const_iterator;
244 const_iterator find (size_type i) const {
245 const_subiterator_type it (data_.find (start () + i));
246 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
247 return const_iterator (*this, it.index ());
249 return const_iterator (*this, it);
253 iterator find (size_type i) {
254 subiterator_type it (data_.find (start () + i));
255 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
256 return iterator (*this, it.index ());
258 return iterator (*this, it);
262 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
263 class const_iterator:
264 public container_const_reference<vector_range>,
265 public iterator_base_traits<typename const_subiterator_type::iterator_category>::template
266 iterator_base<const_iterator, value_type>::type {
268 typedef typename const_subiterator_type::difference_type difference_type;
269 typedef typename const_subiterator_type::value_type value_type;
270 typedef typename const_subiterator_type::reference reference;
271 typedef typename const_subiterator_type::pointer pointer;
273 // Construction and destruction
276 container_const_reference<self_type> (), it_ () {}
278 const_iterator (const self_type &vr, const const_subiterator_type &it):
279 container_const_reference<self_type> (vr), it_ (it) {}
281 const_iterator (const typename self_type::iterator &it): // ISSUE self_type:: stops VC8 using std::iterator here
282 container_const_reference<self_type> (it ()), it_ (it.it_) {}
286 const_iterator &operator ++ () {
291 const_iterator &operator -- () {
296 const_iterator &operator += (difference_type n) {
301 const_iterator &operator -= (difference_type n) {
306 difference_type operator - (const const_iterator &it) const {
307 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
313 const_reference operator * () const {
314 BOOST_UBLAS_CHECK (index () < (*this) ().size (), bad_index ());
318 const_reference operator [] (difference_type n) const {
324 size_type index () const {
325 return it_.index () - (*this) ().start ();
330 const_iterator &operator = (const const_iterator &it) {
331 container_const_reference<self_type>::assign (&it ());
338 bool operator == (const const_iterator &it) const {
339 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
340 return it_ == it.it_;
343 bool operator < (const const_iterator &it) const {
344 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
349 const_subiterator_type it_;
354 const_iterator begin () const {
358 const_iterator end () const {
359 return find (size ());
362 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
364 public container_reference<vector_range>,
365 public iterator_base_traits<typename subiterator_type::iterator_category>::template
366 iterator_base<iterator, value_type>::type {
368 typedef typename subiterator_type::difference_type difference_type;
369 typedef typename subiterator_type::value_type value_type;
370 typedef typename subiterator_type::reference reference;
371 typedef typename subiterator_type::pointer pointer;
373 // Construction and destruction
376 container_reference<self_type> (), it_ () {}
378 iterator (self_type &vr, const subiterator_type &it):
379 container_reference<self_type> (vr), it_ (it) {}
383 iterator &operator ++ () {
388 iterator &operator -- () {
393 iterator &operator += (difference_type n) {
398 iterator &operator -= (difference_type n) {
403 difference_type operator - (const iterator &it) const {
404 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
410 reference operator * () const {
411 BOOST_UBLAS_CHECK (index () < (*this) ().size (), bad_index ());
415 reference operator [] (difference_type n) const {
421 size_type index () const {
422 return it_.index () - (*this) ().start ();
427 iterator &operator = (const iterator &it) {
428 container_reference<self_type>::assign (&it ());
435 bool operator == (const iterator &it) const {
436 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
437 return it_ == it.it_;
440 bool operator < (const iterator &it) const {
441 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
446 subiterator_type it_;
448 friend class const_iterator;
458 return find (size ());
462 typedef reverse_iterator_base<const_iterator> const_reverse_iterator;
463 typedef reverse_iterator_base<iterator> reverse_iterator;
466 const_reverse_iterator rbegin () const {
467 return const_reverse_iterator (end ());
470 const_reverse_iterator rend () const {
471 return const_reverse_iterator (begin ());
474 reverse_iterator rbegin () {
475 return reverse_iterator (end ());
478 reverse_iterator rend () {
479 return reverse_iterator (begin ());
483 vector_closure_type data_;
487 // ------------------
488 // Simple Projections
489 // ------------------
491 /** \brief Return a \c vector_range on a specified vector, a start and stop index.
492 * Return a \c vector_range on a specified vector, a start and stop index. The resulting \c vector_range can be manipulated like a normal vector.
493 * If the specified range falls outside that of of the index range of the vector, then the resulting \c vector_range is not a well formed
494 * Vector Expression and access to an element outside of index range of the vector is \b undefined.
498 vector_range<V> subrange (V &data, typename V::size_type start, typename V::size_type stop) {
499 typedef basic_range<typename V::size_type, typename V::difference_type> range_type;
500 return vector_range<V> (data, range_type (start, stop));
503 /** \brief Return a \c const \c vector_range on a specified vector, a start and stop index.
504 * Return a \c const \c vector_range on a specified vector, a start and stop index. The resulting \c const \c vector_range can be manipulated like a normal vector.
505 *If the specified range falls outside that of of the index range of the vector, then the resulting \c vector_range is not a well formed
506 * Vector Expression and access to an element outside of index range of the vector is \b undefined.
510 vector_range<const V> subrange (const V &data, typename V::size_type start, typename V::size_type stop) {
511 typedef basic_range<typename V::size_type, typename V::difference_type> range_type;
512 return vector_range<const V> (data, range_type (start, stop));
515 // -------------------
516 // Generic Projections
517 // -------------------
519 /** \brief Return a \c const \c vector_range on a specified vector and \c range
520 * Return a \c const \c vector_range on a specified vector and \c range. The resulting \c vector_range can be manipulated like a normal vector.
521 * If the specified range falls outside that of of the index range of the vector, then the resulting \c vector_range is not a well formed
522 * Vector Expression and access to an element outside of index range of the vector is \b undefined.
526 vector_range<V> project (V &data, typename vector_range<V>::range_type const &r) {
527 return vector_range<V> (data, r);
530 /** \brief Return a \c vector_range on a specified vector and \c range
531 * Return a \c vector_range on a specified vector and \c range. The resulting \c vector_range can be manipulated like a normal vector.
532 * If the specified range falls outside that of of the index range of the vector, then the resulting \c vector_range is not a well formed
533 * Vector Expression and access to an element outside of index range of the vector is \b undefined.
537 const vector_range<const V> project (const V &data, typename vector_range<V>::range_type const &r) {
538 // ISSUE was: return vector_range<V> (const_cast<V &> (data), r);
539 return vector_range<const V> (data, r);
542 /** \brief Return a \c const \c vector_range on a specified vector and const \c range
543 * Return a \c const \c vector_range on a specified vector and const \c range. The resulting \c vector_range can be manipulated like a normal vector.
544 * If the specified range falls outside that of of the index range of the vector, then the resulting \c vector_range is not a well formed
545 * Vector Expression and access to an element outside of index range of the vector is \b undefined.
549 vector_range<V> project (vector_range<V> &data, const typename vector_range<V>::range_type &r) {
550 return data.project (r);
553 /** \brief Return a \c vector_range on a specified vector and const \c range
554 * Return a \c vector_range on a specified vector and const \c range. The resulting \c vector_range can be manipulated like a normal vector.
555 * If the specified range falls outside that of of the index range of the vector, then the resulting \c vector_range is not a well formed
556 * Vector Expression and access to an element outside of index range of the vector is \b undefined.
560 const vector_range<V> project (const vector_range<V> &data, const typename vector_range<V>::range_type &r) {
561 return data.project (r);
564 // Specialization of temporary_traits
566 struct vector_temporary_traits< vector_range<V> >
567 : vector_temporary_traits< V > {} ;
569 struct vector_temporary_traits< const vector_range<V> >
570 : vector_temporary_traits< V > {} ;
573 /** \brief A vector referencing a non continuous subvector of elements of vector v containing all elements specified by \c slice.
575 * A vector slice can be used as a normal vector in any expression.
576 * If the specified slice falls outside that of the index slice of the vector, then
577 * the \c vector_slice is not a well formed \i Vector \i Expression and access to an
578 * element outside of index slice of the vector is \b undefined.
580 * A slice is a generalization of a range. In a range going from \f$a\f$ to \f$b\f$,
581 * all elements belong to the range. In a slice, a \i \f$step\f$ can be specified meaning to
582 * take one element over \f$step\f$ in the range specified from \f$a\f$ to \f$b\f$.
583 * Obviously, a slice with a \f$step\f$ of 1 is equivalent to a range.
585 * \tparam V the type of vector referenced (for example \c vector<double>)
589 public vector_expression<vector_slice<V> > {
591 typedef vector_slice<V> self_type;
593 #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS
594 using vector_expression<self_type>::operator ();
596 typedef const V const_vector_type;
597 typedef V vector_type;
598 typedef typename V::size_type size_type;
599 typedef typename V::difference_type difference_type;
600 typedef typename V::value_type value_type;
601 typedef typename V::const_reference const_reference;
602 typedef typename boost::mpl::if_<boost::is_const<V>,
603 typename V::const_reference,
604 typename V::reference>::type reference;
605 typedef typename boost::mpl::if_<boost::is_const<V>,
606 typename V::const_closure_type,
607 typename V::closure_type>::type vector_closure_type;
608 typedef basic_range<size_type, difference_type> range_type;
609 typedef basic_slice<size_type, difference_type> slice_type;
610 typedef const self_type const_closure_type;
611 typedef self_type closure_type;
612 typedef typename storage_restrict_traits<typename V::storage_category,
613 dense_proxy_tag>::storage_category storage_category;
615 // Construction and destruction
617 vector_slice (vector_type &data, const slice_type &s):
618 data_ (data), s_ (s.preprocess (data.size ())) {
619 // Early checking of preconditions here.
620 // BOOST_UBLAS_CHECK (s_.start () <= data_.size () &&
621 // s_.start () + s_.stride () * (s_.size () - (s_.size () > 0)) <= data_.size (), bad_index ());
624 vector_slice (const vector_closure_type &data, const slice_type &s, int):
625 data_ (data), s_ (s.preprocess (data.size ())) {
626 // Early checking of preconditions here.
627 // BOOST_UBLAS_CHECK (s_.start () <= data_.size () &&
628 // s_.start () + s_.stride () * (s_.size () - (s_.size () > 0)) <= data_.size (), bad_index ());
633 size_type start () const {
637 difference_type stride () const {
641 size_type size () const {
647 const vector_closure_type &data () const {
651 vector_closure_type &data () {
656 #ifndef BOOST_UBLAS_PROXY_CONST_MEMBER
658 const_reference operator () (size_type i) const {
659 return data_ (s_ (i));
662 reference operator () (size_type i) {
663 return data_ (s_ (i));
667 const_reference operator [] (size_type i) const {
671 reference operator [] (size_type i) {
676 reference operator () (size_type i) const {
677 return data_ (s_ (i));
681 reference operator [] (size_type i) const {
686 // ISSUE can this be done in free project function?
687 // Although a const function can create a non-const proxy to a non-const object
688 // Critical is that vector_type and data_ (vector_closure_type) are const correct
690 vector_slice<vector_type> project (const range_type &r) const {
691 return vector_slice<vector_type> (data_, s_.compose (r.preprocess (data_.size ())), false);
694 vector_slice<vector_type> project (const slice_type &s) const {
695 return vector_slice<vector_type> (data_, s_.compose (s.preprocess (data_.size ())), false);
700 vector_slice &operator = (const vector_slice &vs) {
701 // ISSUE need a temporary, proxy can be overlaping alias
702 vector_assign<scalar_assign> (*this, typename vector_temporary_traits<V>::type (vs));
706 vector_slice &assign_temporary (vector_slice &vs) {
707 // assign elements, proxied container remains the same
708 vector_assign<scalar_assign> (*this, vs);
713 vector_slice &operator = (const vector_expression<AE> &ae) {
714 vector_assign<scalar_assign> (*this, typename vector_temporary_traits<V>::type (ae));
719 vector_slice &assign (const vector_expression<AE> &ae) {
720 vector_assign<scalar_assign> (*this, ae);
725 vector_slice &operator += (const vector_expression<AE> &ae) {
726 vector_assign<scalar_assign> (*this, typename vector_temporary_traits<V>::type (*this + ae));
731 vector_slice &plus_assign (const vector_expression<AE> &ae) {
732 vector_assign<scalar_plus_assign> (*this, ae);
737 vector_slice &operator -= (const vector_expression<AE> &ae) {
738 vector_assign<scalar_assign> (*this, typename vector_temporary_traits<V>::type (*this - ae));
743 vector_slice &minus_assign (const vector_expression<AE> &ae) {
744 vector_assign<scalar_minus_assign> (*this, ae);
749 vector_slice &operator *= (const AT &at) {
750 vector_assign_scalar<scalar_multiplies_assign> (*this, at);
755 vector_slice &operator /= (const AT &at) {
756 vector_assign_scalar<scalar_divides_assign> (*this, at);
760 // Closure comparison
762 bool same_closure (const vector_slice &vr) const {
763 return (*this).data_.same_closure (vr.data_);
768 bool operator == (const vector_slice &vs) const {
769 return (*this).data_ == vs.data_ && s_ == vs.s_;
774 void swap (vector_slice vs) {
776 BOOST_UBLAS_CHECK (size () == vs.size (), bad_size ());
777 // Sparse ranges may be nonconformant now.
778 // std::swap_ranges (begin (), end (), vs.begin ());
779 vector_swap<scalar_swap> (*this, vs);
783 friend void swap (vector_slice vs1, vector_slice vs2) {
789 // Use slice as an index - FIXME this fails for packed assignment
790 typedef typename slice_type::const_iterator const_subiterator_type;
791 typedef typename slice_type::const_iterator subiterator_type;
794 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
795 typedef indexed_iterator<vector_slice<vector_type>,
796 typename vector_type::iterator::iterator_category> iterator;
797 typedef indexed_const_iterator<vector_slice<vector_type>,
798 typename vector_type::const_iterator::iterator_category> const_iterator;
800 class const_iterator;
806 const_iterator find (size_type i) const {
807 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
808 return const_iterator (*this, i);
810 return const_iterator (*this, s_.begin () + i);
814 iterator find (size_type i) {
815 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
816 return iterator (*this, i);
818 return iterator (*this, s_.begin () + i);
822 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
823 class const_iterator:
824 public container_const_reference<vector_slice>,
825 public iterator_base_traits<typename V::const_iterator::iterator_category>::template
826 iterator_base<const_iterator, value_type>::type {
828 typedef typename V::const_iterator::difference_type difference_type;
829 typedef typename V::const_iterator::value_type value_type;
830 typedef typename V::const_reference reference; //FIXME due to indexing access
831 typedef typename V::const_iterator::pointer pointer;
833 // Construction and destruction
836 container_const_reference<self_type> (), it_ () {}
838 const_iterator (const self_type &vs, const const_subiterator_type &it):
839 container_const_reference<self_type> (vs), it_ (it) {}
841 const_iterator (const typename self_type::iterator &it): // ISSUE self_type:: stops VC8 using std::iterator here
842 container_const_reference<self_type> (it ()), it_ (it.it_) {}
846 const_iterator &operator ++ () {
851 const_iterator &operator -- () {
856 const_iterator &operator += (difference_type n) {
861 const_iterator &operator -= (difference_type n) {
866 difference_type operator - (const const_iterator &it) const {
867 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
873 const_reference operator * () const {
874 // FIXME replace find with at_element
875 BOOST_UBLAS_CHECK (index () < (*this) ().size (), bad_index ());
876 return (*this) ().data_ (*it_);
879 const_reference operator [] (difference_type n) const {
885 size_type index () const {
891 const_iterator &operator = (const const_iterator &it) {
892 container_const_reference<self_type>::assign (&it ());
899 bool operator == (const const_iterator &it) const {
900 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
901 return it_ == it.it_;
904 bool operator < (const const_iterator &it) const {
905 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
910 const_subiterator_type it_;
915 const_iterator begin () const {
919 const_iterator end () const {
920 return find (size ());
923 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
925 public container_reference<vector_slice>,
926 public iterator_base_traits<typename V::iterator::iterator_category>::template
927 iterator_base<iterator, value_type>::type {
929 typedef typename V::iterator::difference_type difference_type;
930 typedef typename V::iterator::value_type value_type;
931 typedef typename V::reference reference; //FIXME due to indexing access
932 typedef typename V::iterator::pointer pointer;
934 // Construction and destruction
937 container_reference<self_type> (), it_ () {}
939 iterator (self_type &vs, const subiterator_type &it):
940 container_reference<self_type> (vs), it_ (it) {}
944 iterator &operator ++ () {
949 iterator &operator -- () {
954 iterator &operator += (difference_type n) {
959 iterator &operator -= (difference_type n) {
964 difference_type operator - (const iterator &it) const {
965 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
971 reference operator * () const {
972 // FIXME replace find with at_element
973 BOOST_UBLAS_CHECK (index () < (*this) ().size (), bad_index ());
974 return (*this) ().data_ (*it_);
977 reference operator [] (difference_type n) const {
984 size_type index () const {
990 iterator &operator = (const iterator &it) {
991 container_reference<self_type>::assign (&it ());
998 bool operator == (const iterator &it) const {
999 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
1000 return it_ == it.it_;
1003 bool operator < (const iterator &it) const {
1004 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
1005 return it_ < it.it_;
1009 subiterator_type it_;
1011 friend class const_iterator;
1021 return find (size ());
1025 typedef reverse_iterator_base<const_iterator> const_reverse_iterator;
1026 typedef reverse_iterator_base<iterator> reverse_iterator;
1029 const_reverse_iterator rbegin () const {
1030 return const_reverse_iterator (end ());
1033 const_reverse_iterator rend () const {
1034 return const_reverse_iterator (begin ());
1037 reverse_iterator rbegin () {
1038 return reverse_iterator (end ());
1041 reverse_iterator rend () {
1042 return reverse_iterator (begin ());
1046 vector_closure_type data_;
1050 // Simple Projections
1053 vector_slice<V> subslice (V &data, typename V::size_type start, typename V::difference_type stride, typename V::size_type size) {
1054 typedef basic_slice<typename V::size_type, typename V::difference_type> slice_type;
1055 return vector_slice<V> (data, slice_type (start, stride, size));
1059 vector_slice<const V> subslice (const V &data, typename V::size_type start, typename V::difference_type stride, typename V::size_type size) {
1060 typedef basic_slice<typename V::size_type, typename V::difference_type> slice_type;
1061 return vector_slice<const V> (data, slice_type (start, stride, size));
1064 // Generic Projections
1067 vector_slice<V> project (V &data, const typename vector_slice<V>::slice_type &s) {
1068 return vector_slice<V> (data, s);
1072 const vector_slice<const V> project (const V &data, const typename vector_slice<V>::slice_type &s) {
1073 // ISSUE was: return vector_slice<V> (const_cast<V &> (data), s);
1074 return vector_slice<const V> (data, s);
1078 vector_slice<V> project (vector_slice<V> &data, const typename vector_slice<V>::slice_type &s) {
1079 return data.project (s);
1083 const vector_slice<V> project (const vector_slice<V> &data, const typename vector_slice<V>::slice_type &s) {
1084 return data.project (s);
1086 // ISSUE in the following two functions it would be logical to use vector_slice<V>::range_type but this confuses VC7.1 and 8.0
1089 vector_slice<V> project (vector_slice<V> &data, const typename vector_range<V>::range_type &r) {
1090 return data.project (r);
1094 const vector_slice<V> project (const vector_slice<V> &data, const typename vector_range<V>::range_type &r) {
1095 return data.project (r);
1098 // Specialization of temporary_traits
1100 struct vector_temporary_traits< vector_slice<V> >
1101 : vector_temporary_traits< V > {} ;
1103 struct vector_temporary_traits< const vector_slice<V> >
1104 : vector_temporary_traits< V > {} ;
1107 // Vector based indirection class
1108 // Contributed by Toon Knapen.
1109 // Extended and optimized by Kresimir Fresl.
1111 /** \brief A vector referencing a non continuous subvector of elements given another vector of indices.
1113 * It is the most general version of any subvectors because it uses another vector of indices to reference
1116 * The vector of indices can be of any type with the restriction that its elements must be
1117 * type-compatible with the size_type \c of the container. In practice, the following are good candidates:
1118 * - \c boost::numeric::ublas::indirect_array<A> where \c A can be \c int, \c size_t, \c long, etc...
1119 * - \c std::vector<A> where \c A can \c int, \c size_t, \c long, etc...
1120 * - \c boost::numeric::ublas::vector<int> can work too (\c int can be replaced by another integer type)
1123 * An indirect vector can be used as a normal vector in any expression. If the specified indirect vector
1124 * falls outside that of the indices of the vector, then the \c vector_indirect is not a well formed
1125 * \i Vector \i Expression and access to an element outside of indices of the vector is \b undefined.
1127 * \tparam V the type of vector referenced (for example \c vector<double>)
1128 * \tparam IA the type of index vector. Default is \c ublas::indirect_array<>
1130 template<class V, class IA>
1131 class vector_indirect:
1132 public vector_expression<vector_indirect<V, IA> > {
1134 typedef vector_indirect<V, IA> self_type;
1136 #ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS
1137 using vector_expression<self_type>::operator ();
1139 typedef const V const_vector_type;
1140 typedef V vector_type;
1141 typedef const IA const_indirect_array_type;
1142 typedef IA indirect_array_type;
1143 typedef typename V::size_type size_type;
1144 typedef typename V::difference_type difference_type;
1145 typedef typename V::value_type value_type;
1146 typedef typename V::const_reference const_reference;
1147 typedef typename boost::mpl::if_<boost::is_const<V>,
1148 typename V::const_reference,
1149 typename V::reference>::type reference;
1150 typedef typename boost::mpl::if_<boost::is_const<V>,
1151 typename V::const_closure_type,
1152 typename V::closure_type>::type vector_closure_type;
1153 typedef basic_range<size_type, difference_type> range_type;
1154 typedef basic_slice<size_type, difference_type> slice_type;
1155 typedef const self_type const_closure_type;
1156 typedef self_type closure_type;
1157 typedef typename storage_restrict_traits<typename V::storage_category,
1158 dense_proxy_tag>::storage_category storage_category;
1160 // Construction and destruction
1162 vector_indirect (vector_type &data, size_type size):
1163 data_ (data), ia_ (size) {}
1165 vector_indirect (vector_type &data, const indirect_array_type &ia):
1166 data_ (data), ia_ (ia.preprocess (data.size ())) {}
1168 vector_indirect (const vector_closure_type &data, const indirect_array_type &ia, int):
1169 data_ (data), ia_ (ia.preprocess (data.size ())) {}
1173 size_type size () const {
1177 const_indirect_array_type &indirect () const {
1181 indirect_array_type &indirect () {
1185 // Storage accessors
1187 const vector_closure_type &data () const {
1191 vector_closure_type &data () {
1196 #ifndef BOOST_UBLAS_PROXY_CONST_MEMBER
1198 const_reference operator () (size_type i) const {
1199 return data_ (ia_ (i));
1202 reference operator () (size_type i) {
1203 return data_ (ia_ (i));
1207 const_reference operator [] (size_type i) const {
1211 reference operator [] (size_type i) {
1216 reference operator () (size_type i) const {
1217 return data_ (ia_ (i));
1221 reference operator [] (size_type i) const {
1226 // ISSUE can this be done in free project function?
1227 // Although a const function can create a non-const proxy to a non-const object
1228 // Critical is that vector_type and data_ (vector_closure_type) are const correct
1230 vector_indirect<vector_type, indirect_array_type> project (const range_type &r) const {
1231 return vector_indirect<vector_type, indirect_array_type> (data_, ia_.compose (r.preprocess (data_.size ())), 0);
1234 vector_indirect<vector_type, indirect_array_type> project (const slice_type &s) const {
1235 return vector_indirect<vector_type, indirect_array_type> (data_, ia_.compose (s.preprocess (data_.size ())), 0);
1238 vector_indirect<vector_type, indirect_array_type> project (const indirect_array_type &ia) const {
1239 return vector_indirect<vector_type, indirect_array_type> (data_, ia_.compose (ia.preprocess (data_.size ())), 0);
1244 vector_indirect &operator = (const vector_indirect &vi) {
1245 // ISSUE need a temporary, proxy can be overlaping alias
1246 vector_assign<scalar_assign> (*this, typename vector_temporary_traits<V>::type (vi));
1250 vector_indirect &assign_temporary (vector_indirect &vi) {
1251 // assign elements, proxied container remains the same
1252 vector_assign<scalar_assign> (*this, vi);
1257 vector_indirect &operator = (const vector_expression<AE> &ae) {
1258 vector_assign<scalar_assign> (*this, typename vector_temporary_traits<V>::type (ae));
1263 vector_indirect &assign (const vector_expression<AE> &ae) {
1264 vector_assign<scalar_assign> (*this, ae);
1269 vector_indirect &operator += (const vector_expression<AE> &ae) {
1270 vector_assign<scalar_assign> (*this, typename vector_temporary_traits<V>::type (*this + ae));
1275 vector_indirect &plus_assign (const vector_expression<AE> &ae) {
1276 vector_assign<scalar_plus_assign> (*this, ae);
1281 vector_indirect &operator -= (const vector_expression<AE> &ae) {
1282 vector_assign<scalar_assign> (*this, typename vector_temporary_traits<V>::type (*this - ae));
1287 vector_indirect &minus_assign (const vector_expression<AE> &ae) {
1288 vector_assign<scalar_minus_assign> (*this, ae);
1293 vector_indirect &operator *= (const AT &at) {
1294 vector_assign_scalar<scalar_multiplies_assign> (*this, at);
1299 vector_indirect &operator /= (const AT &at) {
1300 vector_assign_scalar<scalar_divides_assign> (*this, at);
1304 // Closure comparison
1306 bool same_closure (const vector_indirect &vr) const {
1312 bool operator == (const vector_indirect &vi) const {
1313 return (*this).data_ == vi.data_ && ia_ == vi.ia_;
1318 void swap (vector_indirect vi) {
1320 BOOST_UBLAS_CHECK (size () == vi.size (), bad_size ());
1321 // Sparse ranges may be nonconformant now.
1322 // std::swap_ranges (begin (), end (), vi.begin ());
1323 vector_swap<scalar_swap> (*this, vi);
1327 friend void swap (vector_indirect vi1, vector_indirect vi2) {
1333 // Use indirect array as an index - FIXME this fails for packed assignment
1334 typedef typename IA::const_iterator const_subiterator_type;
1335 typedef typename IA::const_iterator subiterator_type;
1338 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
1339 typedef indexed_iterator<vector_indirect<vector_type, indirect_array_type>,
1340 typename vector_type::iterator::iterator_category> iterator;
1341 typedef indexed_const_iterator<vector_indirect<vector_type, indirect_array_type>,
1342 typename vector_type::const_iterator::iterator_category> const_iterator;
1344 class const_iterator;
1349 const_iterator find (size_type i) const {
1350 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
1351 return const_iterator (*this, i);
1353 return const_iterator (*this, ia_.begin () + i);
1357 iterator find (size_type i) {
1358 #ifdef BOOST_UBLAS_USE_INDEXED_ITERATOR
1359 return iterator (*this, i);
1361 return iterator (*this, ia_.begin () + i);
1365 // Iterators simply are indices.
1367 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
1368 class const_iterator:
1369 public container_const_reference<vector_indirect>,
1370 public iterator_base_traits<typename V::const_iterator::iterator_category>::template
1371 iterator_base<const_iterator, value_type>::type {
1373 typedef typename V::const_iterator::difference_type difference_type;
1374 typedef typename V::const_iterator::value_type value_type;
1375 typedef typename V::const_reference reference; //FIXME due to indexing access
1376 typedef typename V::const_iterator::pointer pointer;
1378 // Construction and destruction
1381 container_const_reference<self_type> (), it_ () {}
1383 const_iterator (const self_type &vi, const const_subiterator_type &it):
1384 container_const_reference<self_type> (vi), it_ (it) {}
1386 const_iterator (const typename self_type::iterator &it): // ISSUE self_type:: stops VC8 using std::iterator here
1387 container_const_reference<self_type> (it ()), it_ (it.it_) {}
1391 const_iterator &operator ++ () {
1396 const_iterator &operator -- () {
1401 const_iterator &operator += (difference_type n) {
1406 const_iterator &operator -= (difference_type n) {
1411 difference_type operator - (const const_iterator &it) const {
1412 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
1413 return it_ - it.it_;
1418 const_reference operator * () const {
1419 // FIXME replace find with at_element
1420 BOOST_UBLAS_CHECK (index () < (*this) ().size (), bad_index ());
1421 return (*this) ().data_ (*it_);
1424 const_reference operator [] (difference_type n) const {
1425 return *(*this + n);
1430 size_type index () const {
1431 return it_.index ();
1436 const_iterator &operator = (const const_iterator &it) {
1437 container_const_reference<self_type>::assign (&it ());
1444 bool operator == (const const_iterator &it) const {
1445 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
1446 return it_ == it.it_;
1449 bool operator < (const const_iterator &it) const {
1450 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
1451 return it_ < it.it_;
1455 const_subiterator_type it_;
1460 const_iterator begin () const {
1464 const_iterator end () const {
1465 return find (size ());
1468 #ifndef BOOST_UBLAS_USE_INDEXED_ITERATOR
1470 public container_reference<vector_indirect>,
1471 public iterator_base_traits<typename V::iterator::iterator_category>::template
1472 iterator_base<iterator, value_type>::type {
1474 typedef typename V::iterator::difference_type difference_type;
1475 typedef typename V::iterator::value_type value_type;
1476 typedef typename V::reference reference; //FIXME due to indexing access
1477 typedef typename V::iterator::pointer pointer;
1479 // Construction and destruction
1482 container_reference<self_type> (), it_ () {}
1484 iterator (self_type &vi, const subiterator_type &it):
1485 container_reference<self_type> (vi), it_ (it) {}
1489 iterator &operator ++ () {
1494 iterator &operator -- () {
1499 iterator &operator += (difference_type n) {
1504 iterator &operator -= (difference_type n) {
1509 difference_type operator - (const iterator &it) const {
1510 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
1511 return it_ - it.it_;
1516 reference operator * () const {
1517 // FIXME replace find with at_element
1518 BOOST_UBLAS_CHECK (index () < (*this) ().size (), bad_index ());
1519 return (*this) ().data_ (*it_);
1522 reference operator [] (difference_type n) const {
1523 return *(*this + n);
1528 size_type index () const {
1529 return it_.index ();
1534 iterator &operator = (const iterator &it) {
1535 container_reference<self_type>::assign (&it ());
1542 bool operator == (const iterator &it) const {
1543 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
1544 return it_ == it.it_;
1547 bool operator < (const iterator &it) const {
1548 BOOST_UBLAS_CHECK ((*this) ().same_closure (it ()), external_logic ());
1549 return it_ < it.it_;
1553 subiterator_type it_;
1555 friend class const_iterator;
1565 return find (size ());
1569 typedef reverse_iterator_base<const_iterator> const_reverse_iterator;
1570 typedef reverse_iterator_base<iterator> reverse_iterator;
1573 const_reverse_iterator rbegin () const {
1574 return const_reverse_iterator (end ());
1577 const_reverse_iterator rend () const {
1578 return const_reverse_iterator (begin ());
1581 reverse_iterator rbegin () {
1582 return reverse_iterator (end ());
1585 reverse_iterator rend () {
1586 return reverse_iterator (begin ());
1590 vector_closure_type data_;
1591 indirect_array_type ia_;
1595 template<class V, class A>
1597 vector_indirect<V, indirect_array<A> > project (V &data, const indirect_array<A> &ia) {
1598 return vector_indirect<V, indirect_array<A> > (data, ia);
1600 template<class V, class A>
1602 const vector_indirect<const V, indirect_array<A> > project (const V &data, const indirect_array<A> &ia) {
1603 // ISSUE was: return vector_indirect<V, indirect_array<A> > (const_cast<V &> (data), ia)
1604 return vector_indirect<const V, indirect_array<A> > (data, ia);
1606 template<class V, class IA>
1608 vector_indirect<V, IA> project (vector_indirect<V, IA> &data, const typename vector_indirect<V, IA>::range_type &r) {
1609 return data.project (r);
1611 template<class V, class IA>
1613 const vector_indirect<V, IA> project (const vector_indirect<V, IA> &data, const typename vector_indirect<V, IA>::range_type &r) {
1614 return data.project (r);
1616 template<class V, class IA>
1618 vector_indirect<V, IA> project (vector_indirect<V, IA> &data, const typename vector_indirect<V, IA>::slice_type &s) {
1619 return data.project (s);
1621 template<class V, class IA>
1623 const vector_indirect<V, IA> project (const vector_indirect<V, IA> &data, const typename vector_indirect<V, IA>::slice_type &s) {
1624 return data.project (s);
1626 template<class V, class A>
1628 vector_indirect<V, indirect_array<A> > project (vector_indirect<V, indirect_array<A> > &data, const indirect_array<A> &ia) {
1629 return data.project (ia);
1631 template<class V, class A>
1633 const vector_indirect<V, indirect_array<A> > project (const vector_indirect<V, indirect_array<A> > &data, const indirect_array<A> &ia) {
1634 return data.project (ia);
1637 // Specialization of temporary_traits
1639 struct vector_temporary_traits< vector_indirect<V> >
1640 : vector_temporary_traits< V > {} ;
1642 struct vector_temporary_traits< const vector_indirect<V> >
1643 : vector_temporary_traits< V > {} ;