Split out LoadFromSMNoteDataStringWithPlayer(). This fills out the NoteData without making any copies of sSMNoteData. Previously, this portion of the code copied the full string twice, once when splitting for measures and once when splitting for lines.

Only make a single copy of the string in LoadFromSMNoteDataString() when stripping out comments. Previously, the string was copied as many times as there were comments. Now, the whole loading can happen with a single copy of the data.
This commit is contained in:
Steve Checkoway
2006-06-20 13:34:28 +00:00
parent 3ee5991c25
commit fff087a76b
2 changed files with 99 additions and 56 deletions
+85 -42
View File
@@ -7,6 +7,7 @@
#include "GameState.h" #include "GameState.h"
#include "RadarValues.h" #include "RadarValues.h"
#include "Foreach.h" #include "Foreach.h"
#include <utility>
NoteType NoteDataUtil::GetSmallestNoteTypeForMeasure( const NoteData &n, int iMeasureIndex ) NoteType NoteDataUtil::GetSmallestNoteTypeForMeasure( const NoteData &n, int iMeasureIndex )
{ {
@@ -46,54 +47,61 @@ NoteType NoteDataUtil::GetSmallestNoteTypeForMeasure( const NoteData &n, int iMe
return nt; return nt;
} }
void NoteDataUtil::LoadFromSMNoteDataString( NoteData &out, RString sSMNoteData ) static void LoadFromSMNoteDataStringWithPlayer( NoteData& out, const RString &sSMNoteData, int start,
int len, PlayerNumber pn, int iNumTracks )
{ {
// /* Don't allocate memory for the entire string, nor per measure. Instead, use the in-place
// Load note data * partial string split twice. By maintaining begin and end pointers to each measure line
// * we can perform this without copying the string at all. */
int size = -1;
/* Clear notes, but keep the same number of tracks. */ const int end = start + len;
int iNumTracks = out.GetNumTracks(); vector<pair<const char *, const char *> > aMeasureLines;
out.Init(); for( unsigned m = 0; true; ++m )
out.SetNumTracks( iNumTracks );
{ {
RString::size_type iIndexCommentStart = 0; /* XXX Ignoring empty seems wrong for measures. It means that ",,," is treated as
* "," where I would expect most people would want 2 empty measures. ",\n,\n,"
* would do as I would expect. */
split( sSMNoteData, ",", start, size, end, true ); // Ignore empty is important.
if( start == end )
break;
while( (iIndexCommentStart = sSMNoteData.find("//", iIndexCommentStart)) != RString::npos ) // Partial string split.
int measureLineStart = start, measureLineSize = -1;
const int measureEnd = start + size;
aMeasureLines.clear();
while( true )
{ {
RString::size_type iIndexCommentEnd = sSMNoteData.find( "\n", iIndexCommentStart ); // Ignore empty is clearly important here.
sSMNoteData.erase( iIndexCommentStart, iIndexCommentEnd - iIndexCommentStart ); split( sSMNoteData, "\n", measureLineStart, measureLineSize, measureEnd, true );
if( measureLineStart == measureEnd )
break;
//RString &line = sSMNoteData.substr( measureLineStart, measureLineSize );
const char *beginLine = sSMNoteData.data() + measureLineStart;
const char *endLine = beginLine + measureLineSize;
while( beginLine < endLine && strchr("\r\n\t ", *beginLine) )
++beginLine;
while( endLine > beginLine && strchr("\r\n\t ", *(endLine - 1)) )
--endLine;
if( beginLine < endLine ) // nonempty
aMeasureLines.push_back( pair<const char *, const char *>(beginLine, endLine) );
} }
}
vector<RString> asMeasures; for( unsigned l=0; l<aMeasureLines.size(); l++ )
split( sSMNoteData, ",", asMeasures, true ); // ignore empty is important
for( unsigned m=0; m<asMeasures.size(); m++ ) // foreach measure
{
RString &sMeasureString = asMeasures[m];
TrimLeft( sMeasureString );
TrimRight( sMeasureString );
vector<RString> asMeasureLines;
split( sMeasureString, "\n", asMeasureLines, true ); // ignore empty is important
for( unsigned l=0; l<asMeasureLines.size(); l++ )
{ {
RString &sMeasureLine = asMeasureLines[l]; //RString &sMeasureLine = asMeasureLines[l];
TrimLeft( sMeasureLine ); const char *p = aMeasureLines[l].first;
TrimRight( sMeasureLine ); const char *const beginLine = p;
const char *const endLine = aMeasureLines[l].second;
const float fPercentIntoMeasure = l/(float)asMeasureLines.size(); const float fPercentIntoMeasure = l/(float)aMeasureLines.size();
const float fBeat = (m + fPercentIntoMeasure) * BEATS_PER_MEASURE; const float fBeat = (m + fPercentIntoMeasure) * BEATS_PER_MEASURE;
const int iIndex = BeatToNoteRow( fBeat ); const int iIndex = BeatToNoteRow( fBeat );
// if( m_iNumTracks != sMeasureLine.GetLength() ) //const char *p = sMeasureLine;
// RageException::Throw( "Actual number of note columns (%d) is different from the StepsType (%d).", m_iNumTracks, sMeasureLine.GetLength() );
const char *p = sMeasureLine;
int iTrack = 0; int iTrack = 0;
while( iTrack < iNumTracks && *p ) while( iTrack < iNumTracks && p < endLine )
{ {
TapNote tn; TapNote tn;
char ch = *p; char ch = *p;
@@ -112,7 +120,7 @@ void NoteDataUtil::LoadFromSMNoteDataString( NoteData &out, RString sSMNoteData
} }
/* Set the hold note to have infinite length. We'll clamp it when /* Set the hold note to have infinite length. We'll clamp it when
* we hit the tail. */ * we hit the tail. */
tn.iDuration = MAX_NOTE_ROW; tn.iDuration = MAX_NOTE_ROW;
break; break;
case '3': case '3':
@@ -121,7 +129,8 @@ void NoteDataUtil::LoadFromSMNoteDataString( NoteData &out, RString sSMNoteData
int iHeadRow; int iHeadRow;
if( !out.IsHoldNoteAtRow( iTrack, iIndex, &iHeadRow ) ) if( !out.IsHoldNoteAtRow( iTrack, iIndex, &iHeadRow ) )
{ {
LOG->Warn( "Unmatched 3 in \"%s\"", sMeasureLine.c_str() ); int n = intptr_t(endLine) - intptr_t(beginLine);
LOG->Warn( "Unmatched 3 in \"%.*s\"", n, beginLine );
} }
else else
{ {
@@ -133,7 +142,7 @@ void NoteDataUtil::LoadFromSMNoteDataString( NoteData &out, RString sSMNoteData
/* This won't write tn, but keep parsing normally anyway. */ /* This won't write tn, but keep parsing normally anyway. */
break; break;
} }
// case 'm': // case 'm':
// Don't be loose with the definition. Use only 'M' since // Don't be loose with the definition. Use only 'M' since
// that's what we've been writing to disk. -Chris // that's what we've been writing to disk. -Chris
case 'M': tn = TAP_ORIGINAL_MINE; break; case 'M': tn = TAP_ORIGINAL_MINE; break;
@@ -150,7 +159,7 @@ void NoteDataUtil::LoadFromSMNoteDataString( NoteData &out, RString sSMNoteData
} }
p++; p++;
// We won't scan past the end of the line so these are safe to do.
#if 0 #if 0
// look for optional attack info (e.g. "{tipsy,50% drunk:15.2}") // look for optional attack info (e.g. "{tipsy,50% drunk:15.2}")
if( *p == '{' ) if( *p == '{' )
@@ -167,7 +176,7 @@ void NoteDataUtil::LoadFromSMNoteDataString( NoteData &out, RString sSMNoteData
} }
// skip past the '}' // skip past the '}'
while( *p ) while( p < endLine )
{ {
if( *(p++) == '}' ) if( *(p++) == '}' )
break; break;
@@ -187,7 +196,7 @@ void NoteDataUtil::LoadFromSMNoteDataString( NoteData &out, RString sSMNoteData
} }
// skip past the ']' // skip past the ']'
while( *p ) while( p < endLine )
{ {
if( *(p++) == ']' ) if( *(p++) == ']' )
break; break;
@@ -198,7 +207,10 @@ void NoteDataUtil::LoadFromSMNoteDataString( NoteData &out, RString sSMNoteData
* to remove anything in this position. We know that there's nothing * to remove anything in this position. We know that there's nothing
* there, so avoid the search. */ * there, so avoid the search. */
if( tn.type != TapNote::empty && ch != '3' ) if( tn.type != TapNote::empty && ch != '3' )
{
tn.pn = pn;
out.SetTapNote( iTrack, iIndex, tn ); out.SetTapNote( iTrack, iIndex, tn );
}
iTrack++; iTrack++;
} }
@@ -224,6 +236,37 @@ void NoteDataUtil::LoadFromSMNoteDataString( NoteData &out, RString sSMNoteData
begin = next; begin = next;
} }
} }
}
void NoteDataUtil::LoadFromSMNoteDataString( NoteData &out, const RString &sSMNoteData_ )
{
//
// Load note data
//
RString sSMNoteData;
RString::size_type iIndexCommentStart = 0;
RString::size_type iIndexCommentEnd = 0;
RString::size_type origSize = sSMNoteData_.size();
const char *p = sSMNoteData_.data();
sSMNoteData.reserve( origSize );
while( (iIndexCommentStart = sSMNoteData.find("//", iIndexCommentEnd)) != RString::npos )
{
sSMNoteData.append( p, iIndexCommentStart - iIndexCommentEnd );
p += iIndexCommentStart - iIndexCommentEnd;
iIndexCommentEnd = sSMNoteData.find( "\n", iIndexCommentStart );
iIndexCommentEnd = (iIndexCommentEnd == RString::npos ? origSize : iIndexCommentEnd+1);
p += iIndexCommentEnd - iIndexCommentStart;
}
sSMNoteData.append( p, origSize - iIndexCommentEnd );
/* Clear notes, but keep the same number of tracks. */
int iNumTracks = out.GetNumTracks();
out.Init();
out.SetNumTracks( iNumTracks );
LoadFromSMNoteDataStringWithPlayer( out, sSMNoteData, 0, sSMNoteData.size(), PLAYER_INVALID, iNumTracks );
} }
void NoteDataUtil::InsertHoldTails( NoteData &inout ) void NoteDataUtil::InsertHoldTails( NoteData &inout )
+1 -1
View File
@@ -17,7 +17,7 @@ struct RadarValues;
namespace NoteDataUtil namespace NoteDataUtil
{ {
NoteType GetSmallestNoteTypeForMeasure( const NoteData &n, int iMeasureIndex ); NoteType GetSmallestNoteTypeForMeasure( const NoteData &n, int iMeasureIndex );
void LoadFromSMNoteDataString( NoteData &out, RString sSMNoteData ); void LoadFromSMNoteDataString( NoteData &out, const RString &sSMNoteData );
void GetSMNoteDataString( const NoteData &in, RString &notes_out ); void GetSMNoteDataString( const NoteData &in, RString &notes_out );
void LoadTransformedSlidingWindow( const NoteData &in, NoteData &out, int iNewNumTracks ); void LoadTransformedSlidingWindow( const NoteData &in, NoteData &out, int iNewNumTracks );
void LoadOverlapped( const NoteData &in, NoteData &out, int iNewNumTracks ); void LoadOverlapped( const NoteData &in, NoteData &out, int iNewNumTracks );