]> git.lyx.org Git - lyx.git/blob - boost/boost/regex/v4/perl_matcher_non_recursive.hpp
update to boost 1.32.0
[lyx.git] / boost / boost / regex / v4 / perl_matcher_non_recursive.hpp
1 /*
2  *
3  * Copyright (c) 2002
4  * Dr John Maddock
5  *
6  * Use, modification and distribution are subject to the 
7  * Boost Software License, Version 1.0. (See accompanying file 
8  * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9  *
10  */
11
12  /*
13   *   LOCATION:    see http://www.boost.org for most recent version.
14   *   FILE         perl_matcher_common.cpp
15   *   VERSION      see <boost/version.hpp>
16   *   DESCRIPTION: Definitions of perl_matcher member functions that are 
17   *                specific to the non-recursive implementation.
18   */
19
20 #ifndef BOOST_REGEX_V4_PERL_MATCHER_NON_RECURSIVE_HPP
21 #define BOOST_REGEX_V4_PERL_MATCHER_NON_RECURSIVE_HPP
22
23 #include <new>
24
25 #ifdef BOOST_HAS_ABI_HEADERS
26 #  include BOOST_ABI_PREFIX
27 #endif
28
29 namespace boost{
30 namespace re_detail{
31
32 template <class T>
33 inline void inplace_destroy(T* p)
34 {
35    (void)p;  // warning suppression
36    p->~T();
37 }
38
39 struct saved_state
40 {
41    union{
42       unsigned int id;
43       // these ensure that this struct gets the same alignment as derived structs:
44       void* padding1;
45       std::size_t padding2;
46       std::ptrdiff_t padding3;
47    };
48    saved_state(unsigned i) : id(i) {}
49 };
50
51 template <class BidiIterator>
52 struct saved_matched_paren : public saved_state
53 {
54    int index;
55    sub_match<BidiIterator> sub;
56    saved_matched_paren(int i, const sub_match<BidiIterator>& s) : saved_state(1), index(i), sub(s){};
57 };
58
59 template <class BidiIterator>
60 struct saved_position : public saved_state
61 {
62    const re_syntax_base* pstate;
63    BidiIterator position;
64    saved_position(const re_syntax_base* ps, BidiIterator pos, int i) : saved_state(i), pstate(ps), position(pos){};
65 };
66
67 template <class BidiIterator>
68 struct saved_assertion : public saved_position<BidiIterator>
69 {
70    bool positive;
71    saved_assertion(bool p, const re_syntax_base* ps, BidiIterator pos) 
72       : saved_position<BidiIterator>(ps, pos, saved_type_assertion), positive(p){};
73 };
74
75 template <class BidiIterator>
76 struct saved_repeater : public saved_state
77 {
78    repeater_count<BidiIterator> count;
79    saved_repeater(int i, repeater_count<BidiIterator>** s, BidiIterator start) 
80       : saved_state(saved_state_repeater_count), count(i,s,start){}
81 };
82
83 struct saved_extra_block : public saved_state
84 {
85    saved_state *base, *end;
86    saved_extra_block(saved_state* b, saved_state* e) 
87       : saved_state(saved_state_extra_block), base(b), end(e) {}
88 };
89
90 struct save_state_init
91 {
92    saved_state** stack;
93    save_state_init(saved_state** base, saved_state** end)
94       : stack(base)
95    {
96       *base = static_cast<saved_state*>(get_mem_block());
97       *end = reinterpret_cast<saved_state*>(reinterpret_cast<char*>(*base)+BOOST_REGEX_BLOCKSIZE);
98       --(*end);
99       (void) new (*end)saved_state(0);
100       assert(*end > *base);
101    }
102    ~save_state_init()
103    {
104       put_mem_block(*stack);
105       *stack = 0;
106    }
107 };
108
109 template <class BidiIterator>
110 struct saved_single_repeat : public saved_state
111 {
112    unsigned count;
113    const re_repeat* rep;
114    BidiIterator last_position;
115    saved_single_repeat(unsigned c, const re_repeat* r, BidiIterator lp, int arg_id) 
116       : saved_state(arg_id), count(c), rep(r), last_position(lp){}
117 };
118
119 template <class BidiIterator, class Allocator, class traits, class Allocator2>
120 bool perl_matcher<BidiIterator, Allocator, traits, Allocator2>::match_all_states()
121 {
122    static matcher_proc_type const s_match_vtable[26] = 
123    {
124       (&perl_matcher<BidiIterator, Allocator, traits, Allocator2>::match_startmark),
125       &perl_matcher<BidiIterator, Allocator, traits, Allocator2>::match_endmark,
126       &perl_matcher<BidiIterator, Allocator, traits, Allocator2>::match_literal,
127       &perl_matcher<BidiIterator, Allocator, traits, Allocator2>::match_start_line,
128       &perl_matcher<BidiIterator, Allocator, traits, Allocator2>::match_end_line,
129       &perl_matcher<BidiIterator, Allocator, traits, Allocator2>::match_wild,
130       &perl_matcher<BidiIterator, Allocator, traits, Allocator2>::match_match,
131       &perl_matcher<BidiIterator, Allocator, traits, Allocator2>::match_word_boundary,
132       &perl_matcher<BidiIterator, Allocator, traits, Allocator2>::match_within_word,
133       &perl_matcher<BidiIterator, Allocator, traits, Allocator2>::match_word_start,
134       &perl_matcher<BidiIterator, Allocator, traits, Allocator2>::match_word_end,
135       &perl_matcher<BidiIterator, Allocator, traits, Allocator2>::match_buffer_start,
136       &perl_matcher<BidiIterator, Allocator, traits, Allocator2>::match_buffer_end,
137       &perl_matcher<BidiIterator, Allocator, traits, Allocator2>::match_backref,
138       &perl_matcher<BidiIterator, Allocator, traits, Allocator2>::match_long_set,
139       &perl_matcher<BidiIterator, Allocator, traits, Allocator2>::match_set,
140       &perl_matcher<BidiIterator, Allocator, traits, Allocator2>::match_jump,
141       &perl_matcher<BidiIterator, Allocator, traits, Allocator2>::match_alt,
142       &perl_matcher<BidiIterator, Allocator, traits, Allocator2>::match_rep,
143       &perl_matcher<BidiIterator, Allocator, traits, Allocator2>::match_combining,
144       &perl_matcher<BidiIterator, Allocator, traits, Allocator2>::match_soft_buffer_end,
145       &perl_matcher<BidiIterator, Allocator, traits, Allocator2>::match_restart_continue,
146       (::boost::is_random_access_iterator<BidiIterator>::value ? &perl_matcher<BidiIterator, Allocator, traits, Allocator2>::match_dot_repeat_fast : &perl_matcher<BidiIterator, Allocator, traits, Allocator2>::match_dot_repeat_slow),
147       &perl_matcher<BidiIterator, Allocator, traits, Allocator2>::match_char_repeat,
148       &perl_matcher<BidiIterator, Allocator, traits, Allocator2>::match_set_repeat,
149       &perl_matcher<BidiIterator, Allocator, traits, Allocator2>::match_long_set_repeat,
150    };
151
152    push_recursion_stopper();
153    do{
154       while(pstate)
155       {
156          matcher_proc_type proc = s_match_vtable[pstate->type];
157          ++state_count;
158          if(!(this->*proc)())
159          {
160             if(state_count > max_state_count)
161                raise_error(traits_inst, REG_ESPACE);
162             if((m_match_flags & match_partial) && (position == last))
163                m_has_partial_match = true;
164             if(false == unwind(false))
165                return m_recursive_result;
166          }
167       }
168    }while(unwind(true));
169    return m_recursive_result;
170 }
171
172 template <class BidiIterator, class Allocator, class traits, class Allocator2>
173 void perl_matcher<BidiIterator, Allocator, traits, Allocator2>::extend_stack()
174 {
175    if(used_block_count)
176    {
177       --used_block_count;
178       saved_state* stack_base;
179       saved_state* backup_state;
180       stack_base = static_cast<saved_state*>(get_mem_block());
181       backup_state = reinterpret_cast<saved_state*>(reinterpret_cast<char*>(stack_base)+BOOST_REGEX_BLOCKSIZE);
182       saved_extra_block* block = static_cast<saved_extra_block*>(backup_state);
183       --block;
184       (void) new (block) saved_extra_block(m_stack_base, m_backup_state);
185       m_stack_base = stack_base;
186       m_backup_state = block;
187    }
188    else
189       raise_error(traits_inst, REG_E_MEMORY);
190 }
191
192 template <class BidiIterator, class Allocator, class traits, class Allocator2>
193 inline void perl_matcher<BidiIterator, Allocator, traits, Allocator2>::push_matched_paren(int index, const sub_match<BidiIterator>& sub)
194 {
195    assert(index);
196    saved_matched_paren<BidiIterator>* pmp = static_cast<saved_matched_paren<BidiIterator>*>(m_backup_state);
197    --pmp;
198    if(pmp < m_stack_base)
199    {
200       extend_stack();
201       pmp = static_cast<saved_matched_paren<BidiIterator>*>(m_backup_state);
202       --pmp;
203    }
204    (void) new (pmp)saved_matched_paren<BidiIterator>(index, sub);
205    m_backup_state = pmp;
206 }
207
208 template <class BidiIterator, class Allocator, class traits, class Allocator2>
209 inline void perl_matcher<BidiIterator, Allocator, traits, Allocator2>::push_recursion_stopper()
210 {
211    saved_state* pmp = m_backup_state;
212    --pmp;
213    if(pmp < m_stack_base)
214    {
215       extend_stack();
216       pmp = m_backup_state;
217       --pmp;
218    }
219    (void) new (pmp)saved_state(saved_type_recurse);
220    m_backup_state = pmp;
221 }
222
223 template <class BidiIterator, class Allocator, class traits, class Allocator2>
224 inline void perl_matcher<BidiIterator, Allocator, traits, Allocator2>::push_assertion(const re_syntax_base* ps, bool positive)
225 {
226    saved_assertion<BidiIterator>* pmp = static_cast<saved_assertion<BidiIterator>*>(m_backup_state);
227    --pmp;
228    if(pmp < m_stack_base)
229    {
230       extend_stack();
231       pmp = static_cast<saved_assertion<BidiIterator>*>(m_backup_state);
232       --pmp;
233    }
234    (void) new (pmp)saved_assertion<BidiIterator>(positive, ps, position);
235    m_backup_state = pmp;
236 }
237
238 template <class BidiIterator, class Allocator, class traits, class Allocator2>
239 inline void perl_matcher<BidiIterator, Allocator, traits, Allocator2>::push_alt(const re_syntax_base* ps)
240 {
241    saved_position<BidiIterator>* pmp = static_cast<saved_position<BidiIterator>*>(m_backup_state);
242    --pmp;
243    if(pmp < m_stack_base)
244    {
245       extend_stack();
246       pmp = static_cast<saved_position<BidiIterator>*>(m_backup_state);
247       --pmp;
248    }
249    (void) new (pmp)saved_position<BidiIterator>(ps, position, saved_state_alt);
250    m_backup_state = pmp;
251 }
252
253 template <class BidiIterator, class Allocator, class traits, class Allocator2>
254 inline void perl_matcher<BidiIterator, Allocator, traits, Allocator2>::push_non_greedy_repeat(const re_syntax_base* ps)
255 {
256    saved_position<BidiIterator>* pmp = static_cast<saved_position<BidiIterator>*>(m_backup_state);
257    --pmp;
258    if(pmp < m_stack_base)
259    {
260       extend_stack();
261       pmp = static_cast<saved_position<BidiIterator>*>(m_backup_state);
262       --pmp;
263    }
264    (void) new (pmp)saved_position<BidiIterator>(ps, position, saved_state_non_greedy_long_repeat);
265    m_backup_state = pmp;
266 }
267
268 template <class BidiIterator, class Allocator, class traits, class Allocator2>
269 inline void perl_matcher<BidiIterator, Allocator, traits, Allocator2>::push_repeater_count(int i, repeater_count<BidiIterator>** s)
270 {
271    saved_repeater<BidiIterator>* pmp = static_cast<saved_repeater<BidiIterator>*>(m_backup_state);
272    --pmp;
273    if(pmp < m_stack_base)
274    {
275       extend_stack();
276       pmp = static_cast<saved_repeater<BidiIterator>*>(m_backup_state);
277       --pmp;
278    }
279    (void) new (pmp)saved_repeater<BidiIterator>(i, s, position);
280    m_backup_state = pmp;
281 }
282
283 template <class BidiIterator, class Allocator, class traits, class Allocator2>
284 inline void perl_matcher<BidiIterator, Allocator, traits, Allocator2>::push_single_repeat(unsigned c, const re_repeat* r, BidiIterator last_position, int id)
285 {
286    saved_single_repeat<BidiIterator>* pmp = static_cast<saved_single_repeat<BidiIterator>*>(m_backup_state);
287    --pmp;
288    if(pmp < m_stack_base)
289    {
290       extend_stack();
291       pmp = static_cast<saved_single_repeat<BidiIterator>*>(m_backup_state);
292       --pmp;
293    }
294    (void) new (pmp)saved_single_repeat<BidiIterator>(c, r, last_position, id);
295    m_backup_state = pmp;
296 }
297
298 template <class BidiIterator, class Allocator, class traits, class Allocator2>
299 bool perl_matcher<BidiIterator, Allocator, traits, Allocator2>::match_startmark()
300 {
301    int index = static_cast<const re_brace*>(pstate)->index;
302    switch(index)
303    {
304    case 0:
305       pstate = pstate->next.p;
306       break;
307    case -1:
308    case -2:
309       {
310          // forward lookahead assert:
311          const re_syntax_base* next_pstate = static_cast<const re_jump*>(pstate->next.p)->alt.p->next.p;
312          pstate = pstate->next.p->next.p;
313          push_assertion(next_pstate, index == -1);
314          break;
315       }
316    case -3:
317       {
318          // independent sub-expression, currently this is always recursive:
319          const re_syntax_base* next_pstate = static_cast<const re_jump*>(pstate->next.p)->alt.p->next.p;
320          pstate = pstate->next.p->next.p;
321          bool r = match_all_states();
322          pstate = next_pstate;
323 #ifdef BOOST_REGEX_MATCH_EXTRA
324          if(r && (m_match_flags & match_extra))
325          {
326             //
327             // our captures have been stored in *m_presult
328             // we need to unpack them, and insert them
329             // back in the right order when we unwind the stack:
330             //
331             match_results<BidiIterator, Allocator> temp_match(*m_presult);
332             unsigned i;
333             for(i = 0; i < temp_match.size(); ++i)
334                (*m_presult)[i].get_captures().clear();
335             // match everything else:
336             r = match_all_states();
337             // now place the stored captures back:
338             for(i = 0; i < temp_match.size(); ++i)
339             {
340                typedef typename sub_match<BidiIterator>::capture_sequence_type seq;
341                seq& s1 = (*m_presult)[i].get_captures();
342                const seq& s2 = temp_match[i].captures();
343                s1.insert(
344                   s1.end(), 
345                   s2.begin(), 
346                   s2.end());
347             }
348          }
349 #endif
350          return r;
351       }
352    default:
353    {
354       assert(index > 0);
355       if((m_match_flags & match_nosubs) == 0)
356       {
357          push_matched_paren(index, (*m_presult)[index]);
358          m_presult->set_first(position, index);
359       }
360       pstate = pstate->next.p;
361       break;
362    }
363    }
364    return true;
365 }
366
367 template <class BidiIterator, class Allocator, class traits, class Allocator2>
368 bool perl_matcher<BidiIterator, Allocator, traits, Allocator2>::match_alt()
369 {
370    bool take_first, take_second;
371    const re_jump* jmp = static_cast<const re_jump*>(pstate);
372
373    // find out which of these two alternatives we need to take:
374    if(position == last)
375    {
376       take_first = jmp->can_be_null & mask_take;
377       take_second = jmp->can_be_null & mask_skip;
378    }
379    else
380    {
381       take_first = access::can_start(*position, jmp->_map, (unsigned char)mask_take);
382       take_second = access::can_start(*position, jmp->_map, (unsigned char)mask_skip);
383   }
384
385    if(take_first)
386    {
387       // we can take the first alternative,
388       // see if we need to push next alternative:
389       if(take_second)
390       {
391          push_alt(jmp->alt.p);
392       }
393       pstate = pstate->next.p;
394       return true;
395    }
396    if(take_second)
397    {
398       pstate = jmp->alt.p;
399       return true;
400    }
401    return false;  // neither option is possible
402 }
403
404 template <class BidiIterator, class Allocator, class traits, class Allocator2>
405 bool perl_matcher<BidiIterator, Allocator, traits, Allocator2>::match_rep()
406 {
407 #ifdef BOOST_MSVC
408 #pragma warning(push)
409 #pragma warning(disable:4127 4244)
410 #endif
411 #ifdef __BORLANDC__
412 #pragma option push -w-8008 -w-8066 -w-8004
413 #endif
414    const re_repeat* rep = static_cast<const re_repeat*>(pstate);
415
416    // find out which of these two alternatives we need to take:
417    bool take_first, take_second;
418    if(position == last)
419    {
420       take_first = rep->can_be_null & mask_take;
421       take_second = rep->can_be_null & mask_skip;
422    }
423    else
424    {
425       take_first = access::can_start(*position, rep->_map, (unsigned char)mask_take);
426       take_second = access::can_start(*position, rep->_map, (unsigned char)mask_skip);
427    }
428
429    if(take_first || (next_count->get_id() != rep->id))
430    {
431       // we're moving to a different repeat from the last
432       // one, so set up a counter object:
433       push_repeater_count(rep->id, &next_count);
434    }
435    //
436    // If we've had at least one repeat already, and the last one 
437    // matched the NULL string then set the repeat count to
438    // maximum:
439    //
440    next_count->check_null_repeat(position, rep->max);
441
442    if(next_count->get_count() < rep->min)
443    {
444       // we must take the repeat:
445       if(take_first)
446       {
447          // increase the counter:
448          ++(*next_count);
449          pstate = rep->next.p;
450          return true;
451       }
452       return false;
453    }
454
455    if(rep->greedy)
456    {
457       // try and take the repeat if we can:
458       if((next_count->get_count() < rep->max) && take_first)
459       {
460          if(take_second)
461          {
462             // store position in case we fail:
463             push_alt(rep->alt.p);
464          }
465          // increase the counter:
466          ++(*next_count);
467          pstate = rep->next.p;
468          return true;
469       }
470       else if(take_second)
471       {
472          pstate = rep->alt.p;
473          return true;
474       }
475       return false; // can't take anything, fail...
476    }
477    else // non-greedy
478    {
479       // try and skip the repeat if we can:
480       if(take_second)
481       {
482          // store position in case we fail:
483          push_non_greedy_repeat(rep->next.p);
484          pstate = rep->alt.p;
485          return true;
486       }
487       if((next_count->get_count() < rep->max) && take_first)
488       {
489          // increase the counter:
490          ++(*next_count);
491          pstate = rep->next.p;
492          return true;
493       }
494    }
495    return false;
496 #ifdef __BORLANDC__
497 #pragma option pop
498 #endif
499 #ifdef BOOST_MSVC
500 #pragma warning(pop)
501 #endif
502 }
503
504 template <class BidiIterator, class Allocator, class traits, class Allocator2>
505 bool perl_matcher<BidiIterator, Allocator, traits, Allocator2>::match_dot_repeat_slow()
506 {
507    unsigned count = 0;
508    const re_repeat* rep = static_cast<const re_repeat*>(pstate);
509    re_syntax_base* psingle = rep->next.p;
510    // match compulsary repeats first:
511    while(count < rep->min)
512    {
513       pstate = psingle;
514       if(!match_wild())
515          return false;
516       ++count;
517    }
518    if(rep->greedy)
519    {
520       // repeat for as long as we can:
521       while(count < rep->max)
522       {
523          pstate = psingle;
524          if(!match_wild())
525             break;
526          ++count;
527       }
528       // remember where we got to if this is a leading repeat:
529       if((rep->leading) && (count < rep->max))
530          restart = position;
531       // push backtrack info if available:
532       if(count - rep->min)
533          push_single_repeat(count, rep, position, saved_state_greedy_single_repeat);
534       // jump to next state:
535       pstate = rep->alt.p;
536       return true;
537    }
538    else
539    {
540       // non-greedy, push state and return true if we can skip:
541       if(count < rep->max)
542          push_single_repeat(count, rep, position, saved_state_rep_slow_dot);
543       pstate = rep->alt.p;
544       return (position == last) ? (rep->can_be_null & mask_skip) : access::can_start(*position, rep->_map, mask_skip);
545    }
546 }
547
548 template <class BidiIterator, class Allocator, class traits, class Allocator2>
549 bool perl_matcher<BidiIterator, Allocator, traits, Allocator2>::match_dot_repeat_fast()
550 {
551    if(m_match_flags & (match_not_dot_newline | match_not_dot_null))
552       return match_dot_repeat_slow();
553
554    const re_repeat* rep = static_cast<const re_repeat*>(pstate);
555    unsigned count = (std::min)(static_cast<unsigned>(re_detail::distance(position, last)), static_cast<unsigned>(rep->greedy ? rep->max : rep->min));
556    if(rep->min > count)
557       return false;  // not enough text left to match
558    std::advance(position, count);
559
560    if(rep->greedy)
561    {
562       if((rep->leading) && (count < rep->max))
563          restart = position;
564       // push backtrack info if available:
565       if(count - rep->min)
566          push_single_repeat(count, rep, position, saved_state_greedy_single_repeat);
567       // jump to next state:
568       pstate = rep->alt.p;
569       return true;
570    }
571    else
572    {
573       // non-greedy, push state and return true if we can skip:
574       if(count < rep->max)
575          push_single_repeat(count, rep, position, saved_state_rep_fast_dot);
576       pstate = rep->alt.p;
577       return (position == last) ? (rep->can_be_null & mask_skip) : access::can_start(*position, rep->_map, mask_skip);
578    }
579 }
580
581 template <class BidiIterator, class Allocator, class traits, class Allocator2>
582 bool perl_matcher<BidiIterator, Allocator, traits, Allocator2>::match_char_repeat()
583 {
584 #ifdef BOOST_MSVC
585 #pragma warning(push)
586 #pragma warning(disable:4127)
587 #endif
588 #ifdef __BORLANDC__
589 #pragma option push -w-8008 -w-8066 -w-8004
590 #endif
591    const re_repeat* rep = static_cast<const re_repeat*>(pstate);
592    assert(1 == static_cast<const re_literal*>(rep->next.p)->length);
593    const char_type what = *reinterpret_cast<const char_type*>(static_cast<const re_literal*>(rep->next.p) + 1);
594    unsigned count = 0;
595    //
596    // start by working out how much we can skip:
597    //
598    unsigned desired = rep->greedy ? rep->max : rep->min;
599    if(::boost::is_random_access_iterator<BidiIterator>::value)
600    {
601       BidiIterator end = position;
602       std::advance(end, (std::min)((unsigned)re_detail::distance(position, last), desired));
603       BidiIterator origin(position);
604       while((position != end) && (traits_inst.translate(*position, icase) == what))
605       {
606          ++position;
607       }
608       count = (unsigned)re_detail::distance(origin, position);
609    }
610    else
611    {
612       while((count < desired) && (position != last) && (traits_inst.translate(*position, icase) == what))
613       {
614          ++position;
615          ++count;
616       }
617    }
618
619    if(count < rep->min)
620       return false;
621
622    if(rep->greedy)
623    {
624       if((rep->leading) && (count < rep->max))
625          restart = position;
626       // push backtrack info if available:
627       if(count - rep->min)
628          push_single_repeat(count, rep, position, saved_state_greedy_single_repeat);
629       // jump to next state:
630       pstate = rep->alt.p;
631       return true;
632    }
633    else
634    {
635       // non-greedy, push state and return true if we can skip:
636       if(count < rep->max)
637          push_single_repeat(count, rep, position, saved_state_rep_char);
638       pstate = rep->alt.p;
639       return (position == last) ? (rep->can_be_null & mask_skip) : access::can_start(*position, rep->_map, mask_skip);
640    }
641 #ifdef __BORLANDC__
642 #pragma option pop
643 #endif
644 #ifdef BOOST_MSVC
645 #pragma warning(pop)
646 #endif
647 }
648
649 template <class BidiIterator, class Allocator, class traits, class Allocator2>
650 bool perl_matcher<BidiIterator, Allocator, traits, Allocator2>::match_set_repeat()
651 {
652 #ifdef BOOST_MSVC
653 #pragma warning(push)
654 #pragma warning(disable:4127)
655 #endif
656 #ifdef __BORLANDC__
657 #pragma option push -w-8008 -w-8066 -w-8004
658 #endif
659    const re_repeat* rep = static_cast<const re_repeat*>(pstate);
660    const unsigned char* map = static_cast<const re_set*>(rep->next.p)->_map;
661    unsigned count = 0;
662    //
663    // start by working out how much we can skip:
664    //
665    unsigned desired = rep->greedy ? rep->max : rep->min;
666    if(::boost::is_random_access_iterator<BidiIterator>::value)
667    {
668       BidiIterator end = position;
669       std::advance(end, (std::min)((unsigned)re_detail::distance(position, last), desired));
670       BidiIterator origin(position);
671       while((position != end) && map[(traits_uchar_type)traits_inst.translate(*position, icase)])
672       {
673          ++position;
674       }
675       count = (unsigned)re_detail::distance(origin, position);
676    }
677    else
678    {
679       while((count < desired) && (position != last) && map[(traits_uchar_type)traits_inst.translate(*position, icase)])
680       {
681          ++position;
682          ++count;
683       }
684    }
685
686    if(count < rep->min)
687       return false;
688
689    if(rep->greedy)
690    {
691       if((rep->leading) && (count < rep->max))
692          restart = position;
693       // push backtrack info if available:
694       if(count - rep->min)
695          push_single_repeat(count, rep, position, saved_state_greedy_single_repeat);
696       // jump to next state:
697       pstate = rep->alt.p;
698       return true;
699    }
700    else
701    {
702       // non-greedy, push state and return true if we can skip:
703       if(count < rep->max)
704          push_single_repeat(count, rep, position, saved_state_rep_short_set);
705       pstate = rep->alt.p;
706       return (position == last) ? (rep->can_be_null & mask_skip) : access::can_start(*position, rep->_map, mask_skip);
707    }
708 #ifdef __BORLANDC__
709 #pragma option pop
710 #endif
711 #ifdef BOOST_MSVC
712 #pragma warning(pop)
713 #endif
714 }
715
716 template <class BidiIterator, class Allocator, class traits, class Allocator2>
717 bool perl_matcher<BidiIterator, Allocator, traits, Allocator2>::match_long_set_repeat()
718 {
719 #ifdef BOOST_MSVC
720 #pragma warning(push)
721 #pragma warning(disable:4127)
722 #endif
723 #ifdef __BORLANDC__
724 #pragma option push -w-8008 -w-8066 -w-8004
725 #endif
726    const re_repeat* rep = static_cast<const re_repeat*>(pstate);
727    const re_set_long* set = static_cast<const re_set_long*>(pstate->next.p);
728    unsigned count = 0;
729    //
730    // start by working out how much we can skip:
731    //
732    unsigned desired = rep->greedy ? rep->max : rep->min;
733    if(::boost::is_random_access_iterator<BidiIterator>::value)
734    {
735       BidiIterator end = position;
736       std::advance(end, (std::min)((unsigned)re_detail::distance(position, last), desired));
737       BidiIterator origin(position);
738       while((position != end) && (position != re_is_set_member(position, last, set, re)))
739       {
740          ++position;
741       }
742       count = (unsigned)re_detail::distance(origin, position);
743    }
744    else
745    {
746       while((count < desired) && (position != last) && (position != re_is_set_member(position, last, set, re)))
747       {
748          ++position;
749          ++count;
750       }
751    }
752
753    if(count < rep->min)
754       return false;
755
756    if(rep->greedy)
757    {
758       if((rep->leading) && (count < rep->max))
759          restart = position;
760       // push backtrack info if available:
761       if(count - rep->min)
762          push_single_repeat(count, rep, position, saved_state_greedy_single_repeat);
763       // jump to next state:
764       pstate = rep->alt.p;
765       return true;
766    }
767    else
768    {
769       // non-greedy, push state and return true if we can skip:
770       if(count < rep->max)
771          push_single_repeat(count, rep, position, saved_state_rep_long_set);
772       pstate = rep->alt.p;
773       return (position == last) ? (rep->can_be_null & mask_skip) : access::can_start(*position, rep->_map, mask_skip);
774    }
775 #ifdef __BORLANDC__
776 #pragma option pop
777 #endif
778 #ifdef BOOST_MSVC
779 #pragma warning(pop)
780 #endif
781 }
782
783 /****************************************************************************
784
785 Unwind and associated proceedures follow, these perform what normal stack
786 unwinding does in the recursive implementation.
787
788 ****************************************************************************/
789
790 template <class BidiIterator, class Allocator, class traits, class Allocator2>
791 bool perl_matcher<BidiIterator, Allocator, traits, Allocator2>::unwind(bool have_match)
792 {
793    static unwind_proc_type const s_unwind_table[14] = 
794    {
795       &perl_matcher<BidiIterator, Allocator, traits, Allocator2>::unwind_end,
796       &perl_matcher<BidiIterator, Allocator, traits, Allocator2>::unwind_paren,
797       &perl_matcher<BidiIterator, Allocator, traits, Allocator2>::unwind_recursion_stopper,
798       &perl_matcher<BidiIterator, Allocator, traits, Allocator2>::unwind_assertion,
799       &perl_matcher<BidiIterator, Allocator, traits, Allocator2>::unwind_alt,
800       &perl_matcher<BidiIterator, Allocator, traits, Allocator2>::unwind_repeater_counter,
801       &perl_matcher<BidiIterator, Allocator, traits, Allocator2>::unwind_extra_block,
802       &perl_matcher<BidiIterator, Allocator, traits, Allocator2>::unwind_greedy_single_repeat,
803       &perl_matcher<BidiIterator, Allocator, traits, Allocator2>::unwind_slow_dot_repeat,
804       &perl_matcher<BidiIterator, Allocator, traits, Allocator2>::unwind_fast_dot_repeat,
805       &perl_matcher<BidiIterator, Allocator, traits, Allocator2>::unwind_char_repeat,
806       &perl_matcher<BidiIterator, Allocator, traits, Allocator2>::unwind_short_set_repeat,
807       &perl_matcher<BidiIterator, Allocator, traits, Allocator2>::unwind_long_set_repeat,
808       &perl_matcher<BidiIterator, Allocator, traits, Allocator2>::unwind_non_greedy_repeat,
809    };
810
811    m_recursive_result = have_match;
812    unwind_proc_type unwinder;
813    bool cont;
814    //
815    // keep unwinding our stack until we have something to do:
816    //
817    do
818    {
819       unwinder = s_unwind_table[m_backup_state->id];
820       cont = (this->*unwinder)(m_recursive_result);
821    }while(cont);
822    //
823    // return true if we have more states to try:
824    //
825    return pstate ? true : false;
826 }
827
828 template <class BidiIterator, class Allocator, class traits, class Allocator2>
829 bool perl_matcher<BidiIterator, Allocator, traits, Allocator2>::unwind_end(bool)
830 {
831    pstate = 0;   // nothing left to search
832    return false; // end of stack nothing more to search
833 }
834
835 template <class BidiIterator, class Allocator, class traits, class Allocator2>
836 bool perl_matcher<BidiIterator, Allocator, traits, Allocator2>::unwind_paren(bool have_match)
837 {
838    saved_matched_paren<BidiIterator>* pmp = static_cast<saved_matched_paren<BidiIterator>*>(m_backup_state);
839    // restore previous values if no match was found:
840    if(have_match == false)
841    {
842       m_presult->set_first(pmp->sub.first, pmp->index);
843       m_presult->set_second(pmp->sub.second, pmp->index, pmp->sub.matched);
844    }
845 #ifdef BOOST_REGEX_MATCH_EXTRA
846    //
847    // we have a match, push the capture information onto the stack:
848    //
849    else if(pmp->sub.matched && (match_extra & m_match_flags))
850       ((*m_presult)[pmp->index]).get_captures().push_back(pmp->sub);
851 #endif
852    // unwind stack:
853    m_backup_state = pmp+1;
854    boost::re_detail::inplace_destroy(pmp);
855    return true; // keep looking
856 }
857
858 template <class BidiIterator, class Allocator, class traits, class Allocator2>
859 bool perl_matcher<BidiIterator, Allocator, traits, Allocator2>::unwind_recursion_stopper(bool)
860 {
861    boost::re_detail::inplace_destroy(m_backup_state++);
862    pstate = 0;   // nothing left to search
863    return false; // end of stack nothing more to search
864 }
865
866 template <class BidiIterator, class Allocator, class traits, class Allocator2>
867 bool perl_matcher<BidiIterator, Allocator, traits, Allocator2>::unwind_assertion(bool r)
868 {
869    saved_assertion<BidiIterator>* pmp = static_cast<saved_assertion<BidiIterator>*>(m_backup_state);
870    pstate = pmp->pstate;
871    position = pmp->position;
872    bool result = (r == pmp->positive);
873    m_recursive_result = pmp->positive ? r : !r;
874    boost::re_detail::inplace_destroy(pmp++);
875    m_backup_state = pmp;
876    return !result; // return false if the assertion was matched to stop search.
877 }
878
879 template <class BidiIterator, class Allocator, class traits, class Allocator2>
880 bool perl_matcher<BidiIterator, Allocator, traits, Allocator2>::unwind_alt(bool r)
881 {
882    saved_position<BidiIterator>* pmp = static_cast<saved_position<BidiIterator>*>(m_backup_state);
883    if(!r)
884    {
885       pstate = pmp->pstate;
886       position = pmp->position;
887    }
888    boost::re_detail::inplace_destroy(pmp++);
889    m_backup_state = pmp;
890    return r; 
891 }
892
893 template <class BidiIterator, class Allocator, class traits, class Allocator2>
894 bool perl_matcher<BidiIterator, Allocator, traits, Allocator2>::unwind_repeater_counter(bool)
895 {
896    saved_repeater<BidiIterator>* pmp = static_cast<saved_repeater<BidiIterator>*>(m_backup_state);
897    boost::re_detail::inplace_destroy(pmp++);
898    m_backup_state = pmp;
899    return true; // keep looking
900 }
901
902 template <class BidiIterator, class Allocator, class traits, class Allocator2>
903 bool perl_matcher<BidiIterator, Allocator, traits, Allocator2>::unwind_extra_block(bool)
904 {
905    saved_extra_block* pmp = static_cast<saved_extra_block*>(m_backup_state);
906    void* condemmed = m_stack_base;
907    m_stack_base = pmp->base;
908    m_backup_state = pmp->end;
909    boost::re_detail::inplace_destroy(pmp);
910    put_mem_block(condemmed);
911    return true; // keep looking
912 }
913
914 template <class BidiIterator, class Allocator, class traits, class Allocator2>
915 inline void perl_matcher<BidiIterator, Allocator, traits, Allocator2>::destroy_single_repeat()
916 {
917    saved_single_repeat<BidiIterator>* p = static_cast<saved_single_repeat<BidiIterator>*>(m_backup_state);
918    boost::re_detail::inplace_destroy(p++);
919    m_backup_state = p;
920 }
921
922 template <class BidiIterator, class Allocator, class traits, class Allocator2>
923 bool perl_matcher<BidiIterator, Allocator, traits, Allocator2>::unwind_greedy_single_repeat(bool r)
924 {
925    saved_single_repeat<BidiIterator>* pmp = static_cast<saved_single_repeat<BidiIterator>*>(m_backup_state);
926
927    // if we have a match, just discard this state:
928    if(r) 
929    {
930       destroy_single_repeat();
931       return true;
932    }
933
934    const re_repeat* rep = pmp->rep;
935    unsigned count = pmp->count;
936    assert(rep->next.p != 0);
937    assert(rep->alt.p != 0);
938
939    count -= rep->min;
940    
941    if((m_match_flags & match_partial) && (position == last))
942       m_has_partial_match = true;
943
944    assert(count);
945    position = pmp->last_position;
946
947    // backtrack till we can skip out:
948    do
949    {
950       --position;
951       --count;
952       ++state_count;
953    }while(count && !access::can_start(*position, rep->_map, mask_skip));
954
955    // if we've hit base, destroy this state:
956    if(count == 0)
957    {
958          destroy_single_repeat();
959          if(!access::can_start(*position, rep->_map, mask_skip))
960             return true;
961    }
962    else
963    {
964       pmp->count = count + rep->min;
965       pmp->last_position = position;
966    }
967    pstate = rep->alt.p;
968    return false;
969 }
970
971 template <class BidiIterator, class Allocator, class traits, class Allocator2>
972 bool perl_matcher<BidiIterator, Allocator, traits, Allocator2>::unwind_slow_dot_repeat(bool r)
973 {
974    saved_single_repeat<BidiIterator>* pmp = static_cast<saved_single_repeat<BidiIterator>*>(m_backup_state);
975
976    // if we have a match, just discard this state:
977    if(r) 
978    {
979       destroy_single_repeat();
980       return true;
981    }
982
983    const re_repeat* rep = pmp->rep;
984    unsigned count = pmp->count;
985    assert(rep->type == syntax_element_dot_rep);
986    assert(rep->next.p != 0);
987    assert(rep->alt.p != 0);
988    assert(rep->next.p->type == syntax_element_wild);
989
990    assert(count < rep->max);
991    pstate = rep->next.p;
992    position = pmp->last_position;
993
994    if(position != last)
995    {
996       // wind forward until we can skip out of the repeat:
997       do
998       {
999          if(!match_wild())
1000          {
1001             // failed repeat match, discard this state and look for another:
1002             destroy_single_repeat();
1003             return true;
1004          }
1005          ++count;
1006          ++state_count;
1007          pstate = rep->next.p;
1008       }while((count < rep->max) && (position != last) && !access::can_start(*position, rep->_map, mask_skip));
1009    }   
1010    if(position == last)
1011    {
1012       // can't repeat any more, remove the pushed state: 
1013       destroy_single_repeat();
1014       if(0 == (rep->can_be_null & mask_skip))
1015          return true;
1016    }
1017    else if(count == rep->max)
1018    {
1019       // can't repeat any more, remove the pushed state: 
1020       destroy_single_repeat();
1021       if(!access::can_start(*position, rep->_map, mask_skip))
1022          return true;
1023    }
1024    else
1025    {
1026       pmp->count = count;
1027       pmp->last_position = position;
1028    }
1029    pstate = rep->alt.p;
1030    return false;
1031 }
1032
1033 template <class BidiIterator, class Allocator, class traits, class Allocator2>
1034 bool perl_matcher<BidiIterator, Allocator, traits, Allocator2>::unwind_fast_dot_repeat(bool r)
1035 {
1036    saved_single_repeat<BidiIterator>* pmp = static_cast<saved_single_repeat<BidiIterator>*>(m_backup_state);
1037
1038    // if we have a match, just discard this state:
1039    if(r) 
1040    {
1041       destroy_single_repeat();
1042       return true;
1043    }
1044
1045    const re_repeat* rep = pmp->rep;
1046    unsigned count = pmp->count;
1047
1048    assert(count < rep->max);
1049    position = pmp->last_position;
1050    if(position != last)
1051    {
1052
1053       // wind forward until we can skip out of the repeat:
1054       do
1055       {
1056          ++position;
1057          ++count;
1058          ++state_count;
1059       }while((count < rep->max) && (position != last) && !access::can_start(*position, rep->_map, mask_skip));
1060    }
1061
1062    if(position == last)
1063    {
1064       // can't repeat any more, remove the pushed state: 
1065       destroy_single_repeat();
1066       if(0 == (rep->can_be_null & mask_skip))
1067          return true;
1068    }
1069    else if(count == rep->max)
1070    {
1071       // can't repeat any more, remove the pushed state: 
1072       destroy_single_repeat();
1073       if(!access::can_start(*position, rep->_map, mask_skip))
1074          return true;
1075    }
1076    else
1077    {
1078       pmp->count = count;
1079       pmp->last_position = position;
1080    }
1081    pstate = rep->alt.p;
1082    return false;
1083 }
1084
1085 template <class BidiIterator, class Allocator, class traits, class Allocator2>
1086 bool perl_matcher<BidiIterator, Allocator, traits, Allocator2>::unwind_char_repeat(bool r)
1087 {
1088    saved_single_repeat<BidiIterator>* pmp = static_cast<saved_single_repeat<BidiIterator>*>(m_backup_state);
1089
1090    // if we have a match, just discard this state:
1091    if(r) 
1092    {
1093       destroy_single_repeat();
1094       return true;
1095    }
1096
1097    const re_repeat* rep = pmp->rep;
1098    unsigned count = pmp->count;
1099    pstate = rep->next.p;
1100    const char_type what = *reinterpret_cast<const char_type*>(static_cast<const re_literal*>(pstate) + 1);
1101    position = pmp->last_position;
1102
1103    assert(rep->type == syntax_element_char_rep);
1104    assert(rep->next.p != 0);
1105    assert(rep->alt.p != 0);
1106    assert(rep->next.p->type == syntax_element_literal);
1107    assert(count < rep->max);
1108
1109    if(position != last)
1110    {
1111       // wind forward until we can skip out of the repeat:
1112       do
1113       {
1114          if(traits_inst.translate(*position, icase) != what)
1115          {
1116             // failed repeat match, discard this state and look for another:
1117             destroy_single_repeat();
1118             return true;
1119          }
1120          ++count;
1121          ++ position;
1122          ++state_count;
1123          pstate = rep->next.p;
1124       }while((count < rep->max) && (position != last) && !access::can_start(*position, rep->_map, mask_skip));
1125    }   
1126    if(position == last)
1127    {
1128       // can't repeat any more, remove the pushed state: 
1129       destroy_single_repeat();
1130       if(0 == (rep->can_be_null & mask_skip))
1131          return true;
1132    }
1133    else if(count == rep->max)
1134    {
1135       // can't repeat any more, remove the pushed state: 
1136       destroy_single_repeat();
1137       if(!access::can_start(*position, rep->_map, mask_skip))
1138          return true;
1139    }
1140    else
1141    {
1142       pmp->count = count;
1143       pmp->last_position = position;
1144    }
1145    pstate = rep->alt.p;
1146    return false;
1147 }
1148
1149 template <class BidiIterator, class Allocator, class traits, class Allocator2>
1150 bool perl_matcher<BidiIterator, Allocator, traits, Allocator2>::unwind_short_set_repeat(bool r)
1151 {
1152    saved_single_repeat<BidiIterator>* pmp = static_cast<saved_single_repeat<BidiIterator>*>(m_backup_state);
1153
1154    // if we have a match, just discard this state:
1155    if(r) 
1156    {
1157       destroy_single_repeat();
1158       return true;
1159    }
1160
1161    const re_repeat* rep = pmp->rep;
1162    unsigned count = pmp->count;
1163    pstate = rep->next.p;
1164    const unsigned char* map = static_cast<const re_set*>(rep->next.p)->_map;
1165    position = pmp->last_position;
1166
1167    assert(rep->type == syntax_element_short_set_rep);
1168    assert(rep->next.p != 0);
1169    assert(rep->alt.p != 0);
1170    assert(rep->next.p->type == syntax_element_set);
1171    assert(count < rep->max);
1172    
1173    if(position != last)
1174    {
1175       // wind forward until we can skip out of the repeat:
1176       do
1177       {
1178          if(!map[(traits_uchar_type)traits_inst.translate(*position, icase)])
1179          {
1180             // failed repeat match, discard this state and look for another:
1181             destroy_single_repeat();
1182             return true;
1183          }
1184          ++count;
1185          ++ position;
1186          ++state_count;
1187          pstate = rep->next.p;
1188       }while((count < rep->max) && (position != last) && !access::can_start(*position, rep->_map, mask_skip));
1189    }   
1190    if(position == last)
1191    {
1192       // can't repeat any more, remove the pushed state: 
1193       destroy_single_repeat();
1194       if(0 == (rep->can_be_null & mask_skip))
1195          return true;
1196    }
1197    else if(count == rep->max)
1198    {
1199       // can't repeat any more, remove the pushed state: 
1200       destroy_single_repeat();
1201       if(!access::can_start(*position, rep->_map, mask_skip))
1202          return true;
1203    }
1204    else
1205    {
1206       pmp->count = count;
1207       pmp->last_position = position;
1208    }
1209    pstate = rep->alt.p;
1210    return false;
1211 }
1212
1213 template <class BidiIterator, class Allocator, class traits, class Allocator2>
1214 bool perl_matcher<BidiIterator, Allocator, traits, Allocator2>::unwind_long_set_repeat(bool r)
1215 {
1216    saved_single_repeat<BidiIterator>* pmp = static_cast<saved_single_repeat<BidiIterator>*>(m_backup_state);
1217
1218    // if we have a match, just discard this state:
1219    if(r)
1220    {
1221       destroy_single_repeat();
1222       return true;
1223    }
1224
1225    const re_repeat* rep = pmp->rep;
1226    unsigned count = pmp->count;
1227    pstate = rep->next.p;
1228    const re_set_long* set = static_cast<const re_set_long*>(pstate);
1229    position = pmp->last_position;
1230
1231    assert(rep->type == syntax_element_long_set_rep);
1232    assert(rep->next.p != 0);
1233    assert(rep->alt.p != 0);
1234    assert(rep->next.p->type == syntax_element_long_set);
1235    assert(position != last);
1236    assert(count < rep->max);
1237
1238    if(position != last)
1239    {
1240       // wind forward until we can skip out of the repeat:
1241       do
1242       {
1243          if(position == re_is_set_member(position, last, set, re))
1244          {
1245             // failed repeat match, discard this state and look for another:
1246             destroy_single_repeat();
1247             return true;
1248          }
1249          ++position;
1250          ++count;
1251          ++state_count;
1252          pstate = rep->next.p;
1253       }while((count < rep->max) && (position != last) && !access::can_start(*position, rep->_map, mask_skip));
1254    }   
1255    if(position == last)
1256    {
1257       // can't repeat any more, remove the pushed state:
1258       destroy_single_repeat();
1259       if(0 == (rep->can_be_null & mask_skip))
1260          return true;
1261    }
1262    else if(count == rep->max)
1263    {
1264       // can't repeat any more, remove the pushed state: 
1265       destroy_single_repeat();
1266       if(!access::can_start(*position, rep->_map, mask_skip))
1267          return true;
1268    }
1269    else
1270    {
1271       pmp->count = count;
1272       pmp->last_position = position;
1273    }
1274    pstate = rep->alt.p;
1275    return false;
1276 }
1277
1278 template <class BidiIterator, class Allocator, class traits, class Allocator2>
1279 bool perl_matcher<BidiIterator, Allocator, traits, Allocator2>::unwind_non_greedy_repeat(bool r)
1280 {
1281    saved_position<BidiIterator>* pmp = static_cast<saved_position<BidiIterator>*>(m_backup_state);
1282    if(!r)
1283    {
1284       position = pmp->position;
1285       pstate = pmp->pstate;
1286       ++(*next_count);
1287    }
1288    boost::re_detail::inplace_destroy(pmp++);
1289    m_backup_state = pmp;
1290    return r;
1291 }
1292
1293 } // namespace re_detail
1294 } // namespace boost
1295
1296 #ifdef BOOST_HAS_ABI_HEADERS
1297 #  include BOOST_ABI_SUFFIX
1298 #endif
1299
1300 #endif
1301
1302