• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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