]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 | ||
36 | 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 | ||
84 | 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 | // | |
134 | 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 | |
169 | 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 | |
186 | 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 | |
211 | 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 | |
234 | 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 | |
243 | bool bos() const | |
244 | { | |
245 | return this->cur_ == this->begin_; | |
246 | } | |
247 | ||
248 | // end of buffer | |
249 | bool eos() | |
250 | { | |
251 | return this->cur_ == this->end_ && this->found_partial_match(); | |
252 | } | |
253 | ||
254 | // is this the regex that is currently executing? | |
255 | 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 | |
261 | sub_match_impl &sub_match(int n) | |
262 | { | |
263 | return this->sub_matches_[n]; | |
264 | } | |
265 | ||
266 | // called when a partial match has succeeded | |
267 | 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> | |
276 | Traits const &get_traits() const | |
277 | { | |
278 | return static_cast<traits_holder<Traits> const *>(this->context_.traits_)->traits(); | |
279 | } | |
280 | ||
281 | private: | |
282 | ||
283 | 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 | ||
299 | 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 | ||
304 | 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> | |
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> | |
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> | |
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> | |
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> | |
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 |