CStrLineIterator クラスを導入して listbox を高速化

CStrNote で行頭位置をキャッシュするパッチが投稿されていました。 listbox が高速になっていい感じなんですが、 note 系命令を使ったプログラムは逆に遅くなってしまいます。これは CStrNote::Select が呼ばれるたびにキャッシュを作っていて、しかも各種 note 系命令を呼び出したときには毎回 CStrNote::Select を呼ぶからかなと思います。

そこで、 CStrNote には触らず新しく CStrLineIterator クラスを作って listbox の処理にはそれを使うようにしてみました。

Index: strnote.cpp
===================================================================
--- strnote.cpp	(リビジョン 164)
+++ strnote.cpp	(作業コピー)
@@ -240,3 +240,62 @@
 	return 0;
 }
 
+//------------------------------------------------------------//
+/*
+	CStrLineIterator
+*/
+//------------------------------------------------------------//
+
+CStrLineIterator::CStrLineIterator( char *str )
+{
+	this->str = str;
+	offset = 0;
+}
+
+
+CStrLineIterator::~CStrLineIterator()
+{
+}
+
+bool CStrLineIterator::hasNext()
+{
+	return str[offset] != '\0';
+}
+
+int CStrLineIterator::next( char *dest, int len )
+{
+	int i = 0;
+	bool over = false;
+	while(1) {
+		char c = str[offset];
+		if( c == '\0' ) {
+			break;
+		}
+#ifdef HSPLINUX
+		if( c == '\n' ) {
+			offset ++;
+			break;
+		}
+#endif
+		if( c == '\r' ) {
+			offset ++;
+			if( str[offset] == '\n' ) {
+				offset ++;
+			}
+			break;
+		}
+		if( i < len ) {
+			dest[i] = c;
+		} else {
+			over = true;
+		}
+		i ++, offset ++;
+	}
+	if( over ) {
+		return -1;
+	}
+	if( i < len ) {
+		dest[i] = '\0';
+	}
+	return i;
+}
Index: strnote.h
===================================================================
--- strnote.h	(リビジョン 164)
+++ strnote.h	(作業コピー)
@@ -31,4 +31,17 @@
 	char nulltmp[4];
 };
 
+//------------------------------------------------------------//
+
+class CStrLineIterator {
+public:
+	CStrLineIterator( char *str );
+	~CStrLineIterator();
+	bool hasNext();
+	int next( char *dest, int len );
+private:
+	char *str;
+	int offset;
+};
+
 #endif
Index: win32gui/hspwnd_obj.cpp
===================================================================
--- win32gui/hspwnd_obj.cpp	(リビジョン 164)
+++ win32gui/hspwnd_obj.cpp	(作業コピー)
@@ -161,16 +161,16 @@
 
 static void Object_SetMultiBox( HSPOBJINFO *info, int type, void *ptr )
 {
-	int i,max;
+	int i;
 	char res[256];
 	UINT m_ini,m_add;
 	HWND hw;
-	CStrNote note;
 
 	hw = info->hCld;
 
 	switch( type ) {
-	case TYPE_STRING:
+	case TYPE_STRING:{
+		CStrLineIterator iterator( (char *)ptr );
 		if ( info->owid ) {
 			m_ini=CB_RESETCONTENT;
 	        m_add=CB_ADDSTRING;
@@ -178,14 +178,14 @@
 			m_ini=LB_RESETCONTENT;
 			m_add=LB_ADDSTRING;
 		}
-		note.Select( (char *)ptr );
-		max = note.GetMaxLine();
 		SendMessage( hw, m_ini, 0, 0L );
-		for( i=0;i<max;i++ ) {
-			note.GetLine( res, i, 255 );
+		while ( iterator.hasNext() ) {
+			iterator.next( res, sizeof res );
+			res[sizeof res-1] = '\0';
 			SendMessage( hw, m_add, 0, (long)res );
 		}
 		break;
+	}
 	case TYPE_INUM:
 		if ( info->owid ) {
 			m_ini=CB_SETCURSEL;

で、以下のスクリプトを素の OpenHSP 、>>525 のパッチを当てた OpenHSP 、 私の CStrLineIterator のパッチを当てた OpenHSP で速度比較してみました。
listbox の処理と noteget ですべての行をなめる処理が入ったスクリプトです。

n = 50000
gosub *build

gsel 0, 1
wait 10

#uselib "winmm"
#cfunc d3timer "timeGetTime"
time = d3timer()
listbox x, 100, a
time = d3timer() - time
pos 70, 0
mes time

wait 100

n = 5000
gosub *build

time = d3timer()
notesel a
repeat notemax
	noteget t, cnt
loop
time = d3timer() - time
mes time

stop

*build
	#define ctype format(%1) strf("%%05d\n", %1)
	sdim a, n * strlen(format(0)) + 1
	i = 0
	repeat n
		poke a, i, format(cnt)
		i += strsize
	loop
	return

結果は以下。