org.mozilla.javascript.ConsString Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aem-sdk-api Show documentation
Show all versions of aem-sdk-api Show documentation
The Adobe Experience Manager SDK
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;
/**
* 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;
}
// Don't let it grow too deep, can cause stack overflows
if (depth > 2000) {
flatten();
}
}
// 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);
appendTo(b);
s1 = b.toString();
s2 = "";
depth = 0;
}
return (String)s1;
}
private synchronized void appendTo(StringBuilder b) {
appendFragment(s1, b);
appendFragment(s2, b);
}
private static void appendFragment(CharSequence s, StringBuilder b) {
if (s instanceof ConsString) {
((ConsString)s).appendTo(b);
} else {
b.append(s);
}
}
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);
}
}