|
@@ -0,0 +1,424 @@
|
|
|
|
|
+/*
|
|
|
|
|
+ * @author Ranides Atterwim <ranides@gmail.com>
|
|
|
|
|
+ * @copyright Ranides Atterwim
|
|
|
|
|
+ * @license WTFPL
|
|
|
|
|
+ * @url http://ranides.net/projects/assira
|
|
|
|
|
+ */
|
|
|
|
|
+package net.ranides.assira.text;
|
|
|
|
|
+
|
|
|
|
|
+import java.io.Reader;
|
|
|
|
|
+import java.io.Serializable;
|
|
|
|
|
+import java.io.Writer;
|
|
|
|
|
+import net.ranides.assira.collection.arrays.ArrayAllocator;
|
|
|
|
|
+import net.ranides.assira.collection.arrays.ArrayUtils;
|
|
|
|
|
+import net.ranides.assira.collection.arrays.NativeArray;
|
|
|
|
|
+import net.ranides.assira.collection.arrays.NativeArrayAllocator;
|
|
|
|
|
+import net.ranides.assira.collection.arrays.NativeArrayUtils;
|
|
|
|
|
+import net.ranides.assira.generic.ValueUtils;
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ *
|
|
|
|
|
+ * @author Ranides Atterwim <ranides@gmail.com>
|
|
|
|
|
+ */
|
|
|
|
|
+public final class StrBuilder implements CharSequence, Appendable, Serializable {
|
|
|
|
|
+
|
|
|
|
|
+ private static final long serialVersionUID = 1L;
|
|
|
|
|
+
|
|
|
|
|
+ protected static final char[] EMPTY = new char[0];
|
|
|
|
|
+
|
|
|
|
|
+ protected static final int CAPACITY = 32;
|
|
|
|
|
+
|
|
|
|
|
+ private char[] buffer;
|
|
|
|
|
+
|
|
|
|
|
+ private int size;
|
|
|
|
|
+
|
|
|
|
|
+ private String blank;
|
|
|
|
|
+
|
|
|
|
|
+ private String endl;
|
|
|
|
|
+
|
|
|
|
|
+ public StrBuilder() {
|
|
|
|
|
+ this(CAPACITY);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public StrBuilder(int initialCapacity) {
|
|
|
|
|
+ buffer = new char[initialCapacity];
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public int length() {
|
|
|
|
|
+ return size;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public char charAt(int index) {
|
|
|
|
|
+ return buffer[index];
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public CharSequence subSequence(int begin, int end) {
|
|
|
|
|
+ NativeArrayAllocator.ensureFromTo(size, begin, end);
|
|
|
|
|
+ return StringUtils.wrap(buffer, begin, end);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public int capacity() {
|
|
|
|
|
+ return buffer.length;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public StrBuilder resize(int length, char c) {
|
|
|
|
|
+ if (length < 0) {
|
|
|
|
|
+ throw new StringIndexOutOfBoundsException(length);
|
|
|
|
|
+ }
|
|
|
|
|
+ if (length > size) {
|
|
|
|
|
+ reserve(length);
|
|
|
|
|
+ ArrayUtils.fill(buffer, size, length, c);
|
|
|
|
|
+ size = length;
|
|
|
|
|
+ }
|
|
|
|
|
+ return this;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public StrBuilder reserve(int capacity) {
|
|
|
|
|
+ if (capacity > buffer.length) {
|
|
|
|
|
+ char[] old = buffer;
|
|
|
|
|
+ buffer = new char[capacity * 2];
|
|
|
|
|
+ System.arraycopy(old, 0, buffer, 0, size);
|
|
|
|
|
+ }
|
|
|
|
|
+ return this;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public StrBuilder trim() {
|
|
|
|
|
+ if (buffer.length > length()) {
|
|
|
|
|
+ char[] old = buffer;
|
|
|
|
|
+ buffer = new char[length()];
|
|
|
|
|
+ System.arraycopy(old, 0, buffer, 0, size);
|
|
|
|
|
+ }
|
|
|
|
|
+ return this;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public StrBuilder trim(int n) {
|
|
|
|
|
+ if (buffer.length > n) {
|
|
|
|
|
+ buffer = ArrayAllocator.trim(buffer, size);
|
|
|
|
|
+ }
|
|
|
|
|
+ return this;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public StrBuilder clear() {
|
|
|
|
|
+ size = 0;
|
|
|
|
|
+ return this;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public StrBuilder setCharAt(int index, char value) {
|
|
|
|
|
+ buffer[index] = value;
|
|
|
|
|
+ return this;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public StrBuilder reverse() {
|
|
|
|
|
+ NativeArrayUtils.reverse(size, NativeArray.wrap(buffer));
|
|
|
|
|
+ return this;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public char[] getChars() {
|
|
|
|
|
+ return getChars(0, size);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public char[] getChars(int begin, int end) {
|
|
|
|
|
+ if (end == begin) {
|
|
|
|
|
+ return EMPTY; //NOPMD
|
|
|
|
|
+ }
|
|
|
|
|
+ return ArrayUtils.slice(buffer, begin, end);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public char[] getChars(char[] target) {
|
|
|
|
|
+ return getChars(0, size, target, 0);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public char[] getChars(int begin, int end, char target[], int offset) {
|
|
|
|
|
+ NativeArrayAllocator.ensureFromTo(size, begin, end);
|
|
|
|
|
+ System.arraycopy(buffer, begin, target, offset, end - begin);
|
|
|
|
|
+ return target;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public boolean equals(Object object) {
|
|
|
|
|
+ if (this == object) {
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!(object instanceof StrBuilder)) {
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ StrBuilder other = (StrBuilder)object;
|
|
|
|
|
+ if (this.size != other.size) {
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ for(int i=0; i<size; i++) {
|
|
|
|
|
+ if(this.buffer[i] != other.buffer[i]) {
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public int hashCode() {
|
|
|
|
|
+ return NativeArray.wrap(buffer).hashCode(0, size);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public String toString() {
|
|
|
|
|
+ return new String(buffer, 0, size);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public StringBuilder toBuilder() {
|
|
|
|
|
+ return new StringBuilder(size).append(buffer, 0, size);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public Writer asWriter() {
|
|
|
|
|
+ return new SWriter();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public Reader asReader() {
|
|
|
|
|
+ return new SReader();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public StrBuilder endl() {
|
|
|
|
|
+ return append(ValueUtils.or(endl, StringUtils.ENDL));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public StrBuilder endl(String value) {
|
|
|
|
|
+ this.endl = value;
|
|
|
|
|
+ return this;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public <T> StrBuilder blank(String value) {
|
|
|
|
|
+ this.blank = value;
|
|
|
|
|
+ return this;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public StrBuilder append() {
|
|
|
|
|
+ return null == blank ? this : append(blank);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public StrBuilder append(CharSequence value) {
|
|
|
|
|
+ return (value == null) ? append() : append(value, 0, value.length());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public StrBuilder append(CharSequence value, int begin, int end) {
|
|
|
|
|
+ if (value == null) {
|
|
|
|
|
+ return append();
|
|
|
|
|
+ }
|
|
|
|
|
+ reserve(length() + (end - begin));
|
|
|
|
|
+ for(int i=begin; i<end; i++) {
|
|
|
|
|
+ buffer[size++] = value.charAt(i);
|
|
|
|
|
+ }
|
|
|
|
|
+ return this;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public StrBuilder append(String value) {
|
|
|
|
|
+ return (value == null) ? append() : append(value, 0, value.length());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public StrBuilder append(String value, int begin, int end) {
|
|
|
|
|
+ if (value == null) {
|
|
|
|
|
+ return append();
|
|
|
|
|
+ }
|
|
|
|
|
+ NativeArrayAllocator.ensureFromTo(value.length(), begin, end);
|
|
|
|
|
+ int n = end - begin;
|
|
|
|
|
+ if (n > 0) {
|
|
|
|
|
+ reserve(size + n);
|
|
|
|
|
+ value.getChars(begin, end, buffer, size);
|
|
|
|
|
+ size += end;
|
|
|
|
|
+ }
|
|
|
|
|
+ return this;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public StrBuilder append(StringBuffer value) {
|
|
|
|
|
+ return (value == null) ? append() : append(value, 0, value.length());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public StrBuilder append(StringBuffer value, int begin, int end) {
|
|
|
|
|
+ if (value == null) {
|
|
|
|
|
+ return append();
|
|
|
|
|
+ }
|
|
|
|
|
+ NativeArrayAllocator.ensureFromTo(value.length(), begin, end);
|
|
|
|
|
+ int n = end - begin;
|
|
|
|
|
+ if (n > 0) {
|
|
|
|
|
+ reserve(size + n);
|
|
|
|
|
+ value.getChars(begin, end, buffer, size);
|
|
|
|
|
+ size += end;
|
|
|
|
|
+ }
|
|
|
|
|
+ return this;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public StrBuilder append(StringBuilder value) {
|
|
|
|
|
+ return (value == null) ? append() : append(value, 0, value.length());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public StrBuilder append(StringBuilder value, int begin, int end) {
|
|
|
|
|
+ if (value == null) {
|
|
|
|
|
+ return append();
|
|
|
|
|
+ }
|
|
|
|
|
+ NativeArrayAllocator.ensureFromTo(value.length(), begin, end);
|
|
|
|
|
+ int n = end - begin;
|
|
|
|
|
+ if (n > 0) {
|
|
|
|
|
+ reserve(size + n);
|
|
|
|
|
+ value.getChars(begin, end, buffer, size);
|
|
|
|
|
+ size += end;
|
|
|
|
|
+ }
|
|
|
|
|
+ return this;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public StrBuilder append(char[] value) {
|
|
|
|
|
+ return (value == null) ? append() : append(value, 0, value.length);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public StrBuilder append(char[] value, int begin, int end) {
|
|
|
|
|
+ if (value == null) {
|
|
|
|
|
+ return append();
|
|
|
|
|
+ }
|
|
|
|
|
+ NativeArrayAllocator.ensureFromTo(value.length, begin, end);
|
|
|
|
|
+ int n = end - begin;
|
|
|
|
|
+ if (n > 0) {
|
|
|
|
|
+ reserve(size + end);
|
|
|
|
|
+ System.arraycopy(value, begin, buffer, size, n);
|
|
|
|
|
+ size += end;
|
|
|
|
|
+ }
|
|
|
|
|
+ return this;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public StrBuilder append(char c) {
|
|
|
|
|
+ reserve(size + 1);
|
|
|
|
|
+ buffer[size++] = c;
|
|
|
|
|
+ return this;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public StrBuilder append(Object value) {
|
|
|
|
|
+ return (value == null) ? append() : append(value.toString());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public StrBuilder append(boolean value) {
|
|
|
|
|
+ return append(value ? "true" : "false");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public StrBuilder append(int value) {
|
|
|
|
|
+ return append(String.valueOf(value));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public StrBuilder append(long value) {
|
|
|
|
|
+ return append(String.valueOf(value));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public StrBuilder append(float value) {
|
|
|
|
|
+ return append(String.valueOf(value));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public StrBuilder append(double value) {
|
|
|
|
|
+ return append(String.valueOf(value));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private final class SReader extends Reader {
|
|
|
|
|
+
|
|
|
|
|
+ private int pos;
|
|
|
|
|
+ private int mark;
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void close() {
|
|
|
|
|
+ // do nothing
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public int read() {
|
|
|
|
|
+ if (!ready()) {
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ }
|
|
|
|
|
+ return buffer[pos++];
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public int read(char target[], int offset, int length) {
|
|
|
|
|
+ if (pos >= length()) {
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (pos + length > length()) {
|
|
|
|
|
+ length = length() - pos;
|
|
|
|
|
+ }
|
|
|
|
|
+ StrBuilder.this.getChars(pos, pos + length, target, offset);
|
|
|
|
|
+ pos += length;
|
|
|
|
|
+ return length;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public long skip(long n) {
|
|
|
|
|
+ if (pos + n > size) {
|
|
|
|
|
+ n = size - pos;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (n < 0) {
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ pos += n;
|
|
|
|
|
+ return n;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public boolean ready() {
|
|
|
|
|
+ return pos < size;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public boolean markSupported() {
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void mark(int readAheadLimit) {
|
|
|
|
|
+ mark = pos;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void reset() {
|
|
|
|
|
+ pos = mark;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private final class SWriter extends Writer {
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void close() {
|
|
|
|
|
+ // do nothing
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void flush() {
|
|
|
|
|
+ // do nothing
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void write(int c) {
|
|
|
|
|
+ StrBuilder.this.append((char) c);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void write(char[] buffer) {
|
|
|
|
|
+ StrBuilder.this.append(buffer);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void write(char[] buffer, int offset, int length) {
|
|
|
|
|
+ StrBuilder.this.append(buffer, offset, length);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void write(String str) {
|
|
|
|
|
+ StrBuilder.this.append(str);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void write(String str, int offset, int length) {
|
|
|
|
|
+ StrBuilder.this.append(str, offset, length);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+}
|