Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Add const_iterator and iterator methods to QgsFields
Because using Q_FOREACH is so much easier to write than an index-based loop.
  • Loading branch information
m-kuhn committed Mar 9, 2016
1 parent 632601b commit 8e4d5a8
Show file tree
Hide file tree
Showing 4 changed files with 266 additions and 1 deletion.
1 change: 1 addition & 0 deletions CMakeLists.txt
Expand Up @@ -383,6 +383,7 @@ ENDIF()
#allow override keyword if available
IF (NOT USE_CXX_11)
ADD_DEFINITIONS("-Doverride=")
ADD_DEFINITIONS("-Dnoexcept=")
ADD_DEFINITIONS("-Dnullptr=0")
ENDIF()

Expand Down
32 changes: 32 additions & 0 deletions src/core/qgsfield.cpp
Expand Up @@ -439,6 +439,38 @@ bool QgsFields::operator==( const QgsFields &other ) const
return d->fields == other.d->fields;
}

QgsFields::const_iterator QgsFields::constBegin() const noexcept
{
return const_iterator( &d->fields.first() );
}

QgsFields::const_iterator QgsFields::constEnd() const noexcept
{
return const_iterator( &d->fields.last() + 1 );
}

QgsFields::const_iterator QgsFields::begin() const noexcept
{
return const_iterator( &d->fields.first() );
}

QgsFields::const_iterator QgsFields::end() const noexcept
{
return const_iterator( &d->fields.last() + 1 );
}

QgsFields::iterator QgsFields::begin()
{
d.detach();
return iterator( &d->fields.first() );
}

QgsFields::iterator QgsFields::end()
{
d.detach();
return iterator( &d->fields.last() + 1 );
}

QIcon QgsFields::iconForField( int fieldIdx ) const
{
static QIcon intIcon;
Expand Down
129 changes: 128 additions & 1 deletion src/core/qgsfield.h
Expand Up @@ -283,12 +283,139 @@ class CORE_EXPORT QgsFields
bool operator==( const QgsFields& other ) const;
//! @note added in 2.6
bool operator!=( const QgsFields& other ) const { return !( *this == other ); }

/** Returns an icon corresponding to a field index, based on the field's type and source
* @note added in QGIS 2.14
*/
QIcon iconForField( int fieldIdx ) const;

///@cond PRIVATE

class const_iterator;

class iterator
{
public:
QgsFields::Field* d;
typedef std::random_access_iterator_tag iterator_category;
typedef qptrdiff difference_type;

inline iterator()
: d( nullptr )
{}
inline iterator( QgsFields::Field *n )
: d( n )
{}

inline QgsField& operator*() const { return d->field; }
inline QgsField* operator->() const { return &d->field; }
inline QgsField& operator[]( difference_type j ) const { return d[j].field; }
inline bool operator==( const iterator &o ) const noexcept { return d == o.d; }
inline bool operator!=( const iterator &o ) const noexcept { return d != o.d; }
inline bool operator<( const iterator& other ) const noexcept { return d < other.d; }
inline bool operator<=( const iterator& other ) const noexcept { return d <= other.d; }
inline bool operator>( const iterator& other ) const noexcept { return d > other.d; }
inline bool operator>=( const iterator& other ) const noexcept { return d >= other.d; }

inline iterator& operator++() { ++d; return *this; }
inline iterator operator++( int ) { QgsFields::Field* n = d; ++d; return n; }
inline iterator& operator--() { d--; return *this; }
inline iterator operator--( int ) { QgsFields::Field* n = d; d--; return n; }
inline iterator& operator+=( difference_type j ) { d += j; return *this; }
inline iterator& operator-=( difference_type j ) { d -= j; return *this; }
inline iterator operator+( difference_type j ) const { return iterator( d + j ); }
inline iterator operator-( difference_type j ) const { return iterator( d -j ); }
inline int operator-( iterator j ) const { return int( d - j.d ); }
};
friend class iterator;

class const_iterator
{
public:
const QgsFields::Field* d;

typedef std::random_access_iterator_tag iterator_category;
typedef qptrdiff difference_type;

inline const_iterator()
: d( nullptr ) {}
inline const_iterator( const QgsFields::Field* f )
: d( f ) {}
inline const_iterator( const const_iterator &o )
: d( o.d ) {}
inline explicit const_iterator( const iterator &o )
: d( o.d ) {}
inline const QgsField& operator*() const { return d->field; }
inline const QgsField* operator->() const { return &d->field; }
inline const QgsField& operator[]( difference_type j ) const noexcept { return d[j].field; }
inline bool operator==( const const_iterator &o ) const noexcept { return d == o.d; }
inline bool operator!=( const const_iterator &o ) const noexcept { return d != o.d; }
inline bool operator<( const const_iterator& other ) const noexcept { return d < other.d; }
inline bool operator<=( const const_iterator& other ) const noexcept { return d <= other.d; }
inline bool operator>( const const_iterator& other ) const noexcept { return d > other.d; }
inline bool operator>=( const const_iterator& other ) const noexcept { return d >= other.d; }
inline const_iterator& operator++() { ++d; return *this; }
inline const_iterator operator++( int ) { const QgsFields::Field* n = d; ++d; return n; }
inline const_iterator& operator--() { d--; return *this; }
inline const_iterator operator--( int ) { const QgsFields::Field* n = d; --d; return n; }
inline const_iterator& operator+=( difference_type j ) { d += j; return *this; }
inline const_iterator& operator-=( difference_type j ) { d -= j; return *this; }
inline const_iterator operator+( difference_type j ) const { return const_iterator( d + j ); }
inline const_iterator operator-( difference_type j ) const { return const_iterator( d -j ); }
inline int operator-( const_iterator j ) const { return int( d - j.d ); }
};
friend class const_iterator;
///@endcond


/**
* Returns a const STL-style iterator pointing to the first item in the list.
*
* @note added in 2.16
* @note not available in Python bindings
*/
const_iterator constBegin() const noexcept;

/**
* Returns a const STL-style iterator pointing to the imaginary item after the last item in the list.
*
* @note added in 2.16
* @note not available in Python bindings
*/
const_iterator constEnd() const noexcept;

/**
* Returns a const STL-style iterator pointing to the first item in the list.
*
* @note added in 2.16
* @note not available in Python bindings
*/
const_iterator begin() const noexcept;

/**
* Returns a const STL-style iterator pointing to the imaginary item after the last item in the list.
*
* @note added in 2.16
* @note not available in Python bindings
*/
const_iterator end() const noexcept;

/**
* Returns an STL-style iterator pointing to the first item in the list.
*
* @note added in 2.16
* @note not available in Python bindings
*/
iterator begin();


/**
* Returns an STL-style iterator pointing to the imaginary item after the last item in the list.
*
* @note added in 2.16
* @note not available in Python bindings
*/
iterator end();

private:

QSharedDataPointer<QgsFieldsPrivate> d;
Expand Down
105 changes: 105 additions & 0 deletions tests/src/core/testqgsfields.cpp
Expand Up @@ -51,6 +51,9 @@ class TestQgsFields: public QObject
void appendExpressionField();
void dataStream();
void field(); //test QgsFields::Field
void qforeach();
void iterator();
void constIterator();

private:
};
Expand Down Expand Up @@ -472,5 +475,107 @@ void TestQgsFields::field()
QVERIFY( field1 != field4 );
}

