blob: 08a344dcd24dbe985bf69897d9cb16a11e2e30fb [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ignite.internal.tostring;
import java.util.Arrays;
/**
* Basic string builder over circular buffer.
*/
class CircularStringBuilder {
/** Value */
private final char[] buf;
/** Writer position (0 if empty). */
private int pos;
/** Value is full flag. */
private boolean full;
/** Number of skipped characters */
private int skipped;
/**
* Creates an CircularStringBuilder of the specified capacity.
*
* @param capacity Buffer capacity.
*/
CircularStringBuilder(int capacity) {
assert capacity > 0 : "Can't allocate CircularStringBuilder with capacity: " + capacity;
buf = new char[capacity];
pos = 0;
skipped = 0;
full = false;
}
/**
* Reset internal builder state
*/
public void reset() {
Arrays.fill(buf, (char)0);
pos = 0;
full = false;
skipped = 0;
}
/**
* Returns the length (character count).
*
* @return the length of the sequence of characters currently
* represented by this object
*/
public int length() {
return full ? buf.length : pos;
}
/**
* Returns the current capacity.
*
* @return the current capacity
*/
public int capacity() {
return buf.length;
}
/**
* Appends the string representation of the {@code Object} argument.
*
* @param obj an {@code Object}.
* @return {@code this} for chaining.
*/
public CircularStringBuilder append(Object obj) {
return append(String.valueOf(obj));
}
/**
* Appends the specified string to this character sequence.
*
* @param str a string.
* @return {@code this} for chaining.
*/
public CircularStringBuilder append(String str) {
if (str == null)
return appendNull();
int strLen = str.length();
if (strLen == 0)
return this;
else if (strLen >= buf.length) {
// String bigger or equal to value length
str.getChars(strLen - buf.length, strLen, buf, 0);
skipped += strLen - buf.length + pos;
pos = buf.length;
full = true;
}
// String is shorter value length
else if (buf.length - pos < strLen) {
// String doesn't fit into remaining part of value array
int firstPart = buf.length - pos;
if (firstPart > 0)
str.getChars(0, firstPart, buf, pos);
str.getChars(firstPart, strLen, buf, 0);
skipped += full ? strLen : strLen - firstPart;
pos = pos + strLen - buf.length;
full = true;
}
else {
// Whole string fin into remaining part of value array
str.getChars(0, strLen, buf, pos);
skipped += full ? strLen : 0;
pos += strLen;
}
return this;
}
/**
* Append StringBuffer.
*
* @param sb StringBuffer to append.
* @return {@code this} for chaining.
*/
public CircularStringBuilder append(StringBuffer sb) {
if (sb == null)
return appendNull();
int strLen = sb.length();
if (strLen == 0)
return this;
if (strLen >= buf.length) {
// String bigger or equal to value length
sb.getChars(strLen - buf.length, strLen, buf, 0);
skipped += strLen - buf.length + pos;
pos = buf.length;
full = true;
}
// String is shorter value length
else if (buf.length - pos < strLen) {
// String doesn't fit into remaining part of value array
int firstPart = buf.length - pos;
if (firstPart > 0)
sb.getChars(0, firstPart, buf, pos);
sb.getChars(firstPart, strLen, buf, 0);
skipped += full ? strLen : strLen - firstPart;
pos = pos + strLen - buf.length;
full = true;
}
else {
// Whole string fin into remaining part of value array
sb.getChars(0, strLen, buf, pos);
skipped += full ? strLen : 0;
pos += strLen;
}
return this;
}
/**
* Append StringBuilder.
*
* @param sb StringBuilder to append.
* @return {@code this} for chaining.
*/
public CircularStringBuilder append(StringBuilder sb) {
if (sb == null)
return appendNull();
int strLen = sb.length();
if (strLen == 0)
return this;
if (strLen >= buf.length) {
// String bigger or equal to value length
sb.getChars(strLen - buf.length, strLen, buf, 0);
skipped += strLen - buf.length + pos;
pos = buf.length;
full = true;
}
// String is shorter value length
else if (buf.length - pos < strLen) {
// String doesn't fit into remaining part of value array
int firstPart = buf.length - pos;
if (firstPart > 0)
sb.getChars(0, firstPart, buf, pos);
sb.getChars(firstPart, strLen, buf, 0);
skipped += full ? strLen : strLen - firstPart;
pos = pos + strLen - buf.length;
full = true;
}
else {
// Whole string fin into remaining part of value array
sb.getChars(0, strLen, buf, pos);
skipped += full ? strLen : 0;
pos += strLen;
}
return this;
}
/**
* @return {@code this} for chaining.
*/
private CircularStringBuilder appendNull() {
return append("null");
}
/**
* @return Count of skipped elements.
*/
public int getSkipped() {
return skipped;
}
/** {@inheritDoc} */
@Override public String toString() {
// Create a copy, don't share the array
if (full && pos < buf.length) {
char[] tmpBuf = new char[buf.length];
int tailLen = buf.length - pos;
System.arraycopy(buf, pos, tmpBuf, 0, tailLen);
System.arraycopy(buf, 0, tmpBuf, tailLen, buf.length - tailLen);
return new String(tmpBuf, 0, tmpBuf.length);
}
else
return new String(buf, 0, pos);
}
}