From 802b2349a1cd175f575a07233a67529a8c9ce52c Mon Sep 17 00:00:00 2001 From: Steve Checkoway Date: Mon, 23 Oct 2006 03:33:24 +0000 Subject: [PATCH] Simplify reverse iterators. There isn't a "past the beginning" iterator so this is hard to make a true bidirectional iterator. Instead restrict this to a single direction based on the m_bReverse parameter. Use the "past the end" iterator in place of the "past the beginning" iterator when in reverse. --- stepmania/src/NoteData.cpp | 157 ++++++++++++++++++++++++------------- stepmania/src/NoteData.h | 36 ++++----- 2 files changed, 120 insertions(+), 73 deletions(-) diff --git a/stepmania/src/NoteData.cpp b/stepmania/src/NoteData.cpp index b127afe8a5..32bec67906 100644 --- a/stepmania/src/NoteData.cpp +++ b/stepmania/src/NoteData.cpp @@ -11,7 +11,6 @@ #include "XmlFile.h" #include "Foreach.h" #include "RageUtil_AutoPtr.h" -#include REGISTER_CLASS_TRAITS( NoteData, new NoteData(*pCopy) ) @@ -898,88 +897,136 @@ void NoteData::LoadFromNode( const XNode* pNode ) ASSERT(0); } -NoteData::reverse_iterator NoteData::rlower_bound( int iTrack, int iRow ) +template +void NoteData::_all_tracks_iterator::Find( bool bReverse ) { - /* This is annoyingly tricky. First, find the upper bound for iRow. The map upper bound is the first - * key that is greater than iRow. If no such key exists in the map, then every key is less than or - * equal to iRow so we want the first. Note that if the map is empty, rbegin() will be the same as - * rend(). If the first key in the map is is greater than iRow then all are so return rend(). If i - * is neither begin() nor end(), then i - 1 (which isn't defined!) is last key in the map that is - * less than or equal to iRow. */ - iterator i = m_TapNotes[iTrack].upper_bound( iRow ); - if( i == m_TapNotes[iTrack].end() ) - return m_TapNotes[iTrack].rbegin(); - if( i == m_TapNotes[iTrack].begin() ) - return m_TapNotes[iTrack].rend(); - return reverse_iterator( --i ); -} - -NoteData::const_reverse_iterator NoteData::rlower_bound( int iTrack, int iRow ) const -{ - return const_cast(this)->rlower_bound( iTrack, iRow ); -} - -template -void NoteData::_all_tracks_iterator::Find() -{ - int iMinRow = m_iEndRow+1; - int iMaxRow = m_iStartRow-1; - // If no notes can be found in the range, m_iTrack will stay -1 and IsAtEnd() will return true. m_iTrack = -1; - for( int iTrack = 0; iTrack < m_NoteData.GetNumTracks(); ++iTrack ) + if( bReverse ) { - iter &i = m_vIters[iTrack]; - if( m_Cond ) + int iMaxRow = m_iStartRow - 1; + for( int iTrack = m_NoteData.GetNumTracks() - 1; iTrack >= 0; --iTrack ) { - while( i != (m_NoteData.*myend)(iTrack) && (bReverse ? (i->first > iMaxRow) : (i->first < iMinRow)) && !m_Cond(i->second) ) - ++i; + iter &i( m_vIters[iTrack] ); + if( m_Cond ) + { + while( i != m_NoteData.end(iTrack) && i->first > iMaxRow && !m_Cond(i->second) ) + { + if( i == m_NoteData.begin(iTrack) ) + i = m_NoteData.end( iTrack ); + else + --i; + } + } + if( i != m_NoteData.end(iTrack) && i->first > iMaxRow ) + { + iMaxRow = i->first; + m_iTrack = iTrack; + } } - - if( i != (m_NoteData.*myend)(iTrack) && (bReverse ? (i->first > iMaxRow) : (i->first < iMinRow)) ) + } + else + { + int iMinRow = m_iEndRow + 1; + for( int iTrack = 0; iTrack < m_NoteData.GetNumTracks(); ++iTrack ) { - (bReverse ? iMaxRow : iMinRow) = i->first; - m_iTrack = iTrack; + iter &i = m_vIters[iTrack]; + if( m_Cond ) + { + while( i != m_NoteData.end(iTrack) && i->first < iMinRow && !m_Cond(i->second) ) + ++i; + } + if( i != m_NoteData.end(iTrack) && i->first < iMinRow ) + { + iMinRow = i->first; + m_iTrack = iTrack; + } } } } -template -NoteData::_all_tracks_iterator::_all_tracks_iterator( ND &nd, int iStartRow, int iEndRow, NoteData::IteratorCond cond ) : - m_NoteData(nd), m_iTrack(0), m_iStartRow(iStartRow), m_iEndRow(iEndRow), m_Cond(cond) +template +NoteData::_all_tracks_iterator::_all_tracks_iterator( ND &nd, int iStartRow, int iEndRow, bool bReverse, NoteData::IteratorCond cond ) : + m_NoteData(nd), m_iTrack(0), m_iStartRow(iStartRow), m_iEndRow(iEndRow), m_bReverse(bReverse), m_Cond(cond) { ASSERT( m_NoteData.GetNumTracks() > 0 ); - for( int iTrack = 0; iTrack < m_NoteData.GetNumTracks(); ++iTrack ) + if( bReverse ) { - iter i = (m_NoteData.*mylower_bound)(iTrack, bReverse?iEndRow:iStartRow); - iter end = (m_NoteData.*myend)(iTrack); - m_vIters.push_back( i ); + for( int iTrack = 0; iTrack < m_NoteData.GetNumTracks(); ++iTrack ) + { + iter i = m_NoteData.upper_bound( iTrack, iEndRow ); + + if( i == m_NoteData.begin(iTrack) ) + m_vIters.push_back( m_NoteData.end(iTrack) ); + else + m_vIters.push_back( --i ); + } } - Find(); + else + { + for( int iTrack = 0; iTrack < m_NoteData.GetNumTracks(); ++iTrack ) + m_vIters.push_back( m_NoteData.lower_bound(iTrack, iStartRow) ); + } + Find( bReverse ); } -template -NoteData::_all_tracks_iterator &NoteData::_all_tracks_iterator::operator++() // preincrement +template +NoteData::_all_tracks_iterator &NoteData::_all_tracks_iterator::operator++() // preincrement { - ++m_vIters[m_iTrack]; - Find(); + if( m_bReverse ) + { + if( m_vIters[m_iTrack] == m_NoteData.begin(m_iTrack) ) + m_vIters[m_iTrack] = m_NoteData.end( m_iTrack ); + else + --m_vIters[m_iTrack]; + } + else + { + ++m_vIters[m_iTrack]; + } + Find( m_bReverse ); return *this; } -template -NoteData::_all_tracks_iterator NoteData::_all_tracks_iterator::operator++( int dummy ) // postincrement +template +NoteData::_all_tracks_iterator NoteData::_all_tracks_iterator::operator++( int dummy ) // postincrement { - _all_tracks_iterator ret(*this); + _all_tracks_iterator ret( *this ); operator++(); return ret; } +/* XXX: This doesn't satisfy the requirements that ++iter; --iter; is a no-op so it cannot be bidirectional for now. */ +#if 0 +template +NoteData::_all_tracks_iterator &NoteData::_all_tracks_iterator::operator--() // predecrement +{ + if( m_bReverse ) + { + ++m_vIters[m_iTrack]; + } + else + { + if( m_vIters[m_iTrack] == m_NoteData.begin(m_iTrack) ) + m_vIters[m_iTrack] = m_NoteData.end( m_iTrack ); + else + --m_vIters[m_iTrack]; + } + Find( !m_bReverse ); + return *this; +} +template +NoteData::_all_tracks_iterator NoteData::_all_tracks_iterator::operator--( int dummy ) // postdecrement +{ + _all_tracks_iterator ret( *this ); + operator--(); + return ret; +} +#endif // Explicit instantiation. -template class NoteData::_all_tracks_iterator; -template class NoteData::_all_tracks_iterator; -template class NoteData::_all_tracks_iterator; -template class NoteData::_all_tracks_iterator; +template class NoteData::_all_tracks_iterator; +template class NoteData::_all_tracks_iterator; /* * (c) 2001-2004 Chris Danford, Glenn Maynard diff --git a/stepmania/src/NoteData.h b/stepmania/src/NoteData.h index e0e8177305..cde5082600 100644 --- a/stepmania/src/NoteData.h +++ b/stepmania/src/NoteData.h @@ -6,6 +6,7 @@ #include "NoteTypes.h" #include #include +#include #define FOREACH_NONEMPTY_ROW_IN_TRACK( nd, track, row ) \ for( int row = -1; (nd).GetNextTapNoteRowForTrack(track,row); ) @@ -46,16 +47,14 @@ public: const_reverse_iterator rend( int iTrack ) const { return m_TapNotes[iTrack].rend(); } iterator lower_bound( int iTrack, int iRow ) { return m_TapNotes[iTrack].lower_bound( iRow ); } const_iterator lower_bound( int iTrack, int iRow ) const { return m_TapNotes[iTrack].lower_bound( iRow ); } - reverse_iterator rlower_bound( int iTrack, int iRow ); - const_reverse_iterator rlower_bound( int iTrack, int iRow ) const; + iterator upper_bound( int iTrack, int iRow ) { return m_TapNotes[iTrack].upper_bound( iRow ); } + const_iterator upper_bound( int iTrack, int iRow ) const { return m_TapNotes[iTrack].upper_bound( iRow ); } void swap( NoteData &nd ) { m_TapNotes.swap( nd.m_TapNotes ); } - - typedef bool (*IteratorCond)( const TapNote& ); // This is ugly to make it templated but I don't want to have to write the same class twice. - template + template class _all_tracks_iterator { ND &m_NoteData; @@ -63,13 +62,16 @@ public: int m_iTrack; const int m_iStartRow; const int m_iEndRow; + const bool m_bReverse; IteratorCond m_Cond; - void Find(); // point m_iTrack at the iterator with the smallest row that meets mCond and is within range -public: - _all_tracks_iterator( ND &nd, int iStartRow, int iEndRow, IteratorCond cond ); + void Find( bool bReverse ); + public: + _all_tracks_iterator( ND &nd, int iStartRow, int iEndRow, bool bReverse, IteratorCond cond ); _all_tracks_iterator &operator++(); // preincrement _all_tracks_iterator operator++( int dummy ); // postincrement + //_all_tracks_iterator &operator--(); // predecrement + //_all_tracks_iterator operator--( int dummy ); // postdecrement inline int Track() const { return m_iTrack; } inline int Row() const { return m_vIters[m_iTrack]->first; } inline bool IsAtEnd() const { return m_iTrack == -1; } @@ -78,11 +80,10 @@ public: inline const TN &operator*() const { DEBUG_ASSERT( !IsAtEnd() ); return m_vIters[m_iTrack]->second; } inline const TN *operator->() const { DEBUG_ASSERT( !IsAtEnd() ); return &m_vIters[m_iTrack]->second; } }; - typedef _all_tracks_iterator all_tracks_iterator; - typedef _all_tracks_iterator all_tracks_const_iterator; - typedef _all_tracks_iterator all_tracks_reverse_iterator; - typedef _all_tracks_iterator all_tracks_const_reverse_iterator; - + typedef _all_tracks_iterator all_tracks_iterator; + typedef _all_tracks_iterator all_tracks_const_iterator; + typedef all_tracks_iterator all_tracks_reverse_iterator; + typedef all_tracks_const_iterator all_tracks_const_reverse_iterator; private: // There's no point in inserting empty notes into the map. // Any blank space in the map is defined to be empty. @@ -119,22 +120,21 @@ public: void GetTapNoteRange( int iTrack, int iStartRow, int iEndRow, TrackMap::iterator &begin, TrackMap::iterator &end ); all_tracks_iterator GetTapNoteRangeAllTracks( int iStartRow, int iEndRow, IteratorCond cond = NULL ) { - return all_tracks_iterator( *this, iStartRow, iEndRow, cond ); + return all_tracks_iterator( *this, iStartRow, iEndRow, false, cond ); } all_tracks_const_iterator GetTapNoteRangeAllTracks( int iStartRow, int iEndRow, IteratorCond cond = NULL) const { - return all_tracks_const_iterator( *this, iStartRow, iEndRow, cond ); + return all_tracks_const_iterator( *this, iStartRow, iEndRow, false, cond ); } all_tracks_reverse_iterator GetTapNoteRangeAllTracksReverse( int iStartRow, int iEndRow, IteratorCond cond = NULL ) { - return all_tracks_reverse_iterator( *this, iStartRow, iEndRow, cond ); + return all_tracks_iterator(*this, iStartRow, iEndRow, true, cond); } all_tracks_const_reverse_iterator GetTapNoteRangeAllTracksReverse( int iStartRow, int iEndRow, IteratorCond cond = NULL) const { - return all_tracks_const_reverse_iterator( *this, iStartRow, iEndRow, cond ); + return all_tracks_const_iterator(*this, iStartRow, iEndRow, true, cond); } - /* Return an iterator range include iStartRow to iEndRow. Extend the range to include * hold notes overlapping the boundary. */ void GetTapNoteRangeInclusive( int iTrack, int iStartRow, int iEndRow, const_iterator &begin, const_iterator &end, bool bIncludeAdjacent=false ) const;