void TestQgsFields::qforeach()
{
QgsFields fields;
QgsField field( QString( "1" ) );
fields.append( field );
QgsField field2( QString( "2" ) );
fields.append( field2 );

int i = 0;
Q_FOREACH ( const QgsField& field, fields )
{
QCOMPARE( field, fields.at( i ) );
++i;
}
}

void TestQgsFields::iterator()
{
QgsFields fields;
QgsField field( QString( "1" ) );
fields.append( field );
QgsField field2( QString( "2" ) );
fields.append( field2 );

QgsFields::iterator it = fields.begin();

QCOMPARE( it->name(), QString( "1" ) );
QCOMPARE(( ++it )->name(), QString( "2" ) );
QCOMPARE(( --it )->name(), QString( "1" ) );
QCOMPARE(( it++ )->name(), QString( "1" ) );
QCOMPARE( it->name(), QString( "2" ) );
it->setName( "Test" );
QCOMPARE(( it-- )->name(), QString( "Test" ) );
QCOMPARE( it->name(), QString( "1" ) );
QCOMPARE( it[1].name(), QString( "Test" ) );
it += 2;
QCOMPARE( it, fields.end() );
it -= 2;
QCOMPARE( it->name(), QString( "1" ) );
QgsFields::iterator it2( it );
QVERIFY( it <= it2 );
QVERIFY( it2 >= it );
it2++;
QVERIFY( it < it2 );
QVERIFY( it <= it2 );
QVERIFY( it2 > it );
QVERIFY( it2 >= it );
QCOMPARE( it2, it + 1 );
QCOMPARE( it, it2 - 1 );
QCOMPARE( it2 - it, 1 );
}


void TestQgsFields::constIterator()
{
QgsFields fields;
QgsField field( QString( QString( "1" ) ) );
fields.append( field );
QgsField field2( QString( QString( "2" ) ) );
fields.append( field2 );

const QgsFields constFields( fields );

QgsFields::const_iterator it = constFields.begin();

QCOMPARE( it->name(), QString( "1" ) );
QCOMPARE(( ++it )->name(), QString( "2" ) );
QCOMPARE(( --it )->name(), QString( "1" ) );
QCOMPARE(( it++ )->name(), QString( "1" ) );
QCOMPARE( it->name(), QString( "2" ) );
QCOMPARE(( it-- )->name(), QString( "2" ) );
QCOMPARE( it->name(), QString( "1" ) );
QCOMPARE( it[1].name(), QString( "2" ) );
it += 2;
QCOMPARE( it, constFields.end() );

QgsFields::const_iterator it2 = fields.constBegin();

QCOMPARE( it2->name(), QString( "1" ) );
QCOMPARE(( ++it2 )->name(), QString( "2" ) );
QCOMPARE(( --it2 )->name(), QString( "1" ) );
QCOMPARE(( it2++ )->name(), QString( "1" ) );
QCOMPARE( it2->name(), QString( "2" ) );
QCOMPARE(( it2-- )->name(), QString( "2" ) );
QCOMPARE( it2->name(), QString( "1" ) );
QCOMPARE( it2[1].name(), QString( "2" ) );
it2 += 2;
QCOMPARE( it2, fields.constEnd() );

QgsFields::const_iterator it3( it );
QVERIFY( it <= it3 );
QVERIFY( it3 >= it );
it3++;
QVERIFY( it < it3 );
QVERIFY( it <= it3 );
QVERIFY( it3 > it );
QVERIFY( it3 >= it );
QCOMPARE( it3, it + 1 );
QCOMPARE( it, it3 - 1 );
QCOMPARE( it3 - it, 1 );
}

QTEST_MAIN( TestQgsFields )
#include "testqgsfields.moc"

1 comment on commit 8e4d5a8

@nyalldawson
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Love it!

Please sign in to comment.