1 ///////////////////////////////////////////////////////////////////////////////
2 // lookbehind_matcher.hpp
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)
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
11 // MS compatible compilers support #pragma once
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>
26 namespace boost { namespace xpressive { namespace detail
29 ///////////////////////////////////////////////////////////////////////////////
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>
36 lookbehind_matcher(Xpr const &xpr, std::size_t wid, bool no, bool pure = Xpr::pure)
42 BOOST_XPR_ENSURE_(!is_unknown(this->width_), regex_constants::error_badlookbehind,
43 "Variable-width look-behind assertions are not supported");
48 this->not_ = !this->not_;
51 template<typename BidiIter, typename Next>
52 bool match(match_state<BidiIter> &state, Next const &next) const
54 return Xpr::pure || this->pure_
55 ? this->match_(state, next, mpl::true_())
56 : this->match_(state, next, mpl::false_());
59 template<typename BidiIter, typename Next>
60 bool match_(match_state<BidiIter> &state, Next const &next, mpl::true_) const
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_))
67 return this->not_ ? next.match(state) : false;
72 if(this->xpr_.match(state))
74 BOOST_ASSERT(state.cur_ == tmp);
85 if(!this->xpr_.match(state))
90 BOOST_ASSERT(state.cur_ == tmp);
97 BOOST_ASSERT(state.cur_ == tmp);
101 template<typename BidiIter, typename Next>
102 bool match_(match_state<BidiIter> &state, Next const &next, mpl::false_) const
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_))
109 return this->not_ ? next.match(state) : false;
112 // matching xpr could produce side-effects, save state
113 memento<BidiIter> mem = save_sub_matches(state);
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);
121 if(this->xpr_.match(state))
123 restore_action_queue(mem, state);
124 restore_sub_matches(mem, state);
125 BOOST_ASSERT(state.cur_ == tmp);
129 restore_action_queue(mem, state);
130 if(next.match(state))
132 reclaim_sub_matches(mem, state, true);
135 reclaim_sub_matches(mem, state, false);
139 if(!this->xpr_.match(state))
142 restore_action_queue(mem, state);
143 reclaim_sub_matches(mem, state, false);
146 BOOST_ASSERT(state.cur_ == tmp);
147 restore_action_queue(mem, state);
148 if(next.match(state))
150 reclaim_sub_matches(mem, state, true);
153 restore_sub_matches(mem, state);
156 BOOST_ASSERT(state.cur_ == tmp);
162 bool pure_; // false if matching xpr_ could modify the sub-matches