• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_RANGE_HPP
24 #define CLOVER_UTIL_RANGE_HPP
25 
26 #include <array>
27 #include <vector>
28 
29 #include "util/adaptor.hpp"
30 
31 namespace clover {
32    ///
33    /// Class that identifies container types where the elements of a
34    /// range can be stored by the type conversion operator.
35    ///
36    /// \a T identifies the range element type.
37    ///
38    template<typename T, typename V>
39    struct range_store_traits;
40 
41    template<typename T, typename S>
42    struct range_store_traits<T, std::vector<S>> {
43       typedef void enable;
44 
45       template<typename R>
46       static std::vector<S>
createclover::range_store_traits47       create(const R &r) {
48          return { r.begin(), r.end() };
49       }
50    };
51 
52    template<typename T, typename S, std::size_t N>
53    struct range_store_traits<T, std::array<S, N>> {
54       typedef void enable;
55 
56       template<typename R>
57       static std::array<S, N>
createclover::range_store_traits58       create(const R &r) {
59          std::array<S, N> v;
60          assert(r.size() == v.size());
61          copy(r, v.begin());
62          return v;
63       }
64    };
65 
66    namespace detail {
67       ///
68       /// Common functionality that is shared by other implementations
69       /// of the container concept.
70       ///
71       template<typename R, typename I, typename CI>
72       class basic_range {
73       public:
74          typedef I iterator;
75          typedef CI const_iterator;
76          typedef typename std::iterator_traits<iterator>::value_type value_type;
77          typedef typename std::iterator_traits<iterator>::reference
78             reference;
79          typedef typename std::iterator_traits<const_iterator>::reference
80             const_reference;
81          typedef typename std::iterator_traits<iterator>::difference_type
82             difference_type;
83          typedef std::size_t size_type;
84 
85          bool
operator ==(const basic_range & r) const86          operator==(const basic_range &r) const {
87             return *static_cast<const R *>(this) == r;
88          }
89 
90          bool
operator !=(const basic_range & r) const91          operator!=(const basic_range &r) const {
92             return !(*this == r);
93          }
94 
95          iterator
begin()96          begin() {
97             return static_cast<R *>(this)->begin();
98          }
99 
100          iterator
end()101          end() {
102             return static_cast<R *>(this)->end();
103          }
104 
105          const_iterator
begin() const106          begin() const {
107             return static_cast<const R *>(this)->begin();
108          }
109 
110          const_iterator
end() const111          end() const {
112             return static_cast<const R *>(this)->end();
113          }
114 
115          std::reverse_iterator<iterator>
rbegin()116          rbegin() {
117             return { begin() };
118          }
119 
120          std::reverse_iterator<iterator>
rend()121          rend() {
122             return { end() };
123          }
124 
125          reference
front()126          front() {
127             return *begin();
128          }
129 
130          reference
back()131          back() {
132             return *(end() - 1);
133          }
134 
135          bool
empty() const136          empty() const {
137             return begin() == end();
138          }
139 
140          reference
at(size_type i)141          at(size_type i) {
142             if (i >= static_cast<const R *>(this)->size())
143                throw std::out_of_range("");
144 
145             return begin()[i];
146          }
147 
148          const_reference
at(size_type i) const149          at(size_type i) const {
150             if (i >= static_cast<const R *>(this)->size())
151                throw std::out_of_range("");
152 
153             return begin()[i];
154          }
155 
156          reference
operator [](size_type i)157          operator[](size_type i) {
158             return begin()[i];
159          }
160 
161          const_reference
operator [](size_type i) const162          operator[](size_type i) const {
163             return begin()[i];
164          }
165 
166          template<typename V>
167          using store_traits = range_store_traits<
168                typename std::remove_cv<value_type>::type, V
169             >;
170 
171          template<typename V,
172                   typename = typename store_traits<V>::enable>
operator V() const173          operator V() const {
174             return store_traits<V>::create(*static_cast<const R *>(this));
175          }
176       };
177    }
178 
179    ///
180    /// Range that contains all elements delimited by an iterator pair
181    /// (\a i, \a j).  Use range() as convenience constructor.
182    ///
183    template<typename I>
184    class iterator_range : public detail::basic_range<iterator_range<I>, I, I> {
185    public:
186       typedef detail::basic_range<iterator_range<I>, I, I> super;
187 
iterator_range()188       iterator_range() : i(), j() {
189       }
190 
iterator_range(I i,I j)191       iterator_range(I i, I j) : i(i), j(j) {
192       }
193 
194       bool
operator ==(const iterator_range & r) const195       operator==(const iterator_range &r) const {
196          return i == r.i && j == r.j;
197       }
198 
199       I
begin() const200       begin() const {
201          return i;
202       }
203 
204       I
end() const205       end() const {
206          return j;
207       }
208 
209       typename super::size_type
size() const210       size() const {
211          return end() - begin();
212       }
213 
214    private:
215       I i, j;
216    };
217 
218    namespace detail {
219       template<typename T>
220       using preferred_iterator_type = decltype(std::declval<T>().begin());
221    }
222 
223    ///
224    /// Range that transforms the contents of a number of source ranges
225    /// \a os element-wise by using the provided functor \a f.  Use
226    /// map() as convenience constructor.
227    ///
228    template<typename F, typename... Os>
229    class adaptor_range :
230       public detail::basic_range<adaptor_range<F, Os...>,
231                                  detail::iterator_adaptor<
232                                     F, detail::preferred_iterator_type<Os>...>,
233                                  detail::iterator_adaptor<
234                                     F, detail::preferred_iterator_type<const Os>...>
235                                  > {
236    public:
237       typedef detail::basic_range<adaptor_range<F, Os...>,
238                                   detail::iterator_adaptor<
239                                      F, detail::preferred_iterator_type<Os>...>,
240                                   detail::iterator_adaptor<
241                                      F, detail::preferred_iterator_type<const Os>...>
242                                   > super;
243 
244       template<typename G, typename... Rs>
adaptor_range(G && f,Rs &&...os)245       adaptor_range(G &&f, Rs &&... os) :
246          f(std::forward<G>(f)), os(std::forward<Rs>(os)...) {
247       }
248 
249       bool
operator ==(const adaptor_range & r) const250       operator==(const adaptor_range &r) const {
251          return f == r.f && os == r.os;
252       }
253 
254       typename super::iterator
begin()255       begin() {
256          return { f, tuple::map(begins(), os) };
257       }
258 
259       typename super::iterator
end()260       end() {
261          return { f, tuple::map(advances_by(size()),
262                                 tuple::map(begins(), os)) };
263       }
264 
265       typename super::const_iterator
begin() const266       begin() const {
267          return { f, tuple::map(begins(), os) };
268       }
269 
270       typename super::const_iterator
end() const271       end() const {
272          return { f, tuple::map(advances_by(size()),
273                                 tuple::map(begins(), os)) };
274       }
275 
276       typename super::size_type
size() const277       size() const {
278          return tuple::apply(minimum(), tuple::map(sizes(), os));
279       }
280 
281    private:
282       F f;
283       std::tuple<Os...> os;
284    };
285 
286    ///
287    /// Range that contains all elements delimited by the index pair
288    /// (\a i, \a j) in the source range \a r.  Use slice() as
289    /// convenience constructor.
290    ///
291    template<typename O>
292    class slice_range :
293       public detail::basic_range<slice_range<O>,
294                                  detail::preferred_iterator_type<O>,
295                                  detail::preferred_iterator_type<const O>> {
296    public:
297       typedef detail::basic_range<slice_range<O>,
298                                  detail::preferred_iterator_type<O>,
299                                  detail::preferred_iterator_type<const O>
300                                   > super;
301 
302       template<typename R>
slice_range(R && r,typename super::size_type i,typename super::size_type j)303       slice_range(R &&r, typename super::size_type i,
304                   typename super::size_type j) :
305          o(std::forward<R>(r)), i(i), j(j) {
306       }
307 
308       bool
operator ==(const slice_range & r) const309       operator==(const slice_range &r) const {
310          return o == r.o && i == r.i && j == r.j;
311       }
312 
313       typename super::iterator
begin()314       begin() {
315          return std::next(o.begin(), i);
316       }
317 
318       typename super::iterator
end()319       end() {
320          return std::next(o.begin(), j);
321       }
322 
323       typename super::const_iterator
begin() const324       begin() const {
325          return std::next(o.begin(), i);
326       }
327 
328       typename super::const_iterator
end() const329       end() const {
330          return std::next(o.begin(), j);
331       }
332 
333       typename super::size_type
size() const334       size() const {
335          return j - i;
336       }
337 
338    private:
339       O o;
340       typename super::size_type i, j;
341    };
342 
343    ///
344    /// Create a range from an iterator pair (\a i, \a j).
345    ///
346    /// \sa iterator_range.
347    ///
348    template<typename T>
349    iterator_range<T>
range(T i,T j)350    range(T i, T j) {
351       return { i, j };
352    }
353 
354    ///
355    /// Create a range of \a n elements starting from iterator \a i.
356    ///
357    /// \sa iterator_range.
358    ///
359    template<typename T>
360    iterator_range<T>
range(T i,typename std::iterator_traits<T>::difference_type n)361    range(T i, typename std::iterator_traits<T>::difference_type n) {
362       return { i, i + n };
363    }
364 
365    ///
366    /// Create a range by transforming the contents of a number of
367    /// source ranges \a rs element-wise using a provided functor \a f.
368    ///
369    /// \sa adaptor_range.
370    ///
371    template<typename F, typename... Rs>
372    adaptor_range<F, Rs...>
map(F && f,Rs &&...rs)373    map(F &&f, Rs &&... rs) {
374       return { std::forward<F>(f), std::forward<Rs>(rs)... };
375    }
376 
377    ///
378    /// Create a range identical to another range \a r.
379    ///
380    template<typename R>
381    adaptor_range<identity, R>
range(R && r)382    range(R &&r) {
383       return { identity(), std::forward<R>(r) };
384    }
385 
386    ///
387    /// Create a range by taking the elements delimited by the index
388    /// pair (\a i, \a j) in a source range \a r.
389    ///
390    /// \sa slice_range.
391    ///
392    template<typename R>
393    slice_range<R>
slice(R && r,typename slice_range<R>::size_type i,typename slice_range<R>::size_type j)394    slice(R &&r, typename slice_range<R>::size_type i,
395          typename slice_range<R>::size_type j) {
396       return { std::forward<R>(r), i, j };
397    }
398 
399    ///
400    /// Range that behaves as a vector of references of type \a T.
401    ///
402    /// Useful because STL containers cannot contain references to
403    /// objects as elements.
404    ///
405    template<typename T>
406    class ref_vector : public adaptor_range<derefs, std::vector<T *>> {
407    public:
ref_vector(std::initializer_list<std::reference_wrapper<T>> il)408       ref_vector(std::initializer_list<std::reference_wrapper<T>> il) :
409          adaptor_range<derefs, std::vector<T *>>(derefs(), map(addresses(), il)) {
410       }
411 
412       template<typename R>
ref_vector(R && r)413       ref_vector(R &&r) : adaptor_range<derefs, std::vector<T *>>(
414          derefs(), map(addresses(), std::forward<R>(r))) {
415       }
416    };
417 }
418 
419 #endif
420