ReadLine が戻れない
(会社で)暇なので、暇つぶしにコンパイル結果の逆アセンブル出力のアセンブリ命令のニモニックの数値をシンボル名に置き換えるフィルタとかを作ってたりする。V850の命令は比較的美しいけど、SHの命令は変態的でやりにくい。
ファイルから1行読み込むのは ReadStream.ReadLine が面倒臭くないんだけど、ポジションを変更できないのが困り物。そもそも、ポジションを変えられないのが分かりにくい。目立つ所に書いとけちゅーねん。
用途的に使いやすいように ReadLine を作り直した。
(会社で)作り終わらなかったので、家に帰って来て一から作り直した。
っていうか、コーディング嫌いやっちゅーねん。
using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; namespace hoge { /// <summary> /// ReadLine メソッドで読み込むポジションを後戻りできるように拡張した。 /// 元の StreamReader の ReadLine は ポジションを移動できない。 /// PopPositionメソッド を呼び出した後 ReadLineメソッド を呼び出すと、 /// PushPositionメソッド を呼び出したポジションから読み込む。(ように見せかける。) /// /// FileStream クラスを拡張して、ReadLineメソッドを実装した方が楽だったのでは…。 /// </summary> class StreamReaderPushPop : StreamReader { /// <summary> /// PopPosition を呼び出して先読みしているか /// </summary> private enum Reader { /// <summary> /// 先読みではない(通常の読み込み) /// </summary> Main, /// <summary> /// 先読み /// </summary> Recon }; private int currentReader = (int)Reader.Main; private bool [] isReadingCache = { false, false }; private int nextReadCacheLineNumber = 0; private int pushedCacheLineNumber = 0; private int cacheLineNumber = 0; /// <summary> /// 先読みした行を溜めておくためのストレージ /// </summary> private Hashtable lineCache; /// <summary> /// 指定したストリーム用の StreamReaderPushPop クラスの新しいインスタンスを初期化します。 /// </summary> /// <param name="fs">このクラスで扱うファイルストリーム</param> /// <exception cref="System.ArgumentException"></exception> /// <exception cref="System.ArgumentNullException"></exception> public StreamReaderPushPop(FileStream fs) : base(fs) { lineCache = new Hashtable(); } /// <summary> /// EndOfStream /// </summary> /// <exception cref="System.ObjectDisposeException">基底クラスの EndOfStream が発生させる例外</exception> public new bool EndOfStream { get { if (isReadingCache[currentReader] == true) { // キャッシュしたデータを読みこんでいる内は、EndOfStream ではない。 return false; } else { return base.EndOfStream; } } } /// <summary> /// 読み込み再開位置をプッシュする。 /// プッシュは高々1回のみ。ネストが必要なら拡張すること。 /// </summary> /// <returns>プッシュ成功 : true, プッシュ失敗(既にプッシュ済み) : false</returns> public bool PushPosition() { bool result = false; if (currentReader == (int)Reader.Main) { currentReader = (int)Reader.Recon; result = true; if (nextReadCacheLineNumber < cacheLineNumber) { isReadingCache[(int)Reader.Recon] = true; pushedCacheLineNumber = nextReadCacheLineNumber; } else { isReadingCache[(int)Reader.Recon] = false; cacheLineNumber = 0; // 行キャッシュ数 0 pushedCacheLineNumber = 0; } } else { // 既にプッシュ済み。 } return result; } /// <summary> /// 読み込み再開位置をポップする。 /// </summary> /// <returns>プッシュ成功 : true, プッシュ失敗(既にプッシュ済み) : false</returns> public bool PopPosition() { bool result = false; if (currentReader == (int)Reader.Recon) { nextReadCacheLineNumber = pushedCacheLineNumber; if (nextReadCacheLineNumber < cacheLineNumber) { isReadingCache[(int)Reader.Main] = true; } currentReader = (int)Reader.Main; result = true; } else { // プッシュされていない。 } return result; } /// <summary> /// 1行を読み込んで返すメソッドの ReadLine のオーバーライド。 /// </summary> /// <returns>読み込んだ文字列</returns> /// <exception cref="System.OutOfMemoryException">基底クラスの ReadLine が発生させる例外</exception> /// <exception cref="System.IO.IOException">基底クラスの ReadLine が発生させる例外</exception> public override string ReadLine() { string line; int sleeper; sleeper = (int)Reader.Recon; if (currentReader == (int)Reader.Recon) { sleeper = (int)Reader.Main; } else { // sleeper = (int)Reader.Sub; } if (isReadingCache[currentReader] == true) { line = (string)lineCache[nextReadCacheLineNumber]; nextReadCacheLineNumber++; if (nextReadCacheLineNumber >= cacheLineNumber) { isReadingCache[currentReader] = false; if (isReadingCache [sleeper]== false) { lineCache.Clear(); } } else { } } else { line = base.ReadLine(); if (currentReader == (int)Reader.Recon) { lineCache[cacheLineNumber] = line; cacheLineNumber++; } } return line; } /// <summary> /// Peekメソッド のオーバーライド。 /// 読み取り可能な次の文字を返しますが、その文字は使用されません。 /// </summary> /// <returns>読みとり可能な次の文字</returns> /// <exception cref="System.IO.IOException">基底クラスの Peek が発生させる例外</exception> public override int Peek() { if (isReadingCache[currentReader] == true) { return ((string)lineCache[nextReadCacheLineNumber])[0]; } else { return base.Peek(); } } } }