1 /*============================================================================== 2 Copyright (c) 2001-2011 Joel de Guzman 3 Copyright (c) 2010 Bryce Lelbach 4 5 Distributed under the Boost Software License, Version 1.0. (See accompanying 6 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 7 ==============================================================================*/ 8 9 #if !defined(BOOST_SPIRIT_SUPPORT_LINE_POS_ITERATOR) 10 #define BOOST_SPIRIT_SUPPORT_LINE_POS_ITERATOR 11 12 #include <boost/iterator/iterator_adaptor.hpp> 13 #include <boost/range/iterator_range.hpp> 14 15 namespace boost { namespace spirit 16 { 17 //[line_pos_iterator_class 18 /*`The `line_pos_iterator` is a lightweight line position iterator. 19 This iterator adapter only stores the current line number, nothing else. 20 Unlike __classic__'s `position_iterator`, it does not store the 21 column number and does not need an end iterator. The current column can 22 be computed, if needed. */ 23 //`[heading Class Reference] 24 template <class Iterator> 25 class line_pos_iterator : public boost::iterator_adaptor< 26 line_pos_iterator<Iterator> // Derived 27 , Iterator // Base 28 , boost::use_default // Value 29 , boost::forward_traversal_tag // CategoryOrTraversal 30 > { 31 public: 32 line_pos_iterator(); 33 34 explicit line_pos_iterator(Iterator); 35 36 std::size_t position() const; 37 38 private: 39 friend class boost::iterator_core_access; 40 41 void increment(); 42 43 std::size_t line; // The line position. 44 typename std::iterator_traits<Iterator>::value_type prev; 45 }; 46 //] 47 48 template <class Iterator> line_pos_iterator()49 line_pos_iterator<Iterator>::line_pos_iterator() : 50 line_pos_iterator::iterator_adaptor_(), line(1), prev(0) { } 51 52 template <class Iterator> line_pos_iterator(Iterator base)53 line_pos_iterator<Iterator>::line_pos_iterator(Iterator base) : 54 line_pos_iterator::iterator_adaptor_(base), line(1), prev(0) { } 55 56 template <class Iterator> position() const57 std::size_t line_pos_iterator<Iterator>::position() const 58 { 59 return line; 60 } 61 62 template<class Iterator> increment()63 void line_pos_iterator<Iterator>::increment() 64 { 65 typename std::iterator_traits<Iterator>::reference 66 ref = *(this->base()); 67 68 switch (ref) { 69 case '\r': 70 if (prev != '\n') 71 ++line; 72 break; 73 case '\n': 74 if (prev != '\r') 75 ++line; 76 break; 77 default: 78 break; 79 } 80 81 prev = ref; 82 ++this->base_reference(); 83 } 84 85 //[line_pos_iterator_utilities 86 //`[heading get_line] 87 template <class Iterator> 88 inline std::size_t get_line(Iterator); 89 /*`Get the line position. Returns -1 if Iterator is not a 90 `line_pos_iterator`. */ 91 92 //`[heading get_line_start] 93 template <class Iterator> 94 inline Iterator get_line_start(Iterator lower_bound, Iterator current); 95 /*`Get an iterator to the beginning of the line. Applicable to any 96 iterator. */ 97 98 //`[heading get_current_line] 99 template <class Iterator> 100 inline iterator_range<Iterator> 101 get_current_line(Iterator lower_bound, Iterator current, 102 Iterator upper_bound); 103 /*`Get an `iterator_range` containing the current line. Applicable to any 104 iterator. */ 105 106 //`[heading get_column] 107 template <class Iterator> 108 inline std::size_t get_column(Iterator lower_bound, Iterator current, 109 std::size_t tabs = 4); 110 /*`Get the current column. Applicable to any iterator. */ 111 //] 112 113 template <class Iterator> get_line(Iterator)114 inline std::size_t get_line(Iterator) 115 { 116 return -1; 117 } 118 119 template <class Iterator> get_line(line_pos_iterator<Iterator> i)120 inline std::size_t get_line(line_pos_iterator<Iterator> i) 121 { 122 return i.position(); 123 } 124 125 template <class Iterator> get_line_start(Iterator lower_bound,Iterator current)126 inline Iterator get_line_start(Iterator lower_bound, Iterator current) 127 { 128 Iterator latest = lower_bound; 129 130 for (Iterator i = lower_bound; i != current; ++i) { 131 switch (*i) { 132 case '\r': 133 case '\n': 134 latest = i; 135 } 136 } 137 138 return latest; 139 } 140 141 template <class Iterator> 142 inline iterator_range<Iterator> get_current_line(Iterator lower_bound,Iterator current,Iterator upper_bound)143 get_current_line(Iterator lower_bound, 144 Iterator current, 145 Iterator upper_bound) 146 { 147 Iterator first = get_line_start(lower_bound, current); 148 Iterator last = get_line_start(current, upper_bound); 149 150 if (last == current) 151 last = upper_bound; 152 153 return iterator_range<Iterator>(first, last); 154 } 155 156 template <class Iterator> get_column(Iterator lower_bound,Iterator current,std::size_t tabs)157 inline std::size_t get_column(Iterator lower_bound, 158 Iterator current, 159 std::size_t tabs) 160 { 161 std::size_t column = 1; 162 Iterator first = get_line_start(lower_bound, current); 163 164 for (Iterator i = first; i != current; ++i) { 165 switch (*i) { 166 case '\t': 167 column += tabs - (column - 1) % tabs; 168 break; 169 default: 170 ++column; 171 } 172 } 173 174 return column; 175 } 176 177 }} 178 179 #endif // BOOST_SPIRIT_SUPPORT_LINE_POS_ITERATOR 180 181