Bug 2679853: flex_string cannot insert from current string.
git-svn-id: svn://svn.code.sf.net/p/loki-lib/code/trunk@1005 7ec92016-0320-0410-acc4-a06ded1c099a
This commit is contained in:
parent
7b99eeed7b
commit
208bbae624
1 changed files with 69 additions and 27 deletions
|
@ -388,8 +388,7 @@ public:
|
||||||
{
|
{
|
||||||
Invariant checker(*this);
|
Invariant checker(*this);
|
||||||
(void) checker;
|
(void) checker;
|
||||||
static std::less_equal<const value_type*> le;
|
if (IsAliasedRange(s, s + n))
|
||||||
if (le(&*begin(), s) && le(s, &*end())) // aliasing
|
|
||||||
{
|
{
|
||||||
const size_type offset = s - &*begin();
|
const size_type offset = s - &*begin();
|
||||||
Storage::reserve(size() + n);
|
Storage::reserve(size() + n);
|
||||||
|
@ -501,6 +500,46 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
// Care must be taken when dereferencing some iterator types.
|
||||||
|
//
|
||||||
|
// Users can implement this function in their namespace if their storage uses a special iterator type,
|
||||||
|
// the function will be found through ADL.
|
||||||
|
template<class Iterator>
|
||||||
|
const typename std::iterator_traits<Iterator>::value_type * DereferenceValidIterator(Iterator it) const
|
||||||
|
{
|
||||||
|
return &*it;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Care must be taken when dereferencing a reverse iterators, hence this special case.
|
||||||
|
// This isn't in the std namespace so as not to pollute it or create name clashes.
|
||||||
|
template<typename Iterator>
|
||||||
|
const typename std::iterator_traits<Iterator>::value_type * DereferenceValidIterator(
|
||||||
|
std::reverse_iterator<Iterator> it) const
|
||||||
|
{
|
||||||
|
return &*--it;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine if the range aliases the current string.
|
||||||
|
//
|
||||||
|
// This method cannot be const because calling begin/end on copy-on-write implementations must have side effects.
|
||||||
|
// A const version wouldn't make the string unique through this call.
|
||||||
|
template<class Iterator>
|
||||||
|
bool IsAliasedRange(Iterator beginIterator, Iterator endIterator)
|
||||||
|
{
|
||||||
|
if(!empty() && beginIterator != endIterator)
|
||||||
|
{
|
||||||
|
typedef const typename std::iterator_traits<Iterator>::value_type * pointer;
|
||||||
|
pointer myBegin(&*begin());
|
||||||
|
pointer myEnd(&*begin() + size());
|
||||||
|
pointer rangeBegin(DereferenceValidIterator(beginIterator));
|
||||||
|
const std::less_equal<pointer> less_equal = std::less_equal<pointer>();
|
||||||
|
if(less_equal(myBegin, rangeBegin) && less_equal(rangeBegin, myEnd))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
template <int i> class Selector {};
|
template <int i> class Selector {};
|
||||||
|
|
||||||
flex_string& InsertImplDiscr(iterator p,
|
flex_string& InsertImplDiscr(iterator p,
|
||||||
|
@ -508,7 +547,7 @@ private:
|
||||||
{
|
{
|
||||||
Invariant checker(*this);
|
Invariant checker(*this);
|
||||||
(void) checker;
|
(void) checker;
|
||||||
assert(p >= begin() && p <= end());
|
assert(begin() <= p && p <= end());
|
||||||
if (capacity() - size() < n)
|
if (capacity() - size() < n)
|
||||||
{
|
{
|
||||||
const size_type sz = p - begin();
|
const size_type sz = p - begin();
|
||||||
|
@ -549,10 +588,24 @@ private:
|
||||||
void InsertImpl(iterator i,
|
void InsertImpl(iterator i,
|
||||||
FwdIterator s1, FwdIterator s2, std::forward_iterator_tag)
|
FwdIterator s1, FwdIterator s2, std::forward_iterator_tag)
|
||||||
{
|
{
|
||||||
// TODO: there is a bug in this method when the range to insert is inside the current range. See bug #2679853.
|
if(s1 == s2)
|
||||||
|
{
|
||||||
|
// Insert an empty range.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(IsAliasedRange(s1, s2))
|
||||||
|
{
|
||||||
|
// The source range is contained in the current string, copy it and recurse.
|
||||||
|
const flex_string temporary(s1, s2);
|
||||||
|
InsertImpl(i, temporary.begin(), temporary.end(),
|
||||||
|
typename std::iterator_traits<FwdIterator>::iterator_category());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Invariant checker(*this);
|
Invariant checker(*this);
|
||||||
(void) checker;
|
(void) checker;
|
||||||
|
|
||||||
const size_type pos = i - begin();
|
const size_type pos = i - begin();
|
||||||
const typename std::iterator_traits<FwdIterator>::difference_type n2 =
|
const typename std::iterator_traits<FwdIterator>::difference_type n2 =
|
||||||
std::distance(s1, s2);
|
std::distance(s1, s2);
|
||||||
|
@ -564,10 +617,8 @@ private:
|
||||||
capacity() - size();
|
capacity() - size();
|
||||||
if (maxn2 < n2)
|
if (maxn2 < n2)
|
||||||
{
|
{
|
||||||
// realloc the string
|
// Reallocate the string.
|
||||||
static const std::less_equal<const value_type*> le =
|
assert(!IsAliasedRange(s1, s2));
|
||||||
std::less_equal<const value_type*>();
|
|
||||||
assert(!(le(&*begin(), &*s1) && le(&*s1, &*end())));
|
|
||||||
reserve(size() + n2);
|
reserve(size() + n2);
|
||||||
i = begin() + pos;
|
i = begin() + pos;
|
||||||
}
|
}
|
||||||
|
@ -670,8 +721,7 @@ public:
|
||||||
return replace(b, b + n1, s1, s1 + n2);
|
return replace(b, b + n1, s1, s1 + n2);
|
||||||
using namespace flex_string_details;
|
using namespace flex_string_details;
|
||||||
const int delta = int(n2 - n1);
|
const int delta = int(n2 - n1);
|
||||||
static const std::less_equal<const value_type*> le;
|
const bool aliased = IsAliasedRange(s1, s1 + n2);
|
||||||
const bool aliased = le(&*begin(), s1) && le(s1, &*end());
|
|
||||||
|
|
||||||
// From here on we're dealing with an aliased replace
|
// From here on we're dealing with an aliased replace
|
||||||
if (delta <= 0)
|
if (delta <= 0)
|
||||||
|
@ -811,33 +861,25 @@ private:
|
||||||
std::distance(s1, s2);
|
std::distance(s1, s2);
|
||||||
assert(n2 >= 0);
|
assert(n2 >= 0);
|
||||||
|
|
||||||
// Make sure the replacement isn't empty.
|
if (IsAliasedRange(s1, s2))
|
||||||
if(0 != n2)
|
|
||||||
{
|
{
|
||||||
// Handle aliased replace
|
// Aliased replace, copy to new string.
|
||||||
static const std::less_equal<const value_type*> le =
|
flex_string temporary;
|
||||||
std::less_equal<const value_type*>();
|
temporary.reserve(size() - n1 + n2);
|
||||||
const bool aliased = le(&*begin(), &*s1) && le(&*s1, &*end());
|
temporary.append(begin(), i1).append(s1, s2).append(i2, end());
|
||||||
if (aliased /* && capacity() < size() - n1 + n2 */)
|
swap(temporary);
|
||||||
{
|
return;
|
||||||
// Aliased replace, copy to new string
|
|
||||||
flex_string temp;
|
|
||||||
temp.reserve(size() - n1 + n2);
|
|
||||||
temp.append(begin(), i1).append(s1, s2).append(i2, end());
|
|
||||||
swap(temp);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (n1 > n2)
|
if (n1 > n2)
|
||||||
{
|
{
|
||||||
// shrinks
|
// Shrinks.
|
||||||
std::copy(s1, s2, i1);
|
std::copy(s1, s2, i1);
|
||||||
erase(i1 + n2, i2);
|
erase(i1 + n2, i2);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// grows
|
// Grows.
|
||||||
flex_string_details::copy_n(s1, n1, i1);
|
flex_string_details::copy_n(s1, n1, i1);
|
||||||
std::advance(s1, n1);
|
std::advance(s1, n1);
|
||||||
insert(i2, s1, s2);
|
insert(i2, s1, s2);
|
||||||
|
|
Loading…
Add table
Reference in a new issue