org.mozilla.javascript.ConsString Maven / Gradle / Ivy
The newest version!
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.javascript;
import java.io.Serializable;
import java.util.ArrayList;
/**
* This class represents a string composed of two components, each of which
* may be a java.lang.String
or another ConsString.
*
* This string representation is optimized for concatenation using the "+"
* operator. Instead of immediately copying both components to a new character
* array, ConsString keeps references to the original components and only
* converts them to a String if either toString() is called or a certain depth
* level is reached.
*
* Note that instances of this class are only immutable if both parts are
* immutable, i.e. either Strings or ConsStrings that are ultimately composed
* of Strings.
*
* Both the name and the concept are borrowed from V8.
*/
public class ConsString implements CharSequence, Serializable {
private static final long serialVersionUID = -8432806714471372570L;
private CharSequence s1, s2;
private final int length;
private int depth;
public ConsString(CharSequence str1, CharSequence str2) {
s1 = str1;
s2 = str2;
length = str1.length() + str2.length();
depth = 1;
if (str1 instanceof ConsString) {
depth += ((ConsString)str1).depth;
}
if (str2 instanceof ConsString) {
depth += ((ConsString)str2).depth;
}
}
// Replace with string representation when serializing
private Object writeReplace() {
return this.toString();
}
@Override
public String toString() {
return depth == 0 ? (String)s1 : flatten();
}
private synchronized String flatten() {
if (depth > 0) {
StringBuilder b = new StringBuilder(length);
ArrayList buffer = new ArrayList();
buffer.add(s2);
buffer.add(s1);
while(!buffer.isEmpty()) {
CharSequence next = buffer.remove(buffer.size() - 1);
if (next instanceof ConsString) {
ConsString casted = (ConsString) next;
buffer.add(casted.s2);
buffer.add(casted.s1);
} else {
b.append(next);
}
}
s1 = b.toString();
s2 = "";
depth = 0;
}
return (String)s1;
}
public int length() {
return length;
}
public char charAt(int index) {
String str = depth == 0 ? (String)s1 : flatten();
return str.charAt(index);
}
public CharSequence subSequence(int start, int end) {
String str = depth == 0 ? (String)s1 : flatten();
return str.substring(start, end);
}
}