That now seems to work nicely with a bidirectional iterator.
I'll report back if I see any further issues, but I'm pretty sure
the remaining problems I'm having are now in my code.
In case you didn't notice my second message: there are some serious problems
with that as a proposed patch (it causes regressions in the test suite).
I've had to do a complete rewrite of that function to get things working
correctly - this also addresses another issue - if the first match found is
near the end of the sequence, then all the distances measured are relative
to the start of the sequence, and that could be a big hit for non-random
access iterators. In this case the workaround is to measure distances from
the start of the first match found (because no match further left than this
can be found by the matcher anyway). I'm still in the process of bolstering
up the test cases to check all this, but all being well the version below
really is the last one! Use this if you're in a rush, otherwise hold off
for a few days while I finish off the new test cases...
John.
template
void BOOST_REGEX_CALL match_results::maybe_assign(const match_results& m)
{
const_iterator p1, p2;
p1 = begin();
p2 = m.begin();
//
// Distances are measured from the start of *this* match, unless this isn't
// a valid match in which case we use the start of the whole sequence. Note
that
// no subsequent match-candidate can ever be to the left of the first match
found.
// This ensures that when we are using bidirectional iterators, that
distances
// measured are as short as possible, and therefore as efficient as possible
// to compute. Finally note that we don't use the "matched" data member to
test
// whether a sub-expression is a valid match, because partial matches set
this
// to false for sub-expression 0.
//
BidiIterator end = this->suffix().second;
BidiIterator base = (p1->first == end) ? this->prefix().first :
(*this)[0].first;
difference_type len1 = 0;
difference_type len2 = 0;
difference_type base1 = 0;
difference_type base2 = 0;
std::size_t i;
for(i = 0; i < size(); ++i, ++p1, ++p2)
{
//
// Leftmost takes priority over longest; handle special cases
// where distances need not be computed first (an optimisation
// for bidirectional iterators: ensure that we don't accidently
// compute the length of the whole sequence, as this can be really
// expensive).
//
if(p1->first == end)
{
if(p2->first != end)
{
// p2 must be better than p1, and no need to calculate
// actual distances:
base1 = 1;
base2 = 0;
break;
}
else
{
// *p1 and *p2 are either unmatched or match end-of sequence,
// either way no need to calculate distances:
if((p1->matched == false) && (p2->matched == true))
break;
if((p1->matched == true) && (p2->matched == false))
return;
continue;
}
}
else if(p2->first == end)
{
// p1 better than p2, and no need to calculate distances:
return;
}
base1 = ::boost::re_detail::distance(base, p1->first);
base2 = ::boost::re_detail::distance(base, p2->first);
BOOST_ASSERT(base1 >= 0);
BOOST_ASSERT(base2 >= 0);
if(base1 < base2) return;
if(base2 < base1) break;
len1 = ::boost::re_detail::distance((BidiIterator)p1->first,
(BidiIterator)p1->second);
len2 = ::boost::re_detail::distance((BidiIterator)p2->first,
(BidiIterator)p2->second);
BOOST_ASSERT(len1 >= 0);
BOOST_ASSERT(len2 >= 0);
if((len1 != len2) || ((p1->matched == false) && (p2->matched == true)))
break;
if((p1->matched == true) && (p2->matched == false))
return;
}
if(i == size())
return;
if(base2 < base1)
*this = m;
else if((len2 > len1) || ((p1->matched == false) && (p2->matched == true)) )
*this = m;
}