You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@marmotta.apache.org by ss...@apache.org on 2013/09/06 14:27:04 UTC
[12/18] temporarily added a patched version of javolution with fast
collections, because the released version has several bugs (see
https://java.net/jira/browse/JAVOLUTION-106 and
https://java.net/jira/browse/JAVOLUTION-105)
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/e43574ef/commons/marmotta-commons/src/ext/java/javolution/text/Text.java
----------------------------------------------------------------------
diff --git a/commons/marmotta-commons/src/ext/java/javolution/text/Text.java b/commons/marmotta-commons/src/ext/java/javolution/text/Text.java
new file mode 100644
index 0000000..285ab34
--- /dev/null
+++ b/commons/marmotta-commons/src/ext/java/javolution/text/Text.java
@@ -0,0 +1,1333 @@
+/*
+ * Javolution - Java(TM) Solution for Real-Time and Embedded Systems
+ * Copyright (C) 2012 - Javolution (http://javolution.org/)
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software is
+ * freely granted, provided that this notice is preserved.
+ */
+package javolution.text;
+
+import java.io.PrintStream;
+
+import javolution.lang.MathLib;
+import javolution.lang.Realtime;
+import javolution.lang.ValueType;
+import javolution.util.FastMap;
+import javolution.util.function.Equalities;
+import javolution.xml.XMLSerializable;
+
+/**
+ * <p> An immutable character sequence with fast {@link #concat concatenation},
+ * {@link #insert insertion} and
+ * {@link #delete deletion} capabilities (O[Log(n)]) instead of
+ * O[n] for StringBuffer/StringBuilder).</p>
+ * <p> This class has the same methods as
+ * <a href="http://java.sun.com/j2se/1.5.0/docs/api/java/lang/String.html">
+ * Java String</a> and
+ * <a href="http://msdn2.microsoft.com/en-us/library/system.string.aspx">
+ * .NET String</a> with the following benefits:<ul>
+ * <li> No need for an intermediate
+ * {@link StringBuffer}/{@link StringBuilder} in order to manipulate
+ * textual documents (insertion, deletion or concatenation).</li>
+ * <li> Bug free. They are not plagued by the {@link String#substring} <a
+ * href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4513622">
+ * memory leak bug</a> (when small substrings prevent memory from
+ * larger string from being garbage collected).</li>
+ * <li> More flexible as they allows for search and comparison with any
+ * <code>java.lang.String</code> or <code>CharSequence</code>.</li>
+ * </ul></p>
+ * <p> {@link Text} literals should be explicitly {@link #intern interned}.
+ * Unlike strings literals and strings-value constant expressions,
+ * interning is not implicit. For example:[code]
+ * final static Text TRUE = new Text("true").intern();
+ * final static Text FALSE = new Text("true").intern("false");
+ * [/code]</p>
+ *
+ * <p><i> Implementation Note: To avoid expensive copy operations ,
+ * {@link Text} instances are broken down into smaller immutable
+ * sequences, they form a minimal-depth binary tree.
+ * The tree is maintained balanced automatically through <a
+ * href="http://en.wikipedia.org/wiki/Tree_rotation">tree rotations</a>.
+ * Insertion/deletions are performed in <code>O[Log(n)]</code>
+ * instead of <code>O[n]</code> for
+ * <code>StringBuffer/StringBuilder</code>.</i></p>
+ *
+ * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
+ * @author Wilfried Middleton
+ * @version 6.0, July 21, 2013
+ */
+@Realtime
+public final class Text implements CharSequence, Comparable<CharSequence>,
+ XMLSerializable, ValueType<Text> {
+
+ private static final long serialVersionUID = 0x600L; // Version.
+
+ /**
+ * Holds the default size for primitive blocks of characters.
+ */
+ private static final int BLOCK_SIZE = 1 << 5;
+
+ /**
+ * Holds the mask used to ensure a block boundary cesures.
+ */
+ private static final int BLOCK_MASK = ~(BLOCK_SIZE - 1);
+
+ /**
+ * Holds the texts interned in immortal memory.
+ */
+ private static final FastMap<Text, Text> INTERN = new FastMap<Text, Text>()
+ .shared();
+
+ /**
+ * Holds an empty character sequence.
+ */
+ public static final Text EMPTY = new Text("").intern();
+
+ /**
+ * Holds the raw data (primitive) or <code>null</code> (composite).
+ */
+ private final char[] _data;
+
+ /**
+ * Holds the total number of characters.
+ */
+ private int _count;
+
+ /**
+ * Holds the head block of character (composite).
+ */
+ private Text _head;
+
+ /**
+ * Holds the tail block of character (composite).
+ */
+ private Text _tail;
+
+ /**
+ * Creates a new text instance.
+ *
+ * @param isPrimitive indicates if primitive or composite.
+ */
+ private Text(boolean isPrimitive) {
+ _data = isPrimitive ? new char[BLOCK_SIZE] : null;
+ }
+
+ /**
+ * Creates a text holding the characters from the specified <code>String
+ * </code>.
+ *
+ * @param str the string holding the character content.
+ */
+ public Text(String str) {
+ this(str.length() <= BLOCK_SIZE);
+ _count = str.length();
+ if (_data != null) { // Primitive.
+ str.getChars(0, _count, _data, 0);
+ } else { // Composite, splits on a block boundary.
+ int half = ((_count + BLOCK_SIZE) >> 1) & BLOCK_MASK;
+ _head = new Text(str.substring(0, half));
+ _tail = new Text(str.substring(half, _count));
+ }
+ }
+
+ /**
+ * Returns the text representing the specified object.
+ *
+ * @param obj the object to represent as text.
+ * @return {@code new TextBuilder().append(obj).toText()}
+ */
+ public static Text valueOf(Object obj) {
+ return new TextBuilder().append(obj).toText();
+ }
+
+ private static Text valueOf(String str) {
+ return Text.valueOf(str, 0, str.length());
+ }
+
+ private static Text valueOf(String str, int start, int end) {
+ int length = end - start;
+ if (length <= BLOCK_SIZE) {
+ Text text = newPrimitive(length);
+ str.getChars(start, end, text._data, 0);
+ return text;
+ } else { // Splits on a block boundary.
+ int half = ((length + BLOCK_SIZE) >> 1) & BLOCK_MASK;
+ return newComposite(Text.valueOf(str, start, start + half),
+ Text.valueOf(str, start + half, end));
+ }
+ }
+
+ /**
+ * Returns the text that contains the characters from the specified
+ * array.
+ *
+ * @param chars the array source of the characters.
+ * @return the corresponding instance.
+ */
+ public static Text valueOf(char[] chars) {
+ return Text.valueOf(chars, 0, chars.length);
+ }
+
+ /**
+ * Returns the text that contains the characters from the specified
+ * subarray of characters.
+ *
+ * @param chars the source of the characters.
+ * @param offset the index of the first character in the data soure.
+ * @param length the length of the text returned.
+ * @return the corresponding instance.
+ * @throws IndexOutOfBoundsException if <code>(offset < 0) ||
+ * (length < 0) || ((offset + length) > chars.length)</code>
+ */
+ public static Text valueOf(char[] chars, int offset, int length) {
+ if ((offset < 0) || (length < 0) || ((offset + length) > chars.length))
+ throw new IndexOutOfBoundsException();
+ if (length <= BLOCK_SIZE) {
+ Text text = Text.newPrimitive(length);
+ System.arraycopy(chars, offset, text._data, 0, length);
+ return text;
+ } else { // Splits on a block boundary.
+ int half = ((length + BLOCK_SIZE) >> 1) & BLOCK_MASK;
+ return Text.newComposite(Text.valueOf(chars, offset, half),
+ Text.valueOf(chars, offset + half, length - half));
+ }
+ }
+
+ /**
+ * Converts a text builder to a text instance (optimization for
+ * TextBuilder.toText()).
+ *
+ * @param start the index of the first character inclusive.
+ * @param end the index of the last character exclusive.
+ * @return the corresponding text instance.
+ */
+ static Text valueOf(TextBuilder tb, int start, int end) {
+ int length = end - start;
+ if (length <= BLOCK_SIZE) {
+ Text text = Text.newPrimitive(length);
+ tb.getChars(start, end, text._data, 0);
+ return text;
+ } else { // Splits on a block boundary.
+ int half = ((length + BLOCK_SIZE) >> 1) & BLOCK_MASK;
+ return Text.newComposite(Text.valueOf(tb, start, start + half),
+ Text.valueOf(tb, start + half, end));
+ }
+ }
+
+ /**
+ * Returns the text representation of the <code>boolean</code> argument.
+ *
+ * @param b a <code>boolean</code>.
+ * @return if the argument is <code>true</code>, the text
+ * <code>"true"</code> is returned; otherwise, the text
+ * <code>"false"</code> is returned.
+ */
+ public static Text valueOf(boolean b) {
+ return b ? TRUE : FALSE;
+ }
+
+ private static final Text TRUE = new Text("true").intern();
+
+ private static final Text FALSE = new Text("false").intern();
+
+ /**
+ * Returns the text instance corresponding to the specified character.
+ *
+ * @param c a character.
+ * @return a text of length <code>1</code> containing <code>'c'</code>.
+ */
+ public static Text valueOf(char c) {
+ Text text = Text.newPrimitive(1);
+ text._data[0] = c;
+ return text;
+ }
+
+ /**
+ * Returns the decimal representation of the specified <code>int</code>
+ * argument.
+ *
+ * @param i the <code>int</code> to format.
+ * @return the corresponding text instance.
+ */
+ public static Text valueOf(int i) {
+ TextBuilder tb = new TextBuilder();
+ return tb.append(i).toText();
+ }
+
+ /**
+ * Returns the radix representation of the specified <code>int</code>
+ * argument.
+ *
+ * @param i the <code>int</code> to format.
+ * @param radix the radix (e.g. <code>16</code> for hexadecimal).
+ * @return the corresponding text instance.
+ */
+ public static Text valueOf(int i, int radix) {
+ TextBuilder tb = new TextBuilder();
+ return tb.append(i, radix).toText();
+ }
+
+ /**
+ * Returns the decimal representation of the specified <code>long</code>
+ * argument.
+ *
+ * @param l the <code>long</code> to format.
+ * @return the corresponding text instance.
+ */
+ public static Text valueOf(long l) {
+ TextBuilder tb = new TextBuilder();
+ return tb.append(l).toText();
+ }
+
+ /**
+ * Returns the radix representation of the specified <code>long</code>
+ * argument.
+ *
+ * @param l the <code>long</code> to format.
+ * @param radix the radix (e.g. <code>16</code> for hexadecimal).
+ * @return the corresponding text instance.
+ */
+ public static Text valueOf(long l, int radix) {
+ TextBuilder tb = new TextBuilder();
+ return tb.append(l, radix).toText();
+ }
+
+ /**
+ * Returns the textual representation of the specified <code>float</code>
+ * instance.
+ *
+ * @param f the <code>float</code> to format.
+ * @return the corresponding text instance.
+ */
+ public static Text valueOf(float f) {
+ TextBuilder tb = new TextBuilder();
+ return tb.append(f).toText();
+ }
+
+ /**
+ * Returns the textual representation of the specified <code>double</code>
+ * argument.
+ *
+ * @param d the <code>double</code> to format.
+ * @return the corresponding text instance.
+ */
+ public static Text valueOf(double d) {
+ TextBuilder tb = new TextBuilder();
+ return tb.append(d).toText();
+ }
+
+ /**
+ * Returns the textual representation of the specified <code>double</code>
+ * argument formatted as specified.
+ *
+ * @param d the <code>double</code> to format.
+ * @param digits the number of significative digits (excludes exponent) or
+ * <code>-1</code> to mimic the standard library (16 or 17 digits).
+ * @param scientific <code>true</code> to forces the use of the scientific
+ * notation (e.g. <code>1.23E3</code>); <code>false</code>
+ * otherwise.
+ * @param showZero <code>true</code> if trailing fractional zeros are
+ * represented; <code>false</code> otherwise.
+ * @return the corresponding text instance.
+ * @throws IllegalArgumentException if <code>(digits > 19)</code>)
+ */
+ public static Text valueOf(double d, int digits, boolean scientific,
+ boolean showZero) {
+ TextBuilder tb = new TextBuilder();
+ return tb.append(d, digits, scientific, showZero).toText();
+ }
+
+ /**
+ * Returns the length of this text.
+ *
+ * @return the number of characters (16-bits Unicode) composing this text.
+ */
+ public int length() {
+ return _count;
+ }
+
+ /**
+ * Returns the concatenation of this text and the textual
+ * representation of the specified object.
+ *
+ * @param obj the object whose textual representation is concatenated.
+ * @return <code>this.concat(Text.valueOf(obj))</code>
+ */
+ public Text plus(Object obj) {
+ return this.concat(Text.valueOf(obj));
+ }
+
+ /**
+ * Returns the concatenation of this text and the specified
+ * <code>String</code> (optimization).
+ *
+ * @param str the string whose characters are concatenated.
+ * @return <code>this.concat(Text.valueOf(obj))</code>
+ */
+ public Text plus(String str) {
+
+ Text merge = this.append(str);
+ return merge != null ? merge : concat(Text.valueOf(str));
+ }
+
+ private Text append(String str) { // Try to append, returns null if cannot.
+ int length = str.length();
+ if (_data == null) {
+ Text merge = _tail.append(str);
+ return merge != null ? Text.newComposite(_head, merge) : null;
+ } else { // Primitive.
+ if (_count + length > BLOCK_SIZE)
+ return null; // Cannot merge.
+ Text text = Text.newPrimitive(_count + length);
+ System.arraycopy(_data, 0, text._data, 0, _count);
+ str.getChars(0, length, text._data, _count);
+ return text;
+ }
+ }
+
+ /**
+ * Concatenates the specified text to the end of this text.
+ * This method is very fast (faster even than
+ * <code>StringBuffer.append(String)</code>) and still returns
+ * a text instance with an internal binary tree of minimal depth!
+ *
+ * @param that the text that is concatenated.
+ * @return <code>this + that</code>
+ */
+ public Text concat(Text that) {
+ // All Text instances are maintained balanced:
+ // (head < tail * 2) & (tail < head * 2)
+
+ final int length = this._count + that._count;
+ if (length <= BLOCK_SIZE) { // Merges to primitive.
+ Text text = Text.newPrimitive(length);
+ this.getChars(0, this._count, text._data, 0);
+ that.getChars(0, that._count, text._data, this._count);
+ return text;
+
+ } else { // Returns a composite.
+ Text head = this;
+ Text tail = that;
+
+ if (((head._count << 1) < tail._count) && (tail._data == null)) { // tail is composite
+ // head too small, returns (head + tail/2) + (tail/2)
+ if (tail._head._count > tail._tail._count) {
+ // Rotates to concatenate with smaller part.
+ tail = tail.rightRotation();
+ }
+ head = head.concat(tail._head);
+ tail = tail._tail;
+
+ } else if (((tail._count << 1) < head._count)
+ && (head._data == null)) { // head is composite.
+ // tail too small, returns (head/2) + (head/2 concat tail)
+ if (head._tail._count > head._head._count) {
+ // Rotates to concatenate with smaller part.
+ head = head.leftRotation();
+ }
+ tail = head._tail.concat(tail);
+ head = head._head;
+ }
+ return Text.newComposite(head, tail);
+ }
+ }
+
+ private Text rightRotation() {
+ // See: http://en.wikipedia.org/wiki/Tree_rotation
+ Text P = this._head;
+ if (P._data != null)
+ return this; // Head not a composite, cannot rotate.
+ Text A = P._head;
+ Text B = P._tail;
+ Text C = this._tail;
+ return Text.newComposite(A, Text.newComposite(B, C));
+ }
+
+ private Text leftRotation() {
+ // See: http://en.wikipedia.org/wiki/Tree_rotation
+ Text Q = this._tail;
+ if (Q._data != null)
+ return this; // Tail not a composite, cannot rotate.
+ Text B = Q._head;
+ Text C = Q._tail;
+ Text A = this._head;
+ return Text.newComposite(Text.newComposite(A, B), C);
+ }
+
+ /**
+ * Returns a portion of this text.
+ *
+ * @param start the index of the first character inclusive.
+ * @return the sub-text starting at the specified position.
+ * @throws IndexOutOfBoundsException if <code>(start < 0) ||
+ * (start > this.length())</code>
+ */
+ public Text subtext(int start) {
+ return subtext(start, length());
+ }
+
+ /**
+ * Returns the text having the specified text inserted at
+ * the specified location.
+ *
+ * @param index the insertion position.
+ * @param txt the text being inserted.
+ * @return <code>subtext(0, index).concat(txt).concat(subtext(index))</code>
+ * @throws IndexOutOfBoundsException if <code>(index < 0) ||
+ * (index > this.length())</code>
+ */
+ public Text insert(int index, Text txt) {
+ return subtext(0, index).concat(txt).concat(subtext(index));
+ }
+
+ /**
+ * Returns the text without the characters between the specified indexes.
+ *
+ * @param start the beginning index, inclusive.
+ * @param end the ending index, exclusive.
+ * @return <code>subtext(0, start).concat(subtext(end))</code>
+ * @throws IndexOutOfBoundsException if <code>(start < 0) || (end < 0) ||
+ * (start > end) || (end > this.length()</code>
+ */
+ public Text delete(int start, int end) {
+ if (start > end)
+ throw new IndexOutOfBoundsException();
+ return subtext(0, start).concat(subtext(end));
+ }
+
+ /**
+ * Replaces each character sequence of this text that matches the specified
+ * target sequence with the specified replacement sequence.
+ *
+ * @param target the character sequence to be replaced.
+ * @param replacement the replacement sequence.
+ * @return the resulting text.
+ */
+ public Text replace(java.lang.CharSequence target,
+ java.lang.CharSequence replacement) {
+ int i = indexOf(target);
+ return (i < 0) ? this : // No target sequence found.
+ subtext(0, i).concat(Text.valueOf(replacement)).concat(
+ subtext(i + target.length()).replace(target,
+ replacement));
+ }
+
+ /**
+ * Replaces the specified characters in this text with the specified
+ * replacement sequence.
+ *
+ * @param charSet the set of characters to be replaced.
+ * @param replacement the replacement sequence.
+ * @return the resulting text.
+ */
+ public Text replace(CharSet charSet, java.lang.CharSequence replacement) {
+ int i = indexOfAny(charSet);
+ return (i < 0) ? this : // No character to replace.
+ subtext(0, i).concat(Text.valueOf(replacement)).concat(
+ subtext(i + 1).replace(charSet, replacement));
+ }
+
+ /**
+ * Returns {@link #subtext(int, int) subtext(start, end)}.
+ *
+ * @param start the index of the first character inclusive.
+ * @param end the index of the last character exclusive.
+ * @return <code>this.subtext(start, end)</code>
+ * @throws IndexOutOfBoundsException if <code>(start < 0) || (end < 0) ||
+ * (start > end) || (end > this.length())</code>
+ */
+ public java.lang.CharSequence subSequence(int start, int end) {
+ return subtext(start, end);
+ }
+
+ /**
+ * Returns the index within this text of the first occurrence
+ * of the specified character sequence searching forward.
+ *
+ * @param csq a character sequence.
+ * @return the index of the first character of the character sequence found;
+ * or <code>-1</code> if the character sequence is not found.
+ */
+ public int indexOf(java.lang.CharSequence csq) {
+ return indexOf(csq, 0);
+ }
+
+ /**
+ * Returns the index within this text of the first occurrence
+ * of the specified characters sequence searching forward from
+ * the specified index.
+ *
+ * @param csq a character sequence.
+ * @param fromIndex the index to start the search from.
+ * @return the index in the range
+ * <code>[fromIndex, length() - csq.length()]</code>
+ * or <code>-1</code> if the character sequence is not found.
+ */
+ public int indexOf(java.lang.CharSequence csq, int fromIndex) {
+
+ // Limit cases.
+ final int csqLength = csq.length();
+ final int min = Math.max(0, fromIndex);
+ final int max = _count - csqLength;
+ if (csqLength == 0) { return (min > max) ? -1 : min; }
+
+ // Searches for csq.
+ final char c = csq.charAt(0);
+ for (int i = indexOf(c, min); (i >= 0) && (i <= max); i = indexOf(c,
+ ++i)) {
+ boolean match = true;
+ for (int j = 1; j < csqLength; j++) {
+ if (this.charAt(i + j) != csq.charAt(j)) {
+ match = false;
+ break;
+ }
+ }
+ if (match) { return i; }
+ }
+ return -1;
+ }
+
+ /**
+ * Returns the index within this text of the last occurrence of
+ * the specified characters sequence searching backward.
+ *
+ * @param csq a character sequence.
+ * @return the index of the first character of the character sequence found;
+ * or <code>-1</code> if the character sequence is not found.
+ */
+ public int lastIndexOf(java.lang.CharSequence csq) {
+ return lastIndexOf(csq, _count);
+ }
+
+ /**
+ * Returns the index within this text of the last occurrence of
+ * the specified character sequence searching backward from the specified
+ * index.
+ *
+ * @param csq a character sequence.
+ * @param fromIndex the index to start the backward search from.
+ * @return the index in the range <code>[0, fromIndex]</code> or
+ * <code>-1</code> if the character sequence is not found.
+ */
+ public int lastIndexOf(java.lang.CharSequence csq, int fromIndex) {
+
+ // Limit cases.
+ final int csqLength = csq.length();
+ final int min = 0;
+ final int max = Math.min(fromIndex, _count - csqLength);
+ if (csqLength == 0) { return (min > max) ? -1 : max; }
+
+ // Searches for csq.
+ final char c = csq.charAt(0);
+ for (int i = lastIndexOf(c, max); (i >= 0); i = lastIndexOf(c, --i)) {
+ boolean match = true;
+ for (int j = 1; j < csqLength; j++) {
+ if (this.charAt(i + j) != csq.charAt(j)) {
+ match = false;
+ break;
+ }
+ }
+ if (match) { return i; }
+ }
+ return -1;
+
+ }
+
+ /**
+ * Indicates if this text starts with the specified prefix.
+ *
+ * @param prefix the prefix.
+ * @return <code>true</code> if the character sequence represented by the
+ * argument is a prefix of the character sequence represented by
+ * this text; <code>false</code> otherwise.
+ */
+ public boolean startsWith(java.lang.CharSequence prefix) {
+ return startsWith(prefix, 0);
+ }
+
+ /**
+ * Indicates if this text ends with the specified suffix.
+ *
+ * @param suffix the suffix.
+ * @return <code>true</code> if the character sequence represented by the
+ * argument is a suffix of the character sequence represented by
+ * this text; <code>false</code> otherwise.
+ */
+ public boolean endsWith(java.lang.CharSequence suffix) {
+ return startsWith(suffix, length() - suffix.length());
+ }
+
+ /**
+ * Indicates if this text starts with the specified prefix
+ * at the specified index.
+ *
+ * @param prefix the prefix.
+ * @param index the index of the prefix location in this string.
+ * @return <code>this.substring(index).startsWith(prefix)</code>
+ */
+ public boolean startsWith(java.lang.CharSequence prefix, int index) {
+ final int prefixLength = prefix.length();
+ if ((index >= 0) && (index <= (this.length() - prefixLength))) {
+ for (int i = 0, j = index; i < prefixLength;) {
+ if (prefix.charAt(i++) != this.charAt(j++)) { return false; }
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Returns a copy of this text, with leading and trailing
+ * whitespace omitted.
+ *
+ * @return a copy of this text with leading and trailing white
+ * space removed, or this text if it has no leading or
+ * trailing white space.
+ */
+ public Text trim() {
+ int first = 0; // First character index.
+ int last = length() - 1; // Last character index.
+ while ((first <= last) && (charAt(first) <= ' ')) {
+ first++;
+ }
+ while ((last >= first) && (charAt(last) <= ' ')) {
+ last--;
+ }
+ return subtext(first, last + 1);
+ }
+
+ /**
+ * Returns a text equals to this one from a pool of
+ * unique text instances.
+ *
+ * @return an unique text instance allocated in permanent memory.
+ */
+ public Text intern() {
+ Text txt = INTERN.putIfAbsent(this, this);
+ return txt == null ? this : txt;
+ }
+
+ /**
+ * Indicates if this text has the same character content as the specified
+ * character sequence.
+ *
+ * @param csq the character sequence to compare with.
+ * @return <code>true</code> if the specified character sequence has the
+ * same character content as this text; <code>false</code> otherwise.
+ */
+ public boolean contentEquals(java.lang.CharSequence csq) {
+ if (csq.length() != _count)
+ return false;
+ for (int i = 0; i < _count;) {
+ if (this.charAt(i) != csq.charAt(i++))
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Indicates if this text has the same character contend as the specified
+ * character sequence ignoring case considerations.
+ *
+ * @param csq the <code>CharSequence</code> to compare this text against.
+ * @return <code>true</code> if the argument and this text are equal,
+ * ignoring case; <code>false</code> otherwise.
+ */
+ public boolean contentEqualsIgnoreCase(java.lang.CharSequence csq) {
+ if (this._count != csq.length())
+ return false;
+ for (int i = 0; i < _count;) {
+ char u1 = this.charAt(i);
+ char u2 = csq.charAt(i++);
+ if (u1 != u2) {
+ u1 = Character.toUpperCase(u1);
+ u2 = Character.toUpperCase(u2);
+ if ((u1 != u2)
+ && (Character.toLowerCase(u1) != Character
+ .toLowerCase(u2)))
+ return false;
+
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Compares this text against the specified object for equality.
+ * Returns <code>true</code> if the specified object is a text having
+ * the same character sequence as this text.
+ * For generic comparaison with any character sequence the
+ * {@link #contentEquals(CharSequence)} should be used.
+ *
+ * @param obj the object to compare with or <code>null</code>.
+ * @return <code>true</code> if that is a text with the same character
+ * sequence as this text; <code>false</code> otherwise.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!(obj instanceof Text))
+ return false;
+ final Text that = (Text) obj;
+ if (this._count != that._count)
+ return false;
+ for (int i = 0; i < _count;) {
+ if (this.charAt(i) != that.charAt(i++))
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Returns the hash code for this text.
+ *
+ * @return the hash code value.
+ */
+ @Override
+ public int hashCode() {
+ int h = 0;
+ final int length = this.length();
+ for (int i = 0; i < length;) {
+ h = 31 * h + charAt(i++);
+ }
+ return h;
+ }
+
+ /**
+ * Compares this text to another character sequence or string
+ * lexicographically.
+ *
+ * @param csq the character sequence to be compared.
+ * @return <code>TypeFormat.LEXICAL_COMPARATOR.compare(this, csq)</code>
+ * @throws ClassCastException if the specifed object is not a
+ * <code>CharSequence</code> or a <code>String</code>.
+ */
+ public int compareTo(CharSequence csq) {
+ return Equalities.LEXICAL.compare(this, csq);
+ }
+
+ /**
+ * Returns <code>this</code> (implements
+ * {@link javolution.lang.ValueType Realtime} interface).
+ *
+ * @return <code>this</code>
+ */
+ public Text toText() {
+ return this;
+ }
+
+ /**
+ * Prints the current statistics on this text tree structure.
+ *
+ * @param out the stream to use for output (e.g. <code>System.out</code>)
+ */
+ public void printStatistics(PrintStream out) {
+ int length = this.length();
+ int leaves = getNbrOfLeaves();
+ synchronized (out) {
+ out.print("LENGTH: " + length());
+ out.print(", MAX DEPTH: " + getDepth());
+ out.print(", NBR OF BRANCHES: " + getNbrOfBranches());
+ out.print(", NBR OF LEAVES: " + leaves);
+ out.print(", AVG LEAVE LENGTH: " + (length + (leaves >> 1))
+ / leaves);
+ out.println();
+ }
+ }
+
+ private int getDepth() {
+ if (_data != null) // Primitive.
+ return 0;
+ return MathLib.max(_head.getDepth(), _tail.getDepth()) + 1;
+ }
+
+ private int getNbrOfBranches() {
+ return (_data == null) ? _head.getNbrOfBranches()
+ + _tail.getNbrOfBranches() + 1 : 0;
+ }
+
+ private int getNbrOfLeaves() {
+ return (_data == null) ? _head.getNbrOfLeaves()
+ + _tail.getNbrOfLeaves() : 1;
+ }
+
+ /**
+ * Converts the characters of this text to lower case.
+ *
+ * @return the text in lower case.
+ * @see Character#toLowerCase(char)
+ */
+ public Text toLowerCase() {
+ if (_data == null) // Composite.
+ return Text.newComposite(_head.toLowerCase(), _tail.toLowerCase());
+ Text text = Text.newPrimitive(_count);
+ for (int i = 0; i < _count;) {
+ text._data[i] = Character.toLowerCase(_data[i++]);
+ }
+ return text;
+ }
+
+ /**
+ * Converts the characters of this text to upper case.
+ *
+ * @return the text in lower case.
+ * @see Character#toUpperCase(char)
+ */
+ public Text toUpperCase() {
+ if (_data == null) // Composite.
+ return newComposite(_head.toUpperCase(), _tail.toUpperCase());
+ Text text = Text.newPrimitive(_count);
+ for (int i = 0; i < _count;) {
+ text._data[i] = Character.toUpperCase(_data[i++]);
+ }
+ return text;
+ }
+
+ /**
+ * Returns the character at the specified index.
+ *
+ * @param index the index of the character.
+ * @return the character at the specified index.
+ * @throws IndexOutOfBoundsException if <code>(index < 0) ||
+ * (index >= this.length())</code>
+ */
+ public char charAt(int index) {
+ if (index >= _count)
+ throw new IndexOutOfBoundsException();
+ return (_data != null) ? _data[index] : (index < _head._count) ? _head
+ .charAt(index) : _tail.charAt(index - _head._count);
+ }
+
+ /**
+ * Returns the index within this text of the first occurrence of the
+ * specified character, starting the search at the beginning.
+ *
+ * @param c the character to search for.
+ * @return the index of the first occurrence of the character in this text
+ * that is greater than or equal to <code>0</code>,
+ * or <code>-1</code> if the character does not occur.
+ */
+ public int indexOf(char c) {
+ return indexOf(c, 0);
+ }
+
+ /**
+ * Returns the index within this text of the first occurrence of the
+ * specified character, starting the search at the specified index.
+ *
+ * @param c the character to search for.
+ * @param fromIndex the index to start the search from.
+ * @return the index of the first occurrence of the character in this text
+ * that is greater than or equal to <code>fromIndex</code>,
+ * or <code>-1</code> if the character does not occur.
+ */
+ public int indexOf(char c, int fromIndex) {
+ if (_data != null) { // Primitive.
+ for (int i = MathLib.max(fromIndex, 0); i < _count; i++) {
+ if (_data[i] == c)
+ return i;
+ }
+ return -1;
+ } else { // Composite.
+ final int cesure = _head._count;
+ if (fromIndex < cesure) {
+ final int headIndex = _head.indexOf(c, fromIndex);
+ if (headIndex >= 0)
+ return headIndex; // Found in head.
+ }
+ final int tailIndex = _tail.indexOf(c, fromIndex - cesure);
+ return (tailIndex >= 0) ? tailIndex + cesure : -1;
+ }
+ }
+
+ /**
+ * Returns the index within this text of the first occurrence of the
+ * specified character, searching backward and starting at the specified
+ * index.
+ *
+ * @param c the character to search for.
+ * @param fromIndex the index to start the search backward from.
+ * @return the index of the first occurrence of the character in this text
+ * that is less than or equal to <code>fromIndex</code>,
+ * or <code>-1</code> if the character does not occur.
+ */
+ public int lastIndexOf(char c, int fromIndex) {
+ if (_data != null) { // Primitive.
+ for (int i = MathLib.min(fromIndex, _count - 1); i >= 0; i--) {
+ if (_data[i] == c)
+ return i;
+ }
+ return -1;
+ } else { // Composite.
+ final int cesure = _head._count;
+ if (fromIndex >= cesure) {
+ final int tailIndex = _tail.lastIndexOf(c, fromIndex - cesure);
+ if (tailIndex >= 0)
+ return tailIndex + cesure; // Found in tail.
+ }
+ return _head.lastIndexOf(c, fromIndex);
+ }
+ }
+
+ /**
+ * Returns a portion of this text.
+ *
+ * @param start the index of the first character inclusive.
+ * @param end the index of the last character exclusive.
+ * @return the sub-text starting at the specified start position and
+ * ending just before the specified end position.
+ * @throws IndexOutOfBoundsException if <code>(start < 0) || (end < 0) ||
+ * (start > end) || (end > this.length())</code>
+ */
+ public Text subtext(int start, int end) {
+ if (_data != null) { // Primitive.
+ if ((start < 0) || (start > end) || (end > _count))
+ throw new IndexOutOfBoundsException();
+ if ((start == 0) && (end == _count))
+ return this;
+ if (start == end)
+ return Text.EMPTY;
+ int length = end - start;
+ Text text = Text.newPrimitive(length);
+ System.arraycopy(_data, start, text._data, 0, length);
+ return text;
+ } else { // Composite.
+ final int cesure = _head._count;
+ if (end <= cesure)
+ return _head.subtext(start, end);
+ if (start >= cesure)
+ return _tail.subtext(start - cesure, end - cesure);
+ if ((start == 0) && (end == _count))
+ return this;
+ // Overlaps head and tail.
+ return _head.subtext(start, cesure).concat(
+ _tail.subtext(0, end - cesure));
+ }
+ }
+
+ /**
+ * Copies the characters from this text into the destination
+ * character array.
+ *
+ * @param start the index of the first character to copy.
+ * @param end the index after the last character to copy.
+ * @param dest the destination array.
+ * @param destPos the start offset in the destination array.
+ * @throws IndexOutOfBoundsException if <code>(start < 0) || (end < 0) ||
+ * (start > end) || (end > this.length())</code>
+ */
+ public void getChars(int start, int end, char dest[], int destPos) {
+ if (_data != null) { // Primitive.
+ if ((start < 0) || (end > _count) || (start > end))
+ throw new IndexOutOfBoundsException();
+ System.arraycopy(_data, start, dest, destPos, end - start);
+ } else { // Composite.
+ final int cesure = _head._count;
+ if (end <= cesure) {
+ _head.getChars(start, end, dest, destPos);
+ } else if (start >= cesure) {
+ _tail.getChars(start - cesure, end - cesure, dest, destPos);
+ } else { // Overlaps head and tail.
+ _head.getChars(start, cesure, dest, destPos);
+ _tail.getChars(0, end - cesure, dest, destPos + cesure - start);
+ }
+ }
+ }
+
+ /**
+ * Returns the <code>String</code> representation of this text.
+ *
+ * @return the <code>java.lang.String</code> for this text.
+ */
+ public String toString() {
+ if (_data != null) { // Primitive.
+ return new String(_data, 0, _count);
+ } else { // Composite.
+ char[] data = new char[_count];
+ this.getChars(0, _count, data, 0);
+ return new String(data, 0, _count);
+ }
+ }
+
+ // Implements ValueType interface.
+ public Text copy() {
+ if (_data != null) { // Primitive.
+ Text text = Text.newPrimitive(_count);
+ System.arraycopy(_data, 0, text._data, 0, _count);
+ return text;
+ } else { // Composite.
+ return Text.newComposite((Text) _head.copy(), (Text) _tail.copy());
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////
+ // Wilfried add-ons (methods provided by Microsoft .Net in C#)
+ //
+ /**
+ * Returns the text that contains a specific length sequence of the
+ * character specified.
+ *
+ * @param c the character to fill this text with.
+ * @param length the length of the text returned.
+ * @return the corresponding instance.
+ * @throws IndexOutOfBoundsException if <code>(length < 0)</code>
+ */
+ public static Text valueOf(char c, int length) {
+ if (length < 0)
+ throw new IndexOutOfBoundsException();
+ if (length <= BLOCK_SIZE) {
+ Text text = Text.newPrimitive(length);
+ for (int i = 0; i < length;) {
+ text._data[i++] = c;
+ }
+ return text;
+ } else {
+ final int middle = (length >> 1);
+ return Text.newComposite(Text.valueOf(c, middle),
+ Text.valueOf(c, length - middle));
+ }
+ }
+
+ /**
+ * Indicates if all characters of this text are whitespaces
+ * (no characters greater than the space character).
+ *
+ *@return <code>true</code> if this text contains only whitespace.
+ */
+ public boolean isBlank() {
+ return isBlank(0, length());
+ }
+
+ /**
+ * Indicates if the specified sub-range of characters of this text
+ * are whitespaces (no characters greater than the space character).
+ *
+ *@param start the start index.
+ *@param length the number of characters to inspect.
+ */
+ public boolean isBlank(int start, int length) {
+ for (; start < length; start++) {
+ if (charAt(start) > ' ')
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Returns a copy of this text, with leading whitespace omitted.
+ *
+ * @return a copy of this text with leading white space removed,
+ * or this text if it has no leading white space.
+ */
+ public Text trimStart() {
+ int first = 0; // First character index.
+ int last = length() - 1; // Last character index.
+ while ((first <= last) && (charAt(first) <= ' ')) {
+ first++;
+ }
+ return subtext(first, last + 1);
+ }
+
+ /**
+ * Returns a copy of this text, with trailing
+ * whitespace omitted.
+ *
+ * @return a copy of this text with trailing white space removed,
+ * or this text if it has no trailing white space.
+ */
+ public Text trimEnd() {
+ int first = 0; // First character index.
+ int last = length() - 1; // Last character index.
+ while ((last >= first) && (charAt(last) <= ' ')) {
+ last--;
+ }
+ return subtext(first, last + 1);
+ }
+
+ /**
+ * Pads this text on the left with spaces to make the minimum total length
+ * as specified.
+ * The new length of the new text is equal to the original length plus
+ * <code>(length()-len)</code> spaces.
+ *
+ * @param len the total number of characters to make this text equal to.
+ * @return a new text or the same text if no padding required.
+ * @throws an IllegalArgumentException if the <code>(len<0)</code>.
+ */
+ public Text padLeft(int len) {
+ return padLeft(len, ' ');
+ }
+
+ /**
+ * Pads this text on the left to make the minimum total length as specified.
+ * Spaces or the given Unicode character are used to pad with.
+ * <br>
+ * The new length of the new text is equal to the original length plus
+ * <code>(length()-len)</code> pad characters.
+ *
+ * @param len the total number of characters to make this text equal to.
+ * @param c the character to pad using.
+ * @return a new text or the same text if no padding required.
+ * @throws an IllegalArgumentException if the <code>(len<0)</code>.
+ */
+ public Text padLeft(int len, char c) {
+ final int padSize = (len <= length()) ? 0 : len - length();
+ return insert(0, Text.valueOf(c, padSize));
+ }
+
+ /**
+ * Pads this text on the right with spaces to make the minimum total length
+ * as specified.
+ * The new length of the new text is equal to the original length plus
+ * <code>(length()-len)</code> spaces.
+ *
+ * @param len the total number of characters to make this text equal to.
+ * @return a new text or the same text if no padding required.
+ * @throws an IllegalArgumentException if the <code>(len<0)</code>.
+ */
+ public Text padRight(int len) {
+ return padRight(len, ' ');
+ }
+
+ /**
+ * Pads this text on the right to make the minimum total length as specified.
+ * Spaces or the given Unicode character are used to pad with.
+ * <br>
+ * The new length of the new text is equal to the original length plus
+ * <code>(length()-len)</code> pad characters.
+ *
+ * @param len the total number of characters to make this text equal to.
+ * @param c the character to pad using.
+ * @return a new text or the same text if no padding required.
+ * @throws an IllegalArgumentException if the <code>(len<0)</code>.
+ */
+ public Text padRight(int len, char c) {
+ final int padSize = (len <= length()) ? 0 : len - length();
+ return concat(Text.valueOf(c, padSize));
+ }
+
+ /**
+ * Returns the index within this text of the first occurrence
+ * of any character in the specified character set.
+ *
+ * @param charSet the character set.
+ * @return the index of the first character that matches one of the
+ * characters in the supplied set; or <code>-1</code> if none.
+ */
+ public int indexOfAny(CharSet charSet) {
+ return indexOfAny(charSet, 0, length());
+ }
+
+ /**
+ * Returns the index within a region of this text of the first occurrence
+ * of any character in the specified character set.
+ *
+ * @param charSet the character set.
+ * @param start the index of the start of the search region in this text.
+ * @return the index of the first character that matches one of the
+ * characters in the supplied set; or <code>-1</code> if none.
+ */
+ public int indexOfAny(CharSet charSet, int start) {
+ return indexOfAny(charSet, start, length() - start);
+ }
+
+ /**
+ * Returns the index within a region of this text of the first occurrence
+ * of any character in the specified character set.
+ *
+ * @param charSet the character set.
+ * @param start the index of the start of the search region in this text.
+ * @param length the length of the region to search.
+ * @return the index of the first character that matches one of the
+ * characters in the supplied array; or <code>-1</code> if none.
+ */
+ public int indexOfAny(CharSet charSet, int start, int length) {
+ final int stop = start + length;
+ for (int i = start; i < stop; i++) {
+ if (charSet.contains(charAt(i)))
+ return i;
+ }
+ return -1;
+ }
+
+ /**
+ * Returns the index within this text of the last occurrence
+ * of any character in the specified character set.
+ *
+ * @param charSet the character set.
+ * @return the index of the last character that matches one of the
+ * characters in the supplied array; or <code>-1</code> if none.
+ */
+ public int lastIndexOfAny(CharSet charSet) {
+ return lastIndexOfAny(charSet, 0, length());
+ }
+
+ /**
+ * Returns the index within a region of this text of the last occurrence
+ * of any character in the specified character set.
+ *
+ * @param charSet the character set.
+ * @param start the index of the start of the search region in this text.
+ * @return the index of the last character that matches one of the
+ * characters in the supplied array; or <code>-1</code> if none.
+ */
+ public int lastIndexOfAny(CharSet charSet, int start) {
+ return lastIndexOfAny(charSet, start, length() - start);
+ }
+
+ /**
+ * Returns the index within a region of this text of the last occurrence
+ * of any character in the specified character set.
+ *
+ * @param charSet the character set.
+ * @param start the index of the start of the search region in this text.
+ * @param length the length of the region to search.
+ * @return the index of the last character that matches one of the
+ * characters in the supplied array; or <code>-1</code> if none.
+ */
+ public int lastIndexOfAny(CharSet charSet, int start, int length) {
+ for (int i = start + length; --i >= start;) {
+ if (charSet.contains(charAt(i)))
+ return i;
+ }
+ return -1;
+ }
+
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /**
+ * Returns a {@link javolution.context.AllocatorContext context allocated}
+ * primitive text instance.
+ *
+ * @param length the primitive length.
+ */
+ private static Text newPrimitive(int length) {
+ Text text = new Text(true);
+ text._count = length;
+ return text;
+ }
+
+ /**
+ * Returns a {@link javolution.context.AllocatorContext context allocated}
+ * composite text instance.
+ *
+ * @param head the composite head.
+ * @param tail the composite tail.
+ */
+ private static Text newComposite(Text head, Text tail) {
+ Text text = new Text(false);
+ text._count = head._count + tail._count;
+ text._head = head;
+ text._tail = tail;
+ return text;
+ }
+
+ @Override
+ public Text value() {
+ return this;
+ }
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/e43574ef/commons/marmotta-commons/src/ext/java/javolution/text/TextBuilder.java
----------------------------------------------------------------------
diff --git a/commons/marmotta-commons/src/ext/java/javolution/text/TextBuilder.java b/commons/marmotta-commons/src/ext/java/javolution/text/TextBuilder.java
new file mode 100644
index 0000000..c5f0a9f
--- /dev/null
+++ b/commons/marmotta-commons/src/ext/java/javolution/text/TextBuilder.java
@@ -0,0 +1,888 @@
+/*
+ * Javolution - Java(TM) Solution for Real-Time and Embedded Systems
+ * Copyright (C) 2012 - Javolution (http://javolution.org/)
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software is
+ * freely granted, provided that this notice is preserved.
+ */
+package javolution.text;
+
+import java.io.Serializable;
+import javolution.lang.MathLib;
+
+/**
+ * <p> An {@link Appendable} text whose capacity expands
+ * gently without incurring expensive resize/copy operations ever.</p>
+ *
+ * <p> This class is not intended for large documents manipulations which
+ * should be performed with the {@link Text} class directly
+ * (<code>O(Log(n))</code> {@link Text#insert insertion} and
+ * {@link Text#delete deletion} capabilities).</p>
+ *
+ * <p> The textual format of any appended object is retrieved
+ * from the current {@link TextContext}.</p>
+ *
+ * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
+ * @version 5.3, January 20, 2008
+ */
+public class TextBuilder implements Appendable, CharSequence, Serializable {
+
+ private static final long serialVersionUID = 0x600L; // Version.
+ // We do a full resize (and copy) only when the capacity is less than C1.
+ // For large collections, multi-dimensional arrays are employed.
+ private static final int B0 = 5; // Initial capacity in bits.
+ private static final int C0 = 1 << B0; // Initial capacity (32)
+ private static final int B1 = 10; // Low array maximum capacity in bits.
+ private static final int C1 = 1 << B1; // Low array maximum capacity (1024).
+ private static final int M1 = C1 - 1; // Mask.
+ // Resizes up to 1024 maximum (32, 64, 128, 256, 512, 1024).
+ private char[] _low = new char[C0];
+ // For larger capacity use multi-dimensional array.
+ private char[][] _high = new char[1][];
+
+ /**
+ * Holds the current length.
+ */
+ private int _length;
+
+ /**
+ * Holds current capacity.
+ */
+ private int _capacity = C0;
+
+ /**
+ * Creates a text builder of small initial capacity.
+ */
+ public TextBuilder() {
+ _high[0] = _low;
+ }
+
+ /**
+ * Creates a text builder holding the specified <code>String</code>
+ * (convenience method).
+ *
+ * @param str the initial string content of this text builder.
+ */
+ public TextBuilder(String str) {
+ this();
+ append(str);
+ }
+
+ /**
+ * Creates a text builder of specified initial capacity.
+ * Unless the text length exceeds the specified capacity, operations
+ * on this text builder will not allocate memory.
+ *
+ * @param capacity the initial capacity.
+ */
+ public TextBuilder(int capacity) {
+ this();
+ while (capacity > _capacity) {
+ increaseCapacity();
+ }
+ }
+
+ /**
+ * Returns the length (character count) of this text builder.
+ *
+ * @return the number of characters (16-bits Unicode).
+ */
+ public final int length() {
+ return _length;
+ }
+
+ /**
+ * Returns the character at the specified index.
+ *
+ * @param index the index of the character.
+ * @return the character at the specified index.
+ * @throws IndexOutOfBoundsException if
+ * <code>(index < 0) || (index >= this.length())</code>.
+ */
+ public final char charAt(int index) {
+ if (index >= _length)
+ throw new IndexOutOfBoundsException();
+ return index < C1 ? _low[index] : _high[index >> B1][index & M1];
+ }
+
+ /**
+ * Copies the character from this text builder into the destination
+ * character array.
+ *
+ * @param srcBegin this text start index.
+ * @param srcEnd this text end index (not included).
+ * @param dst the destination array to copy the data into.
+ * @param dstBegin the offset into the destination array.
+ * @throws IndexOutOfBoundsException if <code>(srcBegin < 0) ||
+ * (dstBegin < 0) || (srcBegin > srcEnd) || (srcEnd > this.length())
+ * || ((dstBegin + srcEnd - srcBegin) > dst.length)</code>
+ */
+ public final void getChars(int srcBegin, int srcEnd, char[] dst,
+ int dstBegin) {
+ if ((srcBegin < 0) || (srcBegin > srcEnd) || (srcEnd > this._length))
+ throw new IndexOutOfBoundsException();
+ for (int i = srcBegin, j = dstBegin; i < srcEnd;) {
+ char[] chars0 = _high[i >> B1];
+ int i0 = i & M1;
+ int length = MathLib.min(C1 - i0, srcEnd - i);
+ System.arraycopy(chars0, i0, dst, j, length);
+ i += length;
+ j += length;
+ }
+ }
+
+ /**
+ * Sets the character at the specified position.
+ *
+ * @param index the index of the character to modify.
+ * @param c the new character.
+ * @throws IndexOutOfBoundsException if <code>(index < 0) ||
+ * (index >= this.length())</code>
+ */
+ public final void setCharAt(int index, char c) {
+ if ((index < 0) || (index >= _length))
+ throw new IndexOutOfBoundsException();
+ _high[index >> B1][index & M1] = c;
+ }
+
+ /**
+ * Convenience method equivalent to {@link #setLength(int, char)
+ * setLength(newLength, '\u0000')}.
+ *
+ * @param newLength the new length of this builder.
+ * @throws IndexOutOfBoundsException if <code>(newLength < 0)</code>
+ */
+ public final void setLength(int newLength) {
+ setLength(newLength, '\u0000');
+ }
+
+ /**
+ * Sets the length of this character builder.
+ * If the length is greater than the current length; the
+ * specified character is inserted.
+ *
+ * @param newLength the new length of this builder.
+ * @param fillChar the character to be appended if required.
+ * @throws IndexOutOfBoundsException if <code>(newLength < 0)</code>
+ */
+ public final void setLength(int newLength, char fillChar) {
+ if (newLength < 0)
+ throw new IndexOutOfBoundsException();
+ if (newLength <= _length)
+ _length = newLength;
+ else
+ for (int i = _length; i++ < newLength;) {
+ append(fillChar);
+ }
+ }
+
+ /**
+ * Returns a {@link java.lang.CharSequence} corresponding
+ * to the character sequence between the specified indexes.
+ *
+ * @param start the index of the first character inclusive.
+ * @param end the index of the last character exclusive.
+ * @return a character sequence.
+ * @throws IndexOutOfBoundsException if <code>(start < 0) || (end < 0) ||
+ * (start > end) || (end > this.length())</code>
+ */
+ public final java.lang.CharSequence subSequence(int start, int end) {
+ if ((start < 0) || (end < 0) || (start > end) || (end > _length))
+ throw new IndexOutOfBoundsException();
+ return Text.valueOf(this, start, end);
+ }
+
+ /**
+ * Appends the specified character.
+ *
+ * @param c the character to append.
+ * @return <code>this</code>
+ */
+ public final TextBuilder append(char c) {
+ if (_length >= _capacity)
+ increaseCapacity();
+ _high[_length >> B1][_length & M1] = c;
+ _length++;
+ return this;
+ }
+
+ /**
+ * Appends the textual representation of the specified object.
+ * This method is equivalent to
+ * {@code TextContext.getFormat(obj.getClass()).format(obj, this)}
+ */
+ public final TextBuilder append(Object obj) {
+ if (obj == null) return append("null");
+ TextFormat<Object> textFormat = TextContext.getFormat(obj.getClass());
+ if (textFormat == null) return append(obj.toString());
+ return textFormat.format(obj, this);
+ }
+
+ /**
+ * Appends the specified character sequence. If the specified character
+ * sequence is <code>null</code> this method is equivalent to
+ * <code>append("null")</code>.
+ *
+ * @param csq the character sequence to append or <code>null</code>.
+ * @return <code>this</code>
+ */
+ public final TextBuilder append(CharSequence csq) {
+ return (csq == null) ? append("null") : append(csq, 0, csq.length());
+ }
+
+ /**
+ * Appends a subsequence of the specified character sequence.
+ * If the specified character sequence is <code>null</code> this method
+ * is equivalent to <code>append("null")</code>.
+ *
+ * @param csq the character sequence to append or <code>null</code>.
+ * @param start the index of the first character to append.
+ * @param end the index after the last character to append.
+ * @return <code>this</code>
+ * @throws IndexOutOfBoundsException if <code>(start < 0) || (end < 0)
+ * || (start > end) || (end > csq.length())</code>
+ */
+ public final TextBuilder append(CharSequence csq, int start,
+ int end) {
+ if (csq == null)
+ return append("null");
+ if ((start < 0) || (end < 0) || (start > end) || (end > csq.length()))
+ throw new IndexOutOfBoundsException();
+ for (int i = start; i < end;) {
+ append(csq.charAt(i++));
+ }
+ return this;
+ }
+
+ /**
+ * Appends the specified string to this text builder.
+ * If the specified string is <code>null</code> this method
+ * is equivalent to <code>append("null")</code>.
+ *
+ * @param str the string to append or <code>null</code>.
+ * @return <code>this</code>
+ */
+ public final TextBuilder append(String str) {
+ return (str == null) ? append("null") : append(str, 0, str.length());
+ }
+
+ /**
+ * Appends a subsequence of the specified string.
+ * If the specified character sequence is <code>null</code> this method
+ * is equivalent to <code>append("null")</code>.
+ *
+ * @param str the string to append or <code>null</code>.
+ * @param start the index of the first character to append.
+ * @param end the index after the last character to append.
+ * @return <code>this</code>
+ * @throws IndexOutOfBoundsException if <code>(start < 0) || (end < 0)
+ * || (start > end) || (end > str.length())</code>
+ */
+ public final TextBuilder append(String str, int start, int end) {
+ if (str == null)
+ return append("null");
+ if ((start < 0) || (end < 0) || (start > end) || (end > str.length()))
+ throw new IndexOutOfBoundsException("start: " + start + ", end: "
+ + end + ", str.length(): " + str.length());
+ int newLength = _length + end - start;
+ while (_capacity < newLength) {
+ increaseCapacity();
+ }
+ for (int i = start, j = _length; i < end;) {
+ char[] chars = _high[j >> B1];
+ int dstBegin = j & M1;
+ int inc = MathLib.min(C1 - dstBegin, end - i);
+ str.getChars(i, (i += inc), chars, dstBegin);
+ j += inc;
+ }
+ _length = newLength;
+ return this;
+ }
+
+ /**
+ * Appends the specified text to this text builder.
+ * If the specified text is <code>null</code> this method
+ * is equivalent to <code>append("null")</code>.
+ *
+ * @param txt the text to append or <code>null</code>.
+ * @return <code>this</code>
+ */
+ public final TextBuilder append(Text txt) {
+ return (txt == null) ? append("null") : append(txt, 0, txt.length());
+ }
+
+ /**
+ * Appends a subsequence of the specified text.
+ * If the specified character sequence is <code>null</code> this method
+ * is equivalent to <code>append("null")</code>.
+ *
+ * @param txt the text to append or <code>null</code>.
+ * @param start the index of the first character to append.
+ * @param end the index after the last character to append.
+ * @return <code>this</code>
+ * @throws IndexOutOfBoundsException if <code>(start < 0) || (end < 0)
+ * || (start > end) || (end > txt.length())</code>
+ */
+ public final TextBuilder append(Text txt, int start, int end) {
+ if (txt == null)
+ return append("null");
+ if ((start < 0) || (end < 0) || (start > end) || (end > txt.length()))
+ throw new IndexOutOfBoundsException();
+ int newLength = _length + end - start;
+ while (_capacity < newLength) {
+ increaseCapacity();
+ }
+ for (int i = start, j = _length; i < end;) {
+ char[] chars = _high[j >> B1];
+ int dstBegin = j & M1;
+ int inc = MathLib.min(C1 - dstBegin, end - i);
+ txt.getChars(i, (i += inc), chars, dstBegin);
+ j += inc;
+ }
+ _length = newLength;
+ return this;
+ }
+
+ /**
+ * Appends the characters from the char array argument.
+ *
+ * @param chars the character array source.
+ * @return <code>this</code>
+ */
+ public final TextBuilder append(char chars[]) {
+ append(chars, 0, chars.length);
+ return this;
+ }
+
+ /**
+ * Appends the characters from a subarray of the char array argument.
+ *
+ * @param chars the character array source.
+ * @param offset the index of the first character to append.
+ * @param length the number of character to append.
+ * @return <code>this</code>
+ * @throws IndexOutOfBoundsException if <code>(offset < 0) ||
+ * (length < 0) || ((offset + length) > chars.length)</code>
+ */
+ public final TextBuilder append(char chars[], int offset, int length) {
+ final int end = offset + length;
+ if ((offset < 0) || (length < 0) || (end > chars.length))
+ throw new IndexOutOfBoundsException();
+ int newLength = _length + length;
+ while (_capacity < newLength) {
+ increaseCapacity();
+ }
+ for (int i = offset, j = _length; i < end;) {
+ char[] dstChars = _high[j >> B1];
+ int dstBegin = j & M1;
+ int inc = MathLib.min(C1 - dstBegin, end - i);
+ System.arraycopy(chars, i, dstChars, dstBegin, inc);
+ i += inc;
+ j += inc;
+ }
+ _length = newLength;
+ return this;
+ }
+
+ /**
+ * Appends the textual representation of the specified <code>boolean</code>
+ * argument.
+ *
+ * @param b the <code>boolean</code> to format.
+ * @return <code>this</code>
+ * @see TypeFormat
+ */
+ public final TextBuilder append(boolean b) {
+ return b ? append("true") : append("false");
+ }
+
+ /**
+ * Appends the decimal representation of the specified <code>int</code>
+ * argument.
+ *
+ * @param i the <code>int</code> to format.
+ * @return <code>this</code>
+ */
+ public final TextBuilder append(int i) {
+ if (i <= 0) {
+ if (i == 0)
+ return append("0");
+ if (i == Integer.MIN_VALUE) // Negation would overflow.
+ return append("-2147483648");
+ append('-');
+ i = -i;
+ }
+ int digits = MathLib.digitLength(i);
+ if (_capacity < _length + digits)
+ increaseCapacity();
+ _length += digits;
+ for (int index = _length - 1;; index--) {
+ int j = i / 10;
+ _high[index >> B1][index & M1] = (char) ('0' + i - (j * 10));
+ if (j == 0)
+ return this;
+ i = j;
+ }
+ }
+
+ /**
+ * Appends the radix representation of the specified <code>int</code>
+ * argument.
+ *
+ * @param i the <code>int</code> to format.
+ * @param radix the radix (e.g. <code>16</code> for hexadecimal).
+ * @return <code>this</code>
+ */
+ public final TextBuilder append(int i, int radix) {
+ if (radix == 10)
+ return append(i); // Faster.
+ if (radix < 2 || radix > 36)
+ throw new IllegalArgumentException("radix: " + radix);
+ if (i < 0) {
+ append('-');
+ if (i == Integer.MIN_VALUE) { // Negative would overflow.
+ appendPositive(-(i / radix), radix);
+ return (TextBuilder) append(DIGIT_TO_CHAR[-(i % radix)]);
+ }
+ i = -i;
+ }
+ appendPositive(i, radix);
+ return this;
+ }
+
+ private void appendPositive(int l1, int radix) {
+ if (l1 >= radix) {
+ int l2 = l1 / radix;
+ // appendPositive(l2, radix);
+ if (l2 >= radix) {
+ int l3 = l2 / radix;
+ // appendPositive(l3, radix);
+ if (l3 >= radix) {
+ int l4 = l3 / radix;
+ appendPositive(l4, radix);
+ append(DIGIT_TO_CHAR[l3 - (l4 * radix)]);
+ } else
+ append(DIGIT_TO_CHAR[l3]);
+ append(DIGIT_TO_CHAR[l2 - (l3 * radix)]);
+ } else
+ append(DIGIT_TO_CHAR[l2]);
+ append(DIGIT_TO_CHAR[l1 - (l2 * radix)]);
+ } else
+ append(DIGIT_TO_CHAR[l1]);
+ }
+
+ private final static char[] DIGIT_TO_CHAR = { '0', '1', '2', '3', '4', '5',
+ '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
+ 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
+ 'w', 'x', 'y', 'z' };
+
+ /**
+ * Appends the decimal representation of the specified <code>long</code>
+ * argument.
+ *
+ * @param l the <code>long</code> to format.
+ * @return <code>this</code>
+ */
+ public final TextBuilder append(long l) {
+ if (l <= 0) {
+ if (l == 0)
+ return append("0");
+ if (l == Long.MIN_VALUE) // Negation would overflow.
+ return append("-9223372036854775808");
+ append('-');
+ l = -l;
+ }
+ if (l <= Integer.MAX_VALUE)
+ return append((int) l);
+ append(l / 1000000000);
+ int i = (int) (l % 1000000000);
+ int digits = MathLib.digitLength(i);
+ append("000000000", 0, 9 - digits);
+ return append(i);
+ }
+
+ /**
+ * Appends the radix representation of the specified <code>long</code>
+ * argument.
+ *
+ * @param l the <code>long</code> to format.
+ * @param radix the radix (e.g. <code>16</code> for hexadecimal).
+ * @return <code>this</code>
+ */
+ public final TextBuilder append(long l, int radix) {
+ if (radix == 10)
+ return append(l); // Faster.
+ if (radix < 2 || radix > 36)
+ throw new IllegalArgumentException("radix: " + radix);
+ if (l < 0) {
+ append('-');
+ if (l == Long.MIN_VALUE) { // Negative would overflow.
+ appendPositive(-(l / radix), radix);
+ return (TextBuilder) append(DIGIT_TO_CHAR[(int) -(l % radix)]);
+ }
+ l = -l;
+ }
+ appendPositive(l, radix);
+ return this;
+ }
+
+ private void appendPositive(long l1, int radix) {
+ if (l1 >= radix) {
+ long l2 = l1 / radix;
+ // appendPositive(l2, radix);
+ if (l2 >= radix) {
+ long l3 = l2 / radix;
+ // appendPositive(l3, radix);
+ if (l3 >= radix) {
+ long l4 = l3 / radix;
+ appendPositive(l4, radix);
+ append(DIGIT_TO_CHAR[(int) (l3 - (l4 * radix))]);
+ } else
+ append(DIGIT_TO_CHAR[(int) l3]);
+ append(DIGIT_TO_CHAR[(int) (l2 - (l3 * radix))]);
+ } else
+ append(DIGIT_TO_CHAR[(int) l2]);
+ append(DIGIT_TO_CHAR[(int) (l1 - (l2 * radix))]);
+ } else
+ append(DIGIT_TO_CHAR[(int) l1]);
+ }
+
+ /**
+ * Appends the textual representation of the specified <code>float</code>.
+ *
+ * @param f the <code>float</code> to format.
+ * @return <code>append(f, 10, (abs(f) >= 1E7) || (abs(f) < 0.001), false)</code>
+ */
+ public final TextBuilder append(float f) {
+ return append(f, 10, (MathLib.abs(f) >= 1E7)
+ || (MathLib.abs(f) < 0.001), false);
+ }
+
+ /**
+ * Appends the textual representation of the specified <code>double</code>;
+ * the number of digits is 17 or 16 when the 16 digits representation
+ * can be parsed back to the same <code>double</code> (mimic the standard
+ * library formatting).
+ *
+ * @param d the <code>double</code> to format.
+ * @return <code>append(d, -1, (MathLib.abs(d) >= 1E7) ||
+ * (MathLib.abs(d) < 0.001), false)</code>
+ */
+ public final TextBuilder append(double d) {
+ return append(d, -1, (MathLib.abs(d) >= 1E7)
+ || (MathLib.abs(d) < 0.001), false);
+ }
+
+ /**
+ * Appends the textual representation of the specified <code>double</code>
+ * according to the specified formatting arguments.
+ *
+ * @param d the <code>double</code> value.
+ * @param digits the number of significative digits (excludes exponent) or
+ * <code>-1</code> to mimic the standard library (16 or 17 digits).
+ * @param scientific <code>true</code> to forces the use of the scientific
+ * notation (e.g. <code>1.23E3</code>); <code>false</code>
+ * otherwise.
+ * @param showZero <code>true</code> if trailing fractional zeros are
+ * represented; <code>false</code> otherwise.
+ * @return <code>TypeFormat.format(d, digits, scientific, showZero, this)</code>
+ * @throws IllegalArgumentException if <code>(digits > 19)</code>)
+ */
+ public final TextBuilder append(double d, int digits, boolean scientific,
+ boolean showZero) {
+ if (digits > 19)
+ throw new IllegalArgumentException("digits: " + digits);
+ if (d != d) // NaN
+ return append("NaN");
+ if (d == Double.POSITIVE_INFINITY)
+ return append("Infinity");
+ if (d == Double.NEGATIVE_INFINITY)
+ return append("-Infinity");
+ if (d == 0.0) { // Zero.
+ if (digits < 0)
+ return append("0.0");
+ append('0');
+ if (showZero) {
+ append('.');
+ for (int j = 1; j < digits; j++) {
+ append('0');
+ }
+ }
+ return this;
+ }
+ if (d < 0) { // Work with positive number.
+ d = -d;
+ append('-');
+ }
+
+ // Find the exponent e such as: value == x.xxx * 10^e
+ int e = MathLib.floorLog10(d);
+
+ long m;
+ if (digits < 0) { // Use 16 or 17 digits.
+ // Try 17 digits.
+ long m17 = MathLib.toLongPow10(d, (17 - 1) - e);
+ // Check if we can use 16 digits.
+ long m16 = m17 / 10;
+ double dd = MathLib.toDoublePow10(m16, e - 16 + 1);
+ if (dd == d) { // 16 digits is enough.
+ digits = 16;
+ m = m16;
+ } else { // We cannot remove the last digit.
+ digits = 17;
+ m = m17;
+ }
+ } else
+ // Use the specified number of digits.
+ m = MathLib.toLongPow10(d, (digits - 1) - e);
+
+ // Formats.
+ if (scientific || (e >= digits)) {
+ // Scientific notation has to be used ("x.xxxEyy").
+ long pow10 = POW10_LONG[digits - 1];
+ int k = (int) (m / pow10); // Single digit.
+ append((char) ('0' + k));
+ m = m - pow10 * k;
+ appendFraction(m, digits - 1, showZero);
+ append('E');
+ append(e);
+ } else { // Dot within the string ("xxxx.xxxxx").
+ int exp = digits - e - 1;
+ if (exp < POW10_LONG.length) {
+ long pow10 = POW10_LONG[exp];
+ long l = m / pow10;
+ append(l);
+ m = m - pow10 * l;
+ } else
+ append('0'); // Result of the division by a power of 10 larger than any long.
+ appendFraction(m, exp, showZero);
+ }
+ return this;
+ }
+
+ private void appendFraction(long l, int digits, boolean showZero) {
+ append('.');
+ if (l == 0)
+ if (showZero)
+ for (int i = 0; i < digits; i++) {
+ append('0');
+ }
+ else
+ append('0');
+ else { // l is different from zero.
+ int length = MathLib.digitLength(l);
+ for (int j = length; j < digits; j++) {
+ append('0'); // Add leading zeros.
+ }
+ if (!showZero)
+ while (l % 10 == 0) {
+ l /= 10; // Remove trailing zeros.
+ }
+ append(l);
+ }
+ }
+
+ private static final long[] POW10_LONG = new long[] { 1L, 10L, 100L, 1000L,
+ 10000L, 100000L, 1000000L, 10000000L, 100000000L, 1000000000L,
+ 10000000000L, 100000000000L, 1000000000000L, 10000000000000L,
+ 100000000000000L, 1000000000000000L, 10000000000000000L,
+ 100000000000000000L, 1000000000000000000L };
+
+ /**
+ * Inserts the specified character sequence at the specified location.
+ *
+ * @param index the insertion position.
+ * @param csq the character sequence being inserted.
+ * @return <code>this</code>
+ * @throws IndexOutOfBoundsException if <code>(index < 0) ||
+ * (index > this.length())</code>
+ */
+ public final TextBuilder insert(int index, java.lang.CharSequence csq) {
+ if ((index < 0) || (index > _length))
+ throw new IndexOutOfBoundsException("index: " + index);
+ final int shift = csq.length();
+ int newLength = _length + shift;
+ while (newLength >= _capacity) {
+ increaseCapacity();
+ }
+ _length = newLength;
+ for (int i = _length - shift; --i >= index;) {
+ this.setCharAt(i + shift, this.charAt(i));
+ }
+ for (int i = csq.length(); --i >= 0;) {
+ this.setCharAt(index + i, csq.charAt(i));
+ }
+ return this;
+ }
+
+ /**
+ * Removes all the characters of this text builder
+ * (equivalent to <code>this.delete(start, this.length())</code>).
+ *
+ * @return <code>this.delete(0, this.length())</code>
+ */
+ public final TextBuilder clear() {
+ _length = 0;
+ return this;
+ }
+
+ /**
+ * Removes the characters between the specified indices.
+ *
+ * @param start the beginning index, inclusive.
+ * @param end the ending index, exclusive.
+ * @return <code>this</code>
+ * @throws IndexOutOfBoundsException if <code>(start < 0) || (end < 0)
+ * || (start > end) || (end > this.length())</code>
+ */
+ public final TextBuilder delete(int start, int end) {
+ if ((start < 0) || (end < 0) || (start > end) || (end > this.length()))
+ throw new IndexOutOfBoundsException();
+ for (int i = end, j = start; i < _length;) {
+ this.setCharAt(j++, this.charAt(i++));
+ }
+ _length -= end - start;
+ return this;
+ }
+
+ /**
+ * Reverses this character sequence.
+ *
+ * @return <code>this</code>
+ */
+ public final TextBuilder reverse() {
+ final int n = _length - 1;
+ for (int j = (n - 1) >> 1; j >= 0;) {
+ char c = charAt(j);
+ setCharAt(j, charAt(n - j));
+ setCharAt(n - j--, c);
+ }
+ return this;
+ }
+
+ /**
+ * Returns the {@link Text} corresponding to this {@link TextBuilder}.
+ *
+ * @return the corresponding {@link Text} instance.
+ */
+ public final Text toText() {
+ return Text.valueOf(this, 0, _length);
+ }
+
+ /**
+ * Returns the <code>String</code> representation of this
+ * {@link TextBuilder}.
+ *
+ * @return the <code>java.lang.String</code> for this text builder.
+ */
+ @Override
+ public final String toString() {
+ return (_length < C1) ? new String(_low, 0, _length) : toLargeString();
+ }
+
+ private String toLargeString() {
+ char[] data = new char[_length];
+ this.getChars(0, _length, data, 0);
+ return new String(data, 0, _length);
+ }
+
+ /**
+ * Returns the <code>CharArray</code> representation of this
+ * {@link TextBuilder}.
+ *
+ * @return the corresponding {@link CharArray} instance.
+ */
+ public final CharArray toCharArray() {
+ CharArray cArray = new CharArray();
+ char[] data;
+ if (_length < C1) {
+ data = _low;
+ } else {
+ data = new char[_length];
+ this.getChars(0, _length, data, 0);
+ }
+ cArray.setArray(data, 0, _length);
+ return cArray;
+ }
+
+ /**
+ * Returns the hash code for this text builder.
+ *
+ * @return the hash code value.
+ */
+ @Override
+ public final int hashCode() {
+ int h = 0;
+ for (int i = 0; i < _length;) {
+ h = 31 * h + charAt(i++);
+ }
+ return h;
+ }
+
+ /**
+ * Compares this text builder against the specified object for equality.
+ * Returns <code>true</code> if the specified object is a text builder
+ * having the same character content.
+ *
+ * @param obj the object to compare with or <code>null</code>.
+ * @return <code>true</code> if that is a text builder with the same
+ * character content as this text; <code>false</code> otherwise.
+ */
+ @Override
+ public final boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!(obj instanceof TextBuilder))
+ return false;
+ TextBuilder that = (TextBuilder) obj;
+ if (this._length != that._length)
+ return false;
+ for (int i = 0; i < _length;) {
+ if (this.charAt(i) != that.charAt(i++))
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Indicates if this text builder has the same character content as the
+ * specified character sequence.
+ *
+ * @param csq the character sequence to compare with.
+ * @return <code>true</code> if the specified character sequence has the
+ * same character content as this text; <code>false</code> otherwise.
+ */
+ public final boolean contentEquals(java.lang.CharSequence csq) {
+ if (csq.length() != _length)
+ return false;
+ for (int i = 0; i < _length;) {
+ char c = _high[i >> B1][i & M1];
+ if (csq.charAt(i++) != c)
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Increases this text builder capacity.
+ */
+ private void increaseCapacity() {
+ if (_capacity < C1) { // For small capacity, resize.
+ _capacity <<= 1;
+ char[] tmp = new char[_capacity];
+ System.arraycopy(_low, 0, tmp, 0, _length);
+ _low = tmp;
+ _high[0] = tmp;
+ } else { // Add a new low block of 1024 elements.
+ int j = _capacity >> B1;
+ if (j >= _high.length) { // Resizes _high.
+ char[][] tmp = new char[_high.length * 2][];
+ System.arraycopy(_high, 0, tmp, 0, _high.length);
+ _high = tmp;
+ }
+ _high[j] = new char[C1];
+ _capacity += C1;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/e43574ef/commons/marmotta-commons/src/ext/java/javolution/text/TextContext.java
----------------------------------------------------------------------
diff --git a/commons/marmotta-commons/src/ext/java/javolution/text/TextContext.java b/commons/marmotta-commons/src/ext/java/javolution/text/TextContext.java
new file mode 100644
index 0000000..cc8311b
--- /dev/null
+++ b/commons/marmotta-commons/src/ext/java/javolution/text/TextContext.java
@@ -0,0 +1,93 @@
+/*
+ * Javolution - Java(TM) Solution for Real-Time and Embedded Systems
+ * Copyright (C) 2012 - Javolution (http://javolution.org/)
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software is
+ * freely granted, provided that this notice is preserved.
+ */
+package javolution.text;
+
+import javolution.context.AbstractContext;
+import javolution.context.FormatContext;
+import javolution.osgi.internal.OSGiServices;
+
+/**
+ * <p> A context for plain text parsing/formatting. This context provides
+ * the {@link javolution.text.TextFormat TextFormat} to parse/format objects
+ * of any class. If not superseded, the text format for a class is specified
+ * by the {@link javolution.text.DefaultTextFormat DefaultTextFormat}
+ * annotation.</p>
+ *
+ * <p> A text context always returns the most specialized format. If the class
+ * has no default format annotation (inherited or not), then the default
+ * {@link java.lang.Object} format (which calls {@link Object#toString})
+ * is returned. A predefined format exists for the following standard types:
+ * <code><ul>
+ * <li>java.lang.Object (parsing not supported, formatting calls toString())</li>
+ * <li>java.lang.Boolean</li>
+ * <li>java.lang.Character</li>
+ * <li>java.lang.Byte</li>
+ * <li>java.lang.Short</li>
+ * <li>java.lang.Integer</li>
+ * <li>java.lang.Long</li>
+ * <li>java.lang.Float</li>
+ * <li>java.lang.Double</li>
+ * <li>java.lang.Class</li>
+ * <li>java.lang.String</li>
+ * <li>java.util.Date (ISO 8601)</li>
+ * <li>java.math.BigInteger</li>
+ * <li>java.math.BigDecimal</li>
+ * <li>java.awt.Color (hexadecimal RGB value, e.g. {@code 0x112233})</li>
+ * <li>java.awt.Font</li>
+ * </ul></code>
+ * </p>
+ *
+ * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
+ * @version 6.0 December 12, 2012
+ */
+public abstract class TextContext extends FormatContext {
+
+ /**
+ * Default constructor.
+ */
+ protected TextContext() {}
+
+ /**
+ * Enters and returns a new text context instance.
+ */
+ public static TextContext enter() {
+ return (TextContext) TextContext.currentTextContext().enterInner();
+ }
+
+ /**
+ * Returns the text format for the specified type. It is the most
+ * specialized format able to parse/format instances of the specified
+ * class. If there is no default format for the specified class,
+ * the standard object format (toString based) is returned.
+ */
+ public static <T> TextFormat<T> getFormat(Class<? extends T> type) {
+ return TextContext.currentTextContext().searchFormat(type);
+ }
+
+ /**
+ * Sets the text format for the specified type (and its sub-types).
+ */
+ public abstract <T> void setFormat(Class<? extends T> type,
+ TextFormat<T> newFormat);
+
+ /**
+ * Searches the most specialized format for the specified type.
+ */
+ protected abstract <T> TextFormat<T> searchFormat(Class<? extends T> type);
+
+ /**
+ * Returns the current text context.
+ */
+ private static TextContext currentTextContext() {
+ TextContext ctx = AbstractContext.current(TextContext.class);
+ if (ctx != null)
+ return ctx;
+ return OSGiServices.getTextContext();
+ }
+}
\ No newline at end of file