問題

問11 次のJavaプログラムの説明及びプログラムを読んで,設問に答えよ。 (Javaプログラムで使用するAPIの説明は,この冊子の末尾を参照してください。)

〔プログラムの説明〕
 ギャップバッファを利用した簡易テキストエディタである。

 ギャップバッファとは,編集対象となる文字列の編集箇所に空き領域を作り,そこに文字を挿入する機構をもつバッファのことである。一般に,テキストの編集時には,文字の挿入,削除などの変更は局所的に集中することが多く,編集箇所にあらかじめ空き領域を作っておくと効率よく変更を行うことができるという利点がある。ギャップバッファ内の空き領域をギャップといい,ギャップバッファ内の文字列をテキストという。ここで,ギャップは,ギャップバッファ内に一つしか存在しない。ただし,文字の挿入によって,ギャップがない状態になる場合がある。

 テキストの表示イメージとギャップバッファを図1に示す(網掛けの部分がギャップである)。

 クラス GapBuffer はギャップバッファの機能を実現する。このクラスの使用者は,テキストを仮想的に連続する文字列として扱うことができ,ギャップの位置やサイズを意識せずに文字の挿入や削除の処理を行う。このとき,図1(1)のように各文字はオフセット値(offset)で指定し,テキストの最初の文字はオフセット値0,テキストの最後の文字はオフセット値“テキストの文字数-1”で指定する。

 図1(2)は,配列buffer内におけるテキストの物理的な表現の例である。フィールドgapOffsetとgapSizeは,それぞれギャップの先頭位置とギャップのサイズを表す。

 図1(2)の状態から“プログラム”と“説明”の間に“の”を挿入する手順を図2に示す。

 まず,“プロ”の直後に“グラム”を移動することで,ギャップを“プログラム”と“説明”の間に移動する(図2(2))。ギャップの先頭に“の”を格納する(図2(3))。この操作によって,ギャップのサイズは1文字分小さくなり,ギャップの先頭位置は1文字分後ろへずれる。

 次に,図2(3)の状態から“プログラムの”の“グ”を削除する手順を図3に示す。

 まず,“ラムの”を“説明”の直前に移動することで,ギャップを“プログ”と“ラムの説明”の間に移動する(図3(2))。ギャップの先頭位置を1文字分前にずらし,ギャップのサイズを 1 文字分増やす(図3(3))。

 クラスGapBufferは,次のコンストラクタ及びメソッドをもつ。

(1)コンストラクタは引数initialTextで指定された文字列をテキストの初期値としてギャップバッファを生成する。ギャップは,テキストの前に作られる。

(2)メソッドinsertは,メソッドconfirmGapを呼んで引数offsetの位置にギャップを移動した上で,引数offsetで指定された位置に,引数chで指定された文字を挿入する。

(3)メソッドdeleteは,引数offsetで指定された位置にある文字を削除する。テキストがない場合は,何もしない。

(4)メソッドcharAtは,引数offsetで指定された位置の文字を返す。

(5)メソッドlengthは,テキストの文字数を返す。

(6)メソッドconfirmGapは,配列bufferにおいて引数newGapOffsetで与えられた位置に1文字以上のギャップがあるようにする。必要であればギャップを指定された位置に移動し,ギャップがない場合は,新たにギャップを作る。

 なお,このクラスの各メソッドが呼び出されるとき,引数は正しいものとする。

 クラスEditorは,GapBufferを利用して,簡易テキストエディタを実現する。メソッドmainに与えられた最初の引数をテキストの初期値とする。カーソルは,文字の間にあり,カーソルの位置はオフセット値で表し,フィールドcursorに保持される。例えば,図4のようにカーソルが“プロ”と“グラム”の間にあるとき,cursorの値は2である。カーソルがテキストの末尾にあるとき,cursorの値はテキストの文字数と同じであり,テキストがないとき,cursorの値は0である。

 文字の入力は,外部で与えられるクラスCharReaderで行う。メソッドgetは,ターミナルから1文字ずつ読み込む。CharReaderには,次の制御文字が定義されている。制御文字以外の文字が入力されたときは,カーソルの位置に文字を挿入し,カーソルを1文字分進める。

1.CharReader.MOVE_FORWARD
 カーソルを1文字分進める。カーソルがテキストの末尾にあるときは,無視する。
2.CharReader.MOVE_BACKWARD
 カーソルを1文字分戻す。カーソルがテキストの先頭にあるときは,無視する。
3.CharReader.DELETE
 カーソルの直後の1文字を削除する。カーソルがテキストの末尾にあるときは,無視する。
4.CharReader.EOF
 エディタを終了する。

 ギャップバッファの内容の表示は,外部で与えられるクラスDisplayで行う。メソッドoutputは,GapBufferのメソッドcharAtを呼び出してギャップバッファのテキストを取得する。