simple_repeat_matcher.hpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // simple_repeat_matcher.hpp
  3. //
  4. // Copyright 2008 Eric Niebler. Distributed under the Boost
  5. // Software License, Version 1.0. (See accompanying file
  6. // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  7. #ifndef BOOST_XPRESSIVE_DETAIL_CORE_MATCHER_SIMPLE_REPEAT_MATCHER_HPP_EAN_10_04_2005
  8. #define BOOST_XPRESSIVE_DETAIL_CORE_MATCHER_SIMPLE_REPEAT_MATCHER_HPP_EAN_10_04_2005
  9. // MS compatible compilers support #pragma once
  10. #if defined(_MSC_VER)
  11. # pragma once
  12. #endif
  13. #include <boost/assert.hpp>
  14. #include <boost/mpl/if.hpp>
  15. #include <boost/mpl/bool.hpp>
  16. #include <boost/next_prior.hpp>
  17. #include <boost/xpressive/detail/detail_fwd.hpp>
  18. #include <boost/xpressive/detail/core/quant_style.hpp>
  19. #include <boost/xpressive/detail/core/state.hpp>
  20. #include <boost/xpressive/detail/static/type_traits.hpp>
  21. namespace boost { namespace xpressive { namespace detail
  22. {
  23. ///////////////////////////////////////////////////////////////////////////////
  24. // simple_repeat_traits
  25. //
  26. struct greedy_slow_tag {};
  27. struct greedy_fast_tag {};
  28. struct non_greedy_tag {};
  29. typedef static_xpression<any_matcher, true_xpression> any_sxpr;
  30. typedef matcher_wrapper<any_matcher> any_dxpr;
  31. template<typename Xpr, typename Greedy, typename Random>
  32. struct simple_repeat_traits
  33. {
  34. typedef typename mpl::if_c<Greedy::value, greedy_slow_tag, non_greedy_tag>::type tag_type;
  35. };
  36. template<>
  37. struct simple_repeat_traits<any_sxpr, mpl::true_, mpl::true_>
  38. {
  39. typedef greedy_fast_tag tag_type;
  40. };
  41. template<>
  42. struct simple_repeat_traits<any_dxpr, mpl::true_, mpl::true_>
  43. {
  44. typedef greedy_fast_tag tag_type;
  45. };
  46. ///////////////////////////////////////////////////////////////////////////////
  47. // simple_repeat_matcher
  48. //
  49. template<typename Xpr, typename Greedy>
  50. struct simple_repeat_matcher
  51. : quant_style_variable_width
  52. {
  53. typedef Xpr xpr_type;
  54. typedef Greedy greedy_type;
  55. Xpr xpr_;
  56. unsigned int min_, max_;
  57. std::size_t width_;
  58. mutable bool leading_;
  59. simple_repeat_matcher(Xpr const &xpr, unsigned int min, unsigned int max, std::size_t width)
  60. : xpr_(xpr)
  61. , min_(min)
  62. , max_(max)
  63. , width_(width)
  64. , leading_(false)
  65. {
  66. // it is the job of the parser to make sure this never happens
  67. BOOST_ASSERT(min <= max);
  68. BOOST_ASSERT(0 != max);
  69. BOOST_ASSERT(0 != width && unknown_width() != width);
  70. BOOST_ASSERT(Xpr::width == unknown_width() || Xpr::width == width);
  71. }
  72. template<typename BidiIter, typename Next>
  73. bool match(match_state<BidiIter> &state, Next const &next) const
  74. {
  75. typedef mpl::bool_<is_random<BidiIter>::value> is_rand;
  76. typedef typename simple_repeat_traits<Xpr, greedy_type, is_rand>::tag_type tag_type;
  77. return this->match_(state, next, tag_type());
  78. }
  79. // greedy, fixed-width quantifier
  80. template<typename BidiIter, typename Next>
  81. bool match_(match_state<BidiIter> &state, Next const &next, greedy_slow_tag) const
  82. {
  83. int const diff = -static_cast<int>(Xpr::width == unknown_width::value ? this->width_ : Xpr::width);
  84. unsigned int matches = 0;
  85. BidiIter const tmp = state.cur_;
  86. // greedily match as much as we can
  87. while(matches < this->max_ && this->xpr_.match(state))
  88. {
  89. ++matches;
  90. }
  91. // If this repeater is at the front of the pattern, note
  92. // how much of the input we consumed so that a repeated search
  93. // doesn't have to cover the same ground again.
  94. if(this->leading_)
  95. {
  96. state.next_search_ = (matches && matches < this->max_)
  97. ? state.cur_
  98. : (tmp == state.end_) ? tmp : boost::next(tmp);
  99. }
  100. if(this->min_ > matches)
  101. {
  102. state.cur_ = tmp;
  103. return false;
  104. }
  105. // try matching the rest of the pattern, and back off if necessary
  106. for(; ; --matches, std::advance(state.cur_, diff))
  107. {
  108. if(next.match(state))
  109. {
  110. return true;
  111. }
  112. else if(this->min_ == matches)
  113. {
  114. state.cur_ = tmp;
  115. return false;
  116. }
  117. }
  118. }
  119. // non-greedy fixed-width quantification
  120. template<typename BidiIter, typename Next>
  121. bool match_(match_state<BidiIter> &state, Next const &next, non_greedy_tag) const
  122. {
  123. BOOST_ASSERT(!this->leading_);
  124. BidiIter const tmp = state.cur_;
  125. unsigned int matches = 0;
  126. for(; matches < this->min_; ++matches)
  127. {
  128. if(!this->xpr_.match(state))
  129. {
  130. state.cur_ = tmp;
  131. return false;
  132. }
  133. }
  134. do
  135. {
  136. if(next.match(state))
  137. {
  138. return true;
  139. }
  140. }
  141. while(matches++ < this->max_ && this->xpr_.match(state));
  142. state.cur_ = tmp;
  143. return false;
  144. }
  145. // when greedily matching any character, skip to the end instead of iterating there.
  146. template<typename BidiIter, typename Next>
  147. bool match_(match_state<BidiIter> &state, Next const &next, greedy_fast_tag) const
  148. {
  149. BidiIter const tmp = state.cur_;
  150. std::size_t const diff_to_end = static_cast<std::size_t>(state.end_ - tmp);
  151. // is there enough room?
  152. if(this->min_ > diff_to_end)
  153. {
  154. if(this->leading_)
  155. {
  156. state.next_search_ = (tmp == state.end_) ? tmp : boost::next(tmp);
  157. }
  158. return false;
  159. }
  160. BidiIter const min_iter = tmp + this->min_;
  161. state.cur_ += (std::min)((std::size_t)this->max_, diff_to_end);
  162. if(this->leading_)
  163. {
  164. state.next_search_ = (diff_to_end && diff_to_end < this->max_)
  165. ? state.cur_
  166. : (tmp == state.end_) ? tmp : boost::next(tmp);
  167. }
  168. for(;; --state.cur_)
  169. {
  170. if(next.match(state))
  171. {
  172. return true;
  173. }
  174. else if(min_iter == state.cur_)
  175. {
  176. state.cur_ = tmp;
  177. return false;
  178. }
  179. }
  180. }
  181. detail::width get_width() const
  182. {
  183. if(this->min_ != this->max_)
  184. {
  185. return unknown_width::value;
  186. }
  187. return this->min_ * this->width_;
  188. }
  189. private:
  190. simple_repeat_matcher &operator =(simple_repeat_matcher const &);
  191. };
  192. // BUGBUG can all non-greedy quantification be done with the fixed width quantifier?
  193. // BUGBUG matchers are chained together using static_xpression so that matchers to
  194. // the left can invoke matchers to the right. This is so that if the left matcher
  195. // succeeds but the right matcher fails, the left matcher is given the opportunity
  196. // to try something else. This is how backtracking works. However, if the left matcher
  197. // can succeed only one way (as with any_matcher, for example), it does not need
  198. // backtracking. In this case, leaving its stack frame active is a waste of stack
  199. // space. Can something be done?
  200. }}}
  201. #endif