Skip to content

Instantly share code, notes, and snippets.

@chris-horner
Created April 14, 2014 06:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chris-horner/10620942 to your computer and use it in GitHub Desktop.
Save chris-horner/10620942 to your computer and use it in GitHub Desktop.
A CharSequence implementation that allocates memory as infrequently as possible
/**
* <p>
* A simplified version of the String class. Unlike the normal implementation of
* String, memory is only allocated during initialisation, or when the internal
* character array must be expanded.
* </p>
* <p>
* This makes it useful for environments where text must be modified at run time
* whilst displaying smooth animations.
* </p>
*
* @author Christopher Horner
*
*/
public class SimpleString implements CharSequence
{
private static final int HASHCODE_PRIME = 37;
private static final int DEFAULT_SIZE = 30;
private static final int ASCII_NUMBER_OFFSET = 48;
private static final String DEFAULT_TEXT = "";
private static final SimpleString subString = new SimpleString();
private char[] charArray;
private int size;
/**
* Creates a new simple string with a default internal array size of 30.
*/
public SimpleString()
{
this(DEFAULT_TEXT, DEFAULT_SIZE);
}
/**
* Creates a new simple string from the provided text with a default
* internal array size of 30, or the length of the initial text (whichever
* is larger).
*
* @param initialText The text the SimpleString should initially contain.
*/
public SimpleString(CharSequence initialText)
{
this(initialText, Math.max(initialText.length(), DEFAULT_SIZE));
}
/**
* Creates a new simple string from the provided text and also sets the
* internal array to the provided size.
*
* @param initialText The text the SimpleString should initially contain.
* @param arraySize The size to set the internal character array to.
*/
public SimpleString(CharSequence initialText, int arraySize)
{
size = initialText.length();
if (arraySize < size)
arraySize = size;
charArray = new char[arraySize];
for (int i = 0; i < size; i++)
charArray[i] = initialText.charAt(i);
}
/**
* Adds the specified text to the end of the simple string. If the text is
* larger than the internal array of the simple string, it will be resized
* to accommodate the text. WARNING, resizing the array will fire the GC on
* Android!
*
* @param textToAppend The text to add to the simple string.
*/
public void append(CharSequence textToAppend)
{
if (textToAppend != null)
{
if (size + textToAppend.length() > charArray.length)
resize(size + textToAppend.length());
for (int i = 0; i < textToAppend.length(); i++)
{
charArray[size] = textToAppend.charAt(i);
size++;
}
}
}
/**
* Adds a single character to the end of the simple string.
*
* @param character The character to add to the simple string.
*/
public void append(char character)
{
if (size + 1 > charArray.length)
resize(size + 1);
charArray[size] = character;
size++;
}
/**
* Adds an integer to the end of the simple string.
*
* @param number The integer to add to the simple string.
*/
public void append(int number)
{
int digit;
int numberOfDigits = (int) (Math.log10((double) number) + 1);
int divisor = (int) Math.pow(10, numberOfDigits - 1);
int remainder = number;
if (size + numberOfDigits > charArray.length)
resize(size + numberOfDigits);
for (int i = 0; i < numberOfDigits; i++)
{
digit = remainder / divisor;
remainder = number % divisor;
divisor /= 10;
charArray[size] = (char) (digit + ASCII_NUMBER_OFFSET);
size++;
}
}
/**
* Removes the last character if possible
*/
public void backspace()
{
if (size > 0)
{
size--;
charArray[size] = ' ';
}
}
/**
* Appends a space character to the end of the SimpleString.
*/
public void insertSpace()
{
if (size + 1 > charArray.length)
resize(size + 1);
charArray[size] = ' ';
size++;
}
/**
* Gets the character at the specified index if able..
*
* @param index The index of the character to obtain.
* @return The character at the specified index.
*/
@Override
public char charAt(int index)
{
if (index < size)
return charArray[index];
else
return ' ';
}
/**
* Blanks out all the internal characters in the array and resets the length
* to zero.
*/
public void clear()
{
for (int i = 0; i < charArray.length; i++)
charArray[i] = ' ';
size = 0;
}
/**
* Compares the given object to the Simple String to see if they are the
* same
*
* @return If the object has the same string as this Simple String
*/
@Override
public boolean equals(Object obj)
{
if (obj == null)
return false;
if (!(obj instanceof CharSequence))
return false;
CharSequence otherString = (CharSequence) obj;
if (size != otherString.length())
return false;
for (int i = 0; i < size; i++)
{
if (charArray[i] != otherString.charAt(i))
return false;
}
return true;
}
/**
* Gets the length of the simple string.
*
* @return The length of the simple string.
*/
@Override
public int length()
{
return size;
}
/**
* <p>
* Resizes the internal character array to accommodate larger character
* sequences.
* </p>
* <p>
* WARNING, this will allocate memory!
* </p>
*
* @param newArrayLength The length to set the internal character array to.
*/
private void resize(int newArrayLength)
{
char[] newCharArray = new char[newArrayLength];
for (int i = 0; i < charArray.length; i++)
newCharArray[i] = charArray[i];
charArray = newCharArray;
}
/**
* Clears the simple string and then performs a deep copy on the specified
* text to copy.
*
* @param textToCopy The text to copy in to the simple string.
*/
public void set(CharSequence textToCopy)
{
if (textToCopy == null)
{
clear();
return;
}
if (charArray.length < textToCopy.length())
resize(textToCopy.length());
this.clear();
for (int i = 0; i < textToCopy.length(); i++)
charArray[i] = textToCopy.charAt(i);
size = textToCopy.length();
}
/**
* Returns a simple string containing all the characters between the
* specified start and end points. Does not allocate memory.
*
* @param start The position to start reading characters.
* @param end The position to stop reading characters.
* @return A simple string containing the desired characters.
*/
@Override
public CharSequence subSequence(int start, int end)
{
subString.clear();
if (start >= 0 && end < size)
{
for (int i = start; i < end; i++)
subString.append(charArray[i]);
}
return subString;
}
/**
* <p>
* Returns a string version of the current charArray.
* </p>
* <p>
* WARNING! This will allocate memory!
* </p>
*
* @return A string of the charArray
*/
@Override
public String toString()
{
return new String(charArray).trim();
}
public char[] getCharArray()
{
return charArray;
}
@Override
public int hashCode()
{
int hashCode = HASHCODE_PRIME * size;
for (int i = 0; i < size; i++)
hashCode += charArray[i];
return hashCode;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment