org.basex.util.History Maven / Gradle / Ivy
package org.basex.util;
/**
* This class stores strings in a history.
*
* @author BaseX Team 2005-22, BSD License
* @author Christian Gruen
*/
public final class History {
/** Maximum size for storing entries in a history (currently: 10 MB). */
private static final int MAXBYTES = 10000000;
/** Maximum number of entries to be stored. */
private static final int MAX = 1024;
/** Text history. */
private final byte[][] hist;
/** Caret history. */
private final int[] caret;
/** Active flag. */
private final boolean active;
/** Maximum of stored entries. */
private int max;
/** History position. */
private int pos;
/** Save position. */
private int saved;
/**
* Constructor.
* @param text initial text
*/
public History(final byte[] text) {
active = text != null;
if(active) {
caret = new int[MAX];
hist = new byte[MAX][];
init(text);
} else {
caret = null;
hist = null;
}
}
/**
* Initializes the history with a text.
* @param text initial text
*/
public void init(final byte[] text) {
hist[0] = text;
pos = 0;
max = 0;
}
/**
* Indicates if the history is active.
* @return result of check
*/
public boolean active() {
return active;
}
/**
* Checks if the history points to the first entry.
* @return result of check
*/
public boolean first() {
return pos == 0;
}
/**
* Checks if the history points to the last entry.
* @return result of check
*/
public boolean last() {
return pos == max;
}
/**
* Returns the previous string and decreases the pointer, or returns {@code null}.
* @return previous string or {@code null}
*/
public byte[] prev() {
return pos > 0 ? hist[--pos] : null;
}
/**
* Returns the next string and increases the pointer, or returns {@code null}.
* @return previous string or {@code null}
*/
public byte[] next() {
return pos < max ? hist[++pos] : null;
}
/**
* Returns the caret position.
* @return caret position
*/
public int caret() {
return caret[pos];
}
/**
* Stores a string in the history.
* @param str string to be stored
* @param oc old caret position
* @param nc new caret position
*/
public void store(final byte[] str, final int oc, final int nc) {
if(!active || str == hist[pos] || Token.eq(str, hist[pos])) return;
// merge consecutive character inputs without deletions
int len = str.length;
if(pos > 0 && saved != pos && caret[pos] == oc && oc + 1 == nc && hist[pos - 1].length < len) {
hist[pos] = str;
caret[pos] = nc;
return;
}
// summarize and limit size of new and existing entries
int off = pos + 1;
for(; off > 0 && len < MAXBYTES; off--) len += hist[off - 1].length;
// enough space: limit number of entries
if(off == 0 && pos + 1 == MAX) off = 1;
// remove entries
if(off > 0) {
Array.remove(hist, 0, off, MAX);
Array.remove(caret, 0, off, MAX);
saved -= off;
pos -= off;
}
// save new entry
if(pos >= 0) caret[pos] = oc;
if(saved > pos) saved = -1;
max = ++pos;
hist[pos] = str;
caret[pos] = nc;
// remove old entries to save memory
for(int p = pos + 1; p < MAX; p++) hist[p] = null;
}
/**
* Sets the saved position.
*/
public void save() {
saved = pos;
}
/**
* Checks if the file has been modified.
* @return result of check
*/
public boolean modified() {
return saved != pos;
}
}