package BigString import ErrorHandling public constant BIG_SUBSTRING_LEN = 450 public constant MAX_SUBSTRINGS = 25 // Lazily evaluated substring public class BigSubString private BigString parent = null BigSubString next = null private int start = 0 int length = 0 private string preinit = null construct(string preInit) this.preinit = preInit this.length = preinit.length() construct(BigString parent, int start, int length) this.parent = parent this.start = start this.length = length function getSingleLength() returns int return length function getCombinedLength() returns int if next != null and next != this return length + next.getCombinedLength() return length function getStart() returns int return start function substring(int offset, int length) returns BigSubString return new BigSubString(parent, start+offset, length) function split(int offset) returns BigSubString length = offset return new BigSubString(parent, offset, length-offset) function getSingle() returns string if getSingleLength() > BIG_SUBSTRING_LEN error("cannot use getSingle on oversized SubStrings. You need to iterate through the chunks") if parent == null and preinit == null error("cannot generate new cache without parent") if preinit != null return preinit else return parent.getSubStringData(this) function getCombined() returns string if getCombinedLength() > BIG_SUBSTRING_LEN error("cannot use getCombined on oversized SubStrings. You need to iterate through the chunks") if parent == null and preinit == null error("cannot generate new cache without parent") var s = "" if preinit != null s += preinit else s += parent.getSubStringData(this) if next != null s += next.getCombined() return s function concat(BigSubString next) returns BigSubString if next == null error("null") var t = this while t.next != null t = t.next t.next = next return this function addToBigString(BigString target) if preinit != null target.addString(preinit) else int off = 0 while length-off > BIG_SUBSTRING_LEN target.addString(parent.getString(start + off, BIG_SUBSTRING_LEN)) off += BIG_SUBSTRING_LEN target.addString(parent.getString(start + off, length-off)) if next != null next.addToBigString(target) function equals(BigSubString other) returns boolean return this.parent == other.parent and this.getCombinedLength() == other.getCombinedLength() and this.start == other.getStart() function hash() returns int int hash = (parent castTo int) * 100000 let len = getCombinedLength() let off = start hash += len * 17 hash += off * 11 return hash ondestroy length = -1 public class BigString private string array[MAX_SUBSTRINGS] substrings private int length = 0 int startoffset = 0 construct() reset() construct(string initial) reset() addString(initial) function reset() for i = 0 to MAX_SUBSTRINGS-1 substrings[i] = "" length = 0 startoffset = 0 function asSubstring() returns BigSubString return new BigSubString(this, 0, length) function getLength() returns int return length-startoffset function addBigString(BigString add) for i = 0 to MAX_SUBSTRINGS-1 if add.substrings[i].length() <= 0 break addString(add.substrings[i]) function addSubString(BigSubString substring) substring.addToBigString(this) function substring(int offset, int length) returns BigSubString return new BigSubString(this, offset, length) function charAt(int offset) returns BigSubString return new BigSubString(this, offset, 1) function addString(string sp) if sp.length() > BIG_SUBSTRING_LEN error("adding too long string") var idx = (getLength() / BIG_SUBSTRING_LEN).toInt() if substrings[idx].length() + sp.length() > BIG_SUBSTRING_LEN let off = BIG_SUBSTRING_LEN-substrings[idx].length() substrings[idx] += sp.substring(0, off) idx++ substrings[idx] += sp.substring(off) else substrings[idx] += sp length += sp.length() function getSubStringData(BigSubString substring) returns string if substring.getStart()+substring.getSingleLength() > length error("string out of bounds: length: " + length.toString() + " s.length: " + substring.getSingleLength().toString() + " s.start: " + substring.getStart().toString()) if substring.getSingleLength() > BIG_SUBSTRING_LEN error("substring is longer than maxsize") let idx = (substring.getStart() / BIG_SUBSTRING_LEN).toInt() let offsetstart = substring.getStart() mod BIG_SUBSTRING_LEN let offsetend = offsetstart + substring.getSingleLength() if offsetend > BIG_SUBSTRING_LEN return substrings[idx].substring(offsetstart, BIG_SUBSTRING_LEN) + substrings[idx+1].substring(0, offsetend-BIG_SUBSTRING_LEN) return substrings[idx].substring(offsetstart, offsetend) function getString(int startpos) returns string if startpos > getLength() or getLength() > BIG_SUBSTRING_LEN error("1Trying to get string out of bounds") let modpos = startpos + startoffset let idx = (modpos / BIG_SUBSTRING_LEN).toInt() let offsetstart = (modpos mod BIG_SUBSTRING_LEN) return substrings[idx].substring(offsetstart, length) function getString(int startpos, int plength) returns string if startpos+plength > getLength() error("2Trying to get string out of bounds") if plength > BIG_SUBSTRING_LEN error("Trying to get oversized string") let modpos = startpos + startoffset let idx = (modpos / BIG_SUBSTRING_LEN).toInt() let offsetstart = (modpos mod BIG_SUBSTRING_LEN) let offsetend = offsetstart + plength if offsetend > BIG_SUBSTRING_LEN return substrings[idx].substring(offsetstart, substrings[idx].length()) + substrings[idx+1].substring(0, offsetend-BIG_SUBSTRING_LEN) return substrings[idx].substring(offsetstart, offsetend) function debugPrint() if DEBUG_LEVEL == Loglevel.TRACE Log.debug("BigString length: " + getLength().toString() + " lines: ") for i = 0 to MAX_SUBSTRINGS-1 if substrings[i].length() > 0 Log.debug("\n\tLine " + i.toString() + " : " + substrings[i]) else break ondestroy length = -1