diff --git a/src/NoteData.cpp b/src/NoteData.cpp index 24bb051fea..52a1daf4ac 100644 --- a/src/NoteData.cpp +++ b/src/NoteData.cpp @@ -1176,6 +1176,48 @@ void NoteData::LoadFromNode( const XNode* pNode ) FAIL_M("NoteData::LoadFromNode() not implemented"); } +void NoteData::AddATIToList(all_tracks_iterator* iter) const +{ + m_atis.insert(iter); +} + +void NoteData::AddATIToList(all_tracks_const_iterator* iter) const +{ + m_const_atis.insert(iter); +} + +void NoteData::RemoveATIFromList(all_tracks_iterator* iter) const +{ + set::iterator pos= m_atis.find(iter); + if(pos != m_atis.end()) + { + m_atis.erase(pos); + } +} + +void NoteData::RemoveATIFromList(all_tracks_const_iterator* iter) const +{ + set::iterator pos= m_const_atis.find(iter); + if(pos != m_const_atis.end()) + { + m_const_atis.erase(pos); + } +} + +void NoteData::RevalidateATIs(vector const& added_or_removed_tracks, bool added) +{ + for(set::iterator cur= m_atis.begin(); + cur != m_atis.end(); ++cur) + { + (*cur)->Revalidate(this, added_or_removed_tracks, added); + } + for(set::iterator cur= m_const_atis.begin(); + cur != m_const_atis.end(); ++cur) + { + (*cur)->Revalidate(this, added_or_removed_tracks, added); + } +} + template void NoteData::_all_tracks_iterator::Find( bool bReverse ) { @@ -1213,14 +1255,18 @@ void NoteData::_all_tracks_iterator::Find( bool bReverse ) } template -NoteData::_all_tracks_iterator::_all_tracks_iterator( ND &nd, int iStartRow, int iEndRow, bool bReverse, bool bInclusive ) : + NoteData::_all_tracks_iterator::_all_tracks_iterator( ND &nd, int iStartRow, int iEndRow, bool bReverse, bool bInclusive ) : m_pNoteData(&nd), m_iTrack(0), m_bReverse(bReverse) { ASSERT( m_pNoteData->GetNumTracks() > 0 ); + m_StartRow= iStartRow; + m_EndRow= iEndRow; + for( int iTrack = 0; iTrack < m_pNoteData->GetNumTracks(); ++iTrack ) { iter begin, end; + m_Inclusive= bInclusive; if( bInclusive ) m_pNoteData->GetTapNoteRangeInclusive( iTrack, iStartRow, iEndRow, begin, end ); else @@ -1228,6 +1274,7 @@ NoteData::_all_tracks_iterator::_all_tracks_iterator( ND &nd, int m_vBeginIters.push_back( begin ); m_vEndIters.push_back( end ); + m_PrevCurrentRows.push_back(0); iter cur; if( m_bReverse ) @@ -1242,6 +1289,7 @@ NoteData::_all_tracks_iterator::_all_tracks_iterator( ND &nd, int } m_vCurrentIters.push_back( cur ); } + m_pNoteData->AddATIToList(this); Find( bReverse ); } @@ -1254,14 +1302,28 @@ NoteData::_all_tracks_iterator::_all_tracks_iterator( const _all_t COPY_OTHER( m_vCurrentIters ), COPY_OTHER( m_vEndIters ), COPY_OTHER( m_iTrack ), - COPY_OTHER( m_bReverse ) + COPY_OTHER( m_bReverse ), + COPY_OTHER( m_PrevCurrentRows ), + COPY_OTHER( m_StartRow ), + COPY_OTHER( m_EndRow ) #undef COPY_OTHER { + m_pNoteData->AddATIToList(this); +} + +template + NoteData::_all_tracks_iterator::~_all_tracks_iterator() +{ + if(m_pNoteData != NULL) + { + m_pNoteData->RemoveATIFromList(this); + } } template NoteData::_all_tracks_iterator &NoteData::_all_tracks_iterator::operator++() // preincrement { + m_PrevCurrentRows[m_iTrack]= Row(); if( m_bReverse ) { if( m_vCurrentIters[m_iTrack] == m_vBeginIters[m_iTrack] ) @@ -1284,6 +1346,71 @@ NoteData::_all_tracks_iterator NoteData::_all_tracks_iterator + void NoteData::_all_tracks_iterator::Revalidate( + ND* notedata, vector const& added_or_removed_tracks, bool added) +{ + m_pNoteData= notedata; + ASSERT( m_pNoteData->GetNumTracks() > 0 ); + if(!added_or_removed_tracks.empty()) + { + if(added) + { + int avg_row= 0; + for(size_t p= 0; p < m_PrevCurrentRows.size(); ++p) + { + avg_row+= m_PrevCurrentRows[p]; + } + avg_row/= m_PrevCurrentRows.size(); + for(size_t a= 0; a < added_or_removed_tracks.size(); ++a) + { + int track_id= added_or_removed_tracks[a]; + m_PrevCurrentRows.insert(m_PrevCurrentRows.begin()+track_id, avg_row); + } + m_vBeginIters.resize(m_pNoteData->GetNumTracks()); + m_vCurrentIters.resize(m_pNoteData->GetNumTracks()); + m_vEndIters.resize(m_pNoteData->GetNumTracks()); + } + else + { + for(size_t a= 0; a < added_or_removed_tracks.size(); ++a) + { + int track_id= added_or_removed_tracks[a]; + m_PrevCurrentRows.erase(m_PrevCurrentRows.begin()+track_id); + } + m_vBeginIters.resize(m_pNoteData->GetNumTracks()); + m_vCurrentIters.resize(m_pNoteData->GetNumTracks()); + m_vEndIters.resize(m_pNoteData->GetNumTracks()); + } + } + for(int track= 0; track < m_pNoteData->GetNumTracks(); ++track) + { + iter begin, end; + if(m_Inclusive) + { + m_pNoteData->GetTapNoteRangeInclusive(track, m_StartRow, m_EndRow, begin, end); + } + else + { + m_pNoteData->GetTapNoteRange(track, m_StartRow, m_EndRow, begin, end); + } + m_vBeginIters[track]= begin; + m_vEndIters[track]= end; + iter cur; + if(m_bReverse) + { + cur= m_pNoteData->upper_bound(track, m_PrevCurrentRows[track]); + } + else + { + cur= m_pNoteData->lower_bound(track, m_PrevCurrentRows[track]); + } + m_vCurrentIters[track]= cur; + } + Find(m_bReverse); +} + /* XXX: This doesn't satisfy the requirements that ++iter; --iter; is a no-op so it cannot be bidirectional for now. */ #if 0 template diff --git a/src/NoteData.h b/src/NoteData.h index 6a7b4bf1d0..40033f1a2f 100644 --- a/src/NoteData.h +++ b/src/NoteData.h @@ -47,7 +47,12 @@ public: const_iterator lower_bound( int iTrack, int iRow ) const { return m_TapNotes[iTrack].lower_bound( iRow ); } 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 ); } + void swap( NoteData &nd ) + { + m_TapNotes.swap(nd.m_TapNotes); + m_atis.swap(nd.m_atis); + m_const_atis.swap(nd.m_const_atis); + } // This is ugly to make it templated but I don't want to have to write the same class twice. @@ -65,10 +70,18 @@ public: int m_iTrack; bool m_bReverse; + // These exist so that the iterator can be revalidated if the NoteData is + // transformed during this iterator's lifetime. + vector m_PrevCurrentRows; + bool m_Inclusive; + int m_StartRow; + int m_EndRow; + void Find( bool bReverse ); public: _all_tracks_iterator( ND &nd, int iStartRow, int iEndRow, bool bReverse, bool bInclusive ); _all_tracks_iterator( const _all_tracks_iterator &other ); + ~_all_tracks_iterator(); _all_tracks_iterator &operator++(); // preincrement _all_tracks_iterator operator++( int dummy ); // postincrement //_all_tracks_iterator &operator--(); // predecrement @@ -81,11 +94,15 @@ public: inline TN *operator->() { DEBUG_ASSERT( !IsAtEnd() ); return &m_vCurrentIters[m_iTrack]->second; } inline const TN &operator*() const { DEBUG_ASSERT( !IsAtEnd() ); return m_vCurrentIters[m_iTrack]->second; } inline const TN *operator->() const { DEBUG_ASSERT( !IsAtEnd() ); return &m_vCurrentIters[m_iTrack]->second; } + // Use when transforming the NoteData. + void Revalidate(ND* notedata, vector const& added_or_removed_tracks, bool added); }; 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; + friend class _all_tracks_iterator; + friend class _all_tracks_iterator; private: // There's no point in inserting empty notes into the map. // Any blank space in the map is defined to be empty. @@ -129,7 +146,17 @@ private: pair GetNumRowsWithSimultaneousTapsTwoPlayer(int minTaps = 2, int startRow = 0, int endRow = MAX_NOTE_ROW) const; - + + // These exist so that they can be revalidated when something that transforms + // the NoteData occurs. -Kyz + mutable set m_atis; + mutable set m_const_atis; + + void AddATIToList(all_tracks_iterator* iter) const; + void AddATIToList(all_tracks_const_iterator* iter) const; + void RemoveATIFromList(all_tracks_iterator* iter) const; + void RemoveATIFromList(all_tracks_const_iterator* iter) const; + public: void Init(); @@ -196,6 +223,10 @@ public: return all_tracks_const_iterator(*this, iStartRow, iEndRow, true, bInclusive ); } + // Call this after using any transform that changes the NoteData. + void RevalidateATIs(vector const& added_or_removed_tracks, bool added); + void TransferATIs(NoteData& to); + /* 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, diff --git a/src/NoteDataUtil.cpp b/src/NoteDataUtil.cpp index 8ad1e123da..b521f84125 100644 --- a/src/NoteDataUtil.cpp +++ b/src/NoteDataUtil.cpp @@ -261,6 +261,7 @@ static void LoadFromSMNoteDataStringWithPlayer( NoteData& out, const RString &sS begin = next; } } + out.RevalidateATIs(vector(), false); } void NoteDataUtil::LoadFromSMNoteDataString( NoteData &out, const RString &sSMNoteData_, bool bComposite ) @@ -311,6 +312,7 @@ void NoteDataUtil::LoadFromSMNoteDataString( NoteData &out, const RString &sSMNo LoadFromSMNoteDataStringWithPlayer( nd, sSMNoteData, start, size, pn, iNumTracks ); } CombineCompositeNoteData( out, vParts ); + out.RevalidateATIs(vector(), false); } void NoteDataUtil::InsertHoldTails( NoteData &inout ) @@ -487,6 +489,7 @@ void NoteDataUtil::CombineCompositeNoteData( NoteData &out, const vector(), false); } @@ -557,6 +560,7 @@ void NoteDataUtil::LoadTransformedSlidingWindow( const NoteData &in, NoteData &o out.SetTapNote( iNewTrack, r, tn ); } } + out.RevalidateATIs(vector(), false); } void PlaceAutoKeysound( NoteData &out, int row, TapNote akTap ) @@ -672,6 +676,7 @@ void NoteDataUtil::LoadOverlapped( const NoteData &in, NoteData &out, int iNewNu PlaceAutoKeysound( out, row, tnFrom ); } } + out.RevalidateATIs(vector(), false); } int FindLongestOverlappingHoldNoteForAnyTrack( const NoteData &in, int iRow ) @@ -981,6 +986,7 @@ void NoteDataUtil::RemoveHoldNotes( NoteData &in, int iStartIndex, int iEndIndex begin->second.type = TapNote::tap; } } + in.RevalidateATIs(vector(), false); } void NoteDataUtil::ChangeRollsToHolds( NoteData &in, int iStartIndex, int iEndIndex ) @@ -997,6 +1003,7 @@ void NoteDataUtil::ChangeRollsToHolds( NoteData &in, int iStartIndex, int iEndIn begin->second.subType = TapNote::hold_head_hold; } } + in.RevalidateATIs(vector(), false); } void NoteDataUtil::ChangeHoldsToRolls( NoteData &in, int iStartIndex, int iEndIndex ) @@ -1013,6 +1020,7 @@ void NoteDataUtil::ChangeHoldsToRolls( NoteData &in, int iStartIndex, int iEndIn begin->second.subType = TapNote::hold_head_roll; } } + in.RevalidateATIs(vector(), false); } void NoteDataUtil::RemoveSimultaneousNotes( NoteData &in, int iMaxSimultaneous, int iStartIndex, int iEndIndex ) @@ -1051,6 +1059,7 @@ void NoteDataUtil::RemoveSimultaneousNotes( NoteData &in, int iMaxSimultaneous, } } } + in.RevalidateATIs(vector(), false); } void NoteDataUtil::RemoveJumps( NoteData &inout, int iStartIndex, int iEndIndex ) @@ -1074,6 +1083,7 @@ void NoteDataUtil::RemoveSpecificTapNotes( NoteData &inout, TapNote::Type tn, in FOREACH_NONEMPTY_ROW_IN_TRACK_RANGE( inout, t, r, iStartIndex, iEndIndex ) if( inout.GetTapNote(t,r).type == tn ) inout.SetTapNote( t, r, TAP_EMPTY ); + inout.RevalidateATIs(vector(), false); } void NoteDataUtil::RemoveMines( NoteData &inout, int iStartIndex, int iEndIndex ) @@ -1110,6 +1120,7 @@ void NoteDataUtil::RemoveAllButOneTap( NoteData &inout, int row ) if( iter != inout.end(track) && iter->second.type == TapNote::tap ) inout.RemoveTapNote( track, iter ); } + inout.RevalidateATIs(vector(), false); } void NoteDataUtil::RemoveAllButPlayer( NoteData &inout, PlayerNumber pn ) @@ -1126,6 +1137,7 @@ void NoteDataUtil::RemoveAllButPlayer( NoteData &inout, PlayerNumber pn ) ++i; } } + inout.RevalidateATIs(vector(), false); } // TODO: Perform appropriate matrix calculations for everything instead. @@ -1536,6 +1548,7 @@ void NoteDataUtil::Turn( NoteData &inout, StepsType st, TrackMapping tt, int iSt SuperShuffleTaps( tempNoteData, iStartIndex, iEndIndex ); inout.CopyAll( tempNoteData ); + inout.RevalidateATIs(vector(), false); } void NoteDataUtil::Backwards( NoteData &inout ) @@ -1560,6 +1573,7 @@ void NoteDataUtil::Backwards( NoteData &inout ) } inout.swap( out ); + inout.RevalidateATIs(vector(), false); } void NoteDataUtil::SwapSides( NoteData &inout ) @@ -1575,6 +1589,7 @@ void NoteDataUtil::SwapSides( NoteData &inout ) NoteData orig( inout ); inout.LoadTransformed( orig, orig.GetNumTracks(), iOriginalTrackToTakeFrom ); + inout.RevalidateATIs(vector(), false); } void NoteDataUtil::Little( NoteData &inout, int iStartIndex, int iEndIndex ) @@ -1589,6 +1604,7 @@ void NoteDataUtil::Little( NoteData &inout, int iStartIndex, int iEndIndex ) inout.SetTapNote( t, i, TAP_EMPTY ); } } + inout.RevalidateATIs(vector(), false); } // Make all quarter notes into jumps. @@ -1641,6 +1657,7 @@ void NoteDataUtil::Wide( NoteData &inout, int iStartIndex, int iEndIndex ) } inout.SetTapNote(iTrackToAdd, i, TAP_ADDITION_TAP); } + inout.RevalidateATIs(vector(), false); } void NoteDataUtil::Big( NoteData &inout, int iStartIndex, int iEndIndex ) @@ -1747,6 +1764,7 @@ void NoteDataUtil::InsertIntelligentTaps( inout.SetTapNote(iTrackOfNoteToAdd, iRowToAdd, TAP_ADDITION_TAP); } + inout.RevalidateATIs(vector(), false); } #if 0 class TrackIterator @@ -1873,6 +1891,7 @@ void NoteDataUtil::AddMines( NoteData &inout, int iStartIndex, int iEndIndex ) iRowCount = 0; } } + inout.RevalidateATIs(vector(), false); } void NoteDataUtil::Echo( NoteData &inout, int iStartIndex, int iEndIndex ) @@ -1927,6 +1946,7 @@ void NoteDataUtil::Echo( NoteData &inout, int iStartIndex, int iEndIndex ) inout.SetTapNote( iEchoTrack, iRowEcho, TAP_ADDITION_TAP ); } + inout.RevalidateATIs(vector(), false); } void NoteDataUtil::Planted( NoteData &inout, int iStartIndex, int iEndIndex ) @@ -1999,7 +2019,7 @@ void NoteDataUtil::ConvertTapsToHolds( NoteData &inout, int iSimultaneousHolds, } } } - + inout.RevalidateATIs(vector(), false); } void NoteDataUtil::Stomp( NoteData &inout, StepsType st, int iStartIndex, int iEndIndex ) @@ -2042,6 +2062,7 @@ void NoteDataUtil::Stomp( NoteData &inout, StepsType st, int iStartIndex, int iE } } } + inout.RevalidateATIs(vector(), false); } void NoteDataUtil::SnapToNearestNoteType( NoteData &inout, NoteType nt1, NoteType nt2, int iStartIndex, int iEndIndex ) @@ -2088,6 +2109,7 @@ void NoteDataUtil::SnapToNearestNoteType( NoteData &inout, NoteType nt1, NoteTyp inout.SetTapNote( c, iNewIndex, tnNew ); } } + inout.RevalidateATIs(vector(), false); } @@ -2254,6 +2276,7 @@ void NoteDataUtil::RemoveStretch( NoteData &inout, StepsType st, int iStartIndex if( !bPassedOneMask ) RemoveAllButOneTap( inout, r ); } + inout.RevalidateATIs(vector(), false); } bool NoteDataUtil::RowPassesValidMask( NoteData &inout, int row, const bool bValidMask[] ) @@ -2277,6 +2300,7 @@ void NoteDataUtil::ConvertAdditionsToRegular( NoteData &inout ) tn.source = TapNote::original; inout.SetTapNote( t, r, tn ); } + inout.RevalidateATIs(vector(), false); } void NoteDataUtil::TransformNoteData( NoteData &nd, const AttackArray &aa, StepsType st, Song* pSong ) @@ -2373,6 +2397,7 @@ void NoteDataUtil::AddTapAttacks( NoteData &nd, Song* pSong ) -1 ); nd.SetTapNote( iTrack, BeatToNoteRow(fBeat), tn ); } + nd.RevalidateATIs(vector(), false); } void NoteDataUtil::Scale( NoteData &nd, float fScale ) @@ -2395,6 +2420,7 @@ void NoteDataUtil::Scale( NoteData &nd, float fScale ) } nd.swap( ndOut ); + nd.RevalidateATIs(vector(), false); } /* XXX: move this to an appropriate place, same place as NoteRowToBeat perhaps? */ @@ -2430,6 +2456,7 @@ void NoteDataUtil::ScaleRegion( NoteData &nd, float fScale, int iStartIndex, int } nd.swap( ndOut ); + nd.RevalidateATIs(vector(), false); } void NoteDataUtil::InsertRows( NoteData &nd, int iStartIndex, int iRowsToAdd ) @@ -2441,6 +2468,7 @@ void NoteDataUtil::InsertRows( NoteData &nd, int iStartIndex, int iRowsToAdd ) temp.CopyRange( nd, iStartIndex, MAX_NOTE_ROW ); nd.ClearRange( iStartIndex, MAX_NOTE_ROW ); nd.CopyRange( temp, 0, MAX_NOTE_ROW, iStartIndex + iRowsToAdd ); + nd.RevalidateATIs(vector(), false); } void NoteDataUtil::DeleteRows( NoteData &nd, int iStartIndex, int iRowsToDelete ) @@ -2452,6 +2480,7 @@ void NoteDataUtil::DeleteRows( NoteData &nd, int iStartIndex, int iRowsToDelete temp.CopyRange( nd, iStartIndex + iRowsToDelete, MAX_NOTE_ROW ); nd.ClearRange( iStartIndex, MAX_NOTE_ROW ); nd.CopyRange( temp, 0, MAX_NOTE_ROW, iStartIndex ); + nd.RevalidateATIs(vector(), false); } void NoteDataUtil::RemoveAllTapsOfType( NoteData& ndInOut, TapNote::Type typeToRemove ) @@ -2470,6 +2499,7 @@ void NoteDataUtil::RemoveAllTapsOfType( NoteData& ndInOut, TapNote::Type typeToR ++iter; } } + ndInOut.RevalidateATIs(vector(), false); } void NoteDataUtil::RemoveAllTapsExceptForType( NoteData& ndInOut, TapNote::Type typeToKeep ) @@ -2485,6 +2515,7 @@ void NoteDataUtil::RemoveAllTapsExceptForType( NoteData& ndInOut, TapNote::Type ++iter; } } + ndInOut.RevalidateATIs(vector(), false); } int NoteDataUtil::GetMaxNonEmptyTrack( const NoteData& in )