StringViewBack.java
package space.sunqian.common.base.string;
import space.sunqian.annotations.Nonnull;
import space.sunqian.annotations.RetainedParam;
import space.sunqian.annotations.ValueClass;
import space.sunqian.common.Check;
import space.sunqian.common.base.exception.UnreachablePointException;
final class StringViewBack {
static @Nonnull StringView view(@Nonnull CharSequence @Nonnull @RetainedParam ... strings) {
return new StringViewImpl(strings);
}
private static final class StringViewImpl implements StringView {
private final @Nonnull CharSequence[] chars;
private final int length;
private StringViewImpl(@Nonnull CharSequence[] chars) {
this.chars = chars;
int c = 0;
for (CharSequence aChar : chars) {
c += aChar.length();
}
this.length = c;
}
@Override
public int length() {
return length;
}
@Override
public char charAt(int index) {
Check.checkInBounds(index, 0, length);
Node node = findNode(index);
return chars[node.charsIndex].charAt(node.charIndex);
}
@Override
public @Nonnull CharSequence subSequence(int start, int end) {
Check.checkInBounds(start, end, 0, length);
if (start == end) {
Node node = findNode(start);
return chars[node.charsIndex].subSequence(node.charIndex, node.charIndex);
}
Node startNode = findNode(start);
Node endNode = findNode(end - 1);
if (startNode.charsIndex == endNode.charsIndex) {
return chars[startNode.charsIndex].subSequence(startNode.charIndex, endNode.charIndex + 1);
}
CharSequence[] subChars = new CharSequence[endNode.charsIndex - startNode.charsIndex + 1];
CharSequence startCs = chars[startNode.charsIndex];
subChars[0] = startCs.subSequence(startNode.charIndex, startCs.length());
CharSequence endCs = chars[endNode.charsIndex];
subChars[subChars.length - 1] = endCs.subSequence(0, endNode.charIndex + 1);
for (int i = 1, j = startNode.charsIndex + 1; i < subChars.length - 1; i++, j++) {
subChars[i] = chars[j];
}
return new StringViewImpl(subChars);
}
@Override
public @Nonnull String toString() {
StringBuilder sb = new StringBuilder(length);
for (CharSequence cs : chars) {
sb.append(cs);
}
return sb.toString();
}
private @Nonnull Node findNode(int index) {
int c = 0;
for (int i = 0; i < chars.length; i++) {
CharSequence cs = chars[i];
if (index < c + cs.length()) {
return new Node(i, index - c);
}
c += cs.length();
}
throw new UnreachablePointException("index: " + index);
}
@ValueClass
private static final class Node {
private final int charsIndex;
private final int charIndex;
private Node(int charsIndex, int charIndex) {
this.charsIndex = charsIndex;
this.charIndex = charIndex;
}
}
}
private StringViewBack() {
}
}