1//
2// Copyright (c) 2003
3// Gunter Winkler, Joerg Walter
4//
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)
8//
9// The authors gratefully acknowledge the support of
10// GeNeSys mbH & Co. KG in producing this work.
11//
12
13#ifndef _BOOST_UBLAS_VECTOR_OF_VECTOR_
14#define _BOOST_UBLAS_VECTOR_OF_VECTOR_
15
16#include <boost/type_traits.hpp>
17
18#include <boost/numeric/ublas/storage_sparse.hpp>
19#include <boost/numeric/ublas/matrix_sparse.hpp>
20
21// Iterators based on ideas of Jeremy Siek
22
23namespace boost { namespace numeric { namespace ublas {
24
25 // uBLAS sparse vector based sparse matrix class
26 // FIXME outer vector can be sparse type but it is completely filled
27 template<class T, class L, class A>
28 class generalized_vector_of_vector:
29 public matrix_container<generalized_vector_of_vector<T, L, A> > {
30
31 typedef T &true_reference;
32 typedef T *pointer;
33 typedef const T *const_pointer;
34 typedef L layout_type;
35 typedef generalized_vector_of_vector<T, L, A> self_type;
36 public:
37#ifdef BOOST_UBLAS_ENABLE_PROXY_SHORTCUTS
38 using matrix_container<self_type>::operator ();
39#endif
40 typedef typename A::size_type size_type;
41 typedef typename A::difference_type difference_type;
42 typedef T value_type;
43 typedef const T &const_reference;
44#ifndef BOOST_UBLAS_STRICT_VECTOR_SPARSE
45 typedef T &reference;
46#else
47 typedef sparse_matrix_element<self_type> reference;
48#endif
49 typedef A array_type;
50 typedef const matrix_reference<const self_type> const_closure_type;
51 typedef matrix_reference<self_type> closure_type;
52 typedef typename A::value_type vector_data_value_type;
53 typedef vector_data_value_type vector_temporary_type;
54 typedef self_type matrix_temporary_type;
55 typedef sparse_tag storage_category;
56 typedef typename L::orientation_category orientation_category;
57
58 // Construction and destruction
59 BOOST_UBLAS_INLINE
60 generalized_vector_of_vector ():
61 matrix_container<self_type> (),
62 size1_ (0), size2_ (0), data_ (1) {
63 const size_type sizeM = layout_type::size_M (size1_, size2_);
64 // create size1+1 empty vector elements
65 data_.insert_element (sizeM, vector_data_value_type ());
66 storage_invariants ();
67 }
68 BOOST_UBLAS_INLINE
69 generalized_vector_of_vector (size_type size1, size_type size2, size_type /*non_zeros = 0*/):
70 matrix_container<self_type> (),
71 size1_ (size1), size2_ (size2), data_ (layout_type::size_M (size1_, size2_) + 1) {
72 const size_type sizeM = layout_type::size_M (size1_, size2_);
73 const size_type sizem = layout_type::size_m (size1_, size2_);
74 for (size_type i = 0; i < sizeM; ++ i) // create size1 vector elements
75 data_.insert_element (i, vector_data_value_type ()) .resize (sizem, false);
76 data_.insert_element (sizeM, vector_data_value_type ());
77 storage_invariants ();
78 }
79 BOOST_UBLAS_INLINE
80 generalized_vector_of_vector (const generalized_vector_of_vector &m):
81 matrix_container<self_type> (),
82 size1_ (m.size1_), size2_ (m.size2_), data_ (m.data_) {
83 storage_invariants ();
84 }
85 template<class AE>
86 BOOST_UBLAS_INLINE
87 generalized_vector_of_vector (const matrix_expression<AE> &ae, size_type /*non_zeros = 0*/):
88 matrix_container<self_type> (),
89 size1_ (ae ().size1 ()), size2_ (ae ().size2 ()), data_ (layout_type::size_M (size1_, size2_) + 1) {
90 const size_type sizeM = layout_type::size_M (size1_, size2_);
91 const size_type sizem = layout_type::size_m (size1_, size2_);
92 for (size_type i = 0; i < sizeM; ++ i) // create size1 vector elements
93 data_.insert_element (i, vector_data_value_type ()) .resize (sizem, false);
94 data_.insert_element (sizeM, vector_data_value_type ());
95 storage_invariants ();
96 matrix_assign<scalar_assign> (*this, ae);
97 }
98
99 // Accessors
100 BOOST_UBLAS_INLINE
101 size_type size1 () const {
102 return size1_;
103 }
104 BOOST_UBLAS_INLINE
105 size_type size2 () const {
106 return size2_;
107 }
108 BOOST_UBLAS_INLINE
109 size_type nnz_capacity () const {
110 size_type non_zeros = 0;
111 for (const_vectoriterator_type itv = data_.begin (); itv != data_.end (); ++ itv)
112 non_zeros += (*itv).nnz_capacity ();
113 return non_zeros;
114 }
115 BOOST_UBLAS_INLINE
116 size_type nnz () const {
117 size_type non_zeros = 0;
118 for (const_vectoriterator_type itv = data_.begin (); itv != data_.end (); ++ itv)
119 non_zeros += (*itv).nnz ();
120 return non_zeros;
121 }
122
123 // Storage accessors
124 BOOST_UBLAS_INLINE
125 const array_type &data () const {
126 return data_;
127 }
128 BOOST_UBLAS_INLINE
129 array_type &data () {
130 return data_;
131 }
132
133 // Resizing
134 BOOST_UBLAS_INLINE
135 void resize (size_type size1, size_type size2, bool preserve = true) {
136 const size_type oldM = layout_type::size_M (size1_, size2_);
137 size1_ = size1;
138 size2_ = size2;
139 const size_type sizeM = layout_type::size_M (size1_, size2_);
140 const size_type sizem = layout_type::size_m (size1_, size2_);
141 data ().resize (sizeM + 1, preserve);
142 if (preserve) {
143 for (size_type i = 0; (i <= oldM) && (i < sizeM); ++ i)
144 ref (data () [i]).resize (sizem, preserve);
145 for (size_type i = oldM+1; i < sizeM; ++ i) // create new vector elements
146 data_.insert_element (i, vector_data_value_type ()) .resize (sizem, false);
147 if (sizeM > oldM) {
148 data_.insert_element (sizeM, vector_data_value_type ());
149 } else {
150 ref (data () [sizeM]).resize (0, false);
151 }
152 } else {
153 for (size_type i = 0; i < sizeM; ++ i)
154 data_.insert_element (i, vector_data_value_type ()) .resize (sizem, false);
155 data_.insert_element (sizeM, vector_data_value_type ());
156 }
157 storage_invariants ();
158 }
159
160 // Element support
161 BOOST_UBLAS_INLINE
162 pointer find_element (size_type i, size_type j) {
163 return const_cast<pointer> (const_cast<const self_type&>(*this).find_element (i, j));
164 }
165 BOOST_UBLAS_INLINE
166 const_pointer find_element (size_type i, size_type j) const {
167 const size_type elementM = layout_type::index_M (i, j);
168 const size_type elementm = layout_type::index_m (i, j);
169 // optimise: check the storage_type and index directly if element always exists
170 if (boost::is_convertible<typename array_type::storage_category, packed_tag>::value) {
171 return & (data () [elementM] [elementm]);
172 }
173 else {
174 const typename array_type::value_type *pv = data ().find_element (elementM);
175 if (!pv)
176 return 0;
177 return pv->find_element (elementm);
178 }
179 }
180
181 // Element access
182 BOOST_UBLAS_INLINE
183 const_reference operator () (size_type i, size_type j) const {
184 const_pointer p = find_element (i, j);
185 // optimise: check the storage_type and index directly if element always exists
186 if (boost::is_convertible<typename array_type::storage_category, packed_tag>::value) {
187 BOOST_UBLAS_CHECK (p, internal_logic () );
188 return *p;
189 }
190 else {
191 if (p)
192 return *p;
193 else
194 return zero_;
195 }
196 }
197 BOOST_UBLAS_INLINE
198 reference operator () (size_type i, size_type j) {
199#ifndef BOOST_UBLAS_STRICT_MATRIX_SPARSE
200 return at_element (i, j);
201#else
202 return reference (*this, i, j);
203#endif
204 }
205
206 // Assignment
207 BOOST_UBLAS_INLINE
208 generalized_vector_of_vector &operator = (const generalized_vector_of_vector &m) {
209 if (this != &m) {
210 size1_ = m.size1_;
211 size2_ = m.size2_;
212 data () = m.data ();
213 }
214 storage_invariants ();
215 return *this;
216 }
217 BOOST_UBLAS_INLINE
218 generalized_vector_of_vector &assign_temporary (generalized_vector_of_vector &m) {
219 swap (m);
220 return *this;
221 }
222 template<class AE>
223 BOOST_UBLAS_INLINE
224 generalized_vector_of_vector &operator = (const matrix_expression<AE> &ae) {
225 self_type temporary (ae);
226 return assign_temporary (m&: temporary);
227 }
228 template<class AE>
229 BOOST_UBLAS_INLINE
230 generalized_vector_of_vector &assign (const matrix_expression<AE> &ae) {
231 matrix_assign<scalar_assign> (*this, ae);
232 return *this;
233 }
234 template<class AE>
235 BOOST_UBLAS_INLINE
236 generalized_vector_of_vector& operator += (const matrix_expression<AE> &ae) {
237 self_type temporary (*this + ae);
238 return assign_temporary (m&: temporary);
239 }
240 template<class AE>
241 BOOST_UBLAS_INLINE
242 generalized_vector_of_vector &plus_assign (const matrix_expression<AE> &ae) {
243 matrix_assign<scalar_plus_assign> (*this, ae);
244 return *this;
245 }
246 template<class AE>
247 BOOST_UBLAS_INLINE
248 generalized_vector_of_vector& operator -= (const matrix_expression<AE> &ae) {
249 self_type temporary (*this - ae);
250 return assign_temporary (m&: temporary);
251 }
252 template<class AE>
253 BOOST_UBLAS_INLINE
254 generalized_vector_of_vector &minus_assign (const matrix_expression<AE> &ae) {
255 matrix_assign<scalar_minus_assign> (*this, ae);
256 return *this;
257 }
258 template<class AT>
259 BOOST_UBLAS_INLINE
260 generalized_vector_of_vector& operator *= (const AT &at) {
261 matrix_assign_scalar<scalar_multiplies_assign> (*this, at);
262 return *this;
263 }
264 template<class AT>
265 BOOST_UBLAS_INLINE
266 generalized_vector_of_vector& operator /= (const AT &at) {
267 matrix_assign_scalar<scalar_divides_assign> (*this, at);
268 return *this;
269 }
270
271 // Swapping
272 BOOST_UBLAS_INLINE
273 void swap (generalized_vector_of_vector &m) {
274 if (this != &m) {
275 std::swap (size1_, m.size1_);
276 std::swap (size2_, m.size2_);
277 data ().swap (m.data ());
278 }
279 storage_invariants ();
280 }
281 BOOST_UBLAS_INLINE
282 friend void swap (generalized_vector_of_vector &m1, generalized_vector_of_vector &m2) {
283 m1.swap (m2);
284 }
285
286 // Sorting
287 void sort () {
288 vectoriterator_type itv (data ().begin ());
289 vectoriterator_type itv_end (data ().end ());
290 while (itv != itv_end) {
291 (*itv).sort ();
292 ++ itv;
293 }
294 }
295
296 // Element insertion and erasure
297 BOOST_UBLAS_INLINE
298 true_reference insert_element (size_type i, size_type j, const_reference t) {
299 const size_type elementM = layout_type::index_M (i, j);
300 const size_type elementm = layout_type::index_m (i, j);
301 vector_data_value_type& vd (ref (data () [elementM]));
302 storage_invariants ();
303 return vd.insert_element (elementm, t);
304 }
305 BOOST_UBLAS_INLINE
306 void append_element (size_type i, size_type j, const_reference t) {
307 const size_type elementM = layout_type::index_M (i, j);
308 const size_type elementm = layout_type::index_m (i, j);
309 vector_data_value_type& vd (ref (data () [elementM]));
310 storage_invariants ();
311 return vd.append_element (elementm, t);
312 }
313 BOOST_UBLAS_INLINE
314 void erase_element (size_type i, size_type j) {
315 vectoriterator_type itv (data ().find (layout_type::index_M (i, j)));
316 if (itv == data ().end ())
317 return;
318 (*itv).erase_element (layout_type::index_m (i, j));
319 storage_invariants ();
320 }
321 BOOST_UBLAS_INLINE
322 void clear () {
323 const size_type sizeM = layout_type::size_M (size1_, size2_);
324 // FIXME should clear data () if this is done via value_type/*zero*/() then it is not size preserving
325 for (size_type i = 0; i < sizeM; ++ i)
326 ref (data () [i]).clear ();
327 storage_invariants ();
328 }
329
330 // Iterator types
331 private:
332 // Use vector iterator
333 typedef typename A::const_iterator const_vectoriterator_type;
334 typedef typename A::iterator vectoriterator_type;
335 typedef typename A::value_type::const_iterator const_subiterator_type;
336 typedef typename A::value_type::iterator subiterator_type;
337
338 BOOST_UBLAS_INLINE
339 true_reference at_element (size_type i, size_type j) {
340 return ref (ref (data () [layout_type::index_M (i, j)]) [layout_type::index_m (i, j)]);
341 }
342
343 public:
344 class const_iterator1;
345 class iterator1;
346 class const_iterator2;
347 class iterator2;
348 typedef reverse_iterator_base1<const_iterator1> const_reverse_iterator1;
349 typedef reverse_iterator_base1<iterator1> reverse_iterator1;
350 typedef reverse_iterator_base2<const_iterator2> const_reverse_iterator2;
351 typedef reverse_iterator_base2<iterator2> reverse_iterator2;
352
353 // Element lookup
354 // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
355 const_iterator1 find1 (int rank, size_type i, size_type j, int direction = 1) const {
356 for (;;) {
357 const_vectoriterator_type itv (data ().find (layout_type::index_M (i, j)));
358 const_vectoriterator_type itv_end (data ().end ());
359 if (itv == itv_end)
360 return const_iterator1 (*this, rank, i, j, itv_end, (*(-- itv)).end ());
361
362 const_subiterator_type it ((*itv).find (layout_type::index_m (i, j)));
363 const_subiterator_type it_end ((*itv).end ());
364 if (rank == 0)
365 return const_iterator1 (*this, rank, i, j, itv, it);
366 if (it != it_end && it.index () == layout_type::index_m (i, j))
367 return const_iterator1 (*this, rank, i, j, itv, it);
368 if (direction > 0) {
369 if (layout_type::fast_i ()) {
370 if (it == it_end)
371 return const_iterator1 (*this, rank, i, j, itv, it);
372 i = it.index ();
373 } else {
374 if (i >= size1_)
375 return const_iterator1 (*this, rank, i, j, itv, it);
376 ++ i;
377 }
378 } else /* if (direction < 0) */ {
379 if (layout_type::fast_i ()) {
380 if (it == (*itv).begin ())
381 return const_iterator1 (*this, rank, i, j, itv, it);
382 --it;
383 i = it.index ();
384 } else {
385 if (i == 0)
386 return const_iterator1 (*this, rank, i, j, itv, it);
387 -- i;
388 }
389 }
390 }
391 }
392 // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
393 iterator1 find1 (int rank, size_type i, size_type j, int direction = 1) {
394 for (;;) {
395 vectoriterator_type itv (data ().find (layout_type::index_M (i, j)));
396 vectoriterator_type itv_end (data ().end ());
397 if (itv == itv_end)
398 return iterator1 (*this, rank, i, j, itv_end, (*(-- itv)).end ());
399
400 subiterator_type it ((*itv).find (layout_type::index_m (i, j)));
401 subiterator_type it_end ((*itv).end ());
402 if (rank == 0)
403 return iterator1 (*this, rank, i, j, itv, it);
404 if (it != it_end && it.index () == layout_type::index_m (i, j))
405 return iterator1 (*this, rank, i, j, itv, it);
406 if (direction > 0) {
407 if (layout_type::fast_i ()) {
408 if (it == it_end)
409 return iterator1 (*this, rank, i, j, itv, it);
410 i = it.index ();
411 } else {
412 if (i >= size1_)
413 return iterator1 (*this, rank, i, j, itv, it);
414 ++ i;
415 }
416 } else /* if (direction < 0) */ {
417 if (layout_type::fast_i ()) {
418 if (it == (*itv).begin ())
419 return iterator1 (*this, rank, i, j, itv, it);
420 --it;
421 i = it.index ();
422 } else {
423 if (i == 0)
424 return iterator1 (*this, rank, i, j, itv, it);
425 -- i;
426 }
427 }
428 }
429 }
430 // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
431 const_iterator2 find2 (int rank, size_type i, size_type j, int direction = 1) const {
432 for (;;) {
433 const_vectoriterator_type itv (data ().find (layout_type::index_M (i, j)));
434 const_vectoriterator_type itv_end (data ().end ());
435 if (itv == itv_end)
436 return const_iterator2 (*this, rank, i, j, itv_end, (*(-- itv)).end ());
437
438 const_subiterator_type it ((*itv).find (layout_type::index_m (i, j)));
439 const_subiterator_type it_end ((*itv).end ());
440 if (rank == 0)
441 return const_iterator2 (*this, rank, i, j, itv, it);
442 if (it != it_end && it.index () == layout_type::index_m (i, j))
443 return const_iterator2 (*this, rank, i, j, itv, it);
444 if (direction > 0) {
445 if (layout_type::fast_j ()) {
446 if (it == it_end)
447 return const_iterator2 (*this, rank, i, j, itv, it);
448 j = it.index ();
449 } else {
450 if (j >= size2_)
451 return const_iterator2 (*this, rank, i, j, itv, it);
452 ++ j;
453 }
454 } else /* if (direction < 0) */ {
455 if (layout_type::fast_j ()) {
456 if (it == (*itv).begin ())
457 return const_iterator2 (*this, rank, i, j, itv, it);
458 --it;
459 j = it.index ();
460 } else {
461 if (j == 0)
462 return const_iterator2 (*this, rank, i, j, itv, it);
463 -- j;
464 }
465 }
466 }
467 }
468 // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
469 iterator2 find2 (int rank, size_type i, size_type j, int direction = 1) {
470 for (;;) {
471 vectoriterator_type itv (data ().find (layout_type::index_M (i, j)));
472 vectoriterator_type itv_end (data ().end ());
473 if (itv == itv_end)
474 return iterator2 (*this, rank, i, j, itv_end, (*(-- itv)).end ());
475
476 subiterator_type it ((*itv).find (layout_type::index_m (i, j)));
477 subiterator_type it_end ((*itv).end ());
478 if (rank == 0)
479 return iterator2 (*this, rank, i, j, itv, it);
480 if (it != it_end && it.index () == layout_type::index_m (i, j))
481 return iterator2 (*this, rank, i, j, itv, it);
482 if (direction > 0) {
483 if (layout_type::fast_j ()) {
484 if (it == it_end)
485 return iterator2 (*this, rank, i, j, itv, it);
486 j = it.index ();
487 } else {
488 if (j >= size2_)
489 return iterator2 (*this, rank, i, j, itv, it);
490 ++ j;
491 }
492 } else /* if (direction < 0) */ {
493 if (layout_type::fast_j ()) {
494 if (it == (*itv).begin ())
495 return iterator2 (*this, rank, i, j, itv, it);
496 --it;
497 j = it.index ();
498 } else {
499 if (j == 0)
500 return iterator2 (*this, rank, i, j, itv, it);
501 -- j;
502 }
503 }
504 }
505 }
506
507
508 class const_iterator1:
509 public container_const_reference<generalized_vector_of_vector>,
510 public bidirectional_iterator_base<sparse_bidirectional_iterator_tag,
511 const_iterator1, value_type> {
512 public:
513 typedef typename generalized_vector_of_vector::difference_type difference_type;
514 typedef typename generalized_vector_of_vector::value_type value_type;
515 typedef typename generalized_vector_of_vector::const_reference reference;
516 typedef const typename generalized_vector_of_vector::pointer pointer;
517
518 typedef const_iterator2 dual_iterator_type;
519 typedef const_reverse_iterator2 dual_reverse_iterator_type;
520
521 // Construction and destruction
522 BOOST_UBLAS_INLINE
523 const_iterator1 ():
524 container_const_reference<self_type> (), rank_ (), i_ (), j_ (), itv_ (), it_ () {}
525 BOOST_UBLAS_INLINE
526 const_iterator1 (const self_type &m, int rank, size_type i, size_type j, const const_vectoriterator_type &itv, const const_subiterator_type &it):
527 container_const_reference<self_type> (m), rank_ (rank), i_ (i), j_ (j), itv_ (itv), it_ (it) {}
528 BOOST_UBLAS_INLINE
529 const_iterator1 (const iterator1 &it):
530 container_const_reference<self_type> (it ()), rank_ (it.rank_), i_ (it.i_), j_ (it.j_), itv_ (it.itv_), it_ (it.it_) {}
531
532 // Arithmetic
533 BOOST_UBLAS_INLINE
534 const_iterator1 &operator ++ () {
535 if (rank_ == 1 && layout_type::fast_i ())
536 ++ it_;
537 else {
538 const self_type &m = (*this) ();
539 i_ = index1 () + 1;
540 if (rank_ == 1 && ++ itv_ == m.end1 ().itv_)
541 *this = m.find1 (rank_, i_, j_, 1);
542 else if (rank_ == 1) {
543 it_ = (*itv_).begin ();
544 if (it_ == (*itv_).end () || index2 () != j_)
545 *this = m.find1 (rank_, i_, j_, 1);
546 }
547 }
548 return *this;
549 }
550 BOOST_UBLAS_INLINE
551 const_iterator1 &operator -- () {
552 if (rank_ == 1 && layout_type::fast_i ())
553 -- it_;
554 else {
555 const self_type &m = (*this) ();
556 i_ = index1 () - 1;
557 if (rank_ == 1 && -- itv_ == m.end1 ().itv_)
558 *this = m.find1 (rank_, i_, j_, -1);
559 else if (rank_ == 1) {
560 it_ = (*itv_).begin ();
561 if (it_ == (*itv_).end () || index2 () != j_)
562 *this = m.find1 (rank_, i_, j_, -1);
563 }
564 }
565 return *this;
566 }
567
568 // Dereference
569 BOOST_UBLAS_INLINE
570 const_reference operator * () const {
571 BOOST_UBLAS_CHECK (index1 () < (*this) ().size1 (), bad_index ());
572 BOOST_UBLAS_CHECK (index2 () < (*this) ().size2 (), bad_index ());
573 if (rank_ == 1) {
574 return *it_;
575 } else {
576 return (*this) () (i_, j_);
577 }
578 }
579
580#ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
581 BOOST_UBLAS_INLINE
582#ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
583 typename self_type::
584#endif
585 const_iterator2 begin () const {
586 const self_type &m = (*this) ();
587 return m.find2 (1, index1 (), 0);
588 }
589 BOOST_UBLAS_INLINE
590#ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
591 typename self_type::
592#endif
593 const_iterator2 cbegin () const {
594 return begin ();
595 }
596 BOOST_UBLAS_INLINE
597#ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
598 typename self_type::
599#endif
600 const_iterator2 end () const {
601 const self_type &m = (*this) ();
602 return m.find2 (1, index1 (), m.size2 ());
603 }
604 BOOST_UBLAS_INLINE
605#ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
606 typename self_type::
607#endif
608 const_iterator2 cend () const {
609 return end ();
610 }
611
612 BOOST_UBLAS_INLINE
613#ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
614 typename self_type::
615#endif
616 const_reverse_iterator2 rbegin () const {
617 return const_reverse_iterator2 (end ());
618 }
619 BOOST_UBLAS_INLINE
620#ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
621 typename self_type::
622#endif
623 const_reverse_iterator2 crbegin () const {
624 return rbegin ();
625 }
626 BOOST_UBLAS_INLINE
627#ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
628 typename self_type::
629#endif
630 const_reverse_iterator2 rend () const {
631 return const_reverse_iterator2 (begin ());
632 }
633 BOOST_UBLAS_INLINE
634#ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
635 typename self_type::
636#endif
637 const_reverse_iterator2 crend () const {
638 return rend ();
639 }
640#endif
641
642 // Indices
643 BOOST_UBLAS_INLINE
644 size_type index1 () const {
645 BOOST_UBLAS_CHECK (*this != (*this) ().find1 (0, (*this) ().size1 (), j_), bad_index ());
646 if (rank_ == 1) {
647 BOOST_UBLAS_CHECK (layout_type::index_M (itv_.index (), it_.index ()) < (*this) ().size1 (), bad_index ());
648 return layout_type::index_M (itv_.index (), it_.index ());
649 } else {
650 return i_;
651 }
652 }
653 BOOST_UBLAS_INLINE
654 size_type index2 () const {
655 BOOST_UBLAS_CHECK (*this != (*this) ().find1 (0, (*this) ().size1 (), j_), bad_index ());
656 if (rank_ == 1) {
657 BOOST_UBLAS_CHECK (layout_type::index_m (itv_.index (), it_.index ()) < (*this) ().size2 (), bad_index ());
658 return layout_type::index_m (itv_.index (), it_.index ());
659 } else {
660 return j_;
661 }
662 }
663
664 // Assignment
665 BOOST_UBLAS_INLINE
666 const_iterator1 &operator = (const const_iterator1 &it) {
667 container_const_reference<self_type>::assign (&it ());
668 rank_ = it.rank_;
669 i_ = it.i_;
670 j_ = it.j_;
671 itv_ = it.itv_;
672 it_ = it.it_;
673 return *this;
674 }
675
676 // Comparison
677 BOOST_UBLAS_INLINE
678 bool operator == (const const_iterator1 &it) const {
679 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
680 // BOOST_UBLAS_CHECK (rank_ == it.rank_, internal_logic ());
681 if (rank_ == 1 || it.rank_ == 1) {
682 return it_ == it.it_;
683 } else {
684 return i_ == it.i_ && j_ == it.j_;
685 }
686 }
687
688 private:
689 int rank_;
690 size_type i_;
691 size_type j_;
692 const_vectoriterator_type itv_;
693 const_subiterator_type it_;
694 };
695
696 BOOST_UBLAS_INLINE
697 const_iterator1 begin1 () const {
698 return find1 (0, 0, 0);
699 }
700 BOOST_UBLAS_INLINE
701 const_iterator1 cbegin1 () const {
702 return begin1 ();
703 }
704 BOOST_UBLAS_INLINE
705 const_iterator1 end1 () const {
706 return find1 (0, size1_, 0);
707 }
708 BOOST_UBLAS_INLINE
709 const_iterator1 cend1 () const {
710 return end1 ();
711 }
712
713 class iterator1:
714 public container_reference<generalized_vector_of_vector>,
715 public bidirectional_iterator_base<sparse_bidirectional_iterator_tag,
716 iterator1, value_type> {
717 public:
718 typedef typename generalized_vector_of_vector::difference_type difference_type;
719 typedef typename generalized_vector_of_vector::value_type value_type;
720 typedef typename generalized_vector_of_vector::true_reference reference;
721 typedef typename generalized_vector_of_vector::pointer pointer;
722
723 typedef iterator2 dual_iterator_type;
724 typedef reverse_iterator2 dual_reverse_iterator_type;
725
726 // Construction and destruction
727 BOOST_UBLAS_INLINE
728 iterator1 ():
729 container_reference<self_type> (), rank_ (), i_ (), j_ (), itv_ (), it_ () {}
730 BOOST_UBLAS_INLINE
731 iterator1 (self_type &m, int rank, size_type i, size_type j, const vectoriterator_type &itv, const subiterator_type &it):
732 container_reference<self_type> (m), rank_ (rank), i_ (i), j_ (j), itv_ (itv), it_ (it) {}
733
734 // Arithmetic
735 BOOST_UBLAS_INLINE
736 iterator1 &operator ++ () {
737 if (rank_ == 1 && layout_type::fast_i ())
738 ++ it_;
739 else {
740 self_type &m = (*this) ();
741 i_ = index1 () + 1;
742 if (rank_ == 1 && ++ itv_ == m.end1 ().itv_)
743 *this = m.find1 (rank_, i_, j_, 1);
744 else if (rank_ == 1) {
745 it_ = (*itv_).begin ();
746 if (it_ == (*itv_).end () || index2 () != j_)
747 *this = m.find1 (rank_, i_, j_, 1);
748 }
749 }
750 return *this;
751 }
752 BOOST_UBLAS_INLINE
753 iterator1 &operator -- () {
754 if (rank_ == 1 && layout_type::fast_i ())
755 -- it_;
756 else {
757 self_type &m = (*this) ();
758 i_ = index1 () - 1;
759 if (rank_ == 1 && -- itv_ == m.end1 ().itv_)
760 *this = m.find1 (rank_, i_, j_, -1);
761 else if (rank_ == 1) {
762 it_ = (*itv_).begin ();
763 if (it_ == (*itv_).end () || index2 () != j_)
764 *this = m.find1 (rank_, i_, j_, -1);
765 }
766 }
767 return *this;
768 }
769
770 // Dereference
771 BOOST_UBLAS_INLINE
772 true_reference operator * () const {
773 BOOST_UBLAS_CHECK (index1 () < (*this) ().size1 (), bad_index ());
774 BOOST_UBLAS_CHECK (index2 () < (*this) ().size2 (), bad_index ());
775 if (rank_ == 1) {
776 return *it_;
777 } else {
778 return (*this) ().at_element (i_, j_);
779 }
780 }
781
782#ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
783 BOOST_UBLAS_INLINE
784#ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
785 typename self_type::
786#endif
787 iterator2 begin () const {
788 self_type &m = (*this) ();
789 return m.find2 (1, index1 (), 0);
790 }
791 BOOST_UBLAS_INLINE
792#ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
793 typename self_type::
794#endif
795 iterator2 end () const {
796 self_type &m = (*this) ();
797 return m.find2 (1, index1 (), m.size2 ());
798 }
799 BOOST_UBLAS_INLINE
800#ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
801 typename self_type::
802#endif
803 reverse_iterator2 rbegin () const {
804 return reverse_iterator2 (end ());
805 }
806 BOOST_UBLAS_INLINE
807#ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
808 typename self_type::
809#endif
810 reverse_iterator2 rend () const {
811 return reverse_iterator2 (begin ());
812 }
813#endif
814
815 // Indices
816 BOOST_UBLAS_INLINE
817 size_type index1 () const {
818 BOOST_UBLAS_CHECK (*this != (*this) ().find1 (0, (*this) ().size1 (), j_), bad_index ());
819 if (rank_ == 1) {
820 BOOST_UBLAS_CHECK (layout_type::index_M (itv_.index (), it_.index ()) < (*this) ().size1 (), bad_index ());
821 return layout_type::index_M (itv_.index (), it_.index ());
822 } else {
823 return i_;
824 }
825 }
826 BOOST_UBLAS_INLINE
827 size_type index2 () const {
828 BOOST_UBLAS_CHECK (*this != (*this) ().find1 (0, (*this) ().size1 (), j_), bad_index ());
829 if (rank_ == 1) {
830 BOOST_UBLAS_CHECK (layout_type::index_m (itv_.index (), it_.index ()) < (*this) ().size2 (), bad_index ());
831 return layout_type::index_m (itv_.index (), it_.index ());
832 } else {
833 return j_;
834 }
835 }
836
837 // Assignment
838 BOOST_UBLAS_INLINE
839 iterator1 &operator = (const iterator1 &it) {
840 container_reference<self_type>::assign (&it ());
841 rank_ = it.rank_;
842 i_ = it.i_;
843 j_ = it.j_;
844 itv_ = it.itv_;
845 it_ = it.it_;
846 return *this;
847 }
848
849 // Comparison
850 BOOST_UBLAS_INLINE
851 bool operator == (const iterator1 &it) const {
852 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
853 // BOOST_UBLAS_CHECK (rank_ == it.rank_, internal_logic ());
854 if (rank_ == 1 || it.rank_ == 1) {
855 return it_ == it.it_;
856 } else {
857 return i_ == it.i_ && j_ == it.j_;
858 }
859 }
860
861 private:
862 int rank_;
863 size_type i_;
864 size_type j_;
865 vectoriterator_type itv_;
866 subiterator_type it_;
867
868 friend class const_iterator1;
869 };
870
871 BOOST_UBLAS_INLINE
872 iterator1 begin1 () {
873 return find1 (0, 0, 0);
874 }
875 BOOST_UBLAS_INLINE
876 iterator1 end1 () {
877 return find1 (0, size1_, 0);
878 }
879
880 class const_iterator2:
881 public container_const_reference<generalized_vector_of_vector>,
882 public bidirectional_iterator_base<sparse_bidirectional_iterator_tag,
883 const_iterator2, value_type> {
884 public:
885 typedef typename generalized_vector_of_vector::difference_type difference_type;
886 typedef typename generalized_vector_of_vector::value_type value_type;
887 typedef typename generalized_vector_of_vector::const_reference reference;
888 typedef const typename generalized_vector_of_vector::pointer pointer;
889
890 typedef const_iterator1 dual_iterator_type;
891 typedef const_reverse_iterator1 dual_reverse_iterator_type;
892
893 // Construction and destruction
894 BOOST_UBLAS_INLINE
895 const_iterator2 ():
896 container_const_reference<self_type> (), rank_ (), i_ (), j_ (), itv_ (), it_ () {}
897 BOOST_UBLAS_INLINE
898 const_iterator2 (const self_type &m, int rank, size_type i, size_type j, const const_vectoriterator_type &itv, const const_subiterator_type &it):
899 container_const_reference<self_type> (m), rank_ (rank), i_ (i), j_ (j), itv_ (itv), it_ (it) {}
900 BOOST_UBLAS_INLINE
901 const_iterator2 (const iterator2 &it):
902 container_const_reference<self_type> (it ()), rank_ (it.rank_), i_ (it.i_), j_ (it.j_), itv_ (it.itv_), it_ (it.it_) {}
903
904 // Arithmetic
905 BOOST_UBLAS_INLINE
906 const_iterator2 &operator ++ () {
907 if (rank_ == 1 && layout_type::fast_j ())
908 ++ it_;
909 else {
910 const self_type &m = (*this) ();
911 j_ = index2 () + 1;
912 if (rank_ == 1 && ++ itv_ == m.end2 ().itv_)
913 *this = m.find2 (rank_, i_, j_, 1);
914 else if (rank_ == 1) {
915 it_ = (*itv_).begin ();
916 if (it_ == (*itv_).end () || index1 () != i_)
917 *this = m.find2 (rank_, i_, j_, 1);
918 }
919 }
920 return *this;
921 }
922 BOOST_UBLAS_INLINE
923 const_iterator2 &operator -- () {
924 if (rank_ == 1 && layout_type::fast_j ())
925 -- it_;
926 else {
927 const self_type &m = (*this) ();
928 j_ = index2 () - 1;
929 if (rank_ == 1 && -- itv_ == m.end2 ().itv_)
930 *this = m.find2 (rank_, i_, j_, -1);
931 else if (rank_ == 1) {
932 it_ = (*itv_).begin ();
933 if (it_ == (*itv_).end () || index1 () != i_)
934 *this = m.find2 (rank_, i_, j_, -1);
935 }
936 }
937 return *this;
938 }
939
940 // Dereference
941 BOOST_UBLAS_INLINE
942 const_reference operator * () const {
943 BOOST_UBLAS_CHECK (index1 () < (*this) ().size1 (), bad_index ());
944 BOOST_UBLAS_CHECK (index2 () < (*this) ().size2 (), bad_index ());
945 if (rank_ == 1) {
946 return *it_;
947 } else {
948 return (*this) () (i_, j_);
949 }
950 }
951
952#ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
953 BOOST_UBLAS_INLINE
954#ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
955 typename self_type::
956#endif
957 const_iterator1 begin () const {
958 const self_type &m = (*this) ();
959 return m.find1 (1, 0, index2 ());
960 }
961 BOOST_UBLAS_INLINE
962#ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
963 typename self_type::
964#endif
965 const_iterator1 cbegin () const {
966 return begin ();
967 }
968 BOOST_UBLAS_INLINE
969#ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
970 typename self_type::
971#endif
972 const_iterator1 end () const {
973 const self_type &m = (*this) ();
974 return m.find1 (1, m.size1 (), index2 ());
975 }
976 BOOST_UBLAS_INLINE
977#ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
978 typename self_type::
979#endif
980 const_iterator1 cend () const {
981 return end ();
982 }
983 BOOST_UBLAS_INLINE
984#ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
985 typename self_type::
986#endif
987 const_reverse_iterator1 rbegin () const {
988 return const_reverse_iterator1 (end ());
989 }
990 BOOST_UBLAS_INLINE
991#ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
992 typename self_type::
993#endif
994 const_reverse_iterator1 crbegin () const {
995 return rbegin ();
996 }
997 BOOST_UBLAS_INLINE
998#ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
999 typename self_type::
1000#endif
1001 const_reverse_iterator1 rend () const {
1002 return const_reverse_iterator1 (begin ());
1003 }
1004 BOOST_UBLAS_INLINE
1005#ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
1006 typename self_type::
1007#endif
1008 const_reverse_iterator1 crend () const {
1009 return rend ();
1010 }
1011#endif
1012
1013 // Indices
1014 BOOST_UBLAS_INLINE
1015 size_type index1 () const {
1016 BOOST_UBLAS_CHECK (*this != (*this) ().find2 (0, i_, (*this) ().size2 ()), bad_index ());
1017 if (rank_ == 1) {
1018 BOOST_UBLAS_CHECK (layout_type::index_M (itv_.index (), it_.index ()) < (*this) ().size1 (), bad_index ());
1019 return layout_type::index_M (itv_.index (), it_.index ());
1020 } else {
1021 return i_;
1022 }
1023 }
1024 BOOST_UBLAS_INLINE
1025 size_type index2 () const {
1026 BOOST_UBLAS_CHECK (*this != (*this) ().find2 (0, i_, (*this) ().size2 ()), bad_index ());
1027 if (rank_ == 1) {
1028 BOOST_UBLAS_CHECK (layout_type::index_m (itv_.index (), it_.index ()) < (*this) ().size2 (), bad_index ());
1029 return layout_type::index_m (itv_.index (), it_.index ());
1030 } else {
1031 return j_;
1032 }
1033 }
1034
1035 // Assignment
1036 BOOST_UBLAS_INLINE
1037 const_iterator2 &operator = (const const_iterator2 &it) {
1038 container_const_reference<self_type>::assign (&it ());
1039 rank_ = it.rank_;
1040 i_ = it.i_;
1041 j_ = it.j_;
1042 itv_ = it.itv_;
1043 it_ = it.it_;
1044 return *this;
1045 }
1046
1047 // Comparison
1048 BOOST_UBLAS_INLINE
1049 bool operator == (const const_iterator2 &it) const {
1050 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
1051 // BOOST_UBLAS_CHECK (rank_ == it.rank_, internal_logic ());
1052 if (rank_ == 1 || it.rank_ == 1) {
1053 return it_ == it.it_;
1054 } else {
1055 return i_ == it.i_ && j_ == it.j_;
1056 }
1057 }
1058
1059 private:
1060 int rank_;
1061 size_type i_;
1062 size_type j_;
1063 const_vectoriterator_type itv_;
1064 const_subiterator_type it_;
1065 };
1066
1067 BOOST_UBLAS_INLINE
1068 const_iterator2 begin2 () const {
1069 return find2 (0, 0, 0);
1070 }
1071 BOOST_UBLAS_INLINE
1072 const_iterator2 cbegin2 () const {
1073 return begin2 ();
1074 }
1075 BOOST_UBLAS_INLINE
1076 const_iterator2 end2 () const {
1077 return find2 (0, 0, size2_);
1078 }
1079 BOOST_UBLAS_INLINE
1080 const_iterator2 cend2 () const {
1081 return end2 ();
1082 }
1083
1084 class iterator2:
1085 public container_reference<generalized_vector_of_vector>,
1086 public bidirectional_iterator_base<sparse_bidirectional_iterator_tag,
1087 iterator2, value_type> {
1088 public:
1089 typedef typename generalized_vector_of_vector::difference_type difference_type;
1090 typedef typename generalized_vector_of_vector::value_type value_type;
1091 typedef typename generalized_vector_of_vector::true_reference reference;
1092 typedef typename generalized_vector_of_vector::pointer pointer;
1093
1094 typedef iterator1 dual_iterator_type;
1095 typedef reverse_iterator1 dual_reverse_iterator_type;
1096
1097 // Construction and destruction
1098 BOOST_UBLAS_INLINE
1099 iterator2 ():
1100 container_reference<self_type> (), rank_ (), i_ (), j_ (), itv_ (), it_ () {}
1101 BOOST_UBLAS_INLINE
1102 iterator2 (self_type &m, int rank, size_type i, size_type j, const vectoriterator_type &itv, const subiterator_type &it):
1103 container_reference<self_type> (m), rank_ (rank), i_ (i), j_ (j), itv_ (itv), it_ (it) {}
1104
1105 // Arithmetic
1106 BOOST_UBLAS_INLINE
1107 iterator2 &operator ++ () {
1108 if (rank_ == 1 && layout_type::fast_j ())
1109 ++ it_;
1110 else {
1111 self_type &m = (*this) ();
1112 j_ = index2 () + 1;
1113 if (rank_ == 1 && ++ itv_ == m.end2 ().itv_)
1114 *this = m.find2 (rank_, i_, j_, 1);
1115 else if (rank_ == 1) {
1116 it_ = (*itv_).begin ();
1117 if (it_ == (*itv_).end () || index1 () != i_)
1118 *this = m.find2 (rank_, i_, j_, 1);
1119 }
1120 }
1121 return *this;
1122 }
1123 BOOST_UBLAS_INLINE
1124 iterator2 &operator -- () {
1125 if (rank_ == 1 && layout_type::fast_j ())
1126 -- it_;
1127 else {
1128 self_type &m = (*this) ();
1129 j_ = index2 () - 1;
1130 if (rank_ == 1 && -- itv_ == m.end2 ().itv_)
1131 *this = m.find2 (rank_, i_, j_, -1);
1132 else if (rank_ == 1) {
1133 it_ = (*itv_).begin ();
1134 if (it_ == (*itv_).end () || index1 () != i_)
1135 *this = m.find2 (rank_, i_, j_, -1);
1136 }
1137 }
1138 return *this;
1139 }
1140
1141 // Dereference
1142 BOOST_UBLAS_INLINE
1143 true_reference operator * () const {
1144 BOOST_UBLAS_CHECK (index1 () < (*this) ().size1 (), bad_index ());
1145 BOOST_UBLAS_CHECK (index2 () < (*this) ().size2 (), bad_index ());
1146 if (rank_ == 1) {
1147 return *it_;
1148 } else {
1149 return (*this) ().at_element (i_, j_);
1150 }
1151 }
1152
1153#ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
1154 BOOST_UBLAS_INLINE
1155#ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
1156 typename self_type::
1157#endif
1158 iterator1 begin () const {
1159 self_type &m = (*this) ();
1160 return m.find1 (1, 0, index2 ());
1161 }
1162 BOOST_UBLAS_INLINE
1163#ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
1164 typename self_type::
1165#endif
1166 iterator1 end () const {
1167 self_type &m = (*this) ();
1168 return m.find1 (1, m.size1 (), index2 ());
1169 }
1170 BOOST_UBLAS_INLINE
1171#ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
1172 typename self_type::
1173#endif
1174 reverse_iterator1 rbegin () const {
1175 return reverse_iterator1 (end ());
1176 }
1177 BOOST_UBLAS_INLINE
1178#ifdef BOOST_UBLAS_MSVC_NESTED_CLASS_RELATION
1179 typename self_type::
1180#endif
1181 reverse_iterator1 rend () const {
1182 return reverse_iterator1 (begin ());
1183 }
1184#endif
1185
1186 // Indices
1187 BOOST_UBLAS_INLINE
1188 size_type index1 () const {
1189 BOOST_UBLAS_CHECK (*this != (*this) ().find2 (0, i_, (*this) ().size2 ()), bad_index ());
1190 if (rank_ == 1) {
1191 BOOST_UBLAS_CHECK (layout_type::index_M (itv_.index (), it_.index ()) < (*this) ().size1 (), bad_index ());
1192 return layout_type::index_M (itv_.index (), it_.index ());
1193 } else {
1194 return i_;
1195 }
1196 }
1197 BOOST_UBLAS_INLINE
1198 size_type index2 () const {
1199 BOOST_UBLAS_CHECK (*this != (*this) ().find2 (0, i_, (*this) ().size2 ()), bad_index ());
1200 if (rank_ == 1) {
1201 BOOST_UBLAS_CHECK (layout_type::index_m (itv_.index (), it_.index ()) < (*this) ().size2 (), bad_index ());
1202 return layout_type::index_m (itv_.index (), it_.index ());
1203 } else {
1204 return j_;
1205 }
1206 }
1207
1208 // Assignment
1209 BOOST_UBLAS_INLINE
1210 iterator2 &operator = (const iterator2 &it) {
1211 container_reference<self_type>::assign (&it ());
1212 rank_ = it.rank_;
1213 i_ = it.i_;
1214 j_ = it.j_;
1215 itv_ = it.itv_;
1216 it_ = it.it_;
1217 return *this;
1218 }
1219
1220 // Comparison
1221 BOOST_UBLAS_INLINE
1222 bool operator == (const iterator2 &it) const {
1223 BOOST_UBLAS_CHECK (&(*this) () == &it (), external_logic ());
1224 // BOOST_UBLAS_CHECK (rank_ == it.rank_, internal_logic ());
1225 if (rank_ == 1 || it.rank_ == 1) {
1226 return it_ == it.it_;
1227 } else {
1228 return i_ == it.i_ && j_ == it.j_;
1229 }
1230 }
1231
1232 private:
1233 int rank_;
1234 size_type i_;
1235 size_type j_;
1236 vectoriterator_type itv_;
1237 subiterator_type it_;
1238
1239 friend class const_iterator2;
1240 };
1241
1242 BOOST_UBLAS_INLINE
1243 iterator2 begin2 () {
1244 return find2 (0, 0, 0);
1245 }
1246 BOOST_UBLAS_INLINE
1247 iterator2 end2 () {
1248 return find2 (0, 0, size2_);
1249 }
1250
1251 // Reverse iterators
1252
1253 BOOST_UBLAS_INLINE
1254 const_reverse_iterator1 rbegin1 () const {
1255 return const_reverse_iterator1 (end1 ());
1256 }
1257 BOOST_UBLAS_INLINE
1258 const_reverse_iterator1 crbegin1 () const {
1259 return rbegin1 ();
1260 }
1261 BOOST_UBLAS_INLINE
1262 const_reverse_iterator1 rend1 () const {
1263 return const_reverse_iterator1 (begin1 ());
1264 }
1265 BOOST_UBLAS_INLINE
1266 const_reverse_iterator1 crend1 () const {
1267 return rend1 ();
1268 }
1269
1270 BOOST_UBLAS_INLINE
1271 reverse_iterator1 rbegin1 () {
1272 return reverse_iterator1 (end1 ());
1273 }
1274 BOOST_UBLAS_INLINE
1275 reverse_iterator1 rend1 () {
1276 return reverse_iterator1 (begin1 ());
1277 }
1278
1279 BOOST_UBLAS_INLINE
1280 const_reverse_iterator2 rbegin2 () const {
1281 return const_reverse_iterator2 (end2 ());
1282 }
1283 BOOST_UBLAS_INLINE
1284 const_reverse_iterator2 crbegin2 () const {
1285 return rbegin2 ();
1286 }
1287 BOOST_UBLAS_INLINE
1288 const_reverse_iterator2 rend2 () const {
1289 return const_reverse_iterator2 (begin2 ());
1290 }
1291 BOOST_UBLAS_INLINE
1292 const_reverse_iterator2 crend2 () const {
1293 return rend2 ();
1294 }
1295
1296 BOOST_UBLAS_INLINE
1297 reverse_iterator2 rbegin2 () {
1298 return reverse_iterator2 (end2 ());
1299 }
1300 BOOST_UBLAS_INLINE
1301 reverse_iterator2 rend2 () {
1302 return reverse_iterator2 (begin2 ());
1303 }
1304
1305 // Serialization
1306 template<class Archive>
1307 void serialize(Archive & ar, const unsigned int /* file_version */){
1308
1309 // we need to copy to a collection_size_type to get a portable
1310 // and efficient serialization
1311 serialization::collection_size_type s1 (size1_);
1312 serialization::collection_size_type s2 (size2_);
1313
1314 // serialize the sizes
1315 ar & serialization::make_nvp(n: "size1",v&: s1)
1316 & serialization::make_nvp(n: "size2",v&: s2);
1317
1318 // copy the values back if loading
1319 if (Archive::is_loading::value) {
1320 size1_ = s1;
1321 size2_ = s2;
1322 }
1323
1324 ar & serialization::make_nvp("data", data_);
1325
1326 storage_invariants();
1327 }
1328
1329 private:
1330 void storage_invariants () const
1331 {
1332 BOOST_UBLAS_CHECK (layout_type::size_M (size1_, size2_) + 1 == data_.size (), internal_logic ());
1333 BOOST_UBLAS_CHECK (data ().begin () != data ().end (), internal_logic ());
1334
1335 }
1336 size_type size1_;
1337 size_type size2_;
1338 array_type data_;
1339 static const value_type zero_;
1340 };
1341
1342 template<class T, class L, class A>
1343 const typename generalized_vector_of_vector<T, L, A>::value_type generalized_vector_of_vector<T, L, A>::zero_ = value_type/*zero*/();
1344
1345}}}
1346
1347#endif
1348

source code of boost/libs/numeric/ublas/include/boost/numeric/ublas/vector_of_vector.hpp