Coverage Report - org.codehaus.plexus.util.TypeFormat
 
Classes in this File Line Coverage Branch Coverage Complexity
TypeFormat
0%
0/268
0%
0/236
7.111
 
 1  
 /*
 2  
  * J.A.D.E. Java(TM) Addition to Default Environment.
 3  
  * Latest release available at http://jade.dautelle.com/
 4  
  * This class is public domain (not copyrighted).
 5  
  */
 6  
 package org.codehaus.plexus.util;
 7  
 
 8  
 /**
 9  
  * <p>
 10  
  * This class provides utility methods to parse <code>CharSequence</code> into primitive types and to format primitive
 11  
  * types into <code>StringBuffer</code>.
 12  
  * </p>
 13  
  * <p>
 14  
  * Methods from this utility class <b>do not create temporary objects</b> and are typically faster than standard library
 15  
  * methods (e.g {@link #parseDouble} is up to 15x faster than <code>Double.parseDouble</code>).
 16  
  * </p>
 17  
  * <p>
 18  
  * For class instances, formatting is typically performed using specialized <code>java.text.Format</code>
 19  
  * (<code>Locale</code> sensitive) and/or using conventional methods (class sensitive). For example:
 20  
  * 
 21  
  * <pre>
 22  
  *     public class Foo {
 23  
  *         public static Foo valueOf(CharSequence chars) {...} // Parses.
 24  
  *         public StringBuffer appendTo(StringBuffer sb) {...} // Formats.
 25  
  *         public String toString() {
 26  
  *             return appendTo(new StringBuffer()).toString();
 27  
  *         }
 28  
  *     }
 29  
  * </pre>
 30  
  * </p>
 31  
  * <p>
 32  
  * <i> This class is <b>public domain</b> (not copyrighted).</i>
 33  
  * </p>
 34  
  *
 35  
  * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
 36  
  * @version 4.6, June 22, 2003
 37  
  */
 38  
 public final class TypeFormat
 39  
 {
 40  
 
 41  
     /**
 42  
      * Holds the characters used to represent numbers.
 43  
      */
 44  0
     private final static char[] DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e',
 45  
         'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' };
 46  
 
 47  
     /**
 48  
      * Default constructor (forbids derivation).
 49  
      */
 50  
     private TypeFormat()
 51  0
     {
 52  0
     }
 53  
 
 54  
     /**
 55  
      * Searches for a particular sequence within a character sequence (general purpose parsing function).
 56  
      *
 57  
      * @param pattern the character sequence to search for.
 58  
      * @param chars the character sequence being searched.
 59  
      * @param fromIndex the index in <code>chars</code> to start the search from.
 60  
      * @return the index in the range <code>[fromIndex, chars.length()-pattern.length()]</code> or <code>-1</code> if
 61  
      *         the character sequence is not found.
 62  
      */
 63  
     public static int indexOf( CharSequence pattern, CharSequence chars, int fromIndex )
 64  
     {
 65  0
         int patternLength = pattern.length();
 66  0
         fromIndex = Math.max( 0, fromIndex );
 67  0
         if ( patternLength != 0 )
 68  
         { // At least one character to search for.
 69  0
             char firstChar = pattern.charAt( 0 );
 70  0
             int last = chars.length() - patternLength;
 71  0
             for ( int i = fromIndex; i <= last; i++ )
 72  
             {
 73  0
                 if ( chars.charAt( i ) == firstChar )
 74  
                 {
 75  0
                     boolean match = true;
 76  0
                     for ( int j = 1; j < patternLength; j++ )
 77  
                     {
 78  0
                         if ( chars.charAt( i + j ) != pattern.charAt( j ) )
 79  
                         {
 80  0
                             match = false;
 81  0
                             break;
 82  
                         }
 83  
                     }
 84  0
                     if ( match )
 85  
                     {
 86  0
                         return i;
 87  
                     }
 88  
                 }
 89  
             }
 90  0
             return -1;
 91  
         }
 92  
         else
 93  
         {
 94  0
             return Math.min( 0, fromIndex );
 95  
         }
 96  
     }
 97  
 
 98  
     /**
 99  
      * Parses the specified <code>CharSequence</code> as a <code>boolean</code>.
 100  
      *
 101  
      * @param chars the character sequence to parse.
 102  
      * @return the corresponding <code>boolean</code>.
 103  
      */
 104  
     public static boolean parseBoolean( CharSequence chars )
 105  
     {
 106  0
         return ( chars.length() == 4 ) && ( chars.charAt( 0 ) == 't' || chars.charAt( 0 ) == 'T' )
 107  
             && ( chars.charAt( 1 ) == 'r' || chars.charAt( 1 ) == 'R' )
 108  
             && ( chars.charAt( 2 ) == 'u' || chars.charAt( 2 ) == 'U' )
 109  
             && ( chars.charAt( 3 ) == 'e' || chars.charAt( 3 ) == 'E' );
 110  
     }
 111  
 
 112  
     /**
 113  
      * Parses the specified <code>CharSequence</code> as a signed decimal <code>short</code>.
 114  
      *
 115  
      * @param chars the character sequence to parse.
 116  
      * @return <code>parseShort(chars, 10)</code>
 117  
      * @throws NumberFormatException if the specified character sequence does not contain a parsable <code>short</code>.
 118  
      * @see #parseShort(CharSequence, int)
 119  
      */
 120  
     public static short parseShort( CharSequence chars )
 121  
     {
 122  0
         return parseShort( chars, 10 );
 123  
     }
 124  
 
 125  
     /**
 126  
      * Parses the specified <code>CharSequence</code> as a signed <code>short</code> in the specified radix. The
 127  
      * characters in the string must all be digits of the specified radix, except the first character which may be a
 128  
      * plus sign <code>'+'</code> or a minus sign <code>'-'</code>.
 129  
      *
 130  
      * @param chars the character sequence to parse.
 131  
      * @param radix the radix to be used while parsing.
 132  
      * @return the corresponding <code>short</code>.
 133  
      * @throws NumberFormatException if the specified character sequence does not contain a parsable <code>short</code>.
 134  
      */
 135  
     public static short parseShort( CharSequence chars, int radix )
 136  
     {
 137  
         try
 138  
         {
 139  0
             boolean isNegative = ( chars.charAt( 0 ) == '-' ) ? true : false;
 140  0
             int result = 0;
 141  0
             int limit = ( isNegative ) ? Short.MIN_VALUE : -Short.MAX_VALUE;
 142  0
             int multmin = limit / radix;
 143  0
             int length = chars.length();
 144  0
             int i = ( isNegative || ( chars.charAt( 0 ) == '+' ) ) ? 1 : 0;
 145  
             while ( true )
 146  
             {
 147  0
                 int digit = Character.digit( chars.charAt( i ), radix );
 148  0
                 int tmp = result * radix;
 149  0
                 if ( ( digit < 0 ) || ( result < multmin ) || ( tmp < limit + digit ) )
 150  
                 { // Overflow.
 151  0
                     throw new NumberFormatException( "For input characters: \"" + chars.toString() + "\"" );
 152  
                 }
 153  
                 // Accumulates negatively.
 154  0
                 result = tmp - digit;
 155  0
                 if ( ++i >= length )
 156  
                 {
 157  0
                     break;
 158  
                 }
 159  0
             }
 160  0
             return (short) ( isNegative ? result : -result );
 161  
         }
 162  0
         catch ( IndexOutOfBoundsException e )
 163  
         {
 164  0
             throw new NumberFormatException( "For input characters: \"" + chars.toString() + "\"" );
 165  
         }
 166  
     }
 167  
 
 168  
     /**
 169  
      * Parses the specified <code>CharSequence</code> as a signed decimal <code>int</code>.
 170  
      *
 171  
      * @param chars the character sequence to parse.
 172  
      * @return <code>parseInt(chars, 10)</code>
 173  
      * @throws NumberFormatException if the specified character sequence does not contain a parsable <code>int</code>.
 174  
      * @see #parseInt(CharSequence, int)
 175  
      */
 176  
     public static int parseInt( CharSequence chars )
 177  
     {
 178  0
         return parseInt( chars, 10 );
 179  
     }
 180  
 
 181  
     /**
 182  
      * Parses the specified <code>CharSequence</code> as a signed <code>int</code> in the specified radix. The
 183  
      * characters in the string must all be digits of the specified radix, except the first character which may be a
 184  
      * plus sign <code>'+'</code> or a minus sign <code>'-'</code>.
 185  
      *
 186  
      * @param chars the character sequence to parse.
 187  
      * @param radix the radix to be used while parsing.
 188  
      * @return the corresponding <code>int</code>.
 189  
      * @throws NumberFormatException if the specified character sequence does not contain a parsable <code>int</code>.
 190  
      */
 191  
     public static int parseInt( CharSequence chars, int radix )
 192  
     {
 193  
         try
 194  
         {
 195  0
             boolean isNegative = ( chars.charAt( 0 ) == '-' ) ? true : false;
 196  0
             int result = 0;
 197  0
             int limit = ( isNegative ) ? Integer.MIN_VALUE : -Integer.MAX_VALUE;
 198  0
             int multmin = limit / radix;
 199  0
             int length = chars.length();
 200  0
             int i = ( isNegative || ( chars.charAt( 0 ) == '+' ) ) ? 1 : 0;
 201  
             while ( true )
 202  
             {
 203  0
                 int digit = Character.digit( chars.charAt( i ), radix );
 204  0
                 int tmp = result * radix;
 205  0
                 if ( ( digit < 0 ) || ( result < multmin ) || ( tmp < limit + digit ) )
 206  
                 { // Overflow.
 207  0
                     throw new NumberFormatException( "For input characters: \"" + chars.toString() + "\"" );
 208  
                 }
 209  
                 // Accumulates negatively to avoid surprises near MAX_VALUE
 210  0
                 result = tmp - digit;
 211  0
                 if ( ++i >= length )
 212  
                 {
 213  0
                     break;
 214  
                 }
 215  0
             }
 216  0
             return isNegative ? result : -result;
 217  
         }
 218  0
         catch ( IndexOutOfBoundsException e )
 219  
         {
 220  0
             throw new NumberFormatException( "For input characters: \"" + chars.toString() + "\"" );
 221  
         }
 222  
     }
 223  
 
 224  
     /**
 225  
      * Parses the specified <code>CharSequence</code> as a signed decimal <code>long</code>.
 226  
      *
 227  
      * @param chars the character sequence to parse.
 228  
      * @return <code>parseLong(chars, 10)</code>
 229  
      * @throws NumberFormatException if the specified character sequence does not contain a parsable <code>long</code>.
 230  
      * @see #parseLong(CharSequence, int)
 231  
      */
 232  
     public static long parseLong( CharSequence chars )
 233  
     {
 234  0
         return parseLong( chars, 10 );
 235  
     }
 236  
 
 237  
     /**
 238  
      * Parses the specified <code>CharSequence</code> as a signed <code>long</code> in the specified radix. The
 239  
      * characters in the string must all be digits of the specified radix, except the first character which may be a
 240  
      * plus sign <code>'+'</code> or a minus sign <code>'-'</code>.
 241  
      *
 242  
      * @param chars the character sequence to parse.
 243  
      * @param radix the radix to be used while parsing.
 244  
      * @return the corresponding <code>long</code>.
 245  
      * @throws NumberFormatException if the specified character sequence does not contain a parsable <code>long</code>.
 246  
      */
 247  
     public static long parseLong( CharSequence chars, int radix )
 248  
     {
 249  
         try
 250  
         {
 251  0
             boolean isNegative = ( chars.charAt( 0 ) == '-' ) ? true : false;
 252  0
             long result = 0;
 253  0
             long limit = ( isNegative ) ? Long.MIN_VALUE : -Long.MAX_VALUE;
 254  0
             long multmin = limit / radix;
 255  0
             int length = chars.length();
 256  0
             int i = ( isNegative || ( chars.charAt( 0 ) == '+' ) ) ? 1 : 0;
 257  
             while ( true )
 258  
             {
 259  0
                 int digit = Character.digit( chars.charAt( i ), radix );
 260  0
                 long tmp = result * radix;
 261  0
                 if ( ( digit < 0 ) || ( result < multmin ) || ( tmp < limit + digit ) )
 262  
                 { // Overflow.
 263  0
                     throw new NumberFormatException( "For input characters: \"" + chars.toString() + "\"" );
 264  
                 }
 265  
                 // Accumulates negatively to avoid surprises near MAX_VALUE
 266  0
                 result = tmp - digit;
 267  0
                 if ( ++i >= length )
 268  
                 {
 269  0
                     break;
 270  
                 }
 271  0
             }
 272  0
             return isNegative ? result : -result;
 273  
         }
 274  0
         catch ( IndexOutOfBoundsException e )
 275  
         {
 276  0
             throw new NumberFormatException( "For input characters: \"" + chars.toString() + "\"" );
 277  
         }
 278  
     }
 279  
 
 280  
     /**
 281  
      * Parses this <code>CharSequence</code> as a <code>float</code>.
 282  
      *
 283  
      * @param chars the character sequence to parse.
 284  
      * @return the float number represented by the specified character sequence.
 285  
      * @throws NumberFormatException if the character sequence does not contain a parsable <code>float</code>.
 286  
      */
 287  
     public static float parseFloat( CharSequence chars )
 288  
     {
 289  0
         double d = parseDouble( chars );
 290  0
         if ( ( d >= Float.MIN_VALUE ) && ( d <= Float.MAX_VALUE ) )
 291  
         {
 292  0
             return (float) d;
 293  
         }
 294  
         else
 295  
         {
 296  0
             throw new NumberFormatException( "Float overflow for input characters: \"" + chars.toString() + "\"" );
 297  
         }
 298  
     }
 299  
 
 300  
     /**
 301  
      * Parses this <code>CharSequence</code> as a <code>double</code>.
 302  
      *
 303  
      * @param chars the character sequence to parse.
 304  
      * @return the double number represented by this character sequence.
 305  
      * @throws NumberFormatException if the character sequence does not contain a parsable <code>double</code>.
 306  
      */
 307  
     public static double parseDouble( CharSequence chars )
 308  
         throws NumberFormatException
 309  
     {
 310  
         try
 311  
         {
 312  0
             int length = chars.length();
 313  0
             double result = 0.0;
 314  0
             int exp = 0;
 315  
 
 316  0
             boolean isNegative = ( chars.charAt( 0 ) == '-' ) ? true : false;
 317  0
             int i = ( isNegative || ( chars.charAt( 0 ) == '+' ) ) ? 1 : 0;
 318  
 
 319  
             // Checks special cases NaN or Infinity.
 320  0
             if ( ( chars.charAt( i ) == 'N' ) || ( chars.charAt( i ) == 'I' ) )
 321  
             {
 322  0
                 if ( chars.toString().equals( "NaN" ) )
 323  
                 {
 324  0
                     return Double.NaN;
 325  
                 }
 326  0
                 else if ( chars.subSequence( i, length ).toString().equals( "Infinity" ) )
 327  
                 {
 328  0
                     return isNegative ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY;
 329  
                 }
 330  
             }
 331  
 
 332  
             // Reads decimal number.
 333  0
             boolean fraction = false;
 334  
             while ( true )
 335  
             {
 336  0
                 char c = chars.charAt( i );
 337  0
                 if ( ( c == '.' ) && ( !fraction ) )
 338  
                 {
 339  0
                     fraction = true;
 340  
                 }
 341  0
                 else if ( ( c == 'e' ) || ( c == 'E' ) )
 342  
                 {
 343  0
                     break;
 344  
                 }
 345  0
                 else if ( ( c >= '0' ) && ( c <= '9' ) )
 346  
                 {
 347  0
                     result = result * 10 + ( c - '0' );
 348  0
                     if ( fraction )
 349  
                     {
 350  0
                         exp--;
 351  
                     }
 352  
                 }
 353  
                 else
 354  
                 {
 355  0
                     throw new NumberFormatException( "For input characters: \"" + chars.toString() + "\"" );
 356  
                 }
 357  0
                 if ( ++i >= length )
 358  
                 {
 359  0
                     break;
 360  
                 }
 361  0
             }
 362  0
             result = isNegative ? -result : result;
 363  
 
 364  
             // Reads exponent (if any).
 365  0
             if ( i < length )
 366  
             {
 367  0
                 i++;
 368  0
                 boolean negE = ( chars.charAt( i ) == '-' ) ? true : false;
 369  0
                 i = ( negE || ( chars.charAt( i ) == '+' ) ) ? i + 1 : i;
 370  0
                 int valE = 0;
 371  
                 while ( true )
 372  
                 {
 373  0
                     char c = chars.charAt( i );
 374  0
                     if ( ( c >= '0' ) && ( c <= '9' ) )
 375  
                     {
 376  0
                         valE = valE * 10 + ( c - '0' );
 377  0
                         if ( valE > 10000000 )
 378  
                         { // Hard-limit to avoid overflow.
 379  0
                             valE = 10000000;
 380  
                         }
 381  
                     }
 382  
                     else
 383  
                     {
 384  0
                         throw new NumberFormatException( "For input characters: \"" + chars.toString() + "\"" );
 385  
                     }
 386  0
                     if ( ++i >= length )
 387  
                     {
 388  0
                         break;
 389  
                     }
 390  0
                 }
 391  0
                 exp += negE ? -valE : valE;
 392  
             }
 393  
 
 394  
             // Returns product decimal number with exponent.
 395  0
             return multE( result, exp );
 396  
 
 397  
         }
 398  0
         catch ( IndexOutOfBoundsException e )
 399  
         {
 400  0
             throw new NumberFormatException( "For input characters: \"" + chars.toString() + "\"" );
 401  
         }
 402  
     }
 403  
 
 404  
     /**
 405  
      * Formats the specified <code>boolean</code> and appends the resulting text to the <code>StringBuffer</code>
 406  
      * argument.
 407  
      *
 408  
      * @param b a <code>boolean</code>.
 409  
      * @param sb the <code>StringBuffer</code> to append.
 410  
      * @return the specified <code>StringBuffer</code> object.
 411  
      * @see #parseBoolean
 412  
      */
 413  
     public static StringBuffer format( boolean b, StringBuffer sb )
 414  
     {
 415  0
         return b ? sb.append( "true" ) : sb.append( "false" );
 416  
     }
 417  
 
 418  
     /**
 419  
      * Formats the specified <code>short</code> and appends the resulting text (decimal representation) to the
 420  
      * <code>StringBuffer</code> argument.
 421  
      * <p>
 422  
      * Note: This method is preferred to <code>StringBuffer.append(short)
 423  
      *           </code> as it does not create temporary <code>String</code> objects (several times faster for small
 424  
      * numbers).
 425  
      * </p>
 426  
      *
 427  
      * @param s the <code>short</code> number.
 428  
      * @param sb the <code>StringBuffer</code> to append.
 429  
      * @return the specified <code>StringBuffer</code> object.
 430  
      * @see #parseShort
 431  
      */
 432  
     public static StringBuffer format( short s, StringBuffer sb )
 433  
     {
 434  0
         return format( (int) s, sb ); // Forwards to int formatting (fast).
 435  
     }
 436  
 
 437  
     /**
 438  
      * Formats the specified <code>short</code> in the specified radix and appends the resulting text to the
 439  
      * <code>StringBuffer</code> argument.
 440  
      *
 441  
      * @param s the <code>short</code> number.
 442  
      * @param radix the radix.
 443  
      * @param sb the <code>StringBuffer</code> to append.
 444  
      * @return the specified <code>StringBuffer</code> object.
 445  
      * @see #parseShort(CharSequence, int) throws IllegalArgumentException if radix is not in [2 .. 36] range.
 446  
      */
 447  
     public static StringBuffer format( short s, int radix, StringBuffer sb )
 448  
     {
 449  0
         return format( (int) s, radix, sb ); // Forwards to int formatting (fast).
 450  
     }
 451  
 
 452  
     /**
 453  
      * Formats the specified <code>int</code> and appends the resulting text (decimal representation) to the
 454  
      * <code>StringBuffer</code> argument.
 455  
      * <p>
 456  
      * Note: This method is preferred to <code>StringBuffer.append(int)
 457  
      *           </code> as it does not create temporary <code>String</code> objects (several times faster for small
 458  
      * numbers).
 459  
      * </p>
 460  
      *
 461  
      * @param i the <code>int</code> number.
 462  
      * @param sb the <code>StringBuffer</code> to append.
 463  
      * @return the specified <code>StringBuffer</code> object.
 464  
      * @see #parseInt
 465  
      */
 466  
     public static StringBuffer format( int i, StringBuffer sb )
 467  
     {
 468  0
         if ( i <= 0 )
 469  
         {
 470  0
             if ( i == Integer.MIN_VALUE )
 471  
             { // Negation would overflow.
 472  0
                 return sb.append( "-2147483648" ); // 11 char max.
 473  
             }
 474  0
             else if ( i == 0 )
 475  
             {
 476  0
                 return sb.append( '0' );
 477  
             }
 478  0
             i = -i;
 479  0
             sb.append( '-' );
 480  
         }
 481  0
         int j = 1;
 482  0
         for ( ; ( j < 10 ) && ( i >= INT_POW_10[j] ); j++ )
 483  
         {
 484  
         }
 485  
         // POW_10[j] > i >= POW_10[j-1]
 486  0
         for ( j--; j >= 0; j-- )
 487  
         {
 488  0
             int pow10 = INT_POW_10[j];
 489  0
             int digit = i / pow10;
 490  0
             i -= digit * pow10;
 491  0
             sb.append( DIGITS[digit] );
 492  
         }
 493  0
         return sb;
 494  
     }
 495  
 
 496  0
     private static final int[] INT_POW_10 = new int[10];
 497  
     static
 498  
     {
 499  0
         int pow = 1;
 500  0
         for ( int i = 0; i < 10; i++ )
 501  
         {
 502  0
             INT_POW_10[i] = pow;
 503  0
             pow *= 10;
 504  
         }
 505  
     }
 506  
 
 507  
     /**
 508  
      * Formats the specified <code>int</code> in the specified radix and appends the resulting text to the
 509  
      * <code>StringBuffer</code> argument.
 510  
      *
 511  
      * @param i the <code>int</code> number.
 512  
      * @param radix the radix.
 513  
      * @param sb the <code>StringBuffer</code> to append.
 514  
      * @return the specified <code>StringBuffer</code> object.
 515  
      * @see #parseInt(CharSequence, int) throws IllegalArgumentException if radix is not in [2 .. 36] range.
 516  
      */
 517  
     public static StringBuffer format( int i, int radix, StringBuffer sb )
 518  
     {
 519  0
         if ( radix == 10 )
 520  
         {
 521  0
             return format( i, sb ); // Faster version.
 522  
         }
 523  0
         else if ( radix < 2 || radix > 36 )
 524  
         {
 525  0
             throw new IllegalArgumentException( "radix: " + radix );
 526  
         }
 527  0
         if ( i < 0 )
 528  
         {
 529  0
             sb.append( '-' );
 530  
         }
 531  
         else
 532  
         {
 533  0
             i = -i;
 534  
         }
 535  0
         format2( i, radix, sb );
 536  0
         return sb;
 537  
     }
 538  
 
 539  
     private static void format2( int i, int radix, StringBuffer sb )
 540  
     {
 541  0
         if ( i <= -radix )
 542  
         {
 543  0
             format2( i / radix, radix, sb );
 544  0
             sb.append( DIGITS[-( i % radix )] );
 545  
         }
 546  
         else
 547  
         {
 548  0
             sb.append( DIGITS[-i] );
 549  
         }
 550  0
     }
 551  
 
 552  
     /**
 553  
      * Formats the specified <code>long</code> and appends the resulting text (decimal representation) to the
 554  
      * <code>StringBuffer</code> argument.
 555  
      * <p>
 556  
      * Note: This method is preferred to <code>StringBuffer.append(long)
 557  
      *           </code> as it does not create temporary <code>String</code> objects (several times faster for small
 558  
      * numbers).
 559  
      * </p>
 560  
      *
 561  
      * @param l the <code>long</code> number.
 562  
      * @param sb the <code>StringBuffer</code> to append.
 563  
      * @return the specified <code>StringBuffer</code> object.
 564  
      * @see #parseLong
 565  
      */
 566  
     public static StringBuffer format( long l, StringBuffer sb )
 567  
     {
 568  0
         if ( l <= 0 )
 569  
         {
 570  0
             if ( l == Long.MIN_VALUE )
 571  
             { // Negation would overflow.
 572  0
                 return sb.append( "-9223372036854775808" ); // 20 characters max.
 573  
             }
 574  0
             else if ( l == 0 )
 575  
             {
 576  0
                 return sb.append( '0' );
 577  
             }
 578  0
             l = -l;
 579  0
             sb.append( '-' );
 580  
         }
 581  0
         int j = 1;
 582  0
         for ( ; ( j < 19 ) && ( l >= LONG_POW_10[j] ); j++ )
 583  
         {
 584  
         }
 585  
         // POW_10[j] > l >= POW_10[j-1]
 586  0
         for ( j--; j >= 0; j-- )
 587  
         {
 588  0
             long pow10 = LONG_POW_10[j];
 589  0
             int digit = (int) ( l / pow10 );
 590  0
             l -= digit * pow10;
 591  0
             sb.append( DIGITS[digit] );
 592  
         }
 593  0
         return sb;
 594  
     }
 595  
 
 596  0
     private static final long[] LONG_POW_10 = new long[19];
 597  
     static
 598  
     {
 599  0
         long pow = 1;
 600  0
         for ( int i = 0; i < 19; i++ )
 601  
         {
 602  0
             LONG_POW_10[i] = pow;
 603  0
             pow *= 10;
 604  
         }
 605  
     }
 606  
 
 607  
     /**
 608  
      * Formats the specified <code>long</code> in the specified radix and appends the resulting text to the
 609  
      * <code>StringBuffer</code> argument.
 610  
      *
 611  
      * @param l the <code>long</code> number.
 612  
      * @param radix the radix.
 613  
      * @param sb the <code>StringBuffer</code> to append.
 614  
      * @return the specified <code>StringBuffer</code> object.
 615  
      * @see #parseLong(CharSequence, int) throws IllegalArgumentException if radix is not in [2 .. 36] range.
 616  
      */
 617  
     public static StringBuffer format( long l, int radix, StringBuffer sb )
 618  
     {
 619  0
         if ( radix == 10 )
 620  
         {
 621  0
             return format( l, sb ); // Faster version.
 622  
         }
 623  0
         else if ( radix < 2 || radix > 36 )
 624  
         {
 625  0
             throw new IllegalArgumentException( "radix: " + radix );
 626  
         }
 627  0
         if ( l < 0 )
 628  
         {
 629  0
             sb.append( '-' );
 630  
         }
 631  
         else
 632  
         {
 633  0
             l = -l;
 634  
         }
 635  0
         format2( l, radix, sb );
 636  0
         return sb;
 637  
     }
 638  
 
 639  
     private static void format2( long l, int radix, StringBuffer sb )
 640  
     {
 641  0
         if ( l <= -radix )
 642  
         {
 643  0
             format2( l / radix, radix, sb );
 644  0
             sb.append( DIGITS[(int) -( l % radix )] );
 645  
         }
 646  
         else
 647  
         {
 648  0
             sb.append( DIGITS[(int) -l] );
 649  
         }
 650  0
     }
 651  
 
 652  
     /**
 653  
      * Formats the specified <code>float</code> and appends the resulting text to the <code>StringBuffer</code>
 654  
      * argument.
 655  
      *
 656  
      * @param f the <code>float</code> number.
 657  
      * @param sb the <code>StringBuffer</code> to append.
 658  
      * @return <code>format(f, 0.0f, sb)</code>
 659  
      * @see #format(float, float, StringBuffer)
 660  
      */
 661  
     public static StringBuffer format( float f, StringBuffer sb )
 662  
     {
 663  0
         return format( f, 0.0f, sb );
 664  
     }
 665  
 
 666  
     /**
 667  
      * Formats the specified <code>float</code> and appends the resulting text to the <code>StringBuffer</code>
 668  
      * argument; the number of significative digits is deduced from the specified precision. All digits at least as
 669  
      * significant as the specified precision are represented. For example:
 670  
      * <ul>
 671  
      * <li><code>format(5.6f, 0.01f, sb)</code> appends <code>"5.60"</code></li>
 672  
      * <li><code>format(5.6f, 0.1f, sb)</code> appends <code>"5.6"</code></li>
 673  
      * <li><code>format(5.6f, 1f, sb)</code> appends <code>"6"</code></li>
 674  
      * </ul>
 675  
      * If the precision is <code>0.0f</code>, the precision is assumed to be the intrinsic <code>float</code> precision
 676  
      * (64 bits IEEE 754 format); no formatting is performed, all significant digits are displayed and trailing zeros
 677  
      * are removed.
 678  
      *
 679  
      * @param f the <code>float</code> number.
 680  
      * @param precision the maximum weight of the last digit represented.
 681  
      * @param sb the <code>StringBuffer</code> to append.
 682  
      * @return the specified <code>StringBuffer</code> object.
 683  
      * @throws IllegalArgumentException if the specified precision is negative or would result in too many digits (19+).
 684  
      */
 685  
     public static StringBuffer format( float f, float precision, StringBuffer sb )
 686  
     {
 687  
         // Adjusts precision.
 688  
         boolean precisionOnLastDigit;
 689  0
         if ( precision > 0.0f )
 690  
         {
 691  0
             precisionOnLastDigit = true;
 692  
         }
 693  0
         else if ( precision == 0.0f )
 694  
         {
 695  0
             if ( f != 0.0f )
 696  
             {
 697  0
                 precisionOnLastDigit = false;
 698  0
                 precision = Math.max( Math.abs( f * FLOAT_RELATIVE_ERROR ), Float.MIN_VALUE );
 699  
             }
 700  
             else
 701  
             {
 702  0
                 return sb.append( "0.0" ); // Exact zero.
 703  
             }
 704  
         }
 705  
         else
 706  
         {
 707  0
             throw new IllegalArgumentException( "precision: Negative values not allowed" );
 708  
         }
 709  0
         return format( f, precision, precisionOnLastDigit, sb );
 710  
     }
 711  
 
 712  
     /**
 713  
      * Formats the specified <code>double</code> and appends the resulting text to the <code>StringBuffer</code>
 714  
      * argument.
 715  
      * <p>
 716  
      * Note : This method is preferred to <code>StringBuffer.append(double)
 717  
      *            </code> or even <code>String.valueOf(double)</code> as it does not create temporary
 718  
      * <code>String</code> or <code>
 719  
      *            FloatingDecimal</code> objects (several times faster, e.g. 15x faster for
 720  
      * <code>Double.MAX_VALUE</code>).
 721  
      * </p>
 722  
      *
 723  
      * @param d the <code>double</code> number.
 724  
      * @param sb the <code>StringBuffer</code> to append.
 725  
      * @return <code>format(d, 0.0, sb)</code>
 726  
      * @see #format(double, double, StringBuffer)
 727  
      */
 728  
     public static StringBuffer format( double d, StringBuffer sb )
 729  
     {
 730  0
         return format( d, 0.0, sb );
 731  
     }
 732  
 
 733  
     /**
 734  
      * Formats the specified <code>double</code> and appends the resulting text to the <code>StringBuffer</code>
 735  
      * argument; the number of significand digits is specified as integer argument.
 736  
      *
 737  
      * @param d the <code>double</code> number.
 738  
      * @param digits the number of significand digits (excludes exponent).
 739  
      * @param sb the <code>StringBuffer</code> to append.
 740  
      * @return the specified <code>StringBuffer</code> object.
 741  
      * @throws IllegalArgumentException if the number of digits is not in range <code>[1..19]</code>.
 742  
      */
 743  
     public static StringBuffer format( double d, int digits, StringBuffer sb )
 744  
     {
 745  0
         if ( ( digits >= 1 ) && ( digits <= 19 ) )
 746  
         {
 747  0
             double precision = Math.abs( d / DOUBLE_POW_10[digits - 1] );
 748  0
             return format( d, precision, sb );
 749  
         }
 750  
         else
 751  
         {
 752  0
             throw new java.lang.IllegalArgumentException( "digits: " + digits + " is not in range [1 .. 19]" );
 753  
         }
 754  
     }
 755  
 
 756  
     /**
 757  
      * Formats the specified <code>double</code> and appends the resulting text to the <code>StringBuffer</code>
 758  
      * argument; the number of significative digits is deduced from the specified precision. All digits at least as
 759  
      * significant as the specified precision are represented. For example:
 760  
      * <ul>
 761  
      * <li><code>format(5.6, 0.01, sb)</code> appends <code>"5.60"</code></li>
 762  
      * <li><code>format(5.6, 0.1, sb)</code> appends <code>"5.6"</code></li>
 763  
      * <li><code>format(5.6, 1, sb)</code> appends <code>"6"</code></li>
 764  
      * </ul>
 765  
      * If the precision is <code>0.0</code>, the precision is assumed to be the intrinsic <code>double</code> precision
 766  
      * (64 bits IEEE 754 format); no formatting is performed, all significant digits are displayed and trailing zeros
 767  
      * are removed.
 768  
      *
 769  
      * @param d the <code>double</code> number.
 770  
      * @param precision the maximum weight of the last digit represented.
 771  
      * @param sb the <code>StringBuffer</code> to append.
 772  
      * @return the specified <code>StringBuffer</code> object.
 773  
      * @throws IllegalArgumentException if the specified precision is negative or would result in too many digits (19+).
 774  
      */
 775  
     public static StringBuffer format( double d, double precision, StringBuffer sb )
 776  
     {
 777  
         // Adjusts precision.
 778  0
         boolean precisionOnLastDigit = false;
 779  0
         if ( precision > 0.0 )
 780  
         {
 781  0
             precisionOnLastDigit = true;
 782  
         }
 783  0
         else if ( precision == 0.0 )
 784  
         {
 785  0
             if ( d != 0.0 )
 786  
             {
 787  0
                 precision = Math.max( Math.abs( d * DOUBLE_RELATIVE_ERROR ), Double.MIN_VALUE );
 788  
             }
 789  
             else
 790  
             {
 791  0
                 return sb.append( "0.0" ); // Exact zero.
 792  
             }
 793  
         }
 794  0
         else if ( precision < 0.0 )
 795  
         { // Not NaN
 796  0
             throw new IllegalArgumentException( "precision: Negative values not allowed" );
 797  
         }
 798  0
         return format( d, precision, precisionOnLastDigit, sb );
 799  
     }
 800  
 
 801  
     /**
 802  
      * Formats the specified <code>double</code> and appends the resulting text to the <code>StringBuffer</code>
 803  
      * argument; the number of significative digits is deduced from the specified precision.
 804  
      *
 805  
      * @param d the <code>double</code> number.
 806  
      * @param precision the maximum weight of the last digit represented.
 807  
      * @param precisionOnLastDigit indicates if the number of digits is deduced from the specified precision.
 808  
      * @param sb the <code>StringBuffer</code> to append.
 809  
      * @return the specified <code>StringBuffer</code> object.
 810  
      */
 811  
     private static StringBuffer format( double d, double precision, boolean precisionOnLastDigit, StringBuffer sb )
 812  
     {
 813  
         // Special cases.
 814  0
         if ( Double.isNaN( d ) )
 815  
         {
 816  0
             return sb.append( "NaN" );
 817  
         }
 818  0
         else if ( Double.isInfinite( d ) )
 819  
         {
 820  0
             return ( d >= 0 ) ? sb.append( "Infinity" ) : sb.append( "-Infinity" );
 821  
         }
 822  0
         if ( d < 0 )
 823  
         {
 824  0
             d = -d;
 825  0
             sb.append( '-' );
 826  
         }
 827  
 
 828  
         // Formats decimal part.
 829  0
         int rank = (int) Math.floor( Math.log( precision ) / LOG_10 );
 830  0
         double digitValue = multE( d, -rank );
 831  0
         if ( digitValue >= Long.MAX_VALUE )
 832  
         {
 833  0
             throw new IllegalArgumentException( "Specified precision would result in too many digits" );
 834  
         }
 835  0
         int digitStart = sb.length();
 836  0
         format( Math.round( digitValue ), sb );
 837  0
         int digitLength = sb.length() - digitStart;
 838  0
         int dotPos = digitLength + rank;
 839  0
         boolean useScientificNotation = false;
 840  
 
 841  
         // Inserts dot ('.')
 842  0
         if ( ( dotPos <= -LEADING_ZEROS.length ) || ( dotPos > digitLength ) )
 843  
         {
 844  
             // Scientific notation has to be used ("x.xxxEyy").
 845  0
             sb.insert( digitStart + 1, '.' );
 846  0
             useScientificNotation = true;
 847  
         }
 848  0
         else if ( dotPos > 0 )
 849  
         {
 850  
             // Dot within the string ("xxxx.xxxxx").
 851  0
             sb.insert( digitStart + dotPos, '.' );
 852  
         }
 853  
         else
 854  
         {
 855  
             // Leading zeros ("0.xxxxx").
 856  0
             sb.insert( digitStart, LEADING_ZEROS[-dotPos] );
 857  
         }
 858  
 
 859  
         // Removes trailing zeros.
 860  0
         if ( !precisionOnLastDigit )
 861  
         {
 862  0
             int newLength = sb.length();
 863  
             do
 864  
             {
 865  0
                 newLength--;
 866  
             }
 867  0
             while ( sb.charAt( newLength ) == '0' );
 868  0
             sb.setLength( newLength + 1 );
 869  
         }
 870  
 
 871  
         // Avoids trailing '.'
 872  0
         if ( sb.charAt( sb.length() - 1 ) == '.' )
 873  
         {
 874  0
             if ( precisionOnLastDigit )
 875  
             {
 876  0
                 sb.setLength( sb.length() - 1 ); // Prefers "xxx" to "xxx."
 877  
             }
 878  
             else
 879  
             {
 880  0
                 sb.append( '0' ); // Prefer "xxx.0" to "xxx."
 881  
             }
 882  
         }
 883  
 
 884  
         // Writes exponent.
 885  0
         if ( useScientificNotation )
 886  
         {
 887  0
             sb.append( 'E' );
 888  0
             format( dotPos - 1, sb );
 889  
         }
 890  
 
 891  0
         return sb;
 892  
     }
 893  
 
 894  0
     private static final double LOG_10 = Math.log( 10 );
 895  
 
 896  0
     private static final float FLOAT_RELATIVE_ERROR = (float) Math.pow( 2, -24 );
 897  
 
 898  0
     private static final double DOUBLE_RELATIVE_ERROR = Math.pow( 2, -53 );
 899  
 
 900  0
     private static String[] LEADING_ZEROS = { "0.", "0.0", "0.00" };
 901  
 
 902  
     /**
 903  
      * Returns the product of the specified value with <code>10</code> raised at the specified power exponent.
 904  
      *
 905  
      * @param value the value.
 906  
      * @param E the exponent.
 907  
      * @return <code>value * 10^E</code>
 908  
      */
 909  
     private static final double multE( double value, int E )
 910  
     {
 911  0
         if ( E >= 0 )
 912  
         {
 913  0
             if ( E <= 308 )
 914  
             {
 915  
                 // Max: 1.7976931348623157E+308
 916  0
                 return value * DOUBLE_POW_10[E];
 917  
             }
 918  
             else
 919  
             {
 920  0
                 value *= 1E21; // Exact multiplicand.
 921  0
                 E = Math.min( 308, E - 21 );
 922  0
                 return value * DOUBLE_POW_10[E];
 923  
             }
 924  
         }
 925  
         else
 926  
         {
 927  0
             if ( E >= -308 )
 928  
             {
 929  0
                 return value / DOUBLE_POW_10[-E];
 930  
             }
 931  
             else
 932  
             {
 933  
                 // Min: 4.9E-324
 934  0
                 value /= 1E21; // Exact divisor.
 935  0
                 E = Math.max( -308, E + 21 );
 936  0
                 return value / DOUBLE_POW_10[-E];
 937  
             }
 938  
         }
 939  
     }
 940  
 
 941  
     // Note: Approximation for exponents > 21. This may introduce round-off
 942  
     // errors (e.g. 1E23 represented as "9.999999999999999E22").
 943  0
     private static final double[] DOUBLE_POW_10 = new double[] {
 944  
 
 945  
         1E000, 1E001, 1E002, 1E003, 1E004, 1E005, 1E006, 1E007, 1E008, 1E009, 1E010, 1E011, 1E012, 1E013, 1E014, 1E015,
 946  
         1E016, 1E017, 1E018, 1E019, 1E020, 1E021, 1E022, 1E023, 1E024, 1E025, 1E026, 1E027, 1E028, 1E029, 1E030, 1E031,
 947  
         1E032, 1E033, 1E034, 1E035, 1E036, 1E037, 1E038, 1E039, 1E040, 1E041, 1E042, 1E043, 1E044, 1E045, 1E046, 1E047,
 948  
         1E048, 1E049, 1E050, 1E051, 1E052, 1E053, 1E054, 1E055, 1E056, 1E057, 1E058, 1E059, 1E060, 1E061, 1E062, 1E063,
 949  
         1E064, 1E065, 1E066, 1E067, 1E068, 1E069, 1E070, 1E071, 1E072, 1E073, 1E074, 1E075, 1E076, 1E077, 1E078, 1E079,
 950  
         1E080, 1E081, 1E082, 1E083, 1E084, 1E085, 1E086, 1E087, 1E088, 1E089, 1E090, 1E091, 1E092, 1E093, 1E094, 1E095,
 951  
         1E096, 1E097, 1E098, 1E099,
 952  
 
 953  
         1E100, 1E101, 1E102, 1E103, 1E104, 1E105, 1E106, 1E107, 1E108, 1E109, 1E110, 1E111, 1E112, 1E113, 1E114, 1E115,
 954  
         1E116, 1E117, 1E118, 1E119, 1E120, 1E121, 1E122, 1E123, 1E124, 1E125, 1E126, 1E127, 1E128, 1E129, 1E130, 1E131,
 955  
         1E132, 1E133, 1E134, 1E135, 1E136, 1E137, 1E138, 1E139, 1E140, 1E141, 1E142, 1E143, 1E144, 1E145, 1E146, 1E147,
 956  
         1E148, 1E149, 1E150, 1E151, 1E152, 1E153, 1E154, 1E155, 1E156, 1E157, 1E158, 1E159, 1E160, 1E161, 1E162, 1E163,
 957  
         1E164, 1E165, 1E166, 1E167, 1E168, 1E169, 1E170, 1E171, 1E172, 1E173, 1E174, 1E175, 1E176, 1E177, 1E178, 1E179,
 958  
         1E180, 1E181, 1E182, 1E183, 1E184, 1E185, 1E186, 1E187, 1E188, 1E189, 1E190, 1E191, 1E192, 1E193, 1E194, 1E195,
 959  
         1E196, 1E197, 1E198, 1E199,
 960  
 
 961  
         1E200, 1E201, 1E202, 1E203, 1E204, 1E205, 1E206, 1E207, 1E208, 1E209, 1E210, 1E211, 1E212, 1E213, 1E214, 1E215,
 962  
         1E216, 1E217, 1E218, 1E219, 1E220, 1E221, 1E222, 1E223, 1E224, 1E225, 1E226, 1E227, 1E228, 1E229, 1E230, 1E231,
 963  
         1E232, 1E233, 1E234, 1E235, 1E236, 1E237, 1E238, 1E239, 1E240, 1E241, 1E242, 1E243, 1E244, 1E245, 1E246, 1E247,
 964  
         1E248, 1E249, 1E250, 1E251, 1E252, 1E253, 1E254, 1E255, 1E256, 1E257, 1E258, 1E259, 1E260, 1E261, 1E262, 1E263,
 965  
         1E264, 1E265, 1E266, 1E267, 1E268, 1E269, 1E270, 1E271, 1E272, 1E273, 1E274, 1E275, 1E276, 1E277, 1E278, 1E279,
 966  
         1E280, 1E281, 1E282, 1E283, 1E284, 1E285, 1E286, 1E287, 1E288, 1E289, 1E290, 1E291, 1E292, 1E293, 1E294, 1E295,
 967  
         1E296, 1E297, 1E298, 1E299,
 968  
 
 969  
         1E300, 1E301, 1E302, 1E303, 1E304, 1E305, 1E306, 1E307, 1E308 };
 970  
 }