]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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> | |
49 | line_pos_iterator<Iterator>::line_pos_iterator() : | |
50 | line_pos_iterator::iterator_adaptor_(), line(1), prev(0) { } | |
51 | ||
52 | template <class Iterator> | |
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> | |
57 | std::size_t line_pos_iterator<Iterator>::position() const | |
58 | { | |
59 | return line; | |
60 | } | |
61 | ||
62 | template<class Iterator> | |
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> | |
114 | inline std::size_t get_line(Iterator) | |
115 | { | |
116 | return -1; | |
117 | } | |
118 | ||
119 | template <class Iterator> | |
120 | inline std::size_t get_line(line_pos_iterator<Iterator> i) | |
121 | { | |
122 | return i.position(); | |
123 | } | |
124 | ||
125 | template <class Iterator> | |
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> | |
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> | |
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 |