Merge branch 'vector-enhancements'
Make wxVector<> more compatible with std::vector<>.
This commit is contained in:
@@ -113,6 +113,34 @@ struct wxVectorMemOpsGeneric
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// We need to distinguish integers from iterators in assign() overloads and the
|
||||||
|
// simplest way to do it would be by using std::iterator_traits<>, however this
|
||||||
|
// might break existing code using custom iterator classes but not specializing
|
||||||
|
// iterator_traits<> for them, so we approach the problem from the other end
|
||||||
|
// and use our own traits that we specialize for all integer types.
|
||||||
|
|
||||||
|
struct IsIntType {};
|
||||||
|
struct IsNotIntType {};
|
||||||
|
|
||||||
|
template <typename T> struct IsInt : IsNotIntType {};
|
||||||
|
|
||||||
|
#define WX_DECLARE_TYPE_IS_INT(type) \
|
||||||
|
template <> struct IsInt<type> : IsIntType {}
|
||||||
|
|
||||||
|
WX_DECLARE_TYPE_IS_INT(unsigned char);
|
||||||
|
WX_DECLARE_TYPE_IS_INT(signed char);
|
||||||
|
WX_DECLARE_TYPE_IS_INT(unsigned short int);
|
||||||
|
WX_DECLARE_TYPE_IS_INT(signed short int);
|
||||||
|
WX_DECLARE_TYPE_IS_INT(unsigned int);
|
||||||
|
WX_DECLARE_TYPE_IS_INT(signed int);
|
||||||
|
WX_DECLARE_TYPE_IS_INT(unsigned long int);
|
||||||
|
WX_DECLARE_TYPE_IS_INT(signed long int);
|
||||||
|
#ifdef wxLongLong_t
|
||||||
|
WX_DECLARE_TYPE_IS_INT(wxLongLong_t);
|
||||||
|
WX_DECLARE_TYPE_IS_INT(wxULongLong_t);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#undef WX_DECLARE_TYPE_IS_INT
|
||||||
|
|
||||||
} // namespace wxPrivate
|
} // namespace wxPrivate
|
||||||
|
|
||||||
@@ -170,6 +198,8 @@ public:
|
|||||||
{ return reverse_iterator(m_ptr + n); }
|
{ return reverse_iterator(m_ptr + n); }
|
||||||
reverse_iterator& operator-=(difference_type n)
|
reverse_iterator& operator-=(difference_type n)
|
||||||
{ m_ptr += n; return *this; }
|
{ m_ptr += n; return *this; }
|
||||||
|
difference_type operator-(const reverse_iterator& it) const
|
||||||
|
{ return it.m_ptr - m_ptr; }
|
||||||
|
|
||||||
reference operator[](difference_type n) const
|
reference operator[](difference_type n) const
|
||||||
{ return *(*this + n); }
|
{ return *(*this + n); }
|
||||||
@@ -215,6 +245,8 @@ public:
|
|||||||
{ return const_reverse_iterator(m_ptr + n); }
|
{ return const_reverse_iterator(m_ptr + n); }
|
||||||
const_reverse_iterator& operator-=(difference_type n)
|
const_reverse_iterator& operator-=(difference_type n)
|
||||||
{ m_ptr += n; return *this; }
|
{ m_ptr += n; return *this; }
|
||||||
|
difference_type operator-(const const_reverse_iterator& it) const
|
||||||
|
{ return it.m_ptr - m_ptr; }
|
||||||
|
|
||||||
const_reference operator[](difference_type n) const
|
const_reference operator[](difference_type n) const
|
||||||
{ return *(*this + n); }
|
{ return *(*this + n); }
|
||||||
@@ -265,23 +297,13 @@ public:
|
|||||||
|
|
||||||
void assign(size_type p_size, const value_type& v)
|
void assign(size_type p_size, const value_type& v)
|
||||||
{
|
{
|
||||||
clear();
|
AssignFromValue(p_size, v);
|
||||||
reserve(p_size);
|
|
||||||
for ( size_t n = 0; n < p_size; n++ )
|
|
||||||
push_back(v);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class InputIterator>
|
template <typename InputIterator>
|
||||||
void assign(InputIterator first, InputIterator last)
|
void assign(InputIterator first, InputIterator last)
|
||||||
{
|
{
|
||||||
clear();
|
AssignDispatch(first, last, typename wxPrivate::IsInt<InputIterator>());
|
||||||
|
|
||||||
// Notice that it would be nice to call reserve() here but we can't do
|
|
||||||
// it for arbitrary input iterators, we should have a dispatch on
|
|
||||||
// iterator type and call it if possible.
|
|
||||||
|
|
||||||
for ( InputIterator it = first; it != last; ++it )
|
|
||||||
push_back(*it);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void swap(wxVector& v)
|
void swap(wxVector& v)
|
||||||
@@ -351,6 +373,12 @@ public:
|
|||||||
return m_capacity;
|
return m_capacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void shrink_to_fit()
|
||||||
|
{
|
||||||
|
m_values = Ops::Realloc(m_values, m_size, m_size);
|
||||||
|
m_capacity = m_size;
|
||||||
|
}
|
||||||
|
|
||||||
bool empty() const
|
bool empty() const
|
||||||
{
|
{
|
||||||
return size() == 0;
|
return size() == 0;
|
||||||
@@ -366,6 +394,25 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool operator==(const wxVector& vb) const
|
||||||
|
{
|
||||||
|
if ( vb.m_size != m_size )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for ( size_type i = 0; i < m_size; i++ )
|
||||||
|
{
|
||||||
|
if ( vb.m_values[i] != m_values[i] )
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const wxVector& vb) const
|
||||||
|
{
|
||||||
|
return !(*this == vb);
|
||||||
|
}
|
||||||
|
|
||||||
void push_back(const value_type& v)
|
void push_back(const value_type& v)
|
||||||
{
|
{
|
||||||
reserve(size() + 1);
|
reserve(size() + 1);
|
||||||
@@ -417,14 +464,14 @@ public:
|
|||||||
const_reverse_iterator rbegin() const { return const_reverse_iterator(end() - 1); }
|
const_reverse_iterator rbegin() const { return const_reverse_iterator(end() - 1); }
|
||||||
const_reverse_iterator rend() const { return const_reverse_iterator(begin() - 1); }
|
const_reverse_iterator rend() const { return const_reverse_iterator(begin() - 1); }
|
||||||
|
|
||||||
iterator insert(iterator it, const value_type& v = value_type())
|
iterator insert(iterator it, size_type count, const value_type& v)
|
||||||
{
|
{
|
||||||
// NB: this must be done before reserve(), because reserve()
|
// NB: this must be done before reserve(), because reserve()
|
||||||
// invalidates iterators!
|
// invalidates iterators!
|
||||||
const size_t idx = it - begin();
|
const size_t idx = it - begin();
|
||||||
const size_t after = end() - it;
|
const size_t after = end() - it;
|
||||||
|
|
||||||
reserve(size() + 1);
|
reserve(size() + count);
|
||||||
|
|
||||||
// the place where the new element is going to be inserted
|
// the place where the new element is going to be inserted
|
||||||
value_type * const place = m_values + idx;
|
value_type * const place = m_values + idx;
|
||||||
@@ -432,27 +479,33 @@ public:
|
|||||||
// unless we're inserting at the end, move following elements out of
|
// unless we're inserting at the end, move following elements out of
|
||||||
// the way:
|
// the way:
|
||||||
if ( after > 0 )
|
if ( after > 0 )
|
||||||
Ops::MemmoveForward(place + 1, place, after);
|
Ops::MemmoveForward(place + count, place, after);
|
||||||
|
|
||||||
// if the ctor called below throws an exception, we need to move all
|
// if the ctor called below throws an exception, we need to move all
|
||||||
// the elements back to their original positions in m_values
|
// the elements back to their original positions in m_values
|
||||||
wxScopeGuard moveBack = wxMakeGuard(
|
wxScopeGuard moveBack = wxMakeGuard(
|
||||||
Ops::MemmoveBackward, place, place + 1, after);
|
Ops::MemmoveBackward, place, place + count, after);
|
||||||
if ( !after )
|
if ( !after )
|
||||||
moveBack.Dismiss();
|
moveBack.Dismiss();
|
||||||
|
|
||||||
// use placement new to initialize new object in preallocated place in
|
// use placement new to initialize new object in preallocated place in
|
||||||
// m_values and store 'v' in it:
|
// m_values and store 'v' in it:
|
||||||
::new(place) value_type(v);
|
for ( size_type i = 0; i < count; i++ )
|
||||||
|
::new(place + i) value_type(v);
|
||||||
|
|
||||||
// now that we did successfully add the new element, increment the size
|
// now that we did successfully add the new element, increment the size
|
||||||
// and disable moving the items back
|
// and disable moving the items back
|
||||||
moveBack.Dismiss();
|
moveBack.Dismiss();
|
||||||
m_size++;
|
m_size += count;
|
||||||
|
|
||||||
return begin() + idx;
|
return begin() + idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iterator insert(iterator it, const value_type& v = value_type())
|
||||||
|
{
|
||||||
|
return insert(it, 1, v);
|
||||||
|
}
|
||||||
|
|
||||||
iterator erase(iterator it)
|
iterator erase(iterator it)
|
||||||
{
|
{
|
||||||
return erase(it, it + 1);
|
return erase(it, it + 1);
|
||||||
@@ -513,6 +566,36 @@ private:
|
|||||||
push_back(v);
|
push_back(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AssignFromValue(size_type p_size, const value_type& v)
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
reserve(p_size);
|
||||||
|
for ( size_t n = 0; n < p_size; n++ )
|
||||||
|
push_back(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputIterator>
|
||||||
|
void AssignDispatch(InputIterator first, InputIterator last,
|
||||||
|
wxPrivate::IsIntType)
|
||||||
|
{
|
||||||
|
AssignFromValue(static_cast<size_type>(first),
|
||||||
|
static_cast<const value_type&>(last));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputIterator>
|
||||||
|
void AssignDispatch(InputIterator first, InputIterator last,
|
||||||
|
wxPrivate::IsNotIntType)
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
|
||||||
|
// Notice that it would be nice to call reserve() here but we can't do
|
||||||
|
// it for arbitrary input iterators, we should have a dispatch on
|
||||||
|
// iterator type and call it if possible.
|
||||||
|
|
||||||
|
for ( InputIterator it = first; it != last; ++it )
|
||||||
|
push_back(*it);
|
||||||
|
}
|
||||||
|
|
||||||
size_type m_size,
|
size_type m_size,
|
||||||
m_capacity;
|
m_capacity;
|
||||||
value_type *m_values;
|
value_type *m_values;
|
||||||
|
@@ -194,11 +194,34 @@ public:
|
|||||||
*/
|
*/
|
||||||
iterator insert(iterator it, const value_type& v = value_type());
|
iterator insert(iterator it, const value_type& v = value_type());
|
||||||
|
|
||||||
|
/**
|
||||||
|
Insert the given number of copies of @a v at the given position.
|
||||||
|
|
||||||
|
@return Iterator for the first inserted item.
|
||||||
|
|
||||||
|
@since 3.1.1
|
||||||
|
*/
|
||||||
|
iterator insert(iterator it, size_type count, const value_type& v);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Assignment operator.
|
Assignment operator.
|
||||||
*/
|
*/
|
||||||
wxVector& operator=(const wxVector& vb);
|
wxVector& operator=(const wxVector& vb);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Equality operator.
|
||||||
|
|
||||||
|
@since 3.1.1
|
||||||
|
*/
|
||||||
|
wxVector& operator==(const wxVector& vb) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Inequality operator.
|
||||||
|
|
||||||
|
@since 3.1.1
|
||||||
|
*/
|
||||||
|
wxVector& operator!=(const wxVector& vb) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Returns item at position @a idx.
|
Returns item at position @a idx.
|
||||||
*/
|
*/
|
||||||
@@ -239,6 +262,18 @@ public:
|
|||||||
void resize(size_type n, const value_type& v);
|
void resize(size_type n, const value_type& v);
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Free unused memory allocated by the vector.
|
||||||
|
|
||||||
|
Reduces the memory used by the vector to the bare minimum required to
|
||||||
|
hold its current number of elements, possibly 0.
|
||||||
|
|
||||||
|
After calling this method, capacity() returns the same as size().
|
||||||
|
|
||||||
|
@since 3.1.1
|
||||||
|
*/
|
||||||
|
void shrink_to_fit();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Returns the size of the vector.
|
Returns the size of the vector.
|
||||||
*/
|
*/
|
||||||
|
@@ -162,6 +162,16 @@ void VectorsTestCase::Insert()
|
|||||||
CPPUNIT_ASSERT( v[1] == 'a' );
|
CPPUNIT_ASSERT( v[1] == 'a' );
|
||||||
CPPUNIT_ASSERT( v[2] == 'X' );
|
CPPUNIT_ASSERT( v[2] == 'X' );
|
||||||
CPPUNIT_ASSERT( v[3] == 'b' );
|
CPPUNIT_ASSERT( v[3] == 'b' );
|
||||||
|
|
||||||
|
v.insert(v.begin() + 3, 3, 'Z');
|
||||||
|
REQUIRE( v.size() == 7 );
|
||||||
|
CHECK( v[0] == '0' );
|
||||||
|
CHECK( v[1] == 'a' );
|
||||||
|
CHECK( v[2] == 'X' );
|
||||||
|
CHECK( v[3] == 'Z' );
|
||||||
|
CHECK( v[4] == 'Z' );
|
||||||
|
CHECK( v[5] == 'Z' );
|
||||||
|
CHECK( v[6] == 'b' );
|
||||||
}
|
}
|
||||||
|
|
||||||
void VectorsTestCase::Erase()
|
void VectorsTestCase::Erase()
|
||||||
@@ -314,3 +324,64 @@ void VectorsTestCase::Sort()
|
|||||||
CPPUNIT_ASSERT( v[idx-1] <= v[idx] );
|
CPPUNIT_ASSERT( v[idx-1] <= v[idx] );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("wxVector::operator==", "[vector][compare]")
|
||||||
|
{
|
||||||
|
wxVector<wxString> v1, v2;
|
||||||
|
CHECK( v1 == v2 );
|
||||||
|
CHECK( !(v1 != v2) );
|
||||||
|
|
||||||
|
v1.push_back("foo");
|
||||||
|
CHECK( v1 != v2 );
|
||||||
|
|
||||||
|
v2.push_back("foo");
|
||||||
|
CHECK( v1 == v2 );
|
||||||
|
|
||||||
|
v1.push_back("bar");
|
||||||
|
v2.push_back("baz");
|
||||||
|
CHECK( v1 != v2 );
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("wxVector::reverse_iterator", "[vector][reverse_iterator]")
|
||||||
|
{
|
||||||
|
wxVector<int> v;
|
||||||
|
for ( int i = 0; i < 10; ++i )
|
||||||
|
v.push_back(i + 1);
|
||||||
|
|
||||||
|
const wxVector<int>::reverse_iterator rb = v.rbegin();
|
||||||
|
const wxVector<int>::reverse_iterator re = v.rend();
|
||||||
|
CHECK( re - rb == 10 );
|
||||||
|
|
||||||
|
wxVector<int>::reverse_iterator ri = rb;
|
||||||
|
++ri;
|
||||||
|
CHECK( ri - rb == 1 );
|
||||||
|
CHECK( re - ri == 9 );
|
||||||
|
|
||||||
|
ri = rb + 2;
|
||||||
|
CHECK( ri - rb == 2 );
|
||||||
|
CHECK( re - ri == 8 );
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("wxVector::capacity", "[vector][capacity][shrink_to_fit]")
|
||||||
|
{
|
||||||
|
wxVector<int> v;
|
||||||
|
CHECK( v.capacity() == 0 );
|
||||||
|
|
||||||
|
v.push_back(0);
|
||||||
|
// When using the standard library vector, we don't know what growth
|
||||||
|
// strategy it uses, so we can't rely on this check passing, but with our
|
||||||
|
// own one we can, allowing us to check that shrink_to_fit() really shrinks
|
||||||
|
// the capacity below.
|
||||||
|
#if !wxUSE_STD_CONTAINERS
|
||||||
|
CHECK( v.capacity() > 1 );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
v.shrink_to_fit();
|
||||||
|
CHECK( v.capacity() == 1 );
|
||||||
|
|
||||||
|
v.erase(v.begin());
|
||||||
|
CHECK( v.capacity() == 1 );
|
||||||
|
|
||||||
|
v.shrink_to_fit();
|
||||||
|
CHECK( v.capacity() == 0 );
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user