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 
39 namespace remora{ namespace iterators{
40 
41 //pure block expressions do not have an iterator but the interface still requires one.
42 // this is our cheap way out.
43 struct no_iterator{};
44 
45 // Iterator tags -- hierarchical definition of storage characteristics
46 struct sparse_bidirectional_iterator_tag: public std::bidirectional_iterator_tag{};
47 struct packed_random_access_iterator_tag: public std::random_access_iterator_tag{};
48 struct dense_random_access_iterator_tag: public packed_random_access_iterator_tag{};
49 
50 /** \brief Base class of all bidirectional iterators.
51  *
52  * \param I the derived iterator type
53  * \param T the value type
54  *
55  * The bidirectional iterator can proceed in both directions
56  * via the post increment and post decrement operator.
57  */
58 template<class I, class T>
59 struct bidirectional_iterator_base:
60  public std::iterator<sparse_bidirectional_iterator_tag, T> {
61  typedef I derived_iterator_type;
62  typedef T derived_value_type;
63 
64  // Arithmetic
65  derived_iterator_type operator ++ (int) {
66  derived_iterator_type &d(*static_cast<const derived_iterator_type *>(this));
67  derived_iterator_type tmp(d);
68  ++ d;
69  return tmp;
70  }
71 
72  derived_iterator_type operator -- (int) {
73  derived_iterator_type &d(*static_cast<const derived_iterator_type *>(this));
74  derived_iterator_type tmp(d);
75  -- d;
76  return tmp;
77  }
78 
79  // Comparison
80 
81  bool operator != (const derived_iterator_type &it) const {
82  const derived_iterator_type *d = static_cast<const derived_iterator_type *>(this);
83  return !(*d == it);
84  }
85 };
86 
87 /** \brief Base class of all random access iterators.
88  *
89  * \param I the derived iterator type
90  * \param T the value type
91  * \param Tag the iterator tag - must be dense/packed_random_access_iterator_tag
92  *
93  * The random access iterator can proceed in both directions
94  * via the post increment/decrement operator or in larger steps
95  * via the +, - and +=, -= operators. The random access iterator
96  * is LessThanComparable.
97  */
98 template<class I, class T, class Tag>
99 struct random_access_iterator_base
100 :public std::iterator<Tag, T> {
101  typedef I derived_iterator_type;
102  typedef T derived_value_type;
103  typedef std::ptrdiff_t difference_type;
104 
105  //~ I operator + (difference_type n) const {
106  //~ I tmp(*static_cast<const I *>(this));
107  //~ return tmp += n;
108  //~ }
109  //~ I operator - (difference_type n) const {
110  //~ I tmp(*static_cast<const I *>(this));
111  //~ return tmp -= n;
112  //~ }
113  friend I operator + (random_access_iterator_base const& it, difference_type n) {
114  I tmp(static_cast<const I&>(it));
115  return tmp += n;
116  }
117  friend I operator - (random_access_iterator_base const& it, difference_type n) {
118  I tmp(static_cast<const I&>(it));
119  return tmp -= n;
120  }
121 
122  friend I operator + (difference_type n, random_access_iterator_base const& it) {
123  I tmp(static_cast<const I&>(it));
124  return tmp += n;
125  }
126  friend I operator - (difference_type n, random_access_iterator_base const& it) {
127  I tmp(static_cast<const I&>(it));
128  return tmp -= n;
129  }
130 };
131 //arithmetic for random_access_iterators
132 template<class I, class T, class Tag>
133 I operator ++ (random_access_iterator_base<I,T,Tag>& it,int) {
134  I& d = static_cast<I&>(it);
135  I tmp(d);
136  ++ d;
137  return tmp;
138 }
139 
140 template<class I, class T, class Tag>
141 I operator -- (random_access_iterator_base<I,T,Tag>& it,int) {
142  I& d = static_cast<I&>(it);
143  I tmp(d);
144  -- d;
145  return tmp;
146 }
147 
148 
149 // Comparison of random_access_iterators
150 template<class I1, class T1, class I2, class T2, class Tag>
151 bool operator != (
152  random_access_iterator_base<I1,T1,Tag> const& it1,
153  random_access_iterator_base<I2,T2,Tag> const& it2
154 ){
155  I1 const& d1 = static_cast<const I1&>(it1);
156  I2 const& d2 = static_cast<const I2&>(it2);
157 
158  return !(d1 == d2);
159 }
160 template<class I1, class T1, class I2, class T2, class Tag>
161 bool operator <= (
162  random_access_iterator_base<I1,T1,Tag> const& it1,
163  random_access_iterator_base<I2,T2,Tag> const& it2
164 ){
165  I1 const& d1 = static_cast<const I1&>(it1);
166  I2 const& d2 = static_cast<const I2&>(it2);
167 
168  return !(d2 < d1);
169 }
170 template<class I1, class T1, class I2, class T2, class Tag>
171 bool operator >= (
172  random_access_iterator_base<I1,T1,Tag> const& it1,
173  random_access_iterator_base<I2,T2,Tag> const& it2
174 ){
175  I1 const& d1 = static_cast<const I1&>(it1);
176  I2 const& d2 = static_cast<const I2&>(it2);
177 
178  return !(d1 < d2);
179 }
180 template<class I1, class T1, class I2, class T2, class Tag>
181 bool operator > (
182  random_access_iterator_base<I1,T1,Tag> const& it1,
183  random_access_iterator_base<I2,T2,Tag> const& it2
184 ){
185  I1 const& d1 = static_cast<const I1&>(it1);
186  I2 const& d2 = static_cast<const I2&>(it2);
187 
188  return d2 < d1;
189 }
190 //traits lass for choosing the right base for wrapping iterators
191 
192 template<class IC>
193 struct iterator_base_traits {};
194 
195 template<>
196 struct iterator_base_traits<sparse_bidirectional_iterator_tag> {
197  template<class I, class T>
198  struct iterator_base {
199  typedef bidirectional_iterator_base<I, T> type;
200  };
201 };
202 template<>
203 struct iterator_base_traits<dense_random_access_iterator_tag> {
204  template<class I, class T>
205  struct iterator_base {
206  typedef random_access_iterator_base<I, T, dense_random_access_iterator_tag> type;
207  };
208 };
209 
210 template<>
211 struct iterator_base_traits<packed_random_access_iterator_tag> {
212  template<class I, class T>
213  struct iterator_base {
214  typedef random_access_iterator_base<I, T, packed_random_access_iterator_tag> type;
215  };
216 };
217 
218 template<class Closure>
219 class indexed_iterator:
220  public random_access_iterator_base<
221  indexed_iterator<Closure>,
222  typename Closure::value_type,
223  dense_random_access_iterator_tag
224  > {
225 public:
226  typedef std::size_t size_type;
227  typedef std::ptrdiff_t difference_type;
228  typedef typename Closure::value_type value_type;
229  typedef typename std::conditional<
230  std::is_const<Closure>::value,
231  typename Closure::const_reference,
232  typename Closure::reference
233  >::type reference;
234 
235  // Construction and destruction
236  indexed_iterator(){}
237  indexed_iterator(Closure container, size_type index)
238  : m_index(index), m_closure(container) {}
239 
240  template<class C>
241  indexed_iterator(indexed_iterator<C> const& iterator)
242  : m_index(iterator.m_index), m_closure(iterator.m_closure) {}
243 
244  // Arithmetic
245  indexed_iterator& operator++() {
246  ++m_index;
247  return *this;
248  }
249  indexed_iterator& operator--() {
250  --m_index;
251  return *this;
252  }
253  indexed_iterator& operator += (difference_type n) {
254  m_index += n;
255  return *this;
256  }
257  indexed_iterator& operator -= (difference_type n) {
258  m_index -= n;
259  return *this;
260  }
261  template<class T>
262  difference_type operator - (indexed_iterator<T> const& it) const {
263  return m_index - it.m_index;
264  }
265 
266  // Dereference
267  reference operator *() const {
268  REMORA_RANGE_CHECK(m_index < m_closure.size());
269  return m_closure(m_index);
270  }
271  reference operator [](difference_type n) const {
272  REMORA_RANGE_CHECK(m_index+n < m_closure.size());
273  return m_closure(m_index+n);
274  }
275 
276  // Index
277  size_type index() const {
278  return m_index;
279  }
280 
281  // Assignment
282  template<class T>
283  indexed_iterator &operator = (indexed_iterator<T> const& it) {
284  m_closure = it.m_closure;
285  m_index = it.m_index;
286  return *this;
287  }
288 
289  // Comparison
290  template<class T>
291  bool operator == (indexed_iterator<T> const& it) const {
292  return m_index == it.m_index;
293  }
294  template<class T>
295  bool operator < (indexed_iterator<T> const& it) const {
296  return m_index < it.m_index;
297  }
298 
299 private:
300  size_type m_index;
301  Closure m_closure;
302  template<class> friend class indexed_iterator;
303 };
304 
305 template<class T, class Tag=dense_random_access_iterator_tag>
306 class dense_storage_iterator:
307 public random_access_iterator_base<
308  dense_storage_iterator<T,Tag>,
309  typename std::remove_const<T>::type,
310  Tag
311 >{
312 public:
313  typedef std::size_t size_type;
314  typedef std::ptrdiff_t difference_type;
315  typedef typename std::remove_const<T>::type value_type;
316  typedef T& reference;
317  typedef T* pointer;
318 
319  // Construction
320  dense_storage_iterator():m_pos(0),m_index(0) {}
321  dense_storage_iterator(pointer pos, size_type index, difference_type stride = 1)
322  :m_pos(pos), m_index(index), m_stride(stride) {}
323 
324  template<class U>
325  dense_storage_iterator(dense_storage_iterator<U,Tag> const& iter)
326  :m_pos(iter.m_pos), m_index(iter.m_index), m_stride(iter.m_stride){}
327 
328  template<class U>
329  dense_storage_iterator& operator=(dense_storage_iterator<U,Tag> const& iter){
330  m_pos = iter.m_pos;
331  m_index = iter.m_index;
332  m_stride = iter.m_stride;
333  return *this;
334  }
335 
336  // Arithmetic
337  dense_storage_iterator& operator ++ () {
338  ++m_index;
339  m_pos += m_stride;
340  return *this;
341  }
342  dense_storage_iterator& operator -- () {
343  --m_index;
344  m_pos -= m_stride;
345  return *this;
346  }
347  dense_storage_iterator& operator += (difference_type n) {
348  m_index += n;
349  m_pos += n*m_stride;
350  return *this;
351  }
352  dense_storage_iterator& operator -= (difference_type n) {
353  m_index -= n;
354  m_pos -= n*m_stride;
355  return *this;
356  }
357  template<class U>
358  difference_type operator - (dense_storage_iterator<U,Tag> const& it) const {
359  //REMORA_RANGE_CHECK(m_pos == it.m_pos);
360  return (difference_type)m_index - (difference_type)it.m_index;
361  }
362 
363  // Dereference
364  reference operator*() const {
365  return *m_pos;
366  }
367  reference operator [](difference_type n) const {
368  return m_pos[m_stride*n];
369  }
370 
371  // Index
372  size_type index() const {
373  return m_index;
374  }
375 
376  // Comparison
377  template<class U>
378  bool operator == (dense_storage_iterator<U,Tag> const& it) const {
379  //REMORA_RANGE_CHECK(m_pos == it.m_pos);
380  //~ REMORA_RANGE_CHECK(m_index < it.m_index);
381  return m_index == it.m_index;
382  }
383  template<class U>
384  bool operator < (dense_storage_iterator<U,Tag> const& it) const {
385  //REMORA_RANGE_CHECK(m_pos == it.m_pos);
386  return m_index < it.m_index;
387  }
388 
389 private:
390  pointer m_pos;
391  size_type m_index;
392  difference_type m_stride;
393  template<class,class> friend class dense_storage_iterator;
394 };
395 template<class T, class I>
396 class compressed_storage_iterator:
397  public bidirectional_iterator_base<
398  compressed_storage_iterator<T,I>,typename std::remove_const<T>::type
399  >{
400 public:
401  typedef typename std::remove_const<T>::type value_type;
402  typedef typename std::remove_const<I>::type size_type;
403  typedef std::ptrdiff_t difference_type;
404  typedef T& reference;
405  typedef T* pointer;
406 
407  // Construction and Assignment
408  compressed_storage_iterator() {}
409  compressed_storage_iterator(
410  T* value_array, I* index_array,
411  size_type position, size_type row = 0
412  )
413  : m_values(value_array),m_indices(index_array)
414  , m_position(position), m_row(row){}
415 
416  template<class U,class V>
417  compressed_storage_iterator(compressed_storage_iterator<U,V> const& it) {
418  m_position = it.m_position;
419  m_row = it.m_row;
420  m_values = it.m_values;
421  m_indices = it.m_indices;
422  }
423 
424  template<class U,class V>
425  compressed_storage_iterator &operator = (compressed_storage_iterator<U,V> const& it) {
426  m_position = it.m_position;
427  m_row = it.m_row;
428  m_values = it.m_values;
429  m_indices = it.m_indices;
430  return *this;
431  }
432 
433  // Arithmetic
434  compressed_storage_iterator &operator++ () {
435  ++m_position;
436  return *this;
437  }
438  compressed_storage_iterator &operator -- () {
439  REMORA_RANGE_CHECK(m_position > 0);
440  --m_position;
441  return *this;
442  }
443 
444  // Dereference
445  reference operator* () const {
446  return m_values[m_position];
447  }
448  size_type index() const {
449  return m_indices[m_position];
450  }
451 
452  template<class U,class V>
453  difference_type operator - (compressed_storage_iterator<U,V> const& it) const {
454  REMORA_RANGE_CHECK(m_values == it.m_values);
455  REMORA_RANGE_CHECK(m_indices == it.m_indices);
456  return difference_type(m_position) - difference_type(it.m_position);
457  }
458 
459  size_type row()const{
460  return m_row;
461  }
462 
463  template<class U,class V>
464  bool operator == (compressed_storage_iterator<U,V> const &it) const {
465  REMORA_RANGE_CHECK(m_values == it.m_values);
466  REMORA_RANGE_CHECK(m_indices == it.m_indices);
467  return m_position == it.m_position;
468  }
469 
470 private:
471  T* m_values;
472  I* m_indices;
473  std::size_t m_position;
474  std::size_t m_row;
475  template<class,class> friend class compressed_storage_iterator;
476 };
477 
478 template<class BaseIterator>
479 class subrange_iterator:
480  public iterator_base_traits<typename BaseIterator::iterator_category>::template
481  iterator_base<subrange_iterator<BaseIterator>, typename BaseIterator::value_type>::type {
482 private:
483  template<class Iterator>
484  Iterator incrementToIndex(
485  Iterator iter, Iterator end, std::size_t index, dense_random_access_iterator_tag
486  ) {
487  REMORA_SIZE_CHECK(iter.index()<= index);
488  return iter+(index-iter.index());
489  }
490  template<class Iterator>
491  Iterator incrementToIndex(
492  Iterator iter, Iterator end, std::size_t index, packed_random_access_iterator_tag
493  ) {
494  if(iter < end ){
495  REMORA_RANGE_CHECK(iter.index() < index);
496  return iter+std::min<std::ptrdiff_t>(std::ptrdiff_t(index-iter.index()),end-iter);
497  }
498  return end;
499  }
500 
501  template<class Iterator>
502  Iterator incrementToIndex(
503  Iterator iter, Iterator end, std::size_t index,sparse_bidirectional_iterator_tag
504  ) {
505  while (iter != end && iter.index() < index)++iter;
506  return iter;
507  }
508  template<class Iterator>
509  Iterator incrementToIndex(
510  Iterator iter, Iterator end, std::size_t index
511  ) {
512  return incrementToIndex(iter,end,index,typename Iterator::iterator_category());
513  }
514 public:
515  typedef typename BaseIterator::value_type value_type;
516  typedef typename BaseIterator::difference_type difference_type;
517  typedef typename BaseIterator::reference reference;
518  typedef typename BaseIterator::pointer pointer;
519 
520  // Construction and destruction
521  subrange_iterator() {}
522 
523  subrange_iterator(BaseIterator const &it, BaseIterator const &end, std::size_t startIterIndex,std::size_t startIndex)
524  : m_iterator(incrementToIndex(it,end,startIterIndex)),m_start(startIndex) {}
525 
526  subrange_iterator(BaseIterator const &it, std::size_t startIndex)
527  : m_iterator(it),m_start(startIndex) {}
528 
529  template<class Iterator>
530  subrange_iterator(subrange_iterator<Iterator> const &it)
531  :m_iterator(it.m_iterator), m_start(it.m_start) {}
532 
533  // Arithmetic
534  subrange_iterator &operator ++ () {
535  ++ m_iterator;
536  return *this;
537  }
538 
539  subrange_iterator &operator -- () {
540  -- m_iterator;
541  return *this;
542  }
543 
544  subrange_iterator &operator += (difference_type n) {
545  m_iterator += n;
546  return *this;
547  }
548 
549  subrange_iterator &operator -= (difference_type n) {
550  m_iterator -= n;
551  return *this;
552  }
553 
554  difference_type operator - (subrange_iterator const &it) const {
555  return m_iterator - it.m_iterator;
556  }
557 
558  // Dereference
559  reference operator * () const {
560  return *m_iterator;
561  }
562  reference operator [](difference_type n) const {
563  return *(*this + n);
564  }
565 
566  // Indices
567  std::size_t index() const {
568  return m_iterator.index() - m_start;
569  }
570 
571  // Assignment
572  template<class Iterator>
573  subrange_iterator &operator = (subrange_iterator<Iterator> const &it) {
574  m_iterator = it.m_iterator;
575  m_start = it.m_start;
576  return *this;
577  }
578 
579  // Comparison
580  template<class Iterator>
581  bool operator == (subrange_iterator<Iterator> const &it) const {
582  return m_iterator == it.m_iterator;
583  }
584  template<class Iterator>
585  bool operator < (subrange_iterator<Iterator> const &it) const {
586  return m_iterator < it.m_iterator;
587  }
588 
589  BaseIterator inner()const {
590  return m_iterator;
591  }
592 
593 private:
594  BaseIterator m_iterator;
595  std::size_t m_start;
596  template<class> friend class subrange_iterator;
597 };
598 
599 
600 template<class T>
601 class constant_iterator:
602 public random_access_iterator_base<
603  constant_iterator<T>,
604  typename std::remove_const<T>::type,
605  dense_random_access_iterator_tag
606 >{
607 public:
608  typedef std::size_t size_type;
609  typedef std::ptrdiff_t difference_type;
610  typedef T value_type;
611  typedef value_type const &reference;
612  typedef value_type const *pointer;
613 
614  // Construction and destruction
615  constant_iterator() {}
616  constant_iterator(value_type value, size_type position)
617  :m_position(position),m_value(value) {}
618 
619  // Arithmetic
620  constant_iterator &operator ++ () {
621  ++ m_position;
622  return *this;
623  }
624  constant_iterator &operator -- () {
625  -- m_position;
626  return *this;
627  }
628  constant_iterator &operator += (difference_type n) {
629  m_position += n;
630  return *this;
631  }
632  constant_iterator &operator -= (difference_type n) {
633  m_position -= n;
634  return *this;
635  }
636  difference_type operator - (constant_iterator const &it) const {
637  return m_position - it.m_position;
638  }
639 
640  // Dereference
641  reference operator * () const {
642  return m_value;
643  }
644  reference operator [](difference_type n) const {
645  return m_value;
646  }
647 
648  // Indices
649  size_type index() const {
650  return m_position;
651  }
652 
653  // Assignment
654  template<class Iter>
655  constant_iterator &operator = (constant_iterator const &it) {
656  m_position = it.m_position;
657  m_value = it.m_value;
658  return *this;
659  }
660 
661  // Comparison
662  bool operator == (constant_iterator const &it) const {
663  return m_position == it.m_position;
664  }
665  bool operator < (constant_iterator const &it) const {
666  return m_position < it.m_position;
667  }
668 private:
669  size_type m_position;
670  value_type m_value;
671 };
672 
673 template<class BaseIterator, class F>
674 class transform_iterator:
675  public iterator_base_traits<typename BaseIterator::iterator_category>::template
676  iterator_base<transform_iterator<BaseIterator,F>, typename BaseIterator::value_type>::type {
677 public:
678  typedef typename BaseIterator::iterator_category iterator_category;
679  typedef std::size_t size_type;
680  typedef std::ptrdiff_t difference_type;
681  typedef typename std::result_of<F(typename BaseIterator::value_type)>::type value_type;
682  typedef value_type reference;
683  typedef value_type *pointer;
684 
685  // Construction and destruction
686  transform_iterator() {}
687  transform_iterator(BaseIterator const &it,F functor)
688  :m_position(it),m_functor(functor) {}
689 
690  // Arithmetic
691  transform_iterator &operator ++ () {
692  ++ m_position;
693  return *this;
694  }
695  transform_iterator &operator -- () {
696  -- m_position;
697  return *this;
698  }
699  transform_iterator &operator += (difference_type n) {
700  m_position += n;
701  return *this;
702  }
703  transform_iterator &operator -= (difference_type n) {
704  m_position -= n;
705  return *this;
706  }
707  difference_type operator - (transform_iterator const &it) const {
708  return m_position - it.m_position;
709  }
710 
711  // Dereference
712  reference operator * () const {
713  return m_functor(*m_position);
714  }
715  reference operator [](difference_type n) const {
716  return *(*this + n);
717  }
718 
719  // Indices
720  size_type index() const {
721  return m_position.index();
722  }
723 
724  // Assignment
725  template<class Iter>
726  transform_iterator &operator = (transform_iterator<Iter,F> const &it) {
727  m_position = it.m_position;
728  m_functor = it.m_functor;
729  return *this;
730  }
731 
732  // Comparison
733  bool operator == (transform_iterator const &it) const {
734  return m_position == it.m_position;
735  }
736  bool operator < (transform_iterator const &it) const {
737  return m_position < it.m_position;
738  }
739 
740 private:
741  BaseIterator m_position;
742  F m_functor;
743 };
744 
745 template<class T>
746 class one_hot_iterator:public bidirectional_iterator_base<one_hot_iterator<T>, T> {
747 public:
748  typedef T value_type;
749  typedef std::ptrdiff_t difference_type;
750  typedef std::size_t size_type;
751  typedef T& reference;
752  typedef T const& const_reference;
753  typedef value_type const* pointer;
754 
755  // Construction and destruction
756  one_hot_iterator(){}
757  one_hot_iterator(size_type index, value_type value, bool isEnd)
758  :m_index(index),m_value(value),m_isEnd(isEnd){}
759 
760  // Arithmetic
761  one_hot_iterator& operator ++ () {
762  m_isEnd = true;
763  return *this;
764  }
765  one_hot_iterator& operator -- () {
766  m_isEnd = false;
767  return *this;
768  }
769 
770  // Dereference
771  reference operator*() const {
772  return m_value;
773  }
774 
775  // Indices
776  size_type index() const{
777  return m_index;
778  }
779 
780  // Assignment
781  one_hot_iterator& operator = (one_hot_iterator const& it) {
782  m_index = it.m_index;
783  m_value = it.m_value;
784  return *this;
785  }
786 
787  // Comparison
788  bool operator == (one_hot_iterator const& it) const {
789  REMORA_RANGE_CHECK(m_index == it.m_index);
790  return m_isEnd == it.m_isEnd;
791  }
792 
793 private:
794  size_type m_index;
795  value_type m_value;
796  bool m_isEnd;
797 };
798 
799 
800 template<class I1, class I2>
801 struct iterator_restrict_traits {
802  typedef I1 iterator_category;
803 };
804 
805 template<>
806 struct iterator_restrict_traits<dense_random_access_iterator_tag, sparse_bidirectional_iterator_tag> {
807  typedef sparse_bidirectional_iterator_tag iterator_category;
808 };
809 
810 template<>
811 struct iterator_restrict_traits<packed_random_access_iterator_tag,dense_random_access_iterator_tag> {
812  typedef dense_random_access_iterator_tag iterator_category;
813 };
814 
815 template<>
816 struct iterator_restrict_traits<packed_random_access_iterator_tag,sparse_bidirectional_iterator_tag> {
817  typedef sparse_bidirectional_iterator_tag iterator_category;
818 };
819 
820 template<class Iterator1, class Iterator2, class F>
821 class binary_transform_iterator:
822 public iterator_base_traits<
823  typename iterator_restrict_traits<
824  typename Iterator1::iterator_category,
825  typename Iterator2::iterator_category
826  >::iterator_category
827 >::template iterator_base<
828  binary_transform_iterator<Iterator1,Iterator2,F>,
829  typename std::result_of<F(typename Iterator1::value_type, typename Iterator2::value_type)>::type
830 >::type{
831 private:
832  typedef typename Iterator1::iterator_category category1;
833  typedef typename Iterator2::iterator_category category2;
834 public:
835  typedef typename iterator_restrict_traits<
836  category1,
837  category2
838  >::iterator_category iterator_category;
839  typedef std::size_t size_type;
840  typedef std::ptrdiff_t difference_type;
841  typedef typename std::result_of<F(typename Iterator1::value_type, typename Iterator2::value_type)>::type value_type;
842  typedef value_type reference;
843  typedef value_type *pointer;
844 
845  // Construction and destruction
846  binary_transform_iterator() {}
847  binary_transform_iterator(
848  F functor,
849  Iterator1 const &it1, Iterator1 const &end1,
850  Iterator2 const &it2, Iterator2 const &end2
851  ):m_index(0)
852  , m_iterator1(it1), m_end1(end1)
853  , m_iterator2(it2), m_end2(end2)
854  , m_functor(functor)
855  {
856  //ensure that both iterators start at a valid location
857  ensureValidPosition(category1(),category2());
858 
859  //we can't get the correct index for end iterators
860  if(m_iterator1 != end1 && m_iterator2 != end2)
861  m_index = std::min(m_iterator1.index(),m_iterator2.index());
862 
863 
864  }
865 
866 private:
867  //we need to handle all specializations independently from each other
868 
869  // Dense specializations are easy
870  void ensureValidPosition(
871  dense_random_access_iterator_tag,
872  dense_random_access_iterator_tag
873  ){}
874  void increment(
875  dense_random_access_iterator_tag,
876  dense_random_access_iterator_tag
877  ) {
878  ++ m_index;
879  ++ m_iterator1;
880  ++ m_iterator2;
881  }
882  void decrement(
883  dense_random_access_iterator_tag,
884  dense_random_access_iterator_tag
885  ) {
886  -- m_index;
887  -- m_iterator1;
888  -- m_iterator2;
889  }
890  void increment(
891  dense_random_access_iterator_tag,
892  dense_random_access_iterator_tag,
893  difference_type n
894  ) {
895  m_index += n;
896  m_iterator1 += n;
897  m_iterator2 += n;
898  }
899  value_type dereference(
900  dense_random_access_iterator_tag,
901  dense_random_access_iterator_tag
902  ) const {
903  return m_functor(*m_iterator1, *m_iterator2);
904  }
905 
906  // Sparse specializations
907  void ensureValidPosition(
908  sparse_bidirectional_iterator_tag,
909  sparse_bidirectional_iterator_tag
910  ){
911  //ensure that both iterators point to the same index
912  if(F::left_zero_remains || F::right_zero_remains){
913  while(
914  m_iterator1 != m_end1 && m_iterator2 != m_end2
915  && m_iterator1.index() != m_iterator2.index()
916  ){
917  if(m_iterator1.index() < m_iterator2.index())
918  ++m_iterator1;
919  else
920  ++m_iterator2;
921  }
922  if( m_iterator1 == m_end1 || m_iterator2 == m_end2){
923  m_iterator2 = m_end2;
924  m_iterator1 = m_end1;
925  }
926  }
927  }
928  void increment(
929  sparse_bidirectional_iterator_tag,
930  sparse_bidirectional_iterator_tag
931  ) {
932  if(F::left_zero_remains || F::right_zero_remains){
933  ++ m_iterator1;
934  ++ m_iterator2;
935  ensureValidPosition(category1(),category2());
936  }else{
937  if (m_iterator1 != m_end1 && m_iterator2 != m_end2){
938  if( m_iterator1.index() == m_iterator2.index()){
939  ++ m_iterator1;
940  ++ m_iterator2;
941  }
942  else if(m_iterator1.index() < m_iterator2.index())
943  ++m_iterator1;
944  else
945  ++m_iterator2;
946  }else if(m_iterator1 != m_end1){
947  ++ m_iterator1;
948  }else{
949  ++ m_iterator2;
950  }
951  }
952  size_type index1 = std::numeric_limits<size_type>::max();
953  size_type index2 = std::numeric_limits<size_type>::max();
954  if(m_iterator1 != m_end1)
955  index1 = m_iterator1.index();
956  if(m_iterator2 != m_end2)
957  index2 = m_iterator2.index();
958 
959  m_index = std::min(index1, index2);
960  }
961  void decrement(
962  sparse_bidirectional_iterator_tag,
963  sparse_bidirectional_iterator_tag
964  ) {
965  if (m_index <= m_iterator1.index())
966  -- m_iterator1;
967  if (m_index <= m_iterator2.index())
968  -- m_iterator2;
969  m_index = std::max(m_iterator1.index(), m_iterator2.index());
970  }
971  void increment(
972  sparse_bidirectional_iterator_tag,
973  sparse_bidirectional_iterator_tag,
974  difference_type n
975  ) {
976  while (n > 0) {
977  increment(category1(),category2());
978  --n;
979  }
980  while (n < 0) {
981  decrement(category1(),category2());
982  ++n;
983  }
984  }
985  value_type dereference(
986  sparse_bidirectional_iterator_tag,
987  sparse_bidirectional_iterator_tag
988  ) const {
989  value_type t1 = value_type/*zero*/();
990  if (m_iterator1 != m_end1 && m_iterator1.index() == m_index)
991  t1 = *m_iterator1;
992  value_type t2 = value_type/*zero*/();
993  if (m_iterator2 != m_end2 && m_iterator2.index() == m_index)
994  t2 = *m_iterator2;
995  return m_functor(t1, t2);
996  }
997 
998  //dense-sparse
999  // Sparse specializations
1000  void ensureValidPosition(
1001  dense_random_access_iterator_tag,
1002  sparse_bidirectional_iterator_tag
1003  ){
1004  if(F::right_zero_remains){
1005  m_iterator1 += m_iterator2.index()-m_iterator1.index();
1006  }
1007  }
1008 
1009  void increment(
1010  dense_random_access_iterator_tag,
1011  sparse_bidirectional_iterator_tag
1012  ) {
1013  if(F::right_zero_remains){
1014  ++ m_iterator2;
1015  m_iterator1 += m_iterator2.index()-m_iterator1.index();
1016  }else{
1017  if (m_iterator2 != m_end2){
1018  if( m_iterator1.index() == m_iterator2.index()){
1019  ++ m_iterator1;
1020  ++ m_iterator2;
1021  }
1022  else if(m_iterator2.index() > m_iterator1.index())
1023  ++m_iterator1;
1024  else
1025  ++m_iterator2;
1026  }else
1027  ++ m_iterator1;
1028  }
1029  size_type index1 = m_iterator1.index();
1030  size_type index2 = std::numeric_limits<size_type>::max();
1031  if(m_iterator2 != m_end2)
1032  index2 = m_iterator2.index();
1033  m_index = std::min(index1, index2);
1034  }
1035  void decrement(
1036  dense_random_access_iterator_tag,
1037  sparse_bidirectional_iterator_tag
1038  ) {
1039  if(F::right_zero_remains){
1040  -- m_iterator2;
1041  m_iterator1 -= m_iterator1.index()-m_iterator2.index();
1042  }else{
1043  if (m_index <= m_iterator1.index())
1044  -- m_iterator1;
1045  if (m_index <= m_iterator2.index())
1046  -- m_iterator2;
1047  m_index = std::max(m_iterator1.index(), m_iterator2.index());
1048  }
1049  }
1050  void increment(
1051  dense_random_access_iterator_tag,
1052  sparse_bidirectional_iterator_tag,
1053  difference_type n
1054  ) {
1055  while (n > 0) {
1056  increment(category1(),category2());
1057  --n;
1058  }
1059  while (n < 0) {
1060  decrement(category1(),category2());
1061  ++n;
1062  }
1063  }
1064  value_type dereference(
1065  dense_random_access_iterator_tag,
1066  sparse_bidirectional_iterator_tag
1067  ) const {
1068  typedef typename Iterator2::value_type value_type2;
1069  value_type t2 = value_type2/*zero*/();
1070  if (m_iterator2 != m_end2 && m_iterator2.index() == m_index)
1071  t2 = *m_iterator2;
1072  return m_functor(*m_iterator1, t2);
1073  }
1074 
1075  //sparse-dense
1076  void ensureValidPosition(
1077  sparse_bidirectional_iterator_tag,
1078  dense_random_access_iterator_tag
1079  ){
1080  if(F::left_zero_remains){
1081  m_iterator2 += m_iterator1.index()-m_iterator2.index();
1082  }
1083  }
1084  void increment(
1085  sparse_bidirectional_iterator_tag,
1086  dense_random_access_iterator_tag
1087  ) {
1088  if(F::left_zero_remains){
1089  ++ m_iterator1;
1090  m_iterator2 += m_iterator1.index()-m_iterator2.index();
1091  }else{
1092  if (m_iterator1 != m_end1){
1093  if( m_iterator1.index() == m_iterator2.index()){
1094  ++ m_iterator1;
1095  ++ m_iterator2;
1096  }
1097  else if(m_iterator1.index() > m_iterator2.index())
1098  ++m_iterator2;
1099  else
1100  ++m_iterator1;
1101  }else
1102  ++ m_iterator2;
1103  }
1104  size_type index1 = std::numeric_limits<size_type>::max();
1105  size_type index2 = m_iterator2.index();
1106  if(m_iterator1 != m_end1)
1107  index1 = m_iterator1.index();
1108  m_index = std::min(index1, index2);
1109  }
1110  void decrement(
1111  sparse_bidirectional_iterator_tag,
1112  dense_random_access_iterator_tag
1113  ) {
1114  if(F::left_zero_remains){
1115  -- m_iterator1;
1116  m_iterator2 -= m_iterator2.index()-m_iterator1.index();
1117  }else{
1118  if (m_index <= m_iterator2.index())
1119  -- m_iterator2;
1120  if (m_index <= m_iterator1.index())
1121  -- m_iterator1;
1122  m_index = std::max(m_iterator1.index(), m_iterator2.index());
1123  }
1124  }
1125  void increment(
1126  sparse_bidirectional_iterator_tag,
1127  dense_random_access_iterator_tag,
1128  difference_type n
1129  ) {
1130  while (n > 0) {
1131  increment(category1(),category2());
1132  --n;
1133  }
1134  while (n < 0) {
1135  decrement(category1(),category2());
1136  ++n;
1137  }
1138  }
1139  value_type dereference(
1140  sparse_bidirectional_iterator_tag,
1141  dense_random_access_iterator_tag
1142  ) const {
1143  typedef typename Iterator1::value_type value_type1;
1144  value_type t1 = value_type1/*zero*/();
1145  if (m_iterator1 != m_end1 && m_iterator1.index() == m_index)
1146  t1 = *m_iterator1;
1147  return m_functor(t1,*m_iterator2);
1148  }
1149 
1150  public:
1151  // Arithmetic
1152  binary_transform_iterator &operator ++ () {
1153  increment(category1(),category2());
1154  return *this;
1155  }
1156  binary_transform_iterator &operator -- () {
1157  decrement(category1(),category2());
1158  return *this;
1159  }
1160  binary_transform_iterator &operator += (difference_type n) {
1161  increment(category1(),category2(), n);
1162  return *this;
1163  }
1164  binary_transform_iterator &operator -= (difference_type n) {
1165  increment(category1(),category2(), -n);
1166  return *this;
1167  }
1168  difference_type operator - (const binary_transform_iterator &it) const {
1169  difference_type diff1 = m_iterator1- it.m_iterator1;
1170  difference_type diff2 = m_iterator2- it.m_iterator2;
1171  return std::abs(diff1) > std::abs(diff2)? diff1:diff2;
1172  }
1173 
1174  // Dereference
1175  reference operator * () const {
1176  return dereference(category1(),category2());
1177  }
1178  reference operator [](difference_type n) const {
1179  return *(*this + n);
1180  }
1181 
1182  // Index
1183  size_type index() const {
1184  return m_index;
1185  }
1186 
1187  // Assignment
1188  binary_transform_iterator &operator = (binary_transform_iterator const &it) {
1189  m_index = it.m_index;
1190  m_iterator1 = it.m_iterator1;
1191  m_end1 = it.m_end1;
1192  m_iterator2 = it.m_iterator2;
1193  m_end2 = it.m_end2;
1194  return *this;
1195  }
1196 
1197  // Comparison
1198  bool operator == (binary_transform_iterator const &it) const {
1199  return m_iterator1 == it.m_iterator1 && m_iterator2 == it.m_iterator2;
1200  }
1201  bool operator < (binary_transform_iterator const &it) const {
1202  return m_iterator1 < it.m_iterator1 || m_iterator2 < it.m_iterator2;
1203  }
1204 private:
1205  size_type m_index;
1206  Iterator1 m_iterator1;
1207  Iterator1 m_end1;
1208  Iterator2 m_iterator2;
1209  Iterator2 m_end2;
1210  F m_functor;
1211 };
1212 
1213 }}
1214 
1215 #endif