line_pos_iterator.hpp 5.6 KB

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