diff --git a/include/boost/regex/config.hpp b/include/boost/regex/config.hpp index e05a904b..eed09caa 100644 --- a/include/boost/regex/config.hpp +++ b/include/boost/regex/config.hpp @@ -468,10 +468,9 @@ void raise_error(const traits& t, unsigned code) # ifdef BOOST_REGEX_HAS_MS_STACK_GUARD # undef BOOST_REGEX_HAS_MS_STACK_GUARD # endif -namespace boost{ namespace re_detail{ -BOOST_REGEX_DECL void* BOOST_REGEX_CALL get_mem_block(); -BOOST_REGEX_DECL void BOOST_REGEX_CALL release_mem_block(void*); -} } +# ifndef BOOST_REGEX_MAX_CACHE_BLOCKS +# define BOOST_REGEX_MAX_CACHE_BLOCKS BOOST_REGEX_MAX_BLOCKS +# endif #endif diff --git a/include/boost/regex/user.hpp b/include/boost/regex/user.hpp index 43191a7f..37f18db8 100644 --- a/include/boost/regex/user.hpp +++ b/include/boost/regex/user.hpp @@ -77,3 +77,9 @@ // used by the non-recursive algorithm. // #define BOOST_REGEX_MAX_BLOCKS 1024 +// define this if you want to set the maximum number of memory blocks +// cached by the non-recursive algorithm: Normally this is the same as +// BOOST_REGEX_MAX_BLOCKS, but can be higher if you have multiple threads +// all using boost.regex, or lower if you don't want boost.regex to cache +// memory. +// #define BOOST_REGEX_MAX_CACHE_BLOCKS 1024 diff --git a/include/boost/regex/v4/mem_block_cache.hpp b/include/boost/regex/v4/mem_block_cache.hpp index 91ed49a7..a2ca3078 100644 --- a/include/boost/regex/v4/mem_block_cache.hpp +++ b/include/boost/regex/v4/mem_block_cache.hpp @@ -16,14 +16,14 @@ * LOCATION: see http://www.boost.org for most recent version. * FILE mem_block_cache.hpp * VERSION see - * DESCRIPTION: Definitions of perl_matcher member functions that are - * specific to the non-recursive implementation. + * DESCRIPTION: memory block cache used by the non-recursive matcher. */ #ifndef BOOST_REGEX_V4_MEM_BLOCK_CACHE_HPP #define BOOST_REGEX_V4_MEM_BLOCK_CACHE_HPP #include +#include #ifdef __BORLANDC__ # pragma option push -a8 -b -Vx -Ve -pc -w-8027 @@ -39,7 +39,9 @@ struct mem_block_node struct mem_block_cache { + // this member has to be statically initialsed: mem_block_node* next; + unsigned cached_blocks; ~mem_block_cache() { @@ -52,19 +54,33 @@ struct mem_block_cache } void* get() { - if(next) +#ifdef BOOST_HAS_THREADS + re_detail::cs_guard g(*re_detail::p_re_lock); +#endif + if(next) { mem_block_node* result = next; next = next->next; + --cached_blocks; return result; } return ::operator new(BOOST_REGEX_BLOCKSIZE); } void put(void* p) { - mem_block_node* old = static_cast(p); - old->next = next; - next = old; +#ifdef BOOST_HAS_THREADS + re_detail::cs_guard g(*re_detail::p_re_lock); +#endif + if(cached_blocks >= BOOST_REGEX_MAX_CACHE_BLOCKS) + { + ::operator delete(p); + } + else + { + mem_block_node* old = static_cast(p); + old->next = next; + next = old; + } } }; diff --git a/include/boost/regex/v4/perl_matcher.hpp b/include/boost/regex/v4/perl_matcher.hpp index 758765d1..f99c740d 100644 --- a/include/boost/regex/v4/perl_matcher.hpp +++ b/include/boost/regex/v4/perl_matcher.hpp @@ -384,6 +384,7 @@ private: bool unwind_char_repeat(bool); bool unwind_short_set_repeat(bool); bool unwind_long_set_repeat(bool); + bool unwind_non_greedy_repeat(bool); void destroy_single_repeat(); void push_matched_paren(int index, const sub_match& sub); void push_recursion_stopper(); @@ -391,6 +392,7 @@ private: void push_alt(const re_syntax_base* ps); void push_repeater_count(int i, repeater_count** s); void push_single_repeat(unsigned c, const re_repeat* r, BidiIterator last_position, int id); + void push_non_greedy_repeat(const re_syntax_base* ps); // pointer to base of stack: diff --git a/include/boost/regex/v4/perl_matcher_common.hpp b/include/boost/regex/v4/perl_matcher_common.hpp index 1abb8a95..001df9bf 100644 --- a/include/boost/regex/v4/perl_matcher_common.hpp +++ b/include/boost/regex/v4/perl_matcher_common.hpp @@ -97,6 +97,7 @@ bool perl_matcher::match() #ifdef BOOST_REGEX_NON_RECURSIVE save_state_init init(&m_stack_base, &m_backup_state); used_block_count = BOOST_REGEX_MAX_BLOCKS; + try{ #endif // reset our state machine: @@ -111,6 +112,17 @@ bool perl_matcher::match() return false; return m_result[0].second == last; +#ifdef BOOST_REGEX_NON_RECURSIVE + } + catch(...) + { + // unwind all pushed states, apart from anything else this + // ensures that all the states are correctly destructed + // not just the memory freed. + while(unwind(true)){} + throw; + } +#endif #ifdef BOOST_REGEX_HAS_MS_STACK_GUARD }__except(EXCEPTION_STACK_OVERFLOW == GetExceptionCode()) { @@ -134,6 +146,7 @@ bool perl_matcher::find() #ifdef BOOST_REGEX_NON_RECURSIVE save_state_init init(&m_stack_base, &m_backup_state); used_block_count = BOOST_REGEX_MAX_BLOCKS; + try{ #endif state_count = 0; @@ -180,6 +193,17 @@ bool perl_matcher::find() matcher_proc_type proc = s_find_vtable[type]; return (this->*proc)(); +#ifdef BOOST_REGEX_NON_RECURSIVE + } + catch(...) + { + // unwind all pushed states, apart from anything else this + // ensures that all the states are correctly destructed + // not just the memory freed. + while(unwind(true)){} + throw; + } +#endif #ifdef BOOST_REGEX_HAS_MS_STACK_GUARD }__except(EXCEPTION_STACK_OVERFLOW == GetExceptionCode()) { @@ -755,6 +779,12 @@ perl_matcher::s_match_vtable[] = &perl_matcher::match_combining, &perl_matcher::match_soft_buffer_end, &perl_matcher::match_restart_continue, +#if 0 + &perl_matcher::match_rep, + &perl_matcher::match_rep, + &perl_matcher::match_rep, + &perl_matcher::match_rep, +#else #if defined(BOOST_MSVC) && (BOOST_MSVC <= 1300) &perl_matcher::match_dot_repeat_fast, #else @@ -763,7 +793,7 @@ perl_matcher::s_match_vtable[] = &perl_matcher::match_char_repeat, &perl_matcher::match_set_repeat, &perl_matcher::match_long_set_repeat, - +#endif }; template diff --git a/include/boost/regex/v4/perl_matcher_non_recursive.hpp b/include/boost/regex/v4/perl_matcher_non_recursive.hpp index 7d69c7d6..8b18300c 100644 --- a/include/boost/regex/v4/perl_matcher_non_recursive.hpp +++ b/include/boost/regex/v4/perl_matcher_non_recursive.hpp @@ -54,7 +54,8 @@ enum saved_state_type saved_state_rep_fast_dot = 9, saved_state_rep_char = 10, saved_state_rep_short_set = 11, - saved_state_rep_long_set = 12 + saved_state_rep_long_set = 12, + saved_state_non_greedy_long_repeat = 13 }; struct saved_state @@ -134,8 +135,6 @@ struct saved_single_repeat : public saved_state template bool perl_matcher::match_all_states() { - if(state_count > max_state_count) - raise_error(traits_inst, REG_ESPACE); push_recursion_stopper(); do{ while(pstate) @@ -144,6 +143,8 @@ bool perl_matcher::match_all_states ++state_count; if(!(this->*proc)()) { + if(state_count > max_state_count) + raise_error(traits_inst, REG_ESPACE); if((m_match_flags & match_partial) && (position == last)) m_has_partial_match = true; if(false == unwind(false)) @@ -235,6 +236,21 @@ inline void perl_matcher::push_alt( m_backup_state = pmp; } +template +inline void perl_matcher::push_non_greedy_repeat(const re_syntax_base* ps) +{ + saved_position* pmp = static_cast*>(m_backup_state); + --pmp; + if(pmp < m_stack_base) + { + extend_stack(); + pmp = static_cast*>(m_backup_state); + --pmp; + } + new (pmp)saved_position(ps, position, saved_state_non_greedy_long_repeat); + m_backup_state = pmp; +} + template inline void perl_matcher::push_repeater_count(int i, repeater_count** s) { @@ -408,19 +424,16 @@ bool perl_matcher::match_rep() if(take_second) { // store position in case we fail: - BidiIterator pos = position; + push_non_greedy_repeat(rep->next.p); pstate = rep->alt.p; - if(match_all_states()) - return true; - // failed alternative, reset posistion and fall through for repeat: - position = pos; + return true; } if((next_count->get_count() < rep->max) && take_first) { // increase the counter: ++(*next_count); pstate = rep->next.p; - return match_all_states(); + return true; } } return false; @@ -1114,6 +1127,21 @@ bool perl_matcher::unwind_long_set_ return false; } +template +bool perl_matcher::unwind_non_greedy_repeat(bool r) +{ + saved_position* pmp = static_cast*>(m_backup_state); + if(!r) + { + position = pmp->position; + pstate = pmp->pstate; + ++(*next_count); + } + destroy(pmp++); + m_backup_state = pmp; + return r; +} + template typename perl_matcher::unwind_proc_type const perl_matcher::s_unwind_table[] = @@ -1131,6 +1159,7 @@ perl_matcher::s_unwind_table[] = &perl_matcher::unwind_char_repeat, &perl_matcher::unwind_short_set_repeat, &perl_matcher::unwind_long_set_repeat, + &perl_matcher::unwind_non_greedy_repeat, }; }