1 ///////////////////////////////////////////////////////////////////////////////
2 // state.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_STATE_HPP_EAN_10_04_2005
9 #define BOOST_XPRESSIVE_DETAIL_CORE_STATE_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/noncopyable.hpp>
17 #include <boost/xpressive/detail/detail_fwd.hpp>
18 #include <boost/xpressive/detail/core/access.hpp>
19 #include <boost/xpressive/detail/core/action.hpp>
20 #include <boost/xpressive/detail/core/sub_match_vector.hpp>
21 #include <boost/xpressive/detail/utility/sequence_stack.hpp>
22 #include <boost/xpressive/detail/core/regex_impl.hpp>
23 #include <boost/xpressive/regex_constants.hpp>
24 
25 namespace boost { namespace xpressive { namespace detail
26 {
27 
28 ///////////////////////////////////////////////////////////////////////////////
29 // match_context
30 //
31 template<typename BidiIter>
32 struct match_context
33 {
34     typedef typename iterator_value<BidiIter>::type char_type;
35 
match_contextboost::xpressive::detail::match_context36     match_context()
37       : results_ptr_(0)
38       , prev_context_(0)
39       , next_ptr_(0)
40       , traits_(0)
41     {
42     }
43 
44     // pointer to the current match results, passed to actions as a parameter.
45     match_results<BidiIter> *results_ptr_;
46 
47     // The previous match context, if this match_context corresponds to a nested regex invocation
48     match_context<BidiIter> *prev_context_;
49 
50     // If this is a nested match, the "next" sub-expression to execute after the nested match
51     matchable<BidiIter> const *next_ptr_;
52 
53     // A pointer to the current traits object
54     detail::traits<char_type> const *traits_;
55 };
56 
57 ///////////////////////////////////////////////////////////////////////////////
58 // attr_context
59 //
60 struct attr_context
61 {
62     // Slots for holding type-erased pointers to attributes
63     void const **attr_slots_;
64 
65     // The previous attr context, if one exists
66     attr_context *prev_attr_context_;
67 };
68 
69 ///////////////////////////////////////////////////////////////////////////////
70 // match_flags
71 //
72 struct match_flags
73 {
74     bool match_all_;
75     bool match_prev_avail_;
76     bool match_bol_;
77     bool match_eol_;
78     bool match_not_bow_;
79     bool match_not_eow_;
80     bool match_not_null_;
81     bool match_continuous_;
82     bool match_partial_;
83 
match_flagsboost::xpressive::detail::match_flags84     explicit match_flags(regex_constants::match_flag_type flags)
85       : match_all_(false)
86       , match_prev_avail_(0 != (flags & regex_constants::match_prev_avail))
87       , match_bol_(match_prev_avail_ || 0 == (flags & regex_constants::match_not_bol))
88       , match_eol_(0 == (flags & regex_constants::match_not_eol))
89       , match_not_bow_(!match_prev_avail_ && 0 != (flags & regex_constants::match_not_bow))
90       , match_not_eow_(0 != (flags & regex_constants::match_not_eow))
91       , match_not_null_(0 != (flags & regex_constants::match_not_null))
92       , match_continuous_(0 != (flags & regex_constants::match_continuous))
93       , match_partial_(0 != (flags & regex_constants::match_partial))
94     {
95     }
96 };
97 
98 ///////////////////////////////////////////////////////////////////////////////
99 // match_state
100 //
101 template<typename BidiIter>
102 struct match_state
103   : noncopyable
104 {
105     typedef BidiIter iterator;
106     typedef core_access<BidiIter> access;
107     typedef detail::match_context<BidiIter> match_context;
108     typedef detail::results_extras<BidiIter> results_extras;
109     typedef detail::regex_impl<BidiIter> regex_impl;
110     typedef detail::matchable<BidiIter> matchable;
111     typedef xpressive::match_results<BidiIter> match_results;
112     typedef detail::sub_match_impl<BidiIter> sub_match_impl;
113     typedef detail::actionable actionable;
114 
115     BidiIter cur_;
116     sub_match_impl *sub_matches_;
117     std::size_t mark_count_;
118     BidiIter begin_;
119     BidiIter end_;
120 
121     match_flags flags_;
122     bool found_partial_match_;
123 
124     match_context context_;
125     results_extras *extras_;
126     actionable action_list_;
127     actionable const **action_list_tail_;
128     action_args_type *action_args_;
129     attr_context attr_context_;
130     BidiIter next_search_;
131 
132     ///////////////////////////////////////////////////////////////////////////////
133     //
match_stateboost::xpressive::detail::match_state134     match_state
135     (
136         BidiIter begin
137       , BidiIter end
138       , match_results &what
139       , regex_impl const &impl
140       , regex_constants::match_flag_type flags
141     )
142       : cur_(begin)
143       , sub_matches_(0)
144       , mark_count_(0)
145       , begin_(begin)
146       , end_(end)
147       , flags_(flags)
148       , found_partial_match_(false)
149       , context_() // zero-initializes the fields of context_
150       , extras_(&core_access<BidiIter>::get_extras(what))
151       , action_list_()
152       , action_list_tail_(&action_list_.next)
153       , action_args_(&core_access<BidiIter>::get_action_args(what))
154       , attr_context_() // zero-initializes the fields of attr_context_
155       , next_search_(begin)
156     {
157         // reclaim any cached memory in the match_results struct
158         this->extras_->sub_match_stack_.unwind();
159 
160         // initialize the context_ struct
161         this->init_(impl, what);
162 
163         // move all the nested match_results structs into the match_results cache
164         this->extras_->results_cache_.reclaim_all(access::get_nested_results(what));
165     }
166 
167     ///////////////////////////////////////////////////////////////////////////////
168     // reset
resetboost::xpressive::detail::match_state169     void reset(match_results &what, regex_impl const &impl)
170     {
171         this->extras_ = &core_access<BidiIter>::get_extras(what);
172         this->action_list_.next = 0;
173         this->action_list_tail_ = &action_list_.next;
174         this->action_args_ = &core_access<BidiIter>::get_action_args(what);
175         this->attr_context_ = attr_context();
176         this->context_.prev_context_ = 0;
177         this->found_partial_match_ = false;
178         this->extras_->sub_match_stack_.unwind();
179         this->init_(impl, what);
180         this->extras_->results_cache_.reclaim_all(access::get_nested_results(what));
181     }
182 
183     ///////////////////////////////////////////////////////////////////////////////
184     // push_context
185     //  called to prepare the state object for a regex match
push_contextboost::xpressive::detail::match_state186     match_context push_context(regex_impl const &impl, matchable const &next, match_context &prev)
187     {
188         // save state
189         match_context context = this->context_;
190 
191         // create a new nested match_results for this regex
192         nested_results<BidiIter> &nested = access::get_nested_results(*context.results_ptr_);
193         match_results &what = this->extras_->results_cache_.append_new(nested);
194 
195         // (re)initialize the match context
196         this->init_(impl, what);
197 
198         // create a linked list of match_context structs
199         this->context_.prev_context_ = &prev;
200         this->context_.next_ptr_ = &next;
201 
202         // record the start of the zero-th sub-match
203         this->sub_matches_[0].begin_ = this->cur_;
204 
205         return context;
206     }
207 
208     ///////////////////////////////////////////////////////////////////////////////
209     // pop_context
210     //  called after a nested match failed to restore the context
pop_contextboost::xpressive::detail::match_state211     bool pop_context(regex_impl const &impl, bool success)
212     {
213         match_context &context = *this->context_.prev_context_;
214         if(!success)
215         {
216             match_results &what = *context.results_ptr_;
217             this->uninit_(impl, what);
218 
219             // send the match_results struct back to the cache
220             nested_results<BidiIter> &nested = access::get_nested_results(what);
221             this->extras_->results_cache_.reclaim_last(nested);
222         }
223 
224         // restore the state
225         this->context_ = context;
226         match_results &results = *this->context_.results_ptr_;
227         this->sub_matches_ = access::get_sub_matches(access::get_sub_match_vector(results));
228         this->mark_count_ = results.size();
229         return success;
230     }
231 
232     ///////////////////////////////////////////////////////////////////////////////
233     // swap_context
swap_contextboost::xpressive::detail::match_state234     void swap_context(match_context &context)
235     {
236         std::swap(this->context_, context);
237         match_results &results = *this->context_.results_ptr_;
238         this->sub_matches_ = access::get_sub_matches(access::get_sub_match_vector(results));
239         this->mark_count_ = results.size();
240     }
241 
242     // beginning of buffer
bosboost::xpressive::detail::match_state243     bool bos() const
244     {
245         return this->cur_ == this->begin_;
246     }
247 
248     // end of buffer
eosboost::xpressive::detail::match_state249     bool eos()
250     {
251         return this->cur_ == this->end_ && this->found_partial_match();
252     }
253 
254     // is this the regex that is currently executing?
is_active_regexboost::xpressive::detail::match_state255     bool is_active_regex(regex_impl const &impl) const
256     {
257         return impl.xpr_.get() == this->context_.results_ptr_->regex_id();
258     }
259 
260     // fetch the n-th sub_match
sub_matchboost::xpressive::detail::match_state261     sub_match_impl &sub_match(int n)
262     {
263         return this->sub_matches_[n];
264     }
265 
266     // called when a partial match has succeeded
set_partial_matchboost::xpressive::detail::match_state267     void set_partial_match()
268     {
269         sub_match_impl &sub0 = this->sub_match(0);
270         sub0.first = sub0.begin_;
271         sub0.second = this->end_;
272         sub0.matched = false;
273     }
274 
275     template<typename Traits>
get_traitsboost::xpressive::detail::match_state276     Traits const &get_traits() const
277     {
278         return static_cast<traits_holder<Traits> const *>(this->context_.traits_)->traits();
279     }
280 
281 private:
282 
init_boost::xpressive::detail::match_state283     void init_(regex_impl const &impl, match_results &what)
284     {
285         regex_id_type const id = impl.xpr_.get();
286         std::size_t const total_mark_count = impl.mark_count_ + impl.hidden_mark_count_ + 1;
287 
288         // initialize the context and the sub_match vector
289         this->context_.results_ptr_ = &what;
290         this->context_.traits_ = impl.traits_.get();
291         this->mark_count_ = impl.mark_count_ + 1;
292         this->sub_matches_ = this->extras_->sub_match_stack_.push_sequence(total_mark_count, sub_match_impl(begin_), detail::fill);
293         this->sub_matches_ += impl.hidden_mark_count_;
294 
295         // initialize the match_results struct
296         access::init_match_results(what, id, impl.traits_, this->sub_matches_, this->mark_count_, impl.named_marks_);
297     }
298 
uninit_boost::xpressive::detail::match_state299     void uninit_(regex_impl const &impl, match_results &)
300     {
301         extras_->sub_match_stack_.unwind_to(this->sub_matches_ - impl.hidden_mark_count_);
302     }
303 
found_partial_matchboost::xpressive::detail::match_state304     bool found_partial_match()
305     {
306         this->found_partial_match_ = true;
307         return true;
308     }
309 };
310 
311 ///////////////////////////////////////////////////////////////////////////////
312 // memento
313 //
314 template<typename BidiIter>
315 struct memento
316 {
317     sub_match_impl<BidiIter> *old_sub_matches_;
318     std::size_t nested_results_count_;
319     actionable const *action_list_head_;
320     actionable const **action_list_tail_;
321     attr_context attr_context_;
322 };
323 
324 ///////////////////////////////////////////////////////////////////////////////
325 // save_sub_matches
326 //
327 template<typename BidiIter>
save_sub_matches(match_state<BidiIter> & state)328 inline memento<BidiIter> save_sub_matches(match_state<BidiIter> &state)
329 {
330     memento<BidiIter> mem =
331     {
332         state.extras_->sub_match_stack_.push_sequence(state.mark_count_, sub_match_impl<BidiIter>(state.begin_))
333       , state.context_.results_ptr_->nested_results().size()
334       , state.action_list_.next
335       , state.action_list_tail_
336       , state.attr_context_
337     };
338     state.action_list_.next = 0;
339     state.action_list_tail_ = &state.action_list_.next;
340     std::copy(state.sub_matches_, state.sub_matches_ + state.mark_count_, mem.old_sub_matches_);
341     return mem;
342 }
343 
344 ///////////////////////////////////////////////////////////////////////////////
345 // restore_action_queue
346 //
347 template<typename BidiIter>
restore_action_queue(memento<BidiIter> const & mem,match_state<BidiIter> & state)348 inline void restore_action_queue(memento<BidiIter> const &mem, match_state<BidiIter> &state)
349 {
350     state.action_list_.next = mem.action_list_head_;
351     state.action_list_tail_ = mem.action_list_tail_;
352     *state.action_list_tail_ = 0;
353 }
354 
355 ///////////////////////////////////////////////////////////////////////////////
356 // restore_sub_matches
357 //
358 template<typename BidiIter>
restore_sub_matches(memento<BidiIter> const & mem,match_state<BidiIter> & state)359 inline void restore_sub_matches(memento<BidiIter> const &mem, match_state<BidiIter> &state)
360 {
361     typedef core_access<BidiIter> access;
362     nested_results<BidiIter> &nested = access::get_nested_results(*state.context_.results_ptr_);
363     std::size_t count = nested.size() - mem.nested_results_count_;
364     state.extras_->results_cache_.reclaim_last_n(nested, count);
365     std::copy(mem.old_sub_matches_, mem.old_sub_matches_ + state.mark_count_, state.sub_matches_);
366     state.extras_->sub_match_stack_.unwind_to(mem.old_sub_matches_);
367     state.attr_context_ = mem.attr_context_;
368 }
369 
370 ///////////////////////////////////////////////////////////////////////////////
371 // reclaim_sub_matches
372 //
373 template<typename BidiIter>
reclaim_sub_matches(memento<BidiIter> const & mem,match_state<BidiIter> & state,bool success)374 inline void reclaim_sub_matches(memento<BidiIter> const &mem, match_state<BidiIter> &state, bool success)
375 {
376     std::size_t count = state.context_.results_ptr_->nested_results().size() - mem.nested_results_count_;
377     if(count == 0)
378     {
379         state.extras_->sub_match_stack_.unwind_to(mem.old_sub_matches_);
380     }
381     // else we have we must orphan this block of backrefs because we are using the stack
382     // space above it.
383 
384     if(!success)
385     {
386         state.attr_context_ = mem.attr_context_;
387     }
388 }
389 
390 ///////////////////////////////////////////////////////////////////////////////
391 // traits_cast
392 //
393 template<typename Traits, typename BidiIter>
traits_cast(match_state<BidiIter> const & state)394 inline Traits const &traits_cast(match_state<BidiIter> const &state)
395 {
396     return state.template get_traits<Traits>();
397 }
398 
399 }}} // namespace boost::xpressive::detail
400 
401 #endif
402