1//
2// Copyright 2013 Francisco Jerez
3//
4// Permission is hereby granted, free of charge, to any person obtaining a
5// copy of this software and associated documentation files (the "Software"),
6// to deal in the Software without restriction, including without limitation
7// the rights to use, copy, modify, merge, publish, distribute, sublicense,
8// and/or sell copies of the Software, and to permit persons to whom the
9// Software is furnished to do so, subject to the following conditions:
10//
11// The above copyright notice and this permission notice shall be included in
12// all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20// OTHER DEALINGS IN THE SOFTWARE.
21//
22
23#ifndef CLOVER_UTIL_ADAPTOR_HPP
24#define CLOVER_UTIL_ADAPTOR_HPP
25
26#include <iterator>
27
28#include "util/tuple.hpp"
29#include "util/pointer.hpp"
30#include "util/functional.hpp"
31
32namespace clover {
33   namespace detail {
34      ///
35      /// Implementation of the iterator concept that transforms the
36      /// value of the source iterators \a Is on dereference by use of
37      /// a functor \a F.
38      ///
39      /// The exact category of the resulting iterator should be the
40      /// least common denominator of the source iterator categories.
41      ///
42      template<typename F, typename... Is>
43      class iterator_adaptor {
44      public:
45         typedef std::forward_iterator_tag iterator_category;
46         typedef typename std::result_of<
47               F(typename std::iterator_traits<Is>::reference...)
48            >::type reference;
49         typedef typename std::remove_reference<reference>::type value_type;
50         typedef pseudo_ptr<value_type> pointer;
51         typedef std::ptrdiff_t difference_type;
52
53         iterator_adaptor() {
54         }
55
56         iterator_adaptor(F f, std::tuple<Is...> &&its) :
57            f(f), its(std::move(its)) {
58         }
59
60         reference
61         operator*() const {
62            return tuple::apply(f, tuple::map(derefs(), its));
63         }
64
65         iterator_adaptor &
66         operator++() {
67            tuple::map(preincs(), its);
68            return *this;
69         }
70
71         iterator_adaptor
72         operator++(int) {
73            auto jt = *this;
74            ++*this;
75            return jt;
76         }
77
78         bool
79         operator==(const iterator_adaptor &jt) const {
80            return its == jt.its;
81         }
82
83         bool
84         operator!=(const iterator_adaptor &jt) const {
85            return its != jt.its;
86         }
87
88         pointer
89         operator->() const {
90            return { **this };
91         }
92
93         iterator_adaptor &
94         operator--() {
95            tuple::map(predecs(), its);
96            return *this;
97         }
98
99         iterator_adaptor
100         operator--(int) {
101            auto jt = *this;
102            --*this;
103            return jt;
104         }
105
106         iterator_adaptor &
107         operator+=(difference_type n) {
108            tuple::map(advances_by(n), its);
109            return *this;
110         }
111
112         iterator_adaptor &
113         operator-=(difference_type n) {
114            tuple::map(advances_by(-n), its);
115            return *this;
116         }
117
118         iterator_adaptor
119         operator+(difference_type n) const {
120            auto jt = *this;
121            jt += n;
122            return jt;
123         }
124
125         iterator_adaptor
126         operator-(difference_type n) const {
127            auto jt = *this;
128            jt -= n;
129            return jt;
130         }
131
132         difference_type
133         operator-(const iterator_adaptor &jt) const {
134            return std::get<0>(its) - std::get<0>(jt.its);
135         }
136
137         reference
138         operator[](difference_type n) const {
139            return *(*this + n);
140         }
141
142         bool
143         operator<(iterator_adaptor &jt) const {
144            return *this - jt < 0;
145         }
146
147         bool
148         operator>(iterator_adaptor &jt) const {
149            return *this - jt > 0;
150         }
151
152         bool
153         operator>=(iterator_adaptor &jt) const {
154            return !(*this < jt);
155         }
156
157         bool
158         operator<=(iterator_adaptor &jt) const {
159            return !(*this > jt);
160         }
161
162      protected:
163         F f;
164         std::tuple<Is...> its;
165      };
166
167      template<typename F, typename... Is>
168      iterator_adaptor<F, Is...>
169      operator+(typename iterator_adaptor<F, Is...>::difference_type n,
170                const iterator_adaptor<F, Is...> &jt) {
171         return (jt + n);
172      }
173
174      template<typename F, typename... Is>
175      iterator_adaptor<F, Is...>
176      operator-(typename iterator_adaptor<F, Is...>::difference_type n,
177                const iterator_adaptor<F, Is...> &jt) {
178         return (jt - n);
179      }
180   }
181}
182
183#endif
184