1 /////////////////////////////////////////////////////////////////////////////// 2 // lookbehind_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 8 #ifndef BOOST_XPRESSIVE_DETAIL_CORE_MATCHER_LOOKBEHIND_MATCHER_HPP_EAN_10_04_2005 9 #define BOOST_XPRESSIVE_DETAIL_CORE_MATCHER_LOOKBEHIND_MATCHER_HPP_EAN_10_04_2005 10 11 // MS compatible compilers support #pragma once 12 #if defined(_MSC_VER) 13 # pragma once 14 #endif 15 16 #include <boost/assert.hpp> 17 #include <boost/xpressive/regex_error.hpp> 18 #include <boost/xpressive/regex_constants.hpp> 19 #include <boost/xpressive/detail/detail_fwd.hpp> 20 #include <boost/xpressive/detail/core/quant_style.hpp> 21 #include <boost/xpressive/detail/core/state.hpp> 22 #include <boost/xpressive/detail/utility/algorithm.hpp> 23 #include <boost/xpressive/detail/utility/save_restore.hpp> 24 #include <boost/xpressive/detail/utility/ignore_unused.hpp> 25 26 namespace boost { namespace xpressive { namespace detail 27 { 28 29 /////////////////////////////////////////////////////////////////////////////// 30 // lookbehind_matcher 31 // Xpr can be either a static_xpression or a shared_matchable 32 template<typename Xpr> 33 struct lookbehind_matcher 34 : quant_style<quant_none, 0, Xpr::pure> 35 { lookbehind_matcherboost::xpressive::detail::lookbehind_matcher36 lookbehind_matcher(Xpr const &xpr, std::size_t wid, bool no, bool pure = Xpr::pure) 37 : xpr_(xpr) 38 , not_(no) 39 , pure_(pure) 40 , width_(wid) 41 { 42 BOOST_XPR_ENSURE_(!is_unknown(this->width_), regex_constants::error_badlookbehind, 43 "Variable-width look-behind assertions are not supported"); 44 } 45 inverseboost::xpressive::detail::lookbehind_matcher46 void inverse() 47 { 48 this->not_ = !this->not_; 49 } 50 51 template<typename BidiIter, typename Next> matchboost::xpressive::detail::lookbehind_matcher52 bool match(match_state<BidiIter> &state, Next const &next) const 53 { 54 return Xpr::pure || this->pure_ 55 ? this->match_(state, next, mpl::true_()) 56 : this->match_(state, next, mpl::false_()); 57 } 58 59 template<typename BidiIter, typename Next> match_boost::xpressive::detail::lookbehind_matcher60 bool match_(match_state<BidiIter> &state, Next const &next, mpl::true_) const 61 { 62 typedef typename iterator_difference<BidiIter>::type difference_type; 63 BidiIter const tmp = state.cur_; 64 if(!detail::advance_to(state.cur_, -static_cast<difference_type>(this->width_), state.begin_)) 65 { 66 state.cur_ = tmp; 67 return this->not_ ? next.match(state) : false; 68 } 69 70 if(this->not_) 71 { 72 if(this->xpr_.match(state)) 73 { 74 BOOST_ASSERT(state.cur_ == tmp); 75 return false; 76 } 77 state.cur_ = tmp; 78 if(next.match(state)) 79 { 80 return true; 81 } 82 } 83 else 84 { 85 if(!this->xpr_.match(state)) 86 { 87 state.cur_ = tmp; 88 return false; 89 } 90 BOOST_ASSERT(state.cur_ == tmp); 91 if(next.match(state)) 92 { 93 return true; 94 } 95 } 96 97 BOOST_ASSERT(state.cur_ == tmp); 98 return false; 99 } 100 101 template<typename BidiIter, typename Next> match_boost::xpressive::detail::lookbehind_matcher102 bool match_(match_state<BidiIter> &state, Next const &next, mpl::false_) const 103 { 104 typedef typename iterator_difference<BidiIter>::type difference_type; 105 BidiIter const tmp = state.cur_; 106 if(!detail::advance_to(state.cur_, -static_cast<difference_type>(this->width_), state.begin_)) 107 { 108 state.cur_ = tmp; 109 return this->not_ ? next.match(state) : false; 110 } 111 112 // matching xpr could produce side-effects, save state 113 memento<BidiIter> mem = save_sub_matches(state); 114 115 if(this->not_) 116 { 117 // negative look-ahead assertions do not trigger partial matches. 118 save_restore<bool> partial_match(state.found_partial_match_); 119 detail::ignore_unused(partial_match); 120 121 if(this->xpr_.match(state)) 122 { 123 restore_action_queue(mem, state); 124 restore_sub_matches(mem, state); 125 BOOST_ASSERT(state.cur_ == tmp); 126 return false; 127 } 128 state.cur_ = tmp; 129 restore_action_queue(mem, state); 130 if(next.match(state)) 131 { 132 reclaim_sub_matches(mem, state, true); 133 return true; 134 } 135 reclaim_sub_matches(mem, state, false); 136 } 137 else 138 { 139 if(!this->xpr_.match(state)) 140 { 141 state.cur_ = tmp; 142 restore_action_queue(mem, state); 143 reclaim_sub_matches(mem, state, false); 144 return false; 145 } 146 BOOST_ASSERT(state.cur_ == tmp); 147 restore_action_queue(mem, state); 148 if(next.match(state)) 149 { 150 reclaim_sub_matches(mem, state, true); 151 return true; 152 } 153 restore_sub_matches(mem, state); 154 } 155 156 BOOST_ASSERT(state.cur_ == tmp); 157 return false; 158 } 159 160 Xpr xpr_; 161 bool not_; 162 bool pure_; // false if matching xpr_ could modify the sub-matches 163 std::size_t width_; 164 }; 165 166 }}} 167 168 #endif 169