sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1415198 - in /sis/branches/JDK7/sis-utility/src: main/java/org/apache/sis/internal/util/ main/java/org/apache/sis/io/ main/java/org/apache/sis/measure/ main/java/org/apache/sis/util/ main/java/org/apache/sis/util/collection/ test/java/org/...
Date Thu, 29 Nov 2012 15:05:54 GMT
Author: desruisseaux
Date: Thu Nov 29 15:05:52 2012
New Revision: 1415198

URL: http://svn.apache.org/viewvc?rev=1415198&view=rev
Log:
Documented in CharSequences the policy about white spaces, and apply it consistently in the
SIS library:
- Use Character.isWhitespace for separating entities (words, elements, tokens...)
- Use Character.isSpaceChar for parsing a single entity (mostly in java.text.Format subclasses)
- Avoid usage of String.trim() - use CharSequences.trimWhitespaces instead.

Modified:
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/Citations.java
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/io/CompoundFormat.java
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/io/TableFormatter.java
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/measure/AngleFormat.java
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/CharSequences.java
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/Exceptions.java
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/Locales.java
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/Numbers.java
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/DefaultTreeTable.java
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/TreeTableFormat.java
    sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/test/XMLComparator.java
    sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/util/CharSequencesTest.java

Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/Citations.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/Citations.java?rev=1415198&r1=1415197&r2=1415198&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/Citations.java
(original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/Citations.java
Thu Nov 29 15:05:52 2012
@@ -23,6 +23,11 @@ import org.opengis.metadata.citation.Cit
 import org.opengis.util.InternationalString;
 import org.apache.sis.util.Static;
 
+import static org.apache.sis.util.CharSequences.trimWhitespaces;
+
+// Related to JDK7
+import java.util.Objects;
+
 
 /**
  * Utility methods working on {@link Citation} objects. The public facade of those methods
is
@@ -79,13 +84,13 @@ public final class Citations extends Sta
             do {
                 if (candidate != null) {
                     // The "null" locale argument is required for getting the unlocalized
version.
-                    final String asString = candidate.toString(null);
-                    if (titleMatches(c1, asString)) {
+                    final String unlocalized = candidate.toString(null);
+                    if (titleMatches(c1, unlocalized)) {
                         return true;
                     }
-                    final String asLocalized = candidate.toString();
-                    if (asLocalized != asString // Slight optimization for a common case.
-                            && titleMatches(c1, asLocalized))
+                    final String localized = candidate.toString();
+                    if (!Objects.equals(localized, unlocalized) // Slight optimization for
a common case.
+                            && titleMatches(c1, localized))
                     {
                         return true;
                     }
@@ -114,19 +119,19 @@ public final class Citations extends Sta
      */
     public static boolean titleMatches(final Citation citation, String title) {
         if (citation != null && title != null) {
-            title = title.trim();
+            title = trimWhitespaces(title);
             InternationalString candidate = citation.getTitle();
             Iterator<? extends InternationalString> iterator = null;
             do {
                 if (candidate != null) {
                     // The "null" locale argument is required for getting the unlocalized
version.
-                    final String asString = candidate.toString(null);
-                    if (asString != null && asString.trim().equalsIgnoreCase(title))
{
+                    final String unlocalized = trimWhitespaces(candidate.toString(null));
+                    if (unlocalized != null && unlocalized.equalsIgnoreCase(title))
{
                         return true;
                     }
-                    final String asLocalized = candidate.toString();
-                    if (asLocalized != asString // Slight optimization for a common case.
-                            && asLocalized != null && asLocalized.trim().equalsIgnoreCase(title))
+                    final String localized = trimWhitespaces(candidate).toString();
+                    if (localized != unlocalized // Slight optimization for a common case.
+                            && (localized != null) && localized.equalsIgnoreCase(title))
                     {
                         return true;
                     }
@@ -203,7 +208,7 @@ public final class Citations extends Sta
      */
     public static boolean identifierMatches(final Citation citation, String identifier) {
         if (citation != null && identifier != null) {
-            identifier = identifier.trim();
+            identifier = trimWhitespaces(identifier);
             final Iterator<? extends Identifier> identifiers = iterator(citation.getIdentifiers());
             if (identifiers == null) {
                 return titleMatches(citation, identifier);
@@ -212,7 +217,7 @@ public final class Citations extends Sta
                 final Identifier id = identifiers.next();
                 if (id != null) {
                     final String code = id.getCode();
-                    if (code != null && identifier.equalsIgnoreCase(code.trim()))
{
+                    if (code != null && identifier.equalsIgnoreCase(trimWhitespaces(code)))
{
                         return true;
                     }
                 }
@@ -237,9 +242,8 @@ public final class Citations extends Sta
             if (it != null) while (it.hasNext()) {
                 final Identifier id = it.next();
                 if (id != null) {
-                    String candidate = id.getCode();
+                    final String candidate = trimWhitespaces(id.getCode());
                     if (candidate != null) {
-                        candidate = candidate.trim();
                         final int length = candidate.length();
                         if (length != 0) {
                             if (identifier == null || length < identifier.length()) {

Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/io/CompoundFormat.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/io/CompoundFormat.java?rev=1415198&r1=1415197&r2=1415198&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/io/CompoundFormat.java (original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/io/CompoundFormat.java Thu
Nov 29 15:05:52 2012
@@ -227,6 +227,12 @@ public abstract class CompoundFormat<T> 
      * {@linkplain Character#isSpaceChar(int) spaces} and
      * {@linkplain Character#isISOControl(int) ISO control characters}.
      *
+     * {@note The usual SIS policy, as documented in the <code>CharSequences</code>
class,
+     * is to test for whitespaces using the <code>Characters.isWhitespace(…)</code>
method.
+     * The combination of <code>isSpaceChar(…)</code> and <code>isISOControl(…)</code>
done
+     * in this <code>parseObject(…)</code> method is more permissive since
it encompasses
+     * all whitespace characters, plus non-breaking spaces and non-white ISO controls.}
+     *
      * @param  text The string representation of the object to parse.
      * @return The parsed object.
      * @throws ParseException If an error occurred while parsing the object.

Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/io/TableFormatter.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/io/TableFormatter.java?rev=1415198&r1=1415197&r2=1415198&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/io/TableFormatter.java (original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/io/TableFormatter.java Thu
Nov 29 15:05:52 2012
@@ -253,29 +253,15 @@ public class TableFormatter extends Filt
     public TableFormatter(final Appendable out, final String separator) {
         super(out);
         /*
-         * Use Character.isSpaceChar(…) instead of Character.isWhitespace(…) because
the former
-         * does not consider control characters (tabulation, group separator, etc.) as spaces.
-         * We presume that if the user wants to put such characters in the border, he has
reasons.
-         *
-         * If this policy is changed, search for other occurrences of 'isSpaceChar' in this
class
-         * for ensuring consistency. Note however that the same policy is not necessarily
applied
-         * everywhere.
+         * Following methods use Character.isWhitespace(…) instead of Character.isSpaceChar(…).
+         * This has the effect of removing some ISO control characters (line feeds, tabulation,
+         * etc.) from the border. If this policy is changed, search for other occurrences
of
+         * 'isWhitespace' in this class for ensuring consistency. Note however that the same
+         * policy is not necessarily applied everywhere.
          */
         final int length = separator.length();
-        int lower = 0;
-        int upper = length;
-        while (lower < length) {
-            final int c = separator.codePointAt(lower);
-            if (!Character.isSpaceChar(c)) break;
-            lower += Character.charCount(c);
-        }
-        while (upper > 0) {
-            final int c = separator.codePointBefore(upper);
-            if (!Character.isSpaceChar(c)) break;
-            upper -= Character.charCount(c);
-        }
-        leftBorder      = separator.substring(lower);
-        rightBorder     = separator.substring(0, upper);
+        leftBorder      = separator.substring(   CharSequences.skipLeadingWhitespaces (separator,
0, length));
+        rightBorder     = separator.substring(0, CharSequences.skipTrailingWhitespaces(separator,
0, length));
         columnSeparator = separator;
     }
 
@@ -315,7 +301,7 @@ public class TableFormatter extends Filt
         assert (verticalBorder >= -1) && (verticalBorder <= +1) : verticalBorder;
         /*
          * Remplaces spaces by the horizontal lines, and vertical lines by an intersection.
-         * Use Character.isSpaceChar(…) instead of Character.isWhitespace(…) for
consistency
+         * Use Character.isWhitespace(…) instead of Character.isSpaceChar(…) for
consistency
          * with the policy used in the constructor, since we work on the same object (namely
          * the border strings).
          */
@@ -324,7 +310,7 @@ public class TableFormatter extends Filt
         for (int i=0; i<borderLength;) {
             int c = border.codePointAt(i);
             i += Character.charCount(c);
-            if (Character.isSpaceChar(c)) {
+            if (Character.isWhitespace(c)) {
                 c = horizontalChar;
             } else {
                 for (int j=0; j<boxCount; j++) {
@@ -773,7 +759,7 @@ public class TableFormatter extends Filt
                         if (isFirstColumn) {
                             writeBorder(-1, verticalBorder, cell.fill);
                         }
-                        repeat(out, cell.fill, Character.isSpaceChar(cell.fill) ? cellPadding
: cellWidth);
+                        repeat(out, cell.fill, Character.isWhitespace(cell.fill) ? cellPadding
: cellWidth);
                         writeBorder(isLastColumn ? +1 : 0, verticalBorder, cell.fill);
                         continue;
                     }

Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/measure/AngleFormat.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/measure/AngleFormat.java?rev=1415198&r1=1415197&r2=1415198&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/measure/AngleFormat.java (original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/measure/AngleFormat.java Thu
Nov 29 15:05:52 2012
@@ -1113,7 +1113,7 @@ scan:   for (int i=0; i<length;) {
                     c = source.codePointAt(index);
                     index += Character.charCount(c);
                 }
-                while (Character.isSpaceChar(c));
+                while (Character.isSpaceChar(c)); // Method shall be consistent with skipSpaces(…)
             }
             if (++field > SECONDS_FIELD) {
                 field = PREFIX_FIELD;
@@ -1132,7 +1132,7 @@ scan:   for (int i=0; i<length;) {
                 c = source.codePointAt(start);
                 start += Character.charCount(c);
             }
-            while (Character.isSpaceChar(c));
+            while (Character.isSpaceChar(c)); // Method shall be consistent with skipSpaces(…)
             switch (c) {
                 case '°' :            pos.setIndex(start); return DEGREES_FIELD;
                 case '′' : case '\'': pos.setIndex(start); return MINUTES_FIELD;
@@ -1144,13 +1144,20 @@ scan:   for (int i=0; i<length;) {
 
     /**
      * Returns the index of the first non-space character in the given string.
+     * This method performs the same work than {@code CharSequences.skipLeadingWhitespaces},
+     * except that it tests for spaces using the {@link Character#isSpaceChar(int)} method
+     * instead than {@link Character#isWhitespace(int)}. The reason is that we really want
+     * to skip no-break spaces, since they are often used inside a single entity (e.g. the
+     * group separator in numbers formatted using the French locale).  Furthermore we do
+     * not want to skip tabulations or line feeds, since they are unlikely to be part of
+     * the angle to parse.
      *
      * @param  source The string being parsed.
      * @param  index  Index of the first {@code source} character to read.
+     * @param  length The length of {@code source}.
      * @return Index of the first non-space character, or the end of string if none.
      */
-    private static int skipSpaces(final String source, int index) {
-        final int length = source.length();
+    private static int skipSpaces(final String source, int index, final int length) {
         while (index < length) {
             final int c = source.codePointAt(index);
             if (!Character.isSpaceChar(c)) break;
@@ -1216,7 +1223,7 @@ scan:   for (int i=0; i<length;) {
                 pos.setIndex(indexStart);
                 return null;
             }
-            index = skipSpaces(source, pos.getIndex());
+            index = skipSpaces(source, pos.getIndex(), length);
             pos.setIndex(index);
             /*
              * Parse the degrees field. If there is no separator between degrees, minutes
@@ -1277,7 +1284,7 @@ BigBoss:    switch (skipSuffix(source, p
                  */
                 case DEGREES_FIELD: {
                     final int indexStartField = pos.getIndex();
-                    index = skipSpaces(source, indexStartField);
+                    index = skipSpaces(source, indexStartField, length);
                     if (!spaceAsSeparator && index != indexStartField) {
                         break BigBoss;
                     }
@@ -1363,7 +1370,7 @@ BigBoss:    switch (skipSuffix(source, p
                         degrees = NaN;
                     }
                     final int indexStartField = pos.getIndex();
-                    index = skipSpaces(source, indexStartField);
+                    index = skipSpaces(source, indexStartField, length);
                     if (!spaceAsSeparator && index != indexStartField) {
                         break BigBoss;
                     }
@@ -1512,7 +1519,7 @@ BigBoss:    switch (skipSuffix(source, p
                 case EAST : pos.setIndex(index); return new Longitude( degrees);
                 case WEST : pos.setIndex(index); return new Longitude(-degrees);
             }
-            if (!Character.isSpaceChar(c)) {
+            if (!Character.isSpaceChar(c)) { // Method shall be consistent with skipSpaces(…)
                 break;
             }
         }
@@ -1535,7 +1542,8 @@ BigBoss:    switch (skipSuffix(source, p
         final ParsePosition pos = new ParsePosition(0);
         final Angle angle = parse(source, pos, true);
         final int offset = pos.getIndex();
-        if (skipSpaces(source, offset) != source.length()) {
+        final int length = source.length();
+        if (skipSpaces(source, offset, length) < length) {
             throw new LocalizedParseException(locale, Angle.class, source, pos);
         }
         return angle;

Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/CharSequences.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/CharSequences.java?rev=1415198&r1=1415197&r2=1415198&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/CharSequences.java (original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/CharSequences.java Thu
Nov 29 15:05:52 2012
@@ -35,6 +35,30 @@ import static org.apache.sis.util.String
  * when appropriate. Consequently those methods should behave correctly with characters outside
  * the <cite>Basic Multilingual Plane</cite> (BMP).
  *
+ * {@section Policy on space characters}
+ * Java defines two methods for testing if a character is a white space:
+ * {@link Character#isWhitespace(int)} and {@link Character#isSpaceChar(int)}.
+ * Those two methods differ in the way they handle {@linkplain Characters#NO_BREAK_SPACE
+ * no-break spaces}, tabulations and line feeds. The general policy in the SIS library is:
+ *
+ * <ul>
+ *   <li>Use {@code isWhitespace(…)} when separating entities (words, numbers,
tokens).
+ *       Using this method, characters separated by a no-break space are considered as
+ *       part of the same entity (e.g. the French locale uses no-break space instead of
+ *       coma as group separator in number representations), while line feeds and
+ *       tabulations are accepted as valid entity separator.</li>
+ *   <li>Use {@code isSpaceChar(…)} when parsing a single entity. Using this method,
+ *       no-break spaces are considered as part of the entity (e.g. the above-cited
+ *       group separator), while line feeds or tabulation mark entity boundaries.</li>
+ * </ul>
+ *
+ * This {@code CharSequences} class consistently uses {@code isWhitespace(…)}, while
+ * {@link java.text.Format} implementations in SIS typically use {@code isSpaceChar(…)}.
+ *
+ * <p>Note that the {@link String#trim()} method doesn't follow any of those politics
and should
+ * generally be avoided. That {@code trim()} method removes every ISO control characters
without
+ * distinction about whether the characters are space or not, and ignore all Unicode spaces.</p>
+ *
  * {@section Handling of null values}
  * Most methods in this class accept a {@code null} {@code CharSequence} argument. In such
cases
  * the method return value is either a {@code null} {@code CharSequence}, an empty array,
or a
@@ -449,6 +473,81 @@ search:     for (; fromIndex <= toIndex;
     }
 
     /**
+     * Returns the index of the first character after all leading whitespace characters
+     * in the given range. If the given range contains only space characters, then this method
+     * returns the index of the first character after the given range, which is always equals
+     * or greater than {@code toIndex}. Note that this character may not exist if {@code
toIndex}
+     * is equals to the text length.
+     *
+     * <p>Special cases:</p>
+     * <ul>
+     *   <li>If {@code fromIndex} is greater than {@code toIndex},
+     *       then this method unconditionally returns {@code fromIndex}.</li>
+     *   <li>If the given range contains only space characters and the character at
{@code toIndex-1}
+     *       is the high surrogate of a valid supplementary code point, then this method
returns
+     *       {@code toIndex+1} since that value is the index of the next code point.</li>
+     *   <li>If {@code fromIndex} is negative or {@code toIndex} is greater than
the text length,
+     *       then the behavior of this method is undefined.</li>
+     * </ul>
+     *
+     * Space characters are identified by the {@link Character#isWhitespace(int)} method.
+     *
+     * @param  text      The string in which to perform the search (can not be null).
+     * @param  fromIndex The index from which to start the search (can not be negative).
+     * @param  toIndex   The index after the last character where to perform the search.
+     * @return The index within the text of the first occurrence of a non-space character,
starting
+     *         at the specified index, or a value equals or greater than {@code toIndex}
if none.
+     *
+     * @see #skipTrailingWhitespaces(CharSequence, int, int)
+     * @see #trimWhitespaces(CharSequence)
+     */
+    public static int skipLeadingWhitespaces(final CharSequence text, int fromIndex, final
int toIndex) {
+        while (fromIndex < toIndex) {
+            final int c = Character.codePointAt(text, fromIndex);
+            if (!Character.isWhitespace(c)) break;
+            fromIndex += Character.charCount(c);
+        }
+        return fromIndex;
+    }
+
+    /**
+     * Returns the index of the last character before all trailing whitespace characters
+     * in the given range. If the given range contains only space characters, then this method
+     * returns the index of the first character in the given range, which is always equals
or
+     * lower than {@code fromIndex}.
+     *
+     * <p>Special cases:</p>
+     * <ul>
+     *   <li>If {@code toIndex} is lower than {@code toIndex},
+     *       then this method unconditionally returns {@code toIndex}.</li>
+     *   <li>If the given range contains only space characters and the character at
{@code fromIndex}
+     *       is the low surrogate of a valid supplementary code point, then this method returns
+     *       {@code fromIndex-1} since that value is the index of the code point.</li>
+     *   <li>If {@code fromIndex} is negative or {@code toIndex} is greater than
the text length,
+     *       then the behavior of this method is undefined.</li>
+     * </ul>
+     *
+     * Space characters are identified by the {@link Character#isWhitespace(int)} method.
+     *
+     * @param  text      The string in which to perform the search (can not be null).
+     * @param  fromIndex The index from which to start the search (can not be negative).
+     * @param  toIndex   The index after the last character where to perform the search.
+     * @return The index within the text of the last occurrence of a non-space character,
starting
+     *         at the specified index, or a value equals or lower than {@code fromIndex}
if none.
+     *
+     * @see #skipLeadingWhitespaces(CharSequence, int, int)
+     * @see #trimWhitespaces(CharSequence)
+     */
+    public static int skipTrailingWhitespaces(final CharSequence text, final int fromIndex,
int toIndex) {
+        while (toIndex > fromIndex) {
+            final int c = Character.codePointBefore(text, toIndex);
+            if (!Character.isWhitespace(c)) break;
+            toIndex -= Character.charCount(c);
+        }
+        return toIndex;
+    }
+
+    /**
      * Splits a text around the given character. The array returned by this method contains
all
      * subsequences of the given text that is terminated by the given character or is terminated
      * by the end of the text. The subsequences in the array are in the order in which they
occur
@@ -464,7 +563,7 @@ search:     for (; fromIndex <= toIndex;
      *   <li>The separator is a simple character instead than a regular expression.</li>
      *   <li>If the {@code separator} argument is {@code '\n'} or {@code '\r'}, then
this method
      *       splits around any of {@code "\r"}, {@code "\n"} or {@code "\r\n"} characters
sequences.
-     *   <li>The leading and trailing spaces of each subsequences are {@linkplain #trimWhitespaces
trimmed}.</li>
+     *   <li>The leading and trailing spaces of each subsequences are trimmed.</li>
      * </ul>
      *
      * @param  text The text to split, or {@code null}.
@@ -486,7 +585,7 @@ search:     for (; fromIndex <= toIndex;
             }
             return strings;
         }
-        // 'excludeEmpty' must use the same criterion than trimWhitespaces(...).
+        // 'excludeEmpty' must use the same criterion than trimWhitespaces(…).
         final boolean excludeEmpty = isWhitespace(separator);
         CharSequence[] strings = new CharSequence[4];
         final int length = text.length();
@@ -623,7 +722,7 @@ search:     for (; fromIndex <= toIndex;
         final CharSequence[] tokens = split(values, separator);
         final double[] parsed = new double[tokens.length];
         for (int i=0; i<tokens.length; i++) {
-            final String token = tokens[i].toString().trim();
+            final String token = trimWhitespaces(tokens[i]).toString();
             parsed[i] = token.isEmpty() ? Double.NaN : Double.parseDouble(token);
         }
         return parsed;
@@ -646,7 +745,7 @@ search:     for (; fromIndex <= toIndex;
         final CharSequence[] tokens = split(values, separator);
         final float[] parsed = new float[tokens.length];
         for (int i=0; i<tokens.length; i++) {
-            final String token = tokens[i].toString().trim();
+            final String token = trimWhitespaces(tokens[i]).toString();
             parsed[i] = token.isEmpty() ? Float.NaN : Float.parseFloat(token);
         }
         return parsed;
@@ -669,7 +768,7 @@ search:     for (; fromIndex <= toIndex;
         final CharSequence[] tokens = split(values, separator);
         final long[] parsed = new long[tokens.length];
         for (int i=0; i<tokens.length; i++) {
-            parsed[i] = Long.parseLong(tokens[i].toString().trim(), radix);
+            parsed[i] = Long.parseLong(trimWhitespaces(tokens[i]).toString(), radix);
         }
         return parsed;
     }
@@ -691,7 +790,7 @@ search:     for (; fromIndex <= toIndex;
         final CharSequence[] tokens = split(values, separator);
         final int[] parsed = new int[tokens.length];
         for (int i=0; i<tokens.length; i++) {
-            parsed[i] = Integer.parseInt(tokens[i].toString().trim(), radix);
+            parsed[i] = Integer.parseInt(trimWhitespaces(tokens[i]).toString(), radix);
         }
         return parsed;
     }
@@ -713,7 +812,7 @@ search:     for (; fromIndex <= toIndex;
         final CharSequence[] tokens = split(values, separator);
         final short[] parsed = new short[tokens.length];
         for (int i=0; i<tokens.length; i++) {
-            parsed[i] = Short.parseShort(tokens[i].toString().trim(), radix);
+            parsed[i] = Short.parseShort(trimWhitespaces(tokens[i]).toString(), radix);
         }
         return parsed;
     }
@@ -735,7 +834,7 @@ search:     for (; fromIndex <= toIndex;
         final CharSequence[] tokens = split(values, separator);
         final byte[] parsed = new byte[tokens.length];
         for (int i=0; i<tokens.length; i++) {
-            parsed[i] = Byte.parseByte(tokens[i].toString().trim(), radix);
+            parsed[i] = Byte.parseByte(trimWhitespaces(tokens[i]).toString(), radix);
         }
         return parsed;
     }
@@ -808,20 +907,39 @@ search:     for (; fromIndex <= toIndex;
     }
 
     /**
-     * Returns a text with leading and trailing white spaces omitted. White spaces are identified
-     * by the {@link Character#isWhitespace(int)} method.
+     * Returns a string with leading and trailing whitespace characters omitted.
+     * This method performs the same work than {@link #trimWhitespaces(CharSequence)},
+     * but is overloaded for the {@code String} type because very often used.
+     *
+     * @param  text The text from which to remove leading and trailing whitespaces, or {@code
null}.
+     * @return A string with leading and trailing whitespaces removed, or {@code null} is
the given
+     *         text was null.
+     */
+    public static String trimWhitespaces(String text) {
+        if (text != null) {
+            final int length = text.length();
+            final int lower = skipLeadingWhitespaces(text, 0, length);
+            text = text.substring(lower, skipTrailingWhitespaces(text, lower, length));
+        }
+        return text;
+    }
+
+    /**
+     * Returns a text with leading and trailing whitespace characters omitted.
+     * Space characters are identified by the {@link Character#isWhitespace(int)} method.
      *
      * <p>This method is similar in purpose to {@link String#trim()}, except that the
later considers
      * every ASCII control codes below 32 to be a whitespace. This have the side effect of
removing
      * ANSI escape sequences (a.k.a. X3.64) as well. Users should invoke this
-     * {@code CharSequences.trimWhitespaces} method instead if they need to preserve
+     * {@code CharSequences.trimWhitespaces(…)} method instead if they need to preserve
      * those ANSI escape sequences.</p>
      *
-     * @param  text The text from which to remove leading and trailing white spaces, or {@code
null}.
-     * @return A characters sequence with leading and trailing white spaces removed,
+     * @param  text The text from which to remove leading and trailing whitespaces, or {@code
null}.
+     * @return A characters sequence with leading and trailing whitespaces removed,
      *         or {@code null} is the given text was null.
      *
-     * @see String#trim()
+     * @see #skipLeadingWhitespaces(CharSequence, int, int)
+     * @see #skipTrailingWhitespaces(CharSequence, int, int)
      */
     public static CharSequence trimWhitespaces(CharSequence text) {
         if (text != null) {
@@ -831,13 +949,12 @@ search:     for (; fromIndex <= toIndex;
     }
 
     /**
-     * Returns a sub-sequence with leading and trailing white spaces omitted.
-     * White spaces are identified by the {@link Character#isWhitespace(int)} method.
+     * Returns a sub-sequence with leading and trailing whitespace characters omitted.
+     * Space characters are identified by the {@link Character#isWhitespace(int)} method.
      *
      * <p>Invoking this method is functionally equivalent to invoking
-     * <code>{@linkplain #trimWhitespaces(CharSequence) trimWhitespaces}(text.subSequence(lower,
-     * upper))</code>, except that only one call to {@link CharSequence#subSequence(int,
int)}
-     * is performed instead of two.</p>
+     * <code>{@linkplain #trimWhitespaces(CharSequence) trimWhitespaces}(text.subSequence(lower,
upper))</code>,
+     * except that only one call to {@link CharSequence#subSequence(int, int)} is performed
instead of two.</p>
      *
      * @param  text  The text from which to remove leading and trailing white spaces.
      * @param  lower Index of the first character to consider for inclusion in the sub-sequence.
@@ -846,18 +963,15 @@ search:     for (; fromIndex <= toIndex;
      * @throws NullPointerException If {@code text} is {@code null}.
      * @throws IndexOutOfBoundsException If {@code lower} or {@code upper} is out of bounds.
      */
-    private static CharSequence trimWhitespaces(final CharSequence text, int lower, int upper)
{
-        while (upper != 0) {
-            final int c = codePointBefore(text, upper);
-            if (!isWhitespace(c)) break;
-            upper -= charCount(c);
-        }
-        while (lower < upper) {
-            final int c = codePointAt(text, lower);
-            if (!isWhitespace(c)) break;
-            lower += charCount(c);
+    public static CharSequence trimWhitespaces(CharSequence text, int lower, int upper) {
+        final int length = text.length();
+        ArgumentChecks.ensureValidIndexRange(length, lower, upper);
+        lower = skipLeadingWhitespaces (text, lower, upper);
+        upper = skipTrailingWhitespaces(text, lower, upper);
+        if (lower != 0 || upper != length) { // Safety in case subSequence doesn't make the
check.
+            text = text.subSequence(lower, upper);
         }
-        return text.subSequence(lower, upper);
+        return text;
     }
 
     /**

Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/Exceptions.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/Exceptions.java?rev=1415198&r1=1415197&r2=1415198&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/Exceptions.java (original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/Exceptions.java Thu Nov
29 15:05:52 2012
@@ -22,6 +22,8 @@ import java.util.Locale;
 import java.sql.SQLException;
 import org.apache.sis.internal.util.LocalizedException;
 
+import static org.apache.sis.util.CharSequences.trimWhitespaces;
+
 
 /**
  * Static methods working with {@link Exception} instances.
@@ -83,9 +85,9 @@ public final class Exceptions extends St
     @SuppressWarnings("unchecked")
     public static <T extends Throwable> T setMessage(final T exception, String message,
final boolean append) {
         if (append) {
-            String em = exception.getLocalizedMessage();
-            if (em != null && !(em = em.trim()).isEmpty()) {
-                final StringBuilder buffer = new StringBuilder(message.trim());
+            final String em = trimWhitespaces(exception.getLocalizedMessage());
+            if (em != null && !em.isEmpty()) {
+                final StringBuilder buffer = new StringBuilder(trimWhitespaces(message));
                 final int length = buffer.length();
                 if (length != 0 && Character.isLetterOrDigit(buffer.charAt(length-1)))
{
                     buffer.append(". ");
@@ -122,17 +124,18 @@ public final class Exceptions extends St
      *         and no exception provide a message.
      */
     public static String formatChainedMessages(final Locale locale, String header, Throwable
cause) {
-        Set<String> done = null;
+        Set<CharSequence> done = null;
         String lineSeparator = null;
         StringBuilder buffer = null;
         while (cause != null) {
-            String message = getLocalizedMessage(cause, locale);
-            if (message != null && !(message = message.trim()).isEmpty()) {
+            final String message = trimWhitespaces(getLocalizedMessage(cause, locale));
+            if (message != null && !message.isEmpty()) {
                 if (buffer == null) {
                     done = new HashSet<>();
                     buffer = new StringBuilder(128);
                     lineSeparator = System.lineSeparator();
-                    if (header != null && !(header = header.trim()).isEmpty()) {
+                    header = trimWhitespaces(header);
+                    if (header != null && !header.isEmpty()) {
                         buffer.append(header);
                         done.add(header);
                         /*
@@ -144,7 +147,7 @@ public final class Exceptions extends St
                          */
                         int s=0;
                         while ((s=header.indexOf(':', s)) >= 0) {
-                            done.add(header.substring(++s).trim());
+                            done.add(trimWhitespaces(header, ++s, header.length()));
                         }
                     }
                 }

Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/Locales.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/Locales.java?rev=1415198&r1=1415197&r2=1415198&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/Locales.java (original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/Locales.java Thu Nov 29
15:05:52 2012
@@ -30,6 +30,7 @@ import org.apache.sis.util.logging.Loggi
 import org.apache.sis.util.resources.Errors;
 
 import static org.apache.sis.util.Arrays.resize;
+import static org.apache.sis.util.CharSequences.trimWhitespaces;
 import static org.apache.sis.util.collection.Collections.hashMapCapacity;
 
 
@@ -229,18 +230,18 @@ public final class Locales extends Stati
         final String language, country, variant;
         int ci = code.indexOf('_');
         if (ci < 0) {
-            language = code.trim();
+            language = trimWhitespaces(code);
             country  = "";
             variant  = "";
         } else {
-            language = code.substring(0, ci).trim();
+            language = (String) trimWhitespaces(code, 0, ci);
             int vi = code.indexOf('_', ++ci);
             if (vi < 0) {
-                country = code.substring(ci).trim();
+                country = (String) trimWhitespaces(code, ci, code.length());
                 variant = "";
             } else {
-                country = code.substring(ci, vi).trim();
-                variant = code.substring(++vi).trim();
+                country = (String) trimWhitespaces(code, ci, vi);
+                variant = (String) trimWhitespaces(code, ++vi, code.length());
                 if (code.indexOf('_', vi) >= 0) {
                     throw new IllegalArgumentException(Errors.format(Errors.Keys.IllegalLanguageCode_1,
code));
                 }

Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/Numbers.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/Numbers.java?rev=1415198&r1=1415197&r2=1415198&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/Numbers.java (original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/Numbers.java Thu Nov 29
15:05:52 2012
@@ -484,7 +484,7 @@ public final class Numbers extends Stati
      * @see #narrowestNumber(long)
      */
     public static Number narrowestNumber(String value) throws NumberFormatException {
-        value = value.trim();
+        value = CharSequences.trimWhitespaces(value);
         final int length = value.length();
         for (int i=0; i<length; i++) {
             final char c = value.charAt(i);
@@ -578,7 +578,7 @@ public final class Numbers extends Stati
              */
             return (T) Character.valueOf(value.isEmpty() ? 0 : value.charAt(0));
         }
-        value = value.trim();
+        value = CharSequences.trimWhitespaces(value);
         if (type == Double .class) return (T) Double .valueOf(value);
         if (type == Float  .class) return (T) Float  .valueOf(value);
         if (type == Long   .class) return (T) Long   .valueOf(value);

Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/DefaultTreeTable.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/DefaultTreeTable.java?rev=1415198&r1=1415197&r2=1415198&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/DefaultTreeTable.java
(original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/DefaultTreeTable.java
Thu Nov 29 15:05:52 2012
@@ -27,6 +27,7 @@ import org.apache.sis.util.ArgumentCheck
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.internal.util.Cloner;
 
+import static org.apache.sis.util.CharSequences.trimWhitespaces;
 import static org.apache.sis.util.collection.Collections.isNullOrEmpty;
 import static org.apache.sis.util.collection.Collections.hashMapCapacity;
 
@@ -720,8 +721,8 @@ public class DefaultTreeTable implements
             if (values != null) {
                 for (final Object value : values) {
                     if (value instanceof CharSequence) {
-                        final String text = value.toString().trim();
-                        if (!text.isEmpty()) {
+                        final String text = trimWhitespaces(value.toString());
+                        if (text != null && !text.isEmpty()) {
                             return text;
                         }
                     }

Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/TreeTableFormat.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/TreeTableFormat.java?rev=1415198&r1=1415197&r2=1415198&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/TreeTableFormat.java
(original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/TreeTableFormat.java
Thu Nov 29 15:05:52 2012
@@ -532,6 +532,11 @@ scan:   for (int i=0; i<length; i++) {
                 if (c != '\r' && c != '\n') break;
                 endOfLine--; // Skip trailing '\r' and '\n'.
             }
+            /*
+             * Skip leading spaces using Character.isSpaceChar(…) instead than isWhitespace(…)
+             * because we need to skip non-breaking spaces as well as ordinary space. We
don't
+             * need to consider line feeds since they were handled by the lines just above.
+             */
             boolean hasChar = false;
             int i; // The indentation of current line.
             for (i=indexOfLineStart; i<endOfLine;) {
@@ -553,12 +558,7 @@ scan:   for (int i=0; i<length; i++) {
              * user-spaces to interfer with the calculation of indentation.
              */
             int indexOfValue = i;
-            while (i > indexOfLineStart) {
-                final int c = Character.codePointBefore(text, i);
-                if (!Character.isSpaceChar(c)) break;
-                i -= Character.charCount(c);
-            }
-            i -= indexOfLineStart;
+            i = CharSequences.skipTrailingWhitespaces(text, indexOfLineStart, i) - indexOfLineStart;
             /*
              * Found the first character which is not part of the indentation. Create a new
root
              * (without parent for now) and parse the values for each column. Columns with
empty
@@ -570,19 +570,10 @@ scan:   for (int i=0; i<length; i++) {
                 for (int ci=0; ci<columns.length; ci++) {
                     final boolean found = matcher.find();
                     int endOfColumn = found ? matcher.start() : endOfLine;
-                    while (indexOfValue < endOfColumn) {
-                        final int c = Character.codePointAt(text, indexOfValue);
-                        if (!Character.isSpaceChar(c)) break;
-                        indexOfValue += Character.charCount(c);
-                    }
-                    // Ignore trailing spaces at the end of this column, then parse the value.
-                    for (int endOfValue = endOfColumn; endOfValue > indexOfValue;) {
-                        final int c = Character.codePointBefore(text, endOfValue);
-                        if (!Character.isSpaceChar(c)) {
-                            parseValue(node, columns[ci], formats[ci], text.subSequence(indexOfValue,
endOfValue).toString());
-                            break;
-                        }
-                        endOfValue -= Character.charCount(c);
+                    indexOfValue   = CharSequences.skipLeadingWhitespaces (text, indexOfValue,
endOfColumn);
+                    int endOfValue = CharSequences.skipTrailingWhitespaces(text, indexOfValue,
endOfColumn);
+                    if (endOfValue > indexOfValue) {
+                        parseValue(node, columns[ci], formats[ci], text.subSequence(indexOfValue,
endOfValue).toString());
                     }
                     if (!found) break;
                     // The end of this column will be the beginning of the next column,

Modified: sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/test/XMLComparator.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/test/XMLComparator.java?rev=1415198&r1=1415197&r2=1415198&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/test/XMLComparator.java (original)
+++ sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/test/XMLComparator.java Thu
Nov 29 15:05:52 2012
@@ -47,6 +47,7 @@ import org.apache.sis.util.ArgumentCheck
 import static java.lang.StrictMath.*;
 import static org.opengis.test.Assert.*;
 import static org.apache.sis.util.Characters.NO_BREAK_SPACE;
+import static org.apache.sis.util.CharSequences.trimWhitespaces;
 
 
 /**
@@ -454,8 +455,8 @@ public strictfp class XMLComparator {
 
                     // For text node, continue the search if the node is empty.
                     case Node.TEXT_NODE: {
-                        final String text = node.getTextContent();
-                        if (text == null || text.trim().isEmpty()) {
+                        final String text = trimWhitespaces(node.getTextContent());
+                        if (text == null || text.isEmpty()) {
                             continue;
                         }
                         break;
@@ -522,7 +523,7 @@ public strictfp class XMLComparator {
      * if it is actually a {@link String} object.
      */
     private static Comparable<?> trim(final Comparable<?> property) {
-        return (property instanceof String) ? ((String) property).trim() : property;
+        return (property instanceof String) ? trimWhitespaces(((String) property)) : property;
     }
 
     /**

Modified: sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/util/CharSequencesTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/util/CharSequencesTest.java?rev=1415198&r1=1415197&r2=1415198&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/util/CharSequencesTest.java
(original)
+++ sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/util/CharSequencesTest.java
Thu Nov 29 15:05:52 2012
@@ -209,7 +209,10 @@ public final strictfp class CharSequence
      */
     @Test
     public void testTrimWhitespaces() {
-        assertEquals("A text.", trimWhitespaces("  A text. "));
+        assertEquals("A text.", trimWhitespaces(               "  A text. "));
+        assertEquals("A text.", trimWhitespaces((CharSequence) "  A text. "));
+        assertEquals("",        trimWhitespaces(               "          "));
+        assertEquals("",        trimWhitespaces((CharSequence) "          "));
     }
 
     /**



Mime
View raw message