iterator.hpp
Go to the documentation of this file.
1/*!
2 * \brief Iterators for elementwise vector expression evaluation
3 *
4 * \author O. Krause
5 * \date 2013
6 *
7 *
8 * \par Copyright 1995-2015 Shark Development Team
9 *
10 * <BR><HR>
11 * This file is part of Shark.
12 * <http://image.diku.dk/shark/>
13 *
14 * Shark is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License as published
16 * by the Free Software Foundation, either version 3 of the License, or
17 * (at your option) any later version.
18 *
19 * Shark is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Lesser General Public License for more details.
23 *
24 * You should have received a copy of the GNU Lesser General Public License
25 * along with Shark. If not, see <http://www.gnu.org/licenses/>.
26 *
27 */
28#ifndef REMORA_DETAIL_ITERATOR_HPP
29#define REMORA_DETAIL_ITERATOR_HPP
30
31#include <iterator>
32#include <type_traits>
33#include <limits>
34#include <algorithm>
35#include <cstdlib>
36
37#include "../detail/check.hpp"
38
39namespace remora{ namespace iterators{
40
41// Iterator tags -- hierarchical definition of storage characteristics
42struct sparse_random_access_iterator_tag: public std::random_access_iterator_tag{};
43struct packed_random_access_iterator_tag: public std::random_access_iterator_tag{};
44struct dense_random_access_iterator_tag: public packed_random_access_iterator_tag{};
45
46/** \brief Base class of all random access iterators.
47 *
48 * \param I the derived iterator type
49 * \param T the value type
50 * \param Tag the iterator tag - must be dense/packed_random_access_iterator_tag
51 *
52 * The random access iterator can proceed in both directions
53 * via the post increment/decrement operator or in larger steps
54 * via the +, - and +=, -= operators. The random access iterator
55 * is LessThanComparable.
56 */
57template<class I, class T, class Tag>
58struct random_access_iterator_base
59:public std::iterator<Tag, T> {
60 typedef I derived_iterator_type;
61 typedef T derived_value_type;
62 typedef std::ptrdiff_t difference_type;
63
64 friend I operator + (random_access_iterator_base const& it, difference_type n) {
65 I tmp(static_cast<const I&>(it));
66 return tmp += n;
67 }
68 friend I operator - (random_access_iterator_base const& it, difference_type n) {
69 I tmp(static_cast<const I&>(it));
70 return tmp -= n;
71 }
72
73 friend I operator + (difference_type n, random_access_iterator_base const& it) {
74 I tmp(static_cast<const I&>(it));
75 return tmp += n;
76 }
77 friend I operator - (difference_type n, random_access_iterator_base const& it) {
78 I tmp(static_cast<const I&>(it));
79 return tmp -= n;
80 }
81};
82//arithmetic for random_access_iterators
83template<class I, class T, class Tag>
84I operator ++ (random_access_iterator_base<I,T,Tag>& it,int) {
85 I& d = static_cast<I&>(it);
86 I tmp(d);
87 ++ d;
88 return tmp;
89}
90
91template<class I, class T, class Tag>
92I operator -- (random_access_iterator_base<I,T,Tag>& it,int) {
93 I& d = static_cast<I&>(it);
94 I tmp(d);
95 -- d;
96 return tmp;
97}
98
99
100// Comparison of random_access_iterators
101template<class I1, class T1, class I2, class T2, class Tag>
102bool operator != (
103 random_access_iterator_base<I1,T1,Tag> const& it1,
104 random_access_iterator_base<I2,T2,Tag> const& it2
105){
106 I1 const& d1 = static_cast<const I1&>(it1);
107 I2 const& d2 = static_cast<const I2&>(it2);
108
109 return !(d1 == d2);
110}
111template<class I1, class T1, class I2, class T2, class Tag>
112bool operator <= (
113 random_access_iterator_base<I1,T1,Tag> const& it1,
114 random_access_iterator_base<I2,T2,Tag> const& it2
115){
116 I1 const& d1 = static_cast<const I1&>(it1);
117 I2 const& d2 = static_cast<const I2&>(it2);
118
119 return !(d2 < d1);
120}
121template<class I1, class T1, class I2, class T2, class Tag>
122bool operator >= (
123 random_access_iterator_base<I1,T1,Tag> const& it1,
124 random_access_iterator_base<I2,T2,Tag> const& it2
125){
126 I1 const& d1 = static_cast<const I1&>(it1);
127 I2 const& d2 = static_cast<const I2&>(it2);
128
129 return !(d1 < d2);
130}
131template<class I1, class T1, class I2, class T2, class Tag>
132bool operator > (
133 random_access_iterator_base<I1,T1,Tag> const& it1,
134 random_access_iterator_base<I2,T2,Tag> const& it2
135){
136 I1 const& d1 = static_cast<const I1&>(it1);
137 I2 const& d2 = static_cast<const I2&>(it2);
138
139 return d2 < d1;
140}
141//traits lass for choosing the right base for wrapping iterators
142
143template<class Closure>
144class indexed_iterator:
145 public random_access_iterator_base<
146 indexed_iterator<Closure>,
147 typename Closure::value_type,
148 dense_random_access_iterator_tag
149 > {
150public:
151 typedef std::size_t size_type;
152 typedef std::ptrdiff_t difference_type;
153 typedef typename Closure::value_type value_type;
154 typedef typename std::conditional<
155 std::is_const<Closure>::value,
156 typename Closure::const_reference,
157 typename Closure::reference
158 >::type reference;
159
160 // Construction and destruction
161 indexed_iterator(){}
162 indexed_iterator(Closure container, size_type index)
163 : m_index(index), m_closure(container) {}
164
165 template<class C>
166 indexed_iterator(indexed_iterator<C> const& iterator)
167 : m_index(iterator.m_index), m_closure(iterator.m_closure) {}
168
169 // Arithmetic
170 indexed_iterator& operator++() {
171 ++m_index;
172 return *this;
173 }
174 indexed_iterator& operator--() {
175 --m_index;
176 return *this;
177 }
178 indexed_iterator& operator += (difference_type n) {
179 m_index += n;
180 return *this;
181 }
182 indexed_iterator& operator -= (difference_type n) {
183 m_index -= n;
184 return *this;
185 }
186 template<class T>
187 difference_type operator - (indexed_iterator<T> const& it) const {
188 return m_index - it.m_index;
189 }
190
191 // Dereference
192 reference operator *() const {
193 REMORA_RANGE_CHECK(m_index < m_closure.size());
194 return m_closure(m_index);
195 }
196 reference operator [](difference_type n) const {
197 REMORA_RANGE_CHECK(m_index+n < m_closure.size());
198 return m_closure(m_index+n);
199 }
200
201 // Index
202 size_type index() const {
203 return m_index;
204 }
205
206 // Assignment
207 template<class T>
208 indexed_iterator &operator = (indexed_iterator<T> const& it) {
209 m_closure = it.m_closure;
210 m_index = it.m_index;
211 return *this;
212 }
213
214 // Comparison
215 template<class T>
216 bool operator == (indexed_iterator<T> const& it) const {
217 return m_index == it.m_index;
218 }
219 template<class T>
220 bool operator < (indexed_iterator<T> const& it) const {
221 return m_index < it.m_index;
222 }
223
224private:
225 size_type m_index;
226 Closure m_closure;
227 template<class> friend class indexed_iterator;
228};
229
230template<class T, class Tag=dense_random_access_iterator_tag>
231class dense_storage_iterator:
232public random_access_iterator_base<
233 dense_storage_iterator<T,Tag>,
234 typename std::remove_const<T>::type,
235 Tag
236>{
237public:
238 typedef std::size_t size_type;
239 typedef std::ptrdiff_t difference_type;
240 typedef typename std::remove_const<T>::type value_type;
241 typedef T& reference;
242 typedef T* pointer;
243
244 // Construction
245 dense_storage_iterator():m_pos(0),m_index(0) {}
246 dense_storage_iterator(pointer pos, size_type index, difference_type stride = 1)
247 :m_pos(pos), m_index(index), m_stride(stride) {}
248
249 template<class U>
250 dense_storage_iterator(dense_storage_iterator<U,Tag> const& iter)
251 :m_pos(iter.m_pos), m_index(iter.m_index), m_stride(iter.m_stride){}
252
253 template<class U>
254 dense_storage_iterator& operator=(dense_storage_iterator<U,Tag> const& iter){
255 m_pos = iter.m_pos;
256 m_index = iter.m_index;
257 m_stride = iter.m_stride;
258 return *this;
259 }
260
261 // Arithmetic
262 dense_storage_iterator& operator ++ () {
263 ++m_index;
264 m_pos += m_stride;
265 return *this;
266 }
267 dense_storage_iterator& operator -- () {
268 --m_index;
269 m_pos -= m_stride;
270 return *this;
271 }
272 dense_storage_iterator& operator += (difference_type n) {
273 m_index += n;
274 m_pos += n*m_stride;
275 return *this;
276 }
277 dense_storage_iterator& operator -= (difference_type n) {
278 m_index -= n;
279 m_pos -= n*m_stride;
280 return *this;
281 }
282 template<class U>
283 difference_type operator - (dense_storage_iterator<U,Tag> const& it) const {
284 //REMORA_RANGE_CHECK(m_pos == it.m_pos);
285 return (difference_type)m_index - (difference_type)it.m_index;
286 }
287
288 // Dereference
289 reference operator*() const {
290 return *m_pos;
291 }
292 reference operator [](difference_type n) const {
293 return m_pos[m_stride*n];
294 }
295
296 // Index
297 size_type index() const {
298 return m_index;
299 }
300
301 // Comparison
302 template<class U>
303 bool operator == (dense_storage_iterator<U,Tag> const& it) const {
304 //REMORA_RANGE_CHECK(m_pos == it.m_pos);
305 //~ REMORA_RANGE_CHECK(m_index < it.m_index);
306 return m_index == it.m_index;
307 }
308 template<class U>
309 bool operator < (dense_storage_iterator<U,Tag> const& it) const {
310 //REMORA_RANGE_CHECK(m_pos == it.m_pos);
311 return m_index < it.m_index;
312 }
313
314private:
315 pointer m_pos;
316 size_type m_index;
317 difference_type m_stride;
318 template<class,class> friend class dense_storage_iterator;
319};
320template<class T, class I>
321class compressed_storage_iterator:
322public random_access_iterator_base<
323 compressed_storage_iterator<T,I>,
324 typename std::remove_const<T>::type,
325 sparse_random_access_iterator_tag
326>{
327public:
328 typedef typename std::remove_const<T>::type value_type;
329 typedef typename std::remove_const<I>::type size_type;
330 typedef std::ptrdiff_t difference_type;
331 typedef T& reference;
332 typedef T* pointer;
333
334 // Construction and Assignment
335 compressed_storage_iterator() {}
336 compressed_storage_iterator(
337 T* value_array, I* index_array,
338 size_type position, size_type major_pos = 0
339 )
340 : m_values(value_array),m_indices(index_array)
341 , m_position(position), m_major_pos(major_pos){}
342
343 template<class U,class V>
344 compressed_storage_iterator(compressed_storage_iterator<U,V> const& it) {
345 m_position = it.m_position;
346 m_major_pos = it.m_major_pos;
347 m_values = it.m_values;
348 m_indices = it.m_indices;
349 }
350
351 template<class U,class V>
352 compressed_storage_iterator &operator = (compressed_storage_iterator<U,V> const& it) {
353 m_position = it.m_position;
354 m_major_pos = it.m_major_pos;
355 m_values = it.m_values;
356 m_indices = it.m_indices;
357 return *this;
358 }
359
360 // Arithmetic
361 compressed_storage_iterator &operator++ () {
362 ++m_position;
363 return *this;
364 }
365 compressed_storage_iterator &operator -- () {
366 REMORA_RANGE_CHECK(m_position > 0);
367 --m_position;
368 return *this;
369 }
370
371 compressed_storage_iterator &operator += (difference_type n) {
372 m_position += n;
373 return *this;
374 }
375 compressed_storage_iterator &operator -= (difference_type n) {
376 m_position -= n;
377 return *this;
378 }
379
380 // Dereference
381 reference operator* () const {
382 return m_values[m_position];
383 }
384 reference operator [](difference_type n) const {
385 return m_values[m_position+n];
386 }
387 size_type index() const {
388 return m_indices[m_position];
389 }
390
391 template<class U,class V>
392 difference_type operator - (compressed_storage_iterator<U,V> const& it) const {
393 REMORA_RANGE_CHECK(m_values == it.m_values);
394 REMORA_RANGE_CHECK(m_indices == it.m_indices);
395 return difference_type(m_position) - difference_type(it.m_position);
396 }
397
398 size_type major_index()const{
399 return m_major_pos;
400 }
401
402 template<class U,class V>
403 bool operator == (compressed_storage_iterator<U,V> const &it) const {
404 REMORA_RANGE_CHECK(m_values == it.m_values);
405 REMORA_RANGE_CHECK(m_indices == it.m_indices);
406 return m_position == it.m_position;
407 }
408
409private:
410 T* m_values;
411 I* m_indices;
412 std::size_t m_position;
413 std::size_t m_major_pos;
414 template<class,class> friend class compressed_storage_iterator;
415};
416
417
418
419template<class T>
420class constant_iterator:
421public random_access_iterator_base<
422 constant_iterator<T>,
423 typename std::remove_const<T>::type,
424 dense_random_access_iterator_tag
425>{
426public:
427 typedef std::size_t size_type;
428 typedef std::ptrdiff_t difference_type;
429 typedef T value_type;
430 typedef value_type const &reference;
431 typedef value_type const *pointer;
432
433 // Construction and destruction
434 constant_iterator() {}
435 constant_iterator(value_type value, size_type position)
436 :m_position(position),m_value(value) {}
437
438 // Arithmetic
439 constant_iterator &operator ++ () {
440 ++ m_position;
441 return *this;
442 }
443 constant_iterator &operator -- () {
444 -- m_position;
445 return *this;
446 }
447 constant_iterator &operator += (difference_type n) {
448 m_position += n;
449 return *this;
450 }
451 constant_iterator &operator -= (difference_type n) {
452 m_position -= n;
453 return *this;
454 }
455 difference_type operator - (constant_iterator const &it) const {
456 return m_position - it.m_position;
457 }
458
459 // Dereference
460 reference operator * () const {
461 return m_value;
462 }
463 reference operator [](difference_type n) const {
464 return m_value;
465 }
466
467 // Indices
468 size_type index() const {
469 return m_position;
470 }
471
472 // Assignment
473 template<class Iter>
474 constant_iterator &operator = (constant_iterator const &it) {
475 m_position = it.m_position;
476 m_value = it.m_value;
477 return *this;
478 }
479
480 // Comparison
481 bool operator == (constant_iterator const &it) const {
482 return m_position == it.m_position;
483 }
484 bool operator < (constant_iterator const &it) const {
485 return m_position < it.m_position;
486 }
487private:
488 size_type m_position;
489 value_type m_value;
490};
491
492template<class BaseIterator, class F>
493class transform_iterator:
494public random_access_iterator_base<
495 transform_iterator<BaseIterator,F>,
496 typename BaseIterator::value_type,
497 typename BaseIterator::iterator_category
498>{
499public:
500 typedef typename BaseIterator::iterator_category iterator_category;
501 typedef std::size_t size_type;
502 typedef std::ptrdiff_t difference_type;
503 typedef typename std::result_of<F(typename BaseIterator::value_type)>::type value_type;
504 typedef value_type reference;
505 typedef value_type *pointer;
506
507 // Construction and destruction
508 transform_iterator() {}
509 transform_iterator(BaseIterator const &it,F functor)
510 :m_position(it),m_functor(functor) {}
511
512 // Arithmetic
513 transform_iterator &operator ++ () {
514 ++ m_position;
515 return *this;
516 }
517 transform_iterator &operator -- () {
518 -- m_position;
519 return *this;
520 }
521 transform_iterator &operator += (difference_type n) {
522 m_position += n;
523 return *this;
524 }
525 transform_iterator &operator -= (difference_type n) {
526 m_position -= n;
527 return *this;
528 }
529 difference_type operator - (transform_iterator const &it) const {
530 return m_position - it.m_position;
531 }
532
533 // Dereference
534 reference operator * () const {
535 return m_functor(*m_position);
536 }
537 reference operator [](difference_type n) const {
538 return *(*this + n);
539 }
540
541 // Indices
542 size_type index() const {
543 return m_position.index();
544 }
545
546 // Assignment
547 template<class Iter>
548 transform_iterator &operator = (transform_iterator<Iter,F> const &it) {
549 m_position = it.m_position;
550 m_functor = it.m_functor;
551 return *this;
552 }
553
554 // Comparison
555 bool operator == (transform_iterator const &it) const {
556 return m_position == it.m_position;
557 }
558 bool operator < (transform_iterator const &it) const {
559 return m_position < it.m_position;
560 }
561
562private:
563 BaseIterator m_position;
564 F m_functor;
565};
566
567template<class T>
568class one_hot_iterator:public random_access_iterator_base<
569 one_hot_iterator<T>, T, sparse_random_access_iterator_tag
570> {
571public:
572 typedef T value_type;
573 typedef std::ptrdiff_t difference_type;
574 typedef std::size_t size_type;
575 typedef T& reference;
576 typedef T const& const_reference;
577 typedef value_type const* pointer;
578
579 // Construction and destruction
580 one_hot_iterator(){}
581 one_hot_iterator(size_type index, value_type value, bool isEnd)
582 :m_index(index),m_value(value),m_isEnd(isEnd){}
583
584 // Arithmetic
585 one_hot_iterator& operator ++ () {
586 m_isEnd = true;
587 return *this;
588 }
589 one_hot_iterator& operator -- () {
590 m_isEnd = false;
591 return *this;
592 }
593 one_hot_iterator &operator += (difference_type n) {
594 m_isEnd += n;
595 return *this;
596 }
597 one_hot_iterator &operator -= (difference_type n) {
598 m_isEnd -= n;
599 return *this;
600 }
601
602
603 // Dereference
604 reference operator*() const {
605 return m_value;
606 }
607
608 // Indices
609 size_type index() const{
610 return m_index;
611 }
612 difference_type operator - (one_hot_iterator const &it) const {
613 return m_isEnd - it.m_isEnd;
614 }
615
616 // Assignment
617 one_hot_iterator& operator = (one_hot_iterator const& it) {
618 m_index = it.m_index;
619 m_value = it.m_value;
620 return *this;
621 }
622
623 // Comparison
624 bool operator == (one_hot_iterator const& it) const {
625 REMORA_RANGE_CHECK(m_index == it.m_index);
626 return m_isEnd == it.m_isEnd;
627 }
628 bool operator < (one_hot_iterator const &it) const {
629 return m_isEnd < it.m_isEnd;
630 }
631
632private:
633 size_type m_index;
634 value_type m_value;
635 bool m_isEnd;
636};
637
638
639template<class I1, class I2>
640struct iterator_restrict_traits {
641 typedef I1 iterator_category;
642};
643
644template<>
645struct iterator_restrict_traits<dense_random_access_iterator_tag, sparse_random_access_iterator_tag> {
646 typedef sparse_random_access_iterator_tag iterator_category;
647};
648
649template<>
650struct iterator_restrict_traits<packed_random_access_iterator_tag,dense_random_access_iterator_tag> {
651 typedef dense_random_access_iterator_tag iterator_category;
652};
653
654template<>
655struct iterator_restrict_traits<packed_random_access_iterator_tag,sparse_random_access_iterator_tag> {
656 typedef sparse_random_access_iterator_tag iterator_category;
657};
658
659template<class Iterator1, class Iterator2, class F>
660class binary_transform_iterator:
661public random_access_iterator_base<
662 binary_transform_iterator<Iterator1,Iterator2,F>,
663 typename std::result_of<F(typename Iterator1::value_type, typename Iterator2::value_type)>::type,
664 typename iterator_restrict_traits<
665 typename Iterator1::iterator_category,
666 typename Iterator2::iterator_category
667 >::iterator_category
668>{
669private:
670 typedef typename Iterator1::iterator_category category1;
671 typedef typename Iterator2::iterator_category category2;
672public:
673 typedef typename iterator_restrict_traits<
674 category1,
675 category2
676 >::iterator_category iterator_category;
677 typedef std::size_t size_type;
678 typedef std::ptrdiff_t difference_type;
679 typedef typename std::result_of<F(typename Iterator1::value_type, typename Iterator2::value_type)>::type value_type;
680 typedef value_type reference;
681 typedef value_type *pointer;
682
683 // Construction and destruction
684 binary_transform_iterator() {}
685 binary_transform_iterator(
686 F functor,
687 Iterator1 const &it1, Iterator1 const &end1,
688 Iterator2 const &it2, Iterator2 const &end2
689 ):m_index(0)
690 , m_iterator1(it1), m_end1(end1)
691 , m_iterator2(it2), m_end2(end2)
692 , m_functor(functor)
693 {
694 //ensure that both iterators start at a valid location
695 ensureValidPosition(category1(),category2());
696
697 //we can't get the correct index for end iterators
698 if(m_iterator1 != end1 && m_iterator2 != end2)
699 m_index = std::min(m_iterator1.index(),m_iterator2.index());
700
701
702 }
703
704private:
705 //we need to handle all specializations independently from each other
706
707 // Dense specializations are easy
708 void ensureValidPosition(
709 dense_random_access_iterator_tag,
710 dense_random_access_iterator_tag
711 ){}
712 void increment(
713 dense_random_access_iterator_tag,
714 dense_random_access_iterator_tag
715 ) {
716 ++ m_index;
717 ++ m_iterator1;
718 ++ m_iterator2;
719 }
720 void decrement(
721 dense_random_access_iterator_tag,
722 dense_random_access_iterator_tag
723 ) {
724 -- m_index;
725 -- m_iterator1;
726 -- m_iterator2;
727 }
728 void increment(
729 dense_random_access_iterator_tag,
730 dense_random_access_iterator_tag,
731 difference_type n
732 ) {
733 m_index += n;
734 m_iterator1 += n;
735 m_iterator2 += n;
736 }
737 value_type dereference(
738 dense_random_access_iterator_tag,
739 dense_random_access_iterator_tag
740 ) const {
741 return m_functor(*m_iterator1, *m_iterator2);
742 }
743
744 // Sparse specializations
745 void ensureValidPosition(
746 sparse_random_access_iterator_tag,
747 sparse_random_access_iterator_tag
748 ){
749 //ensure that both iterators point to the same index
750 if(F::left_zero_remains || F::right_zero_remains){
751 while(
752 m_iterator1 != m_end1 && m_iterator2 != m_end2
753 && m_iterator1.index() != m_iterator2.index()
754 ){
755 if(m_iterator1.index() < m_iterator2.index())
756 ++m_iterator1;
757 else
758 ++m_iterator2;
759 }
760 if( m_iterator1 == m_end1 || m_iterator2 == m_end2){
761 m_iterator2 = m_end2;
762 m_iterator1 = m_end1;
763 }
764 }
765 }
766 void increment(
767 sparse_random_access_iterator_tag,
768 sparse_random_access_iterator_tag
769 ) {
770 if(F::left_zero_remains || F::right_zero_remains){
771 ++ m_iterator1;
772 ++ m_iterator2;
773 ensureValidPosition(category1(),category2());
774 }else{
775 if (m_iterator1 != m_end1 && m_iterator2 != m_end2){
776 if( m_iterator1.index() == m_iterator2.index()){
777 ++ m_iterator1;
778 ++ m_iterator2;
779 }
780 else if(m_iterator1.index() < m_iterator2.index())
781 ++m_iterator1;
782 else
783 ++m_iterator2;
784 }else if(m_iterator1 != m_end1){
785 ++ m_iterator1;
786 }else{
787 ++ m_iterator2;
788 }
789 }
790 size_type index1 = std::numeric_limits<size_type>::max();
791 size_type index2 = std::numeric_limits<size_type>::max();
792 if(m_iterator1 != m_end1)
793 index1 = m_iterator1.index();
794 if(m_iterator2 != m_end2)
795 index2 = m_iterator2.index();
796
797 m_index = std::min(index1, index2);
798 }
799 void decrement(
800 sparse_random_access_iterator_tag,
801 sparse_random_access_iterator_tag
802 ) {
803 if (m_index <= m_iterator1.index())
804 -- m_iterator1;
805 if (m_index <= m_iterator2.index())
806 -- m_iterator2;
807 m_index = std::max(m_iterator1.index(), m_iterator2.index());
808 }
809 void increment(
810 sparse_random_access_iterator_tag,
811 sparse_random_access_iterator_tag,
812 difference_type n
813 ) {
814 while (n > 0) {
815 increment(category1(),category2());
816 --n;
817 }
818 while (n < 0) {
819 decrement(category1(),category2());
820 ++n;
821 }
822 }
823 value_type dereference(
824 sparse_random_access_iterator_tag,
825 sparse_random_access_iterator_tag
826 ) const {
827 value_type t1 = value_type/*zero*/();
828 if (m_iterator1 != m_end1 && m_iterator1.index() == m_index)
829 t1 = *m_iterator1;
830 value_type t2 = value_type/*zero*/();
831 if (m_iterator2 != m_end2 && m_iterator2.index() == m_index)
832 t2 = *m_iterator2;
833 return m_functor(t1, t2);
834 }
835
836 //dense-sparse
837 // Sparse specializations
838 void ensureValidPosition(
839 dense_random_access_iterator_tag,
840 sparse_random_access_iterator_tag
841 ){
842 if(F::right_zero_remains){
843 m_iterator1 += m_iterator2.index()-m_iterator1.index();
844 }
845 }
846
847 void increment(
848 dense_random_access_iterator_tag,
849 sparse_random_access_iterator_tag
850 ) {
851 if(F::right_zero_remains){
852 ++ m_iterator2;
853 m_iterator1 += m_iterator2.index()-m_iterator1.index();
854 }else{
855 if (m_iterator2 != m_end2){
856 if( m_iterator1.index() == m_iterator2.index()){
857 ++ m_iterator1;
858 ++ m_iterator2;
859 }
860 else if(m_iterator2.index() > m_iterator1.index())
861 ++m_iterator1;
862 else
863 ++m_iterator2;
864 }else
865 ++ m_iterator1;
866 }
867 size_type index1 = m_iterator1.index();
868 size_type index2 = std::numeric_limits<size_type>::max();
869 if(m_iterator2 != m_end2)
870 index2 = m_iterator2.index();
871 m_index = std::min(index1, index2);
872 }
873 void decrement(
874 dense_random_access_iterator_tag,
875 sparse_random_access_iterator_tag
876 ) {
877 if(F::right_zero_remains){
878 -- m_iterator2;
879 m_iterator1 -= m_iterator1.index()-m_iterator2.index();
880 }else{
881 if (m_index <= m_iterator1.index())
882 -- m_iterator1;
883 if (m_index <= m_iterator2.index())
884 -- m_iterator2;
885 m_index = std::max(m_iterator1.index(), m_iterator2.index());
886 }
887 }
888 void increment(
889 dense_random_access_iterator_tag,
890 sparse_random_access_iterator_tag,
891 difference_type n
892 ) {
893 while (n > 0) {
894 increment(category1(),category2());
895 --n;
896 }
897 while (n < 0) {
898 decrement(category1(),category2());
899 ++n;
900 }
901 }
902 value_type dereference(
903 dense_random_access_iterator_tag,
904 sparse_random_access_iterator_tag
905 ) const {
906 typedef typename Iterator2::value_type value_type2;
907 value_type t2 = value_type2/*zero*/();
908 if (m_iterator2 != m_end2 && m_iterator2.index() == m_index)
909 t2 = *m_iterator2;
910 return m_functor(*m_iterator1, t2);
911 }
912
913 //sparse-dense
914 void ensureValidPosition(
915 sparse_random_access_iterator_tag,
916 dense_random_access_iterator_tag
917 ){
918 if(F::left_zero_remains){
919 m_iterator2 += m_iterator1.index()-m_iterator2.index();
920 }
921 }
922 void increment(
923 sparse_random_access_iterator_tag,
924 dense_random_access_iterator_tag
925 ) {
926 if(F::left_zero_remains){
927 ++ m_iterator1;
928 m_iterator2 += m_iterator1.index()-m_iterator2.index();
929 }else{
930 if (m_iterator1 != m_end1){
931 if( m_iterator1.index() == m_iterator2.index()){
932 ++ m_iterator1;
933 ++ m_iterator2;
934 }
935 else if(m_iterator1.index() > m_iterator2.index())
936 ++m_iterator2;
937 else
938 ++m_iterator1;
939 }else
940 ++ m_iterator2;
941 }
942 size_type index1 = std::numeric_limits<size_type>::max();
943 size_type index2 = m_iterator2.index();
944 if(m_iterator1 != m_end1)
945 index1 = m_iterator1.index();
946 m_index = std::min(index1, index2);
947 }
948 void decrement(
949 sparse_random_access_iterator_tag,
950 dense_random_access_iterator_tag
951 ) {
952 if(F::left_zero_remains){
953 -- m_iterator1;
954 m_iterator2 -= m_iterator2.index()-m_iterator1.index();
955 }else{
956 if (m_index <= m_iterator2.index())
957 -- m_iterator2;
958 if (m_index <= m_iterator1.index())
959 -- m_iterator1;
960 m_index = std::max(m_iterator1.index(), m_iterator2.index());
961 }
962 }
963 void increment(
964 sparse_random_access_iterator_tag,
965 dense_random_access_iterator_tag,
966 difference_type n
967 ) {
968 while (n > 0) {
969 increment(category1(),category2());
970 --n;
971 }
972 while (n < 0) {
973 decrement(category1(),category2());
974 ++n;
975 }
976 }
977 value_type dereference(
978 sparse_random_access_iterator_tag,
979 dense_random_access_iterator_tag
980 ) const {
981 typedef typename Iterator1::value_type value_type1;
982 value_type t1 = value_type1/*zero*/();
983 if (m_iterator1 != m_end1 && m_iterator1.index() == m_index)
984 t1 = *m_iterator1;
985 return m_functor(t1,*m_iterator2);
986 }
987
988 public:
989 // Arithmetic
990 binary_transform_iterator &operator ++ () {
991 increment(category1(),category2());
992 return *this;
993 }
994 binary_transform_iterator &operator -- () {
995 decrement(category1(),category2());
996 return *this;
997 }
998 binary_transform_iterator &operator += (difference_type n) {
999 increment(category1(),category2(), n);
1000 return *this;
1001 }
1002 binary_transform_iterator &operator -= (difference_type n) {
1003 increment(category1(),category2(), -n);
1004 return *this;
1005 }
1006 difference_type operator - (const binary_transform_iterator &it) const {
1007 difference_type diff1 = m_iterator1- it.m_iterator1;
1008 difference_type diff2 = m_iterator2- it.m_iterator2;
1009 return std::abs(diff1) > std::abs(diff2)? diff1:diff2;
1010 }
1011
1012 // Dereference
1013 reference operator * () const {
1014 return dereference(category1(),category2());
1015 }
1016 reference operator [](difference_type n) const {
1017 return *(*this + n);
1018 }
1019
1020 // Index
1021 size_type index() const {
1022 return m_index;
1023 }
1024
1025 // Comparison
1026 bool operator == (binary_transform_iterator const &it) const {
1027 return m_iterator1 == it.m_iterator1 && m_iterator2 == it.m_iterator2;
1028 }
1029 bool operator < (binary_transform_iterator const &it) const {
1030 return m_iterator1 < it.m_iterator1 || m_iterator2 < it.m_iterator2;
1031 }
1032private:
1033 size_type m_index;
1034 Iterator1 m_iterator1;
1035 Iterator1 m_end1;
1036 Iterator2 m_iterator2;
1037 Iterator2 m_end2;
1038 F m_functor;
1039};
1040
1041}}
1042
1043#endif