ProcessSmartTabsの最適化

概要

タブ文字をホワイトスペースに置換する関数を最適化する。
別にそんなにボトルネックになっている箇所ではないが、見るからに非効率そうだったので私でも多少は改善できそうだ。
ということでトライしてみた。

Before

dp.sh.Highlighter.prototype.ProcessSmartTabs = function(code)
{
	var lines	= code.split('\n');
	var result	= '';
	var tabSize	= 4;
	var tab		= '\t';

	function InsertSpaces(line, pos, count)
	{
		var left	= line.substr(0, pos);
		var right	= line.substr(pos + 1, line.length);
		var spaces	= '';
		
		for(var i = 0; i < count; i++)
			spaces += ' ';
		
		return left + spaces + right;
	}

	function ProcessLine(line, tabSize)
	{
		if(line.indexOf(tab) == -1)
			return line;

		var pos = 0;

		while((pos = line.indexOf(tab)) != -1)
		{
			var spaces = tabSize - pos % tabSize;
			
			line = InsertSpaces(line, pos, spaces);
		}
		
		return line;
	}

	for(var i = 0; i < lines.length; i++)
		result += ProcessLine(lines[i], tabSize) + '\n';
	
	return result;
}

After

dp.sh.Highlighter.prototype.ProcessSmartTabs = function(code) {
	var lines	= code.split('\n');
	var tabSize	= 4;
	var sptab = [""," ","  ","   ","    "];
	var t		= '\t';

	function ProcessLine(line, tabSize) {
		var pos = 0;
		while((pos = line.indexOf(t,pos)) != -1)
			line = line.substr(0, pos)+sptab[tabSize - pos % tabSize]+line.substr(pos + 1);

		return line;
	}

	for(var i = 0; i < lines.length; i++)
		lines[i] = ProcessLine(lines[i], tabSize);

	return lines.join("\n")+"\n";
}

感想

例によってWitchGarden側に詳細は記載している。
http://tsuge.astgate.biz/witchgarden/?dp%2esyntaxhighlighter%2f%ba%c7%c5%ac%b2%bd%c8%c7%a4%ce%ba%ee%c0%ae
resultをlines.joinに変えるだけで結構速くなるはず。
基本的にスクリプト型の言語はネイティブコードを呼ぶようにした方が速いので(当然だが)、劇的な速度アップが望めるのはjoinくらい。他は処理速度を上げるより、ソースコード量減量程度がメインだろう。一応少しは上げたつもりだが。
ものっそい気にいらないのはココ。

		while((pos = line.indexOf(t,pos)) != -1)
			line = line.substr(0, pos)+sptab[tabSize - pos % tabSize]+line.substr(pos + 1);

場合によっては結構膨大なバッファを持つStringを三つ生成。しかも一行につきtab文字数分生成と破壊を繰り返す。うーむ・・。
行頭だけは別処理に分ければ最適化されるか、なんて思ったりもしたが、Web公開型ソースでそんなにタブらないだろうと思って結局やめておいた。
line.replace("\t",[""," "," "," "," "],添え字はtabSize-index%tabSize)
なんて書けたらいいんだけど・・。
ふぅ、頭の良くなる薬が欲しいもんだ。

2006/08/16 追記

仕様確認漏れで、最後の一行が出力されなくなっていたので修正。
Before

	return lines.join("\n");

After

	return lines.join("\n")+"\n";

なんでやねんと思いつつ・・。