/*============================================================================== Copyright (c) 2001-2011 Joel de Guzman Copyright (c) 2010 Bryce Lelbach Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ==============================================================================*/ #if !defined(BOOST_SPIRIT_SUPPORT_LINE_POS_ITERATOR) #define BOOST_SPIRIT_SUPPORT_LINE_POS_ITERATOR #include #include namespace boost { namespace spirit { //[line_pos_iterator_class /*`The `line_pos_iterator` is a lightweight line position iterator. This iterator adapter only stores the current line number, nothing else. Unlike __classic__'s `position_iterator`, it does not store the column number and does not need an end iterator. The current column can be computed, if needed. */ //`[heading Class Reference] template class line_pos_iterator : public boost::iterator_adaptor< line_pos_iterator // Derived , Iterator // Base , boost::use_default // Value , boost::forward_traversal_tag // CategoryOrTraversal > { public: line_pos_iterator(); explicit line_pos_iterator(Iterator); std::size_t position() const; private: friend class boost::iterator_core_access; void increment(); std::size_t line; // The line position. typename std::iterator_traits::value_type prev; }; //] template line_pos_iterator::line_pos_iterator() : line_pos_iterator::iterator_adaptor_(), line(1), prev(0) { } template line_pos_iterator::line_pos_iterator(Iterator base) : line_pos_iterator::iterator_adaptor_(base), line(1), prev(0) { } template std::size_t line_pos_iterator::position() const { return line; } template void line_pos_iterator::increment() { typename std::iterator_traits::reference ref = *(this->base()); switch (ref) { case '\r': if (prev != '\n') ++line; break; case '\n': if (prev != '\r') ++line; break; default: break; } prev = ref; ++this->base_reference(); } //[line_pos_iterator_utilities //`[heading get_line] template inline std::size_t get_line(Iterator); /*`Get the line position. Returns -1 if Iterator is not a `line_pos_iterator`. */ //`[heading get_line_start] template inline Iterator get_line_start(Iterator lower_bound, Iterator current); /*`Get an iterator to the beginning of the line. Applicable to any iterator. */ //`[heading get_current_line] template inline iterator_range get_current_line(Iterator lower_bound, Iterator current, Iterator upper_bound); /*`Get an `iterator_range` containing the current line. Applicable to any iterator. */ //`[heading get_column] template inline std::size_t get_column(Iterator lower_bound, Iterator current, std::size_t tabs = 4); /*`Get the current column. Applicable to any iterator. */ //] template inline std::size_t get_line(Iterator) { return -1; } template inline std::size_t get_line(line_pos_iterator i) { return i.position(); } template inline Iterator get_line_start(Iterator lower_bound, Iterator current) { Iterator latest = lower_bound; for (Iterator i = lower_bound; i != current; ++i) { switch (*i) { case '\r': case '\n': latest = i; } } return latest; } template inline iterator_range get_current_line(Iterator lower_bound, Iterator current, Iterator upper_bound) { Iterator first = get_line_start(lower_bound, current); Iterator last = get_line_start(current, upper_bound); if (last == current) last = upper_bound; return iterator_range(first, last); } template inline std::size_t get_column(Iterator lower_bound, Iterator current, std::size_t tabs) { std::size_t column = 1; Iterator first = get_line_start(lower_bound, current); for (Iterator i = first; i != current; ++i) { switch (*i) { case '\t': column += tabs - (column - 1) % tabs; break; default: ++column; } } return column; } }} #endif // BOOST_SPIRIT_SUPPORT_LINE_POS_ITERATOR