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)
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 * common to both the recursive and non-recursive versions.
20 #ifndef BOOST_REGEX_V4_PERL_MATCHER_COMMON_HPP
21 #define BOOST_REGEX_V4_PERL_MATCHER_COMMON_HPP
25 #pragma warning(disable: 4103)
27 #ifdef BOOST_HAS_ABI_HEADERS
28 # include BOOST_ABI_PREFIX
35 # pragma option push -w-8008 -w-8066
38 # pragma warning(push)
40 #pragma warning(disable:4800)
45 namespace BOOST_REGEX_DETAIL_NS{
47 template <class BidiIterator, class Allocator, class traits>
48 void perl_matcher<BidiIterator, Allocator, traits>::construct_init(const basic_regex<char_type, traits>& e, match_flag_type f)
50 typedef typename regex_iterator_traits<BidiIterator>::iterator_category category;
51 typedef typename basic_regex<char_type, traits>::flag_type expression_flag_type;
55 // precondition failure: e is not a valid regex.
56 std::invalid_argument ex("Invalid regular expression object");
57 boost::throw_exception(ex);
61 estimate_max_state_count(static_cast<category*>(0));
62 expression_flag_type re_f = re.flags();
63 icase = re_f & regex_constants::icase;
64 if(!(m_match_flags & (match_perl|match_posix)))
66 if((re_f & (regbase::main_option_type|regbase::no_perl_ex)) == 0)
67 m_match_flags |= match_perl;
68 else if((re_f & (regbase::main_option_type|regbase::emacs_ex)) == (regbase::basic_syntax_group|regbase::emacs_ex))
69 m_match_flags |= match_perl;
70 else if((re_f & (regbase::main_option_type|regbase::literal)) == (regbase::literal))
71 m_match_flags |= match_perl;
73 m_match_flags |= match_posix;
75 if(m_match_flags & match_posix)
77 m_temp_match.reset(new match_results<BidiIterator, Allocator>());
78 m_presult = m_temp_match.get();
81 m_presult = &m_result;
82 #ifdef BOOST_REGEX_NON_RECURSIVE
85 #elif defined(BOOST_REGEX_RECURSIVE)
86 m_can_backtrack = true;
87 m_have_accept = false;
89 // find the value to use for matching word boundaries:
90 m_word_mask = re.get_data().m_word_mask;
91 // find bitmask to use for matching '.':
92 match_any_mask = static_cast<unsigned char>((f & match_not_dot_newline) ? BOOST_REGEX_DETAIL_NS::test_not_newline : BOOST_REGEX_DETAIL_NS::test_newline);
93 // Disable match_any if requested in the state machine:
94 if(e.get_data().m_disable_match_any)
95 m_match_flags &= regex_constants::match_not_any;
98 template <class BidiIterator, class Allocator, class traits>
99 void perl_matcher<BidiIterator, Allocator, traits>::estimate_max_state_count(std::random_access_iterator_tag*)
102 // How many states should we allow our machine to visit before giving up?
103 // This is a heuristic: it takes the greater of O(N^2) and O(NS^2)
104 // where N is the length of the string, and S is the number of states
105 // in the machine. It's tempting to up this to O(N^2S) or even O(N^2S^2)
106 // but these take unreasonably amounts of time to bale out in pathological
109 // Calculate NS^2 first:
111 static const std::ptrdiff_t k = 100000;
112 std::ptrdiff_t dist = boost::BOOST_REGEX_DETAIL_NS::distance(base, last);
115 std::ptrdiff_t states = re.size();
118 if ((std::numeric_limits<std::ptrdiff_t>::max)() / states < states)
120 max_state_count = (std::min)((std::ptrdiff_t)BOOST_REGEX_MAX_STATE_COUNT, (std::numeric_limits<std::ptrdiff_t>::max)() - 2);
124 if((std::numeric_limits<std::ptrdiff_t>::max)() / dist < states)
126 max_state_count = (std::min)((std::ptrdiff_t)BOOST_REGEX_MAX_STATE_COUNT, (std::numeric_limits<std::ptrdiff_t>::max)() - 2);
130 if((std::numeric_limits<std::ptrdiff_t>::max)() - k < states)
132 max_state_count = (std::min)((std::ptrdiff_t)BOOST_REGEX_MAX_STATE_COUNT, (std::numeric_limits<std::ptrdiff_t>::max)() - 2);
137 max_state_count = states;
140 // Now calculate N^2:
143 if((std::numeric_limits<std::ptrdiff_t>::max)() / dist < states)
145 max_state_count = (std::min)((std::ptrdiff_t)BOOST_REGEX_MAX_STATE_COUNT, (std::numeric_limits<std::ptrdiff_t>::max)() - 2);
149 if((std::numeric_limits<std::ptrdiff_t>::max)() - k < states)
151 max_state_count = (std::min)((std::ptrdiff_t)BOOST_REGEX_MAX_STATE_COUNT, (std::numeric_limits<std::ptrdiff_t>::max)() - 2);
156 // N^2 can be a very large number indeed, to prevent things getting out
157 // of control, cap the max states:
159 if(states > BOOST_REGEX_MAX_STATE_COUNT)
160 states = BOOST_REGEX_MAX_STATE_COUNT;
162 // If (the possibly capped) N^2 is larger than our first estimate,
165 if(states > max_state_count)
166 max_state_count = states;
169 template <class BidiIterator, class Allocator, class traits>
170 inline void perl_matcher<BidiIterator, Allocator, traits>::estimate_max_state_count(void*)
172 // we don't know how long the sequence is:
173 max_state_count = BOOST_REGEX_MAX_STATE_COUNT;
176 #ifdef BOOST_REGEX_HAS_MS_STACK_GUARD
177 template <class BidiIterator, class Allocator, class traits>
178 inline bool perl_matcher<BidiIterator, Allocator, traits>::protected_call(
179 protected_proc_type proc)
181 ::boost::BOOST_REGEX_DETAIL_NS::concrete_protected_call
182 <perl_matcher<BidiIterator, Allocator, traits> >
184 return obj.execute();
189 template <class BidiIterator, class Allocator, class traits>
190 inline bool perl_matcher<BidiIterator, Allocator, traits>::match()
192 #ifdef BOOST_REGEX_HAS_MS_STACK_GUARD
193 return protected_call(&perl_matcher<BidiIterator, Allocator, traits>::match_imp);
199 template <class BidiIterator, class Allocator, class traits>
200 bool perl_matcher<BidiIterator, Allocator, traits>::match_imp()
202 // initialise our stack if we are non-recursive:
203 #ifdef BOOST_REGEX_NON_RECURSIVE
204 save_state_init init(&m_stack_base, &m_backup_state);
205 used_block_count = BOOST_REGEX_MAX_BLOCKS;
206 #if !defined(BOOST_NO_EXCEPTIONS)
211 // reset our state machine:
215 m_match_flags |= regex_constants::match_all;
216 m_presult->set_size((m_match_flags & match_nosubs) ? 1u : static_cast<typename results_type::size_type>(1u + re.mark_count()), search_base, last);
217 m_presult->set_base(base);
218 m_presult->set_named_subs(this->re.get_named_subs());
219 if(m_match_flags & match_posix)
220 m_result = *m_presult;
221 verify_options(re.flags(), m_match_flags);
222 if(0 == match_prefix())
224 return (m_result[0].second == last) && (m_result[0].first == base);
226 #if defined(BOOST_REGEX_NON_RECURSIVE) && !defined(BOOST_NO_EXCEPTIONS)
230 // unwind all pushed states, apart from anything else this
231 // ensures that all the states are correctly destructed
232 // not just the memory freed.
233 while(unwind(true)){}
239 template <class BidiIterator, class Allocator, class traits>
240 inline bool perl_matcher<BidiIterator, Allocator, traits>::find()
242 #ifdef BOOST_REGEX_HAS_MS_STACK_GUARD
243 return protected_call(&perl_matcher<BidiIterator, Allocator, traits>::find_imp);
249 template <class BidiIterator, class Allocator, class traits>
250 bool perl_matcher<BidiIterator, Allocator, traits>::find_imp()
252 static matcher_proc_type const s_find_vtable[7] =
254 &perl_matcher<BidiIterator, Allocator, traits>::find_restart_any,
255 &perl_matcher<BidiIterator, Allocator, traits>::find_restart_word,
256 &perl_matcher<BidiIterator, Allocator, traits>::find_restart_line,
257 &perl_matcher<BidiIterator, Allocator, traits>::find_restart_buf,
258 &perl_matcher<BidiIterator, Allocator, traits>::match_prefix,
259 &perl_matcher<BidiIterator, Allocator, traits>::find_restart_lit,
260 &perl_matcher<BidiIterator, Allocator, traits>::find_restart_lit,
263 // initialise our stack if we are non-recursive:
264 #ifdef BOOST_REGEX_NON_RECURSIVE
265 save_state_init init(&m_stack_base, &m_backup_state);
266 used_block_count = BOOST_REGEX_MAX_BLOCKS;
267 #if !defined(BOOST_NO_EXCEPTIONS)
273 if((m_match_flags & regex_constants::match_init) == 0)
275 // reset our state machine:
276 search_base = position = base;
277 pstate = re.get_first_state();
278 m_presult->set_size((m_match_flags & match_nosubs) ? 1u : static_cast<typename results_type::size_type>(1u + re.mark_count()), base, last);
279 m_presult->set_base(base);
280 m_presult->set_named_subs(this->re.get_named_subs());
281 m_match_flags |= regex_constants::match_init;
286 search_base = position = m_result[0].second;
287 // If last match was null and match_not_null was not set then increment
288 // our start position, otherwise we go into an infinite loop:
289 if(((m_match_flags & match_not_null) == 0) && (m_result.length() == 0))
297 m_presult->set_size((m_match_flags & match_nosubs) ? 1u : static_cast<typename results_type::size_type>(1u + re.mark_count()), search_base, last);
298 //if((base != search_base) && (base == backstop))
299 // m_match_flags |= match_prev_avail;
301 if(m_match_flags & match_posix)
303 m_result.set_size(static_cast<typename results_type::size_type>(1u + re.mark_count()), base, last);
304 m_result.set_base(base);
307 verify_options(re.flags(), m_match_flags);
308 // find out what kind of expression we have:
309 unsigned type = (m_match_flags & match_continuous) ?
310 static_cast<unsigned int>(regbase::restart_continue)
311 : static_cast<unsigned int>(re.get_restart_type());
313 // call the appropriate search routine:
314 matcher_proc_type proc = s_find_vtable[type];
315 return (this->*proc)();
317 #if defined(BOOST_REGEX_NON_RECURSIVE) && !defined(BOOST_NO_EXCEPTIONS)
321 // unwind all pushed states, apart from anything else this
322 // ensures that all the states are correctly destructed
323 // not just the memory freed.
324 while(unwind(true)){}
330 template <class BidiIterator, class Allocator, class traits>
331 bool perl_matcher<BidiIterator, Allocator, traits>::match_prefix()
333 m_has_partial_match = false;
334 m_has_found_match = false;
335 pstate = re.get_first_state();
336 m_presult->set_first(position);
339 if(!m_has_found_match && m_has_partial_match && (m_match_flags & match_partial))
341 m_has_found_match = true;
342 m_presult->set_second(last, 0, false);
344 if((m_match_flags & match_posix) == match_posix)
346 m_result.maybe_assign(*m_presult);
349 #ifdef BOOST_REGEX_MATCH_EXTRA
350 if(m_has_found_match && (match_extra & m_match_flags))
353 // we have a match, reverse the capture information:
355 for(unsigned i = 0; i < m_presult->size(); ++i)
357 typename sub_match<BidiIterator>::capture_sequence_type & seq = ((*m_presult)[i]).get_captures();
358 std::reverse(seq.begin(), seq.end());
362 if(!m_has_found_match)
363 position = restart; // reset search postion
364 #ifdef BOOST_REGEX_RECURSIVE
365 m_can_backtrack = true; // reset for further searches
367 return m_has_found_match;
370 template <class BidiIterator, class Allocator, class traits>
371 bool perl_matcher<BidiIterator, Allocator, traits>::match_literal()
373 unsigned int len = static_cast<const re_literal*>(pstate)->length;
374 const char_type* what = reinterpret_cast<const char_type*>(static_cast<const re_literal*>(pstate) + 1);
376 // compare string with what we stored in
378 for(unsigned int i = 0; i < len; ++i, ++position)
380 if((position == last) || (traits_inst.translate(*position, icase) != what[i]))
383 pstate = pstate->next.p;
387 template <class BidiIterator, class Allocator, class traits>
388 bool perl_matcher<BidiIterator, Allocator, traits>::match_start_line()
390 if(position == backstop)
392 if((m_match_flags & match_prev_avail) == 0)
394 if((m_match_flags & match_not_bol) == 0)
396 pstate = pstate->next.p;
402 else if(m_match_flags & match_single_line)
405 // check the previous value character:
406 BidiIterator t(position);
410 if(is_separator(*t) && !((*t == static_cast<char_type>('\r')) && (*position == static_cast<char_type>('\n'))) )
412 pstate = pstate->next.p;
416 else if(is_separator(*t))
418 pstate = pstate->next.p;
424 template <class BidiIterator, class Allocator, class traits>
425 bool perl_matcher<BidiIterator, Allocator, traits>::match_end_line()
429 if(m_match_flags & match_single_line)
431 // we're not yet at the end so *first is always valid:
432 if(is_separator(*position))
434 if((position != backstop) || (m_match_flags & match_prev_avail))
436 // check that we're not in the middle of \r\n sequence
437 BidiIterator t(position);
439 if((*t == static_cast<char_type>('\r')) && (*position == static_cast<char_type>('\n')))
444 pstate = pstate->next.p;
448 else if((m_match_flags & match_not_eol) == 0)
450 pstate = pstate->next.p;
456 template <class BidiIterator, class Allocator, class traits>
457 bool perl_matcher<BidiIterator, Allocator, traits>::match_wild()
461 if(is_separator(*position) && ((match_any_mask & static_cast<const re_dot*>(pstate)->mask) == 0))
463 if((*position == char_type(0)) && (m_match_flags & match_not_dot_null))
465 pstate = pstate->next.p;
470 template <class BidiIterator, class Allocator, class traits>
471 bool perl_matcher<BidiIterator, Allocator, traits>::match_word_boundary()
473 bool b; // indcates whether next character is a word character
476 // prev and this character must be opposites:
477 b = traits_inst.isctype(*position, m_word_mask);
481 if (m_match_flags & match_not_eow)
485 if((position == backstop) && ((m_match_flags & match_prev_avail) == 0))
487 if(m_match_flags & match_not_bow)
495 b ^= traits_inst.isctype(*position, m_word_mask);
500 pstate = pstate->next.p;
503 return false; // no match if we get to here...
506 template <class BidiIterator, class Allocator, class traits>
507 bool perl_matcher<BidiIterator, Allocator, traits>::match_within_word()
511 // both prev and this character must be m_word_mask:
512 bool prev = traits_inst.isctype(*position, m_word_mask);
515 if((position == backstop) && ((m_match_flags & match_prev_avail) == 0))
520 b = traits_inst.isctype(*position, m_word_mask);
525 pstate = pstate->next.p;
532 template <class BidiIterator, class Allocator, class traits>
533 bool perl_matcher<BidiIterator, Allocator, traits>::match_word_start()
536 return false; // can't be starting a word if we're already at the end of input
537 if(!traits_inst.isctype(*position, m_word_mask))
538 return false; // next character isn't a word character
539 if((position == backstop) && ((m_match_flags & match_prev_avail) == 0))
541 if(m_match_flags & match_not_bow)
542 return false; // no previous input
546 // otherwise inside buffer:
547 BidiIterator t(position);
549 if(traits_inst.isctype(*t, m_word_mask))
550 return false; // previous character not non-word
552 // OK we have a match:
553 pstate = pstate->next.p;
557 template <class BidiIterator, class Allocator, class traits>
558 bool perl_matcher<BidiIterator, Allocator, traits>::match_word_end()
560 if((position == backstop) && ((m_match_flags & match_prev_avail) == 0))
561 return false; // start of buffer can't be end of word
562 BidiIterator t(position);
564 if(traits_inst.isctype(*t, m_word_mask) == false)
565 return false; // previous character wasn't a word character
569 if(m_match_flags & match_not_eow)
570 return false; // end of buffer but not end of word
574 // otherwise inside buffer:
575 if(traits_inst.isctype(*position, m_word_mask))
576 return false; // next character is a word character
578 pstate = pstate->next.p;
579 return true; // if we fall through to here then we've succeeded
582 template <class BidiIterator, class Allocator, class traits>
583 bool perl_matcher<BidiIterator, Allocator, traits>::match_buffer_start()
585 if((position != backstop) || (m_match_flags & match_not_bob))
588 pstate = pstate->next.p;
592 template <class BidiIterator, class Allocator, class traits>
593 bool perl_matcher<BidiIterator, Allocator, traits>::match_buffer_end()
595 if((position != last) || (m_match_flags & match_not_eob))
598 pstate = pstate->next.p;
602 template <class BidiIterator, class Allocator, class traits>
603 bool perl_matcher<BidiIterator, Allocator, traits>::match_backref()
606 // Compare with what we previously matched.
607 // Note that this succeeds if the backref did not partisipate
608 // in the match, this is in line with ECMAScript, but not Perl
611 int index = static_cast<const re_brace*>(pstate)->index;
614 named_subexpressions::range_type r = re.get_data().equal_range(index);
615 BOOST_ASSERT(r.first != r.second);
618 index = r.first->index;
620 }while((r.first != r.second) && ((*m_presult)[index].matched != true));
623 if((m_match_flags & match_perl) && !(*m_presult)[index].matched)
626 BidiIterator i = (*m_presult)[index].first;
627 BidiIterator j = (*m_presult)[index].second;
630 if((position == last) || (traits_inst.translate(*position, icase) != traits_inst.translate(*i, icase)))
635 pstate = pstate->next.p;
639 template <class BidiIterator, class Allocator, class traits>
640 bool perl_matcher<BidiIterator, Allocator, traits>::match_long_set()
642 typedef typename traits::char_class_type char_class_type;
643 // let the traits class do the work:
646 BidiIterator t = re_is_set_member(position, last, static_cast<const re_set_long<char_class_type>*>(pstate), re.get_data(), icase);
649 pstate = pstate->next.p;
656 template <class BidiIterator, class Allocator, class traits>
657 bool perl_matcher<BidiIterator, Allocator, traits>::match_set()
661 if(static_cast<const re_set*>(pstate)->_map[static_cast<unsigned char>(traits_inst.translate(*position, icase))])
663 pstate = pstate->next.p;
670 template <class BidiIterator, class Allocator, class traits>
671 bool perl_matcher<BidiIterator, Allocator, traits>::match_jump()
673 pstate = static_cast<const re_jump*>(pstate)->alt.p;
677 template <class BidiIterator, class Allocator, class traits>
678 bool perl_matcher<BidiIterator, Allocator, traits>::match_combining()
682 if(is_combining(traits_inst.translate(*position, icase)))
685 while((position != last) && is_combining(traits_inst.translate(*position, icase)))
687 pstate = pstate->next.p;
691 template <class BidiIterator, class Allocator, class traits>
692 bool perl_matcher<BidiIterator, Allocator, traits>::match_soft_buffer_end()
694 if(m_match_flags & match_not_eob)
696 BidiIterator p(position);
697 while((p != last) && is_separator(traits_inst.translate(*p, icase)))++p;
700 pstate = pstate->next.p;
704 template <class BidiIterator, class Allocator, class traits>
705 bool perl_matcher<BidiIterator, Allocator, traits>::match_restart_continue()
707 if(position == search_base)
709 pstate = pstate->next.p;
715 template <class BidiIterator, class Allocator, class traits>
716 bool perl_matcher<BidiIterator, Allocator, traits>::match_backstep()
719 #pragma warning(push)
720 #pragma warning(disable:4127)
722 if( ::boost::is_random_access_iterator<BidiIterator>::value)
724 std::ptrdiff_t maxlen = ::boost::BOOST_REGEX_DETAIL_NS::distance(backstop, position);
725 if(maxlen < static_cast<const re_brace*>(pstate)->index)
727 std::advance(position, -static_cast<const re_brace*>(pstate)->index);
731 int c = static_cast<const re_brace*>(pstate)->index;
734 if(position == backstop)
739 pstate = pstate->next.p;
746 template <class BidiIterator, class Allocator, class traits>
747 inline bool perl_matcher<BidiIterator, Allocator, traits>::match_assert_backref()
749 // return true if marked sub-expression N has been matched:
750 int index = static_cast<const re_brace*>(pstate)->index;
754 // Magic value for a (DEFINE) block:
759 // Have we matched subexpression "index"?
760 // Check if index is a hash value:
763 named_subexpressions::range_type r = re.get_data().equal_range(index);
764 while(r.first != r.second)
766 if((*m_presult)[r.first->index].matched)
776 result = (*m_presult)[index].matched;
778 pstate = pstate->next.p;
782 // Have we recursed into subexpression "index"?
783 // If index == 0 then check for any recursion at all, otherwise for recursion to -index-1.
784 int idx = -(index+1);
787 named_subexpressions::range_type r = re.get_data().equal_range(idx);
788 int stack_index = recursion_stack.empty() ? -1 : recursion_stack.back().idx;
789 while(r.first != r.second)
791 result |= (stack_index == r.first->index);
798 result = !recursion_stack.empty() && ((recursion_stack.back().idx == idx) || (index == 0));
800 pstate = pstate->next.p;
805 template <class BidiIterator, class Allocator, class traits>
806 bool perl_matcher<BidiIterator, Allocator, traits>::match_fail()
808 // Just force a backtrack:
812 template <class BidiIterator, class Allocator, class traits>
813 bool perl_matcher<BidiIterator, Allocator, traits>::match_accept()
815 if(!recursion_stack.empty())
817 return skip_until_paren(recursion_stack.back().idx);
821 return skip_until_paren(INT_MAX);
825 template <class BidiIterator, class Allocator, class traits>
826 bool perl_matcher<BidiIterator, Allocator, traits>::find_restart_any()
829 #pragma warning(push)
830 #pragma warning(disable:4127)
832 const unsigned char* _map = re.get_map();
835 // skip everything we can't match:
836 while((position != last) && !can_start(*position, _map, (unsigned char)mask_any) )
840 // run out of characters, try a null match if possible:
842 return match_prefix();
845 // now try and obtain a match:
858 template <class BidiIterator, class Allocator, class traits>
859 bool perl_matcher<BidiIterator, Allocator, traits>::find_restart_word()
862 #pragma warning(push)
863 #pragma warning(disable:4127)
865 // do search optimised for word starts:
866 const unsigned char* _map = re.get_map();
867 if((m_match_flags & match_prev_avail) || (position != base))
869 else if(match_prefix())
873 while((position != last) && traits_inst.isctype(*position, m_word_mask))
875 while((position != last) && !traits_inst.isctype(*position, m_word_mask))
880 if(can_start(*position, _map, (unsigned char)mask_any) )
894 template <class BidiIterator, class Allocator, class traits>
895 bool perl_matcher<BidiIterator, Allocator, traits>::find_restart_line()
897 // do search optimised for line starts:
898 const unsigned char* _map = re.get_map();
901 while(position != last)
903 while((position != last) && !is_separator(*position))
910 if(re.can_be_null() && match_prefix())
915 if( can_start(*position, _map, (unsigned char)mask_any) )
927 template <class BidiIterator, class Allocator, class traits>
928 bool perl_matcher<BidiIterator, Allocator, traits>::find_restart_buf()
930 if((position == base) && ((m_match_flags & match_not_bob) == 0))
931 return match_prefix();
935 template <class BidiIterator, class Allocator, class traits>
936 bool perl_matcher<BidiIterator, Allocator, traits>::find_restart_lit()
940 return false; // can't possibly match if we're at the end already
942 unsigned type = (m_match_flags & match_continuous) ?
943 static_cast<unsigned int>(regbase::restart_continue)
944 : static_cast<unsigned int>(re.get_restart_type());
946 const kmp_info<char_type>* info = access::get_kmp(re);
948 const char_type* x = info->pstr;
950 while (position != last)
952 while((j > -1) && (x[j] != traits_inst.translate(*position, icase)))
953 j = info->kmp_next[j];
958 if(type == regbase::restart_fixed_lit)
960 std::advance(position, -j);
962 std::advance(restart, len);
963 m_result.set_first(position);
964 m_result.set_second(restart);
971 std::advance(position, -j);
976 for(int k = 0; (restart != position) && (k < j); ++k, --restart)
977 {} // dwa 10/20/2000 - warning suppression for MWCW
981 j = 0; //we could do better than this...
986 if((m_match_flags & match_partial) && (position == last) && j)
988 // we need to check for a partial match:
990 std::advance(position, -j);
991 return match_prefix();
997 } // namespace BOOST_REGEX_DETAIL_NS
1002 # pragma warning(pop)
1009 #pragma warning(push)
1010 #pragma warning(disable: 4103)
1012 #ifdef BOOST_HAS_ABI_HEADERS
1013 # include BOOST_ABI_SUFFIX
1016 #pragma warning(pop)