• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 // Copyright (C) 2008-2018 Lorenzo Caminiti
3 // Distributed under the Boost Software License, Version 1.0 (see accompanying
4 // file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt).
5 // See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html
6 
7 #include <boost/contract/call_if.hpp>
8 #include <type_traits>
9 #include <iterator>
10 #include <functional> // std::bind for generic lambdas.
11 #include <vector>
12 #include <list>
13 #include <sstream>
14 
15 template<typename Iter>
16 struct is_random_access_iterator : std::is_same<
17     typename std::iterator_traits<Iter>::iterator_category,
18     std::random_access_iterator_tag
19 > {};
20 
21 template<typename Iter>
22 struct is_bidirectional_iterator : std::is_same<
23     typename std::iterator_traits<Iter>::iterator_category,
24     std::bidirectional_iterator_tag
25 > {};
26 
27 template<typename Iter>
28 struct is_input_iterator : std::is_same<
29     typename std::iterator_traits<Iter>::iterator_category,
30     std::input_iterator_tag
31 > {};
32 
33 //[call_if_cxx14
34 template<typename Iter, typename Dist>
myadvance(Iter & i,Dist n)35 void myadvance(Iter& i, Dist n) {
36     Iter* p = &i; // So captures change actual pointed iterator value.
37     boost::contract::call_if<is_random_access_iterator<Iter> >(
38         std::bind([] (auto p, auto n) { // C++14 generic lambda.
39             *p += n;
40         }, p, n)
41     ).template else_if<is_bidirectional_iterator<Iter> >(
42         std::bind([] (auto p, auto n) {
43             if(n >= 0) while(n--) ++*p;
44             else while(n++) --*p;
45         }, p, n)
46     ).template else_if<is_input_iterator<Iter> >(
47         std::bind([] (auto p, auto n) {
48             while(n--) ++*p;
49         }, p, n)
50     ).else_(
51         std::bind([] (auto false_) {
52             static_assert(false_, "requires at least input iterator");
53         }, std::false_type()) // Use constexpr value.
54     );
55 }
56 //]
57 
58 struct x {}; // Test not an iterator (static_assert failure in else_ above).
59 
60 namespace std {
61     template<>
62     struct iterator_traits<x> {
63         typedef void iterator_category;
64     };
65 }
66 
main()67 int main() {
68     std::vector<char> v;
69     v.push_back('a');
70     v.push_back('b');
71     v.push_back('c');
72     v.push_back('d');
73     std::vector<char>::iterator r = v.begin(); // Random iterator.
74     myadvance(r, 1);
75     assert(*r == 'b');
76 
77     std::list<char> l(v.begin(), v.end());
78     std::list<char>::iterator b = l.begin(); // Bidirectional iterator.
79     myadvance(b, 2);
80     assert(*b == 'c');
81 
82     std::istringstream s("a b c d");
83     std::istream_iterator<char> i(s);
84     myadvance(i, 3);
85     assert(*i == 'd');
86 
87     // x j;
88     // myadvance(j, 0); // Error (correctly because x not even input iter).
89 
90     return 0;
91 }
92 
93