• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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