/*
Реализация среды исполнения языка программирования
Объектно-ориентированный продвинутый векторный транслятор
Copyright © 2021, 2024, 2026 Малик Разработчик
Это свободная программа: вы можете перераспространять ее и/или изменять
ее на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
в каком она была опубликована Фондом свободного программного обеспечения;
либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
Эта программа распространяется в надежде, что она будет полезной,
но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
общественной лицензии GNU.
Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
вместе с этой программой. Если это не так, см.
<https://www.gnu.org/licenses/>.
*/
package avt.lang;
import avt.lang.array.*;
import platform.independent.streamformat.*;
public class StringBuilder(Object, MutableDataHolder, CharSequence, DataHolder, Cloneable, Measureable, MutableMeasureable, ResizeableCharArray, MutableCharArray, CharArray)
{
protected int fldLength;
protected char[] fldContent;
public () { fldContent = new char[0x3f]; }
public (int initialCapacity) { fldContent = new char[initialCapacity <= 1 ? 1 : initialCapacity]; }
protected (int length, char[] content) {
fldLength = length;
fldContent = content;
}
public String toString() { return new String(fldContent, 0, fldLength); }
public void clear() { setLength(0); }
public void getChars(int beginIndex, int endIndex, MutableCharArray dst, int offset) {
checkBounds(beginIndex, endIndex);
if(dst == null)
{
throw new NullPointerException(String.format(package.getResourceString("null-pointer.argument"), new Object[] { "dst" }));
}
int length = endIndex - beginIndex;
Array.checkBounds(dst, offset, length);
if(dst instanceof StringBuilder) dst = ((StringBuilder) dst).fldContent;
if(dst instanceof char[])
{
Array.copy(fldContent, beginIndex, (char[]) dst, offset, length);
return;
}
for(char[] content = fldContent; length-- > 0; ) dst[offset++] = content[beginIndex++];
}
public void copyInto(MutableCharArray dst, int offset) {
if(dst == null)
{
throw new NullPointerException(String.format(package.getResourceString("null-pointer.argument"), new Object[] { "dst" }));
}
int length = fldLength;
Array.checkBounds(dst, offset, length);
if(dst instanceof StringBuilder) dst = ((StringBuilder) dst).fldContent;
if(dst instanceof char[])
{
Array.copy(fldContent, 0, (char[]) dst, offset, length);
return;
}
for(char[] content = fldContent, int index = 0; length-- > 0; ) dst[offset++] = content[index++];
}
public boolean isEmpty() { return fldLength <= 0; }
public char[] toCharArray() {
int length = fldLength;
char[] result = new char[length];
Array.copy(fldContent, 0, result, 0, length);
return result;
}
public StringBuilder join(CharSequence anot) {
if(anot != null) appendArray(anot, 0, anot.length);
return this;
}
public StringBuilder join(CharSequence[] seqs) {
if(seqs != null) for(int index = 0, int limit = seqs.length; index < limit; index++)
{
CharArray array = seqs[index];
if(array != null) appendArray(array, 0, array.length);
}
return this;
}
public StringBuilder join(CharSequence[] seqs, int offset, int length) {
if(seqs != null) for(int2 bounds = Array.intersectBounds(seqs, offset, length), int index = bounds[0], int limit = index + bounds[1]; index < limit; index++)
{
CharArray array = seqs[index];
if(array != null) appendArray(array, 0, array.length);
}
return this;
}
public StringBuilder subsequence(int beginIndex) {
int endIndex = fldLength;
checkBounds(beginIndex, endIndex);
deleteTails(beginIndex, endIndex, false);
return this;
}
public StringBuilder subsequence(int beginIndex, int endIndex) {
checkBounds(beginIndex, endIndex);
deleteTails(beginIndex, endIndex, false);
return this;
}
public StringBuilder clone() { return new StringBuilder(fldLength, fldContent.clone()); }
public void ensureCapacity(int minCapacity) {
if(minCapacity < 0) return;
char[] content = fldContent;
int curCapacity = content.length;
if(minCapacity <= curCapacity) return;
int newCapacity = curCapacity >= (Int.MAX_VALUE >> 1) ? Int.MAX_VALUE : curCapacity << 1 | 1;
if(minCapacity > newCapacity) newCapacity = minCapacity;
Array.copy(content, 0, fldContent = new char[newCapacity], 0, curCapacity);
}
public int indexOf(int chr, int startFromIndex) {
int length = fldLength;
if(startFromIndex < 0) startFromIndex = 0;
return startFromIndex >= length || chr < 0 || chr > 0xffff ? -1 : Array.indexOf(chr, fldContent, startFromIndex, length - startFromIndex);
}
public int indexOf(CharSequence str, int startFromIndex) {
if(str == null)
{
throw new NullPointerException(String.format(package.getResourceString("null-pointer.argument"), new Object[] { "str" }));
}
int anotLength = str.length;
int thisLength = fldLength - anotLength;
if(startFromIndex < 0) startFromIndex = 0;
if(startFromIndex > thisLength++) return -1;
if(anotLength-- <= 0) return startFromIndex;
char[] anotContent = str instanceof StringBuilder ? ((StringBuilder) str).fldContent : str.toCharArray();
char[] thisContent = fldContent;
char first = anotContent[0];
do
{
int thisIndex = Array.indexOf(first, thisContent, startFromIndex, thisLength - startFromIndex);
if(thisIndex < 0) break;
startFromIndex = thisIndex++;
if(anotLength <= 0 || Array.offsetOfNonEqual(thisContent, thisIndex, anotContent, 1, anotLength) == Comparable.INDEFINITE) return startFromIndex;
} while(++startFromIndex < thisLength);
return -1;
}
public int indexOfNon(int chr, int startFromIndex) {
int length = fldLength;
if(startFromIndex < 0) startFromIndex = 0;
return startFromIndex >= length ? -1 : chr < 0 || chr > 0xffff ? startFromIndex : Array.indexOfNon(chr, fldContent, startFromIndex, length - startFromIndex);
}
public int lastIndexOf(int chr, int startFromIndex) {
int length = fldLength;
if(startFromIndex >= length) startFromIndex = length - 1;
return startFromIndex < 0 || chr < 0 || chr > 0xffff ? -1 : Array.lastIndexOf(chr, fldContent, startFromIndex, 0);
}
public int lastIndexOf(CharSequence str, int startFromIndex) {
if(str == null)
{
throw new NullPointerException(String.format(package.getResourceString("null-pointer.argument"), new Object[] { "str" }));
}
int anotLength = str.length;
int thisLength = fldLength - anotLength;
if(startFromIndex > thisLength) startFromIndex = thisLength;
if(startFromIndex < 0) return -1;
if(anotLength-- <= 0) return startFromIndex;
char[] anotContent = str instanceof StringBuilder ? ((StringBuilder) str).fldContent : str.toCharArray();
char[] thisContent = fldContent;
char first = anotContent[0];
do
{
int thisIndex = Array.lastIndexOf(first, thisContent, startFromIndex, 0);
if(thisIndex < 0) break;
startFromIndex = thisIndex++;
if(anotLength <= 0 || Array.offsetOfNonEqual(thisContent, thisIndex, anotContent, 1, anotLength) == Comparable.INDEFINITE) return startFromIndex;
} while(--startFromIndex >= 0);
return -1;
}
public int lastIndexOfNon(int chr, int startFromIndex) {
int length = fldLength;
if(startFromIndex >= length) startFromIndex = length - 1;
return startFromIndex < 0 ? -1 : chr < 0 || chr > 0xffff ? startFromIndex : Array.lastIndexOfNon(chr, fldContent, startFromIndex, 0);
}
public int insert(int index, boolean src) {
String array = String.valueOf(src);
return insertArray(index, array, 0, array.length);
}
public int insert(int index, char src) { return insertChar(index, src); }
public int insert(int index, byte src) {
String array = String.valueOf(src);
return insertArray(index, array, 0, array.length);
}
public int insert(int index, short src) {
String array = String.valueOf(src);
return insertArray(index, array, 0, array.length);
}
public int insert(int index, int src) {
String array = String.valueOf(src);
return insertArray(index, array, 0, array.length);
}
public int insert(int index, long src) {
String array = String.valueOf(src);
return insertArray(index, array, 0, array.length);
}
public int insert(int index, float src) {
String array = String.valueOf(src);
return insertArray(index, array, 0, array.length);
}
public int insert(int index, double src) {
String array = String.valueOf(src);
return insertArray(index, array, 0, array.length);
}
public int insert(int index, real src) {
String array = String.valueOf(src);
return insertArray(index, array, 0, array.length);
}
public int insert(int index, Object src) {
CharArray array = src instanceof CharArray ? (CharArray) src : String.valueOf(src);
return insertArray(index, array, 0, array.length);
}
public int insert(int index, CharArray src, int offset, int length) {
if(src == null)
{
throw new NullPointerException(String.format(package.getResourceString("null-pointer.argument"), new Object[] { "src" }));
}
Array.checkBounds(src, offset, length);
return insertArray(index, src, offset, length);
}
public int insertf(int index, String form, ObjectArray data) {
if(form == null)
{
throw new NullPointerException(String.format(package.getResourceString("null-pointer.argument"), new Object[] { "form" }));
}
String array = String.format(form, data);
return insertArray(index, array, 0, array.length);
}
public int replace(int beginIndex, int endIndex, boolean src) {
checkBounds(beginIndex, endIndex);
String array = String.valueOf(src);
return replaceArray(beginIndex, endIndex, array, 0, array.length);
}
public int replace(int beginIndex, int endIndex, char src) {
checkBounds(beginIndex, endIndex);
return replaceChar(beginIndex, endIndex, src);
}
public int replace(int beginIndex, int endIndex, byte src) {
checkBounds(beginIndex, endIndex);
String array = String.valueOf(src);
return replaceArray(beginIndex, endIndex, array, 0, array.length);
}
public int replace(int beginIndex, int endIndex, short src) {
checkBounds(beginIndex, endIndex);
String array = String.valueOf(src);
return replaceArray(beginIndex, endIndex, array, 0, array.length);
}
public int replace(int beginIndex, int endIndex, int src) {
checkBounds(beginIndex, endIndex);
String array = String.valueOf(src);
return replaceArray(beginIndex, endIndex, array, 0, array.length);
}
public int replace(int beginIndex, int endIndex, long src) {
checkBounds(beginIndex, endIndex);
String array = String.valueOf(src);
return replaceArray(beginIndex, endIndex, array, 0, array.length);
}
public int replace(int beginIndex, int endIndex, float src) {
checkBounds(beginIndex, endIndex);
String array = String.valueOf(src);
return replaceArray(beginIndex, endIndex, array, 0, array.length);
}
public int replace(int beginIndex, int endIndex, double src) {
checkBounds(beginIndex, endIndex);
String array = String.valueOf(src);
return replaceArray(beginIndex, endIndex, array, 0, array.length);
}
public int replace(int beginIndex, int endIndex, real src) {
checkBounds(beginIndex, endIndex);
String array = String.valueOf(src);
return replaceArray(beginIndex, endIndex, array, 0, array.length);
}
public int replace(int beginIndex, int endIndex, Object src) {
checkBounds(beginIndex, endIndex);
CharArray array = src instanceof CharArray ? (CharArray) src : String.valueOf(src);
return replaceArray(beginIndex, endIndex, array, 0, array.length);
}
public int replace(int beginIndex, int endIndex, CharArray src, int offset, int length) {
checkBounds(beginIndex, endIndex);
if(src == null)
{
throw new NullPointerException(String.format(package.getResourceString("null-pointer.argument"), new Object[] { "src" }));
}
Array.checkBounds(src, offset, length);
return replaceArray(beginIndex, endIndex, src, offset, length);
}
public int replacef(int beginIndex, int endIndex, String form, ObjectArray data) {
checkBounds(beginIndex, endIndex);
if(form == null)
{
throw new NullPointerException(String.format(package.getResourceString("null-pointer.argument"), new Object[] { "form" }));
}
String array = String.format(form, data);
return replaceArray(beginIndex, endIndex, array, 0, array.length);
}
public StringBuilder append(boolean src) {
String array = String.valueOf(src);
appendArray(array, 0, array.length);
return this;
}
public StringBuilder append(char src) {
appendChar(src);
return this;
}
public StringBuilder append(byte src) {
String array = String.valueOf(src);
appendArray(array, 0, array.length);
return this;
}
public StringBuilder append(short src) {
String array = String.valueOf(src);
appendArray(array, 0, array.length);
return this;
}
public StringBuilder append(int src) {
String array = String.valueOf(src);
appendArray(array, 0, array.length);
return this;
}
public StringBuilder append(long src) {
String array = String.valueOf(src);
appendArray(array, 0, array.length);
return this;
}
public StringBuilder append(float src) {
String array = String.valueOf(src);
appendArray(array, 0, array.length);
return this;
}
public StringBuilder append(double src) {
String array = String.valueOf(src);
appendArray(array, 0, array.length);
return this;
}
public StringBuilder append(real src) {
String array = String.valueOf(src);
appendArray(array, 0, array.length);
return this;
}
public StringBuilder append(Object src) {
CharArray array = src instanceof CharArray ? (CharArray) src : String.valueOf(src);
appendArray(array, 0, array.length);
return this;
}
public StringBuilder append(CharArray src, int offset, int length) {
if(src == null)
{
throw new NullPointerException(String.format(package.getResourceString("null-pointer.argument"), new Object[] { "src" }));
}
Array.checkBounds(src, offset, length);
appendArray(src, offset, length);
return this;
}
public StringBuilder appendf(String form, ObjectArray data) {
if(form == null)
{
throw new NullPointerException(String.format(package.getResourceString("null-pointer.argument"), new Object[] { "form" }));
}
String array = String.format(form, data);
appendArray(array, 0, array.length);
return this;
}
public StringBuilder reverse() {
reverseContent();
return this;
}
public StringBuilder delete(int index) {
checkIndex(index);
deletePortion(index, index + 1);
return this;
}
public StringBuilder delete(int beginIndex, int endIndex) {
checkBounds(beginIndex, endIndex);
deletePortion(beginIndex, endIndex);
return this;
}
public StringBuilder deleteTailSpaces() {
int chi = 0;
int chj = fldLength - 1;
char[] content = fldContent;
while(chi <= chj && content[chi] <= '\u0020') chi++;
while(chi <= chj && content[chj] <= '\u0020') chj--;
deleteTails(chi, chj + 1, false);
return this;
}
public StringBuilder trimTailSpaces() {
int chi = 0;
int chj = fldLength - 1;
char[] content = fldContent;
while(chi <= chj && content[chi] <= '\u0020') chi++;
while(chi <= chj && content[chj] <= '\u0020') chj--;
deleteTails(chi, chj + 1, true);
return this;
}
public StringBuilder trimToLength() {
deleteTails(0, fldLength, true);
return this;
}
public StringBuilder trimToSubsequence(int beginIndex) {
int endIndex = fldLength;
checkBounds(beginIndex, endIndex);
deleteTails(beginIndex, endIndex, true);
return this;
}
public StringBuilder trimToSubsequence(int beginIndex, int endIndex) {
checkBounds(beginIndex, endIndex);
deleteTails(beginIndex, endIndex, true);
return this;
}
public String displayString() { return new String(fldContent, 0, fldLength); }
public final int indexOf(int chr) { return indexOf(chr, 0); }
public final int indexOf(CharSequence str) { return indexOf(str, 0); }
public final int indexOfNon(int chr) { return indexOfNon(chr, 0); }
public final int lastIndexOf(int chr) { return lastIndexOf(chr, Int.MAX_VALUE); }
public final int lastIndexOf(CharSequence str) { return lastIndexOf(str, Int.MAX_VALUE); }
public final int lastIndexOfNon(int chr) { return lastIndexOfNon(chr, Int.MAX_VALUE); }
public int length { read = fldLength, write = setLength }
public int capacity { read = fldContent.length }
public void operator []=(int index, char component) {
checkIndex(index);
setChar(index, component);
}
public char operator [](int index) {
checkIndex(index);
return fldContent[index];
}
protected void checkIndex(int index) {
if(index < 0 || index >= fldLength)
{
throw new StringIndexOutOfBoundsException(package.getResourceString("out-of-bounds.string-index"));
}
}
protected void checkBounds(int beginIndex, int endIndex) {
int length = fldLength;
if((beginIndex | endIndex) < 0 || beginIndex > length || endIndex > length || beginIndex > endIndex)
{
throw new StringIndexOutOfBoundsException(package.getResourceString("out-of-bounds.string-index"));
}
}
protected void reverseContent() {
for(char[] content = fldContent, int length = fldLength, int chi = length >> 1, int chj = length - chi; chi-- > 0; chj++)
{
char chr = content[chi];
content[chi] = content[chj];
content[chj] = chr;
}
}
protected void setLength(int newLength) {
if(newLength < 0)
{
throw new NegativeArrayLengthException(package.getResourceString("negative-array-length"));
}
int curLength = fldLength;
char[] content = fldContent;
if(newLength > content.length) content = madeLarger(newLength);
if(newLength > curLength) Array.fill(content, curLength, newLength - curLength, '\0');
fldLength = newLength;
}
protected void setChar(int index, char src) { fldContent[index] = src; }
protected void deletePortion(int beginIndex, int endIndex) {
int count = endIndex - beginIndex;
int curLength = fldLength;
int newLength = curLength - count;
if(count > 0)
{
char[] content = fldContent;
Array.copy(content, endIndex, content, beginIndex, curLength - endIndex);
}
fldLength = newLength;
}
protected void deleteTails(int beginIndex, int endIndex, boolean isTrim) {
int newLength = endIndex - beginIndex;
char[] content = fldContent;
if(!isTrim)
{
if(beginIndex > 0) Array.copy(content, beginIndex, content, 0, newLength);
fldLength = newLength;
return;
}
if(beginIndex > 0 || endIndex < content.length)
{
Array.copy(content, beginIndex, fldContent = new char[newLength], 0, newLength);
fldLength = newLength;
}
}
protected void appendChar(char src) {
int length = fldLength;
char[] content = madeLarger(length + 1);
content[length++] = src;
fldLength = length;
}
protected void appendArray(CharArray src, int offset, int length) {
int curLength = fldLength;
int newLength = curLength + length;
char[] content = madeLarger(newLength);
if(src instanceof char[])
{
Array.copy((char[]) src, offset, content, curLength, length);
} else if(src instanceof CharSequence)
{
((CharSequence) src).getChars(offset, offset + length, content, curLength);
} else
{
while(length-- > 0) content[curLength++] = src[offset++];
}
fldLength = newLength;
}
protected int insertChar(int index, char src) {
int length = fldLength;
char[] content = madeLarger(length + 1);
if(index < 0) index = 0;
if(index > length) index = length;
int result = index + 1;
Array.copy(content, index, content, result, length++ - index);
content[index] = src;
fldLength = length;
return result;
}
protected int insertArray(int index, CharArray src, int offset, int length) {
int curLength = fldLength;
int newLength = curLength + length;
char[] content = madeLarger(newLength);
if(index < 0) index = 0;
if(index > curLength) index = curLength;
int result = index + length;
Array.copy(content, index, content, result, curLength - index);
if(src instanceof char[])
{
Array.copy((char[]) src, offset, content, index, length);
} else if(src instanceof CharSequence)
{
((CharSequence) src).getChars(offset, offset + length, content, index);
} else
{
while(length-- > 0) content[index++] = src[offset++];
}
fldLength = newLength;
return result;
}
protected int replaceChar(int beginIndex, int endIndex, char src) {
int result = beginIndex + 1;
int curLength = fldLength;
int newLength = curLength - endIndex + result;
char[] content = madeLarger(newLength);
Array.copy(content, endIndex, content, result, curLength - endIndex);
content[beginIndex] = src;
fldLength = newLength;
return result;
}
protected int replaceArray(int beginIndex, int endIndex, CharArray src, int offset, int length) {
int result = beginIndex + length;
int curLength = fldLength;
int newLength = curLength - endIndex + result;
char[] content = madeLarger(newLength);
Array.copy(content, endIndex, content, result, curLength - endIndex);
if(src instanceof char[])
{
Array.copy((char[]) src, offset, content, beginIndex, length);
} else if(src instanceof CharSequence)
{
((CharSequence) src).getChars(offset, offset + length, content, beginIndex);
} else
{
while(length-- > 0) content[beginIndex++] = src[offset++];
}
fldLength = newLength;
return result;
}
protected char[] madeLarger(int minCapacity) {
if(minCapacity < 0)
{
throw new BufferTooLargeError(package.getResourceString("!error.buffer-too-large"));
}
char[] content = fldContent;
int curCapacity = content.length;
if(minCapacity > curCapacity)
{
int newCapacity = curCapacity >= (Int.MAX_VALUE >> 1) ? Int.MAX_VALUE : curCapacity << 1 | 1;
if(minCapacity > newCapacity) newCapacity = minCapacity;
Array.copy(content, 0, fldContent = content = new char[newCapacity], 0, curCapacity);
}
return content;
}
}