/** * Represents a single line of text (i.e., with no newlines) and allows new * characters to be inserted at any point in middle. */ public class TextLine { // RI: prefix != null and suffix != null and // 0 <= prefixLen < prefix.length and // 0 <= suffixLen < suffix.length // AF(this) = prefix[0..prefixLen-1] + reverse(suffix[0..suffixLen-1]) private char[] prefix, suffix; private int prefixLen, suffixLen; /** @effects makes this an empty line */ public TextLine() { prefix = new char[3]; suffix = new char[3]; } /** @returns length of this */ public int getLength() { return prefixLen + suffixLen; } /** @returns this (as a string) */ public String getText() { StringBuilder buf = new StringBuilder(); buf.append(prefix, 0, prefixLen); // Inv: buf = prefix[0..prefixLen-1] + reverse(suffix[i+1..suffixLen-1]) for (int i = suffixLen - 1; i >= 0; i--) buf.append(suffix[i]); return buf.toString(); } /** @requires 0 <= col <= length * @modifies this * @effects this_post = this_pre[0..col-1] + ch + this_pre[col..] */ public void insert(int col, char ch) { moveSplitTo(col); prefix = ensureSpace(prefix, prefixLen + 1); prefix[prefixLen] = ch; prefixLen += 1; checkRep(); } /** @requires 0 <= col < length * @modifies this * @effects this_post = this_pre[0..col-1] + this_pre[col+1..] */ public void remove(int col) { moveSplitTo(col); suffixLen--; checkRep(); } /** @requires 0 <= col <= length * @modifies this * @effects this is unchanged and prefixLen = col */ private void moveSplitTo(int col) { if (prefixLen > col) { suffix = ensureSpace(suffix, prefixLen + suffixLen - col); do { // Inv: this is unchanged suffix[suffixLen++] = prefix[--prefixLen]; } while (prefixLen > col); } else if (prefixLen < col) { prefix = ensureSpace(prefix, col); do { // Inv: this is unchanged prefix[prefixLen++] = suffix[--suffixLen]; } while (prefixLen < col); } else { // split is already in the right place } } /** @returns an array containing the same chars plus any padding necessary to * make the length at least len */ private static char[] ensureSpace(char[] chars, int len) { if (len <= chars.length) { return chars; } else { char[] newChars = new char[Math.max(len, 2 * chars.length)]; System.arraycopy(chars, 0, newChars, 0, chars.length); return newChars; } } /** Checks that RI holds. */ private void checkRep() { assert prefix != null; assert suffix != null; assert 0 <= prefixLen && prefixLen < prefix.length; assert 0 <= suffixLen && suffixLen < suffix.length; } }