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