blob: 0b2aec8ce9fdc6ab829d02b6f838153fa30b16a8 [file] [log] [blame]
/*==============================================================================
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 <boost/iterator/iterator_adaptor.hpp>
#include <boost/range/iterator_range.hpp>
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 Iterator>
class line_pos_iterator : public boost::iterator_adaptor<
line_pos_iterator<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<Iterator>::value_type prev;
};
//]
template <class Iterator>
line_pos_iterator<Iterator>::line_pos_iterator() :
line_pos_iterator::iterator_adaptor_(), line(1), prev(0) { }
template <class Iterator>
line_pos_iterator<Iterator>::line_pos_iterator(Iterator base) :
line_pos_iterator::iterator_adaptor_(base), line(1), prev(0) { }
template <class Iterator>
std::size_t line_pos_iterator<Iterator>::position() const
{
return line;
}
template<class Iterator>
void line_pos_iterator<Iterator>::increment()
{
typename std::iterator_traits<Iterator>::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 <class Iterator>
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 <class Iterator>
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 <class Iterator>
inline iterator_range<Iterator>
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 <class Iterator>
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 <class Iterator>
inline std::size_t get_line(Iterator)
{
return -1;
}
template <class Iterator>
inline std::size_t get_line(line_pos_iterator<Iterator> i)
{
return i.position();
}
template <class Iterator>
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 <class Iterator>
inline iterator_range<Iterator>
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<Iterator>(first, last);
}
template <class Iterator>
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