0001: /*
0002: * Javolution - Java(TM) Solution for Real-Time and Embedded Systems
0003: * Copyright (C) 2006 - Javolution (http://javolution.org/)
0004: * All rights reserved.
0005: *
0006: * Permission to use, copy, modify, and distribute this software is
0007: * freely granted, provided that this notice is preserved.
0008: */
0009: package javolution.text;
0010:
0011: import j2me.lang.CharSequence;
0012: import javolution.text.TextFormat.Cursor;
0013:
0014: import java.io.IOException;
0015:
0016: /**
0017: * <p> This class provides utility methods to parse <code>CharSequence</code>
0018: * into primitive types and to format primitive types into any
0019: * <code>Appendable</code>.</p>
0020: *
0021: * <p> Methods from this class <b>do not create temporary objects</b> and
0022: * are typically faster than standard library methods (see
0023: * <a href="http://javolution.org/doc/benchmark.html">benchmark</a>).</p>
0024: *
0025: * <p> The number of digits when formatting floating point numbers can be
0026: * specified. The default setting for <code>double</code> is 17 digits
0027: * or even 16 digits when the conversion is lossless back and forth
0028: * (mimic the standard library formatting). For example:[code]
0029: * TypeFormat.format(0.2, a) = "0.2" // 17 or 16 digits (as long as lossless conversion), remove trailing zeros.
0030: * TypeFormat.format(0.2, 17, false, false, a) = "0.20000000000000001" // Closest 17 digits number.
0031: * TypeFormat.format(0.2, 19, false, false, a) = "0.2000000000000000111" // Closest 19 digits.
0032: * TypeFormat.format(0.2, 4, false, false, a) = "0.2" // Fixed-point notation, remove trailing zeros.
0033: * TypeFormat.format(0.2, 4, false, true, a) = "0.2000" // Fixed-point notation, fixed number of digits.
0034: * TypeFormat.format(0.2, 4, true, false, a) = "2.0E-1" // Scientific notation, remove trailing zeros.
0035: * TypeFormat.format(0.2, 4, true, true, a) = "2.000E-1" // Scientific notation, fixed number of digits.
0036: * [/code]</p>
0037: *
0038: * <p> For non-primitive objects, formatting is typically performed using
0039: * specialized {@link TextFormat} instances.</p>
0040: *
0041: * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
0042: * @version 4.1, November 30, 2006
0043: */
0044: public final class TypeFormat {
0045:
0046: /**
0047: * Default constructor (forbids derivation).
0048: */
0049: private TypeFormat() {
0050: }
0051:
0052: /**
0053: * Parses the specified character sequence as a <code>boolean</code>.
0054: *
0055: * @param csq the character sequence to parse.
0056: * @return the corresponding boolean value.
0057: * @throws IllegalArgumentException if the specified character sequence
0058: * is different from "true" or "false" ignoring cases.
0059: */
0060: public static boolean parseBoolean(CharSequence csq) {
0061: if ((csq.length() == 4)
0062: && (csq.charAt(0) == 't' || csq.charAt(0) == 'T')
0063: && (csq.charAt(1) == 'r' || csq.charAt(1) == 'R')
0064: && (csq.charAt(2) == 'u' || csq.charAt(2) == 'U')
0065: && (csq.charAt(3) == 'e' || csq.charAt(3) == 'E')) {
0066: return true;
0067: } else if ((csq.length() == 5)
0068: && (csq.charAt(0) == 'f' || csq.charAt(0) == 'F')
0069: && (csq.charAt(1) == 'a' || csq.charAt(1) == 'A')
0070: && (csq.charAt(2) == 'l' || csq.charAt(2) == 'L')
0071: && (csq.charAt(3) == 's' || csq.charAt(3) == 'S')
0072: && (csq.charAt(4) == 'e' || csq.charAt(4) == 'E')) {
0073: return false;
0074: }
0075: throw new IllegalArgumentException("Cannot parse " + csq
0076: + " as boolean");
0077: }
0078:
0079: /**
0080: * Equivalent to {@link #parseBoolean(CharSequence)}
0081: * (for J2ME compatibility).
0082: */
0083: public static boolean parseBoolean(String csq) {
0084: if ((csq.length() == 4)
0085: && (csq.charAt(0) == 't' || csq.charAt(0) == 'T')
0086: && (csq.charAt(1) == 'r' || csq.charAt(1) == 'R')
0087: && (csq.charAt(2) == 'u' || csq.charAt(2) == 'U')
0088: && (csq.charAt(3) == 'e' || csq.charAt(3) == 'E')) {
0089: return true;
0090: } else if ((csq.length() == 5)
0091: && (csq.charAt(0) == 'f' || csq.charAt(0) == 'F')
0092: && (csq.charAt(1) == 'a' || csq.charAt(1) == 'A')
0093: && (csq.charAt(2) == 'l' || csq.charAt(2) == 'L')
0094: && (csq.charAt(3) == 's' || csq.charAt(3) == 'S')
0095: && (csq.charAt(4) == 'e' || csq.charAt(4) == 'E')) {
0096: return false;
0097: }
0098: throw new IllegalArgumentException("Cannot parse " + csq
0099: + " as boolean");
0100: }
0101:
0102: /**
0103: * Parses the specified character sequence from the specified position
0104: * as a <code>boolean</code>.
0105: *
0106: * @param csq the character sequence to parse.
0107: * @param cursor the current cursor position (being maintained).
0108: * @return the next boolean value.
0109: * @throws IllegalArgumentException if the character sequence from the
0110: * specified position is different from "true" or "false" ignoring
0111: * cases.
0112: */
0113: public static boolean parseBoolean(CharSequence csq, Cursor cursor) {
0114: final int i = cursor.getIndex();
0115: if ((cursor.getEndIndex() >= i + 4)
0116: && (csq.charAt(i) == 't' || csq.charAt(i) == 'T')
0117: && (csq.charAt(i + 1) == 'r' || csq.charAt(i + 1) == 'R')
0118: && (csq.charAt(i + 2) == 'u' || csq.charAt(i + 2) == 'U')
0119: && (csq.charAt(i + 3) == 'e' || csq.charAt(i + 3) == 'E')) {
0120: cursor.increment(4);
0121: return true;
0122: }
0123: if ((cursor.getEndIndex() >= i + 5)
0124: && (csq.charAt(i) == 'f' || csq.charAt(i) == 'F')
0125: && (csq.charAt(i + 1) == 'a' || csq.charAt(i + 1) == 'A')
0126: && (csq.charAt(i + 2) == 'l' || csq.charAt(i + 2) == 'L')
0127: && (csq.charAt(i + 3) == 's' || csq.charAt(i + 3) == 'S')
0128: && (csq.charAt(i + 4) == 'e' || csq.charAt(i + 4) == 'E')) {
0129: cursor.increment(5);
0130: return false;
0131: }
0132: throw new IllegalArgumentException("Cannot parse boolean "
0133: + csq.subSequence(cursor.getIndex(), cursor
0134: .getEndIndex()));
0135: }
0136:
0137: /**
0138: * Parses the specified character sequence as a signed decimal
0139: * <code>byte</code>.
0140: *
0141: * @param csq the character sequence to parse.
0142: * @return <code>parseByte(csq, 10)</code>
0143: * @throws NumberFormatException if the specified character sequence
0144: * does not contain a parsable <code>byte</code>.
0145: * @see #parseByte(CharSequence, int)
0146: */
0147: public static byte parseByte(CharSequence csq) {
0148: return parseByte(csq, 10);
0149: }
0150:
0151: /**
0152: * Parses the specified character sequence as a signed <code>byte</code>
0153: * in the specified radix.
0154: *
0155: * @param csq the character sequence to parse.
0156: * @param radix the radix to be used while parsing.
0157: * @return the corresponding <code>byte</code>.
0158: * @throws NumberFormatException if the specified character sequence
0159: * does not contain a parsable <code>byte</code>.
0160: */
0161: public static byte parseByte(CharSequence csq, int radix) {
0162: int i = parseInt(csq, radix);
0163: if ((i < Byte.MIN_VALUE) || (i > Byte.MAX_VALUE))
0164: throw new NumberFormatException("Overflow");
0165: return (byte) i;
0166: }
0167:
0168: /**
0169: * Parses the specified character sequence from the specified position
0170: * as a signed <code>byte</code> in the specified radix.
0171: *
0172: * @param csq the character sequence to parse.
0173: * @param radix the radix to be used while parsing.
0174: * @param cursor the current cursor position (being maintained).
0175: * @return the corresponding <code>byte</code>.
0176: * @throws NumberFormatException if the specified character sequence
0177: * does not contain a parsable <code>byte</code>.
0178: */
0179: public static byte parseByte(CharSequence csq, int radix,
0180: Cursor cursor) {
0181: int i = parseInt(csq, radix, cursor);
0182: if ((i < Byte.MIN_VALUE) || (i > Byte.MAX_VALUE))
0183: throw new NumberFormatException("Overflow");
0184: return (byte) i;
0185: }
0186:
0187: /**
0188: * Parses the specified character sequence as a signed decimal
0189: * <code>short</code>.
0190: *
0191: * @param csq the character sequence to parse.
0192: * @return <code>parseShort(csq, 10)</code>
0193: * @throws NumberFormatException if the specified character sequence
0194: * does not contain a parsable <code>short</code>.
0195: * @see #parseShort(CharSequence, int)
0196: */
0197: public static short parseShort(CharSequence csq) {
0198: return parseShort(csq, 10);
0199: }
0200:
0201: /**
0202: * Parses the specified character sequence as a signed <code>short</code>
0203: * in the specified radix.
0204: *
0205: * @param csq the character sequence to parse.
0206: * @param radix the radix to be used while parsing.
0207: * @return the corresponding <code>short</code>.
0208: * @throws NumberFormatException if the specified character sequence
0209: * does not contain a parsable <code>short</code>.
0210: */
0211: public static short parseShort(CharSequence csq, int radix) {
0212: int i = parseInt(csq, radix);
0213: if ((i < Short.MIN_VALUE) || (i > Short.MAX_VALUE))
0214: throw new NumberFormatException("Overflow");
0215: return (short) i;
0216: }
0217:
0218: /**
0219: * Parses the specified character sequence from the specified position
0220: * as a signed <code>short</code> in the specified radix.
0221: *
0222: * @param csq the character sequence to parse.
0223: * @param radix the radix to be used while parsing.
0224: * @param cursor the current cursor position (being maintained).
0225: * @return the corresponding <code>short</code>.
0226: * @throws NumberFormatException if the specified character sequence
0227: * does not contain a parsable <code>short</code>.
0228: */
0229: public static short parseShort(CharSequence csq, int radix,
0230: Cursor cursor) {
0231: int i = parseInt(csq, radix, cursor);
0232: if ((i < Short.MIN_VALUE) || (i > Short.MAX_VALUE))
0233: throw new NumberFormatException("Overflow");
0234: return (short) i;
0235: }
0236:
0237: /**
0238: * Parses the specified character sequence as a signed <code>int</code>.
0239: *
0240: * @param csq the character sequence to parse.
0241: * @return <code>parseInt(csq, 10)</code>
0242: * @throws NumberFormatException if the specified character sequence
0243: * does not contain a parsable <code>int</code>.
0244: * @see #parseInt(CharSequence, int)
0245: */
0246: public static int parseInt(CharSequence csq) {
0247: return parseInt(csq, 10);
0248: }
0249:
0250: /**
0251: * Equivalent to {@link #parseInt(CharSequence)} (for J2ME compatibility).
0252: */
0253: public static int parseInt(String str) {
0254: return parseIntString(str, 10, null);
0255: }
0256:
0257: /**
0258: * Parses the specified character sequence as a signed <code>int</code>
0259: * in the specified radix.
0260: *
0261: * @param csq the character sequence to parse.
0262: * @param radix the radix to be used while parsing.
0263: * @return the corresponding <code>int</code>.
0264: * @throws NumberFormatException if the specified character sequence
0265: * does not contain a parsable <code>int</code>.
0266: */
0267: public static int parseInt(CharSequence csq, int radix) {
0268: return parseInt(csq, radix, null);
0269: }
0270:
0271: /**
0272: * Equivalent to {@link #parseInt(CharSequence, int)}
0273: * (for J2ME compatibility).
0274: */
0275: public static int parseInt(String str, int radix) {
0276: return parseIntString(str, radix, null);
0277: }
0278:
0279: /**
0280: * Parses the specified character sequence from the specified position
0281: * as a signed <code>int</code> in the specified radix.
0282: *
0283: * @param csq the character sequence to parse.
0284: * @param radix the radix to be used while parsing.
0285: * @param cursor the current cursor position (being maintained) or
0286: * <code>null</code> if the whole character sequence is parsed.
0287: * @return the corresponding <code>int</code>.
0288: * @throws NumberFormatException if the specified character sequence
0289: * does not contain a parsable <code>int</code>.
0290: */
0291: public static int parseInt(CharSequence csq, int radix,
0292: Cursor cursor) {
0293: // Avoids dynamic cost of CharSequence.charAt
0294: if (csq instanceof CharArray)
0295: return parseIntCharArray((CharArray) csq, radix, cursor);
0296: if (csq instanceof TextBuilder)
0297: return parseIntTextBuilder((TextBuilder) csq, radix, cursor);
0298: if (csq instanceof Text)
0299: return parseIntText((Text) csq, radix, cursor);
0300: if (((Object) csq) instanceof String)
0301: return parseIntString((String) ((Object) csq), radix,
0302: cursor);
0303: return parseIntCharSequence(csq, radix, cursor);
0304: }
0305:
0306: private static int parseIntCharArray(CharArray csq, int radix,
0307: Cursor cursor) {
0308: // Parsing block identical for all CharSequences.
0309: final int start = (cursor != null) ? cursor.getIndex() : 0;
0310: final int end = (cursor != null) ? cursor.getEndIndex() : csq
0311: .length();
0312: boolean isNegative = false;
0313: int result = 0; // Accumulates negatively (avoid MIN_VALUE overflow).
0314: int i = start;
0315: for (; i < end; i++) {
0316: char c = csq.charAt(i);
0317: int digit = (c <= '9') ? c - '0'
0318: : ((c <= 'Z') && (c >= 'A')) ? c - 'A' + 10
0319: : ((c <= 'z') && (c >= 'a')) ? c - 'a' + 10
0320: : -1;
0321: if ((digit >= 0) && (digit < radix)) {
0322: int newResult = result * radix - digit;
0323: if (newResult > result)
0324: throw new NumberFormatException("Overflow");
0325: result = newResult;
0326: } else if ((c == '-') && (i == start)) {
0327: isNegative = true;
0328: } else if ((c == '+') && (i == start)) {
0329: // Ok.
0330: } else {
0331: if (cursor == null)
0332: throw new NumberFormatException(
0333: "Incomplete parsing");
0334: break; // Done.
0335: }
0336: }
0337: // Requires one valid digit character and checks for opposite overflow.
0338: if ((result == 0) && ((end == 0) || (csq.charAt(i - 1) != '0')))
0339: throw new NumberFormatException("Cannot parse " + csq
0340: + " as int");
0341: if ((result == Integer.MIN_VALUE) && !isNegative)
0342: throw new NumberFormatException("Overflow");
0343: if (cursor != null)
0344: cursor.setIndex(i);
0345: return isNegative ? result : -result;
0346: }
0347:
0348: private static int parseIntTextBuilder(TextBuilder csq, int radix,
0349: Cursor cursor) {
0350: // Parsing block identical for all CharSequences.
0351: final int start = (cursor != null) ? cursor.getIndex() : 0;
0352: final int end = (cursor != null) ? cursor.getEndIndex() : csq
0353: .length();
0354: boolean isNegative = false;
0355: int result = 0; // Accumulates negatively (avoid MIN_VALUE overflow).
0356: int i = start;
0357: for (; i < end; i++) {
0358: char c = csq.charAt(i);
0359: int digit = (c <= '9') ? c - '0'
0360: : ((c <= 'Z') && (c >= 'A')) ? c - 'A' + 10
0361: : ((c <= 'z') && (c >= 'a')) ? c - 'a' + 10
0362: : -1;
0363: if ((digit >= 0) && (digit < radix)) {
0364: int newResult = result * radix - digit;
0365: if (newResult > result)
0366: throw new NumberFormatException("Overflow");
0367: result = newResult;
0368: } else if ((c == '-') && (i == start)) {
0369: isNegative = true;
0370: } else if ((c == '+') && (i == start)) {
0371: // Ok.
0372: } else {
0373: if (cursor == null)
0374: throw new NumberFormatException(
0375: "Incomplete parsing");
0376: break; // Done.
0377: }
0378: }
0379: // Requires one valid digit character and checks for opposite overflow.
0380: if ((result == 0) && ((end == 0) || (csq.charAt(i - 1) != '0')))
0381: throw new NumberFormatException("Cannot parse " + csq
0382: + " as int");
0383: if ((result == Integer.MIN_VALUE) && !isNegative)
0384: throw new NumberFormatException("Overflow");
0385: if (cursor != null)
0386: cursor.setIndex(i);
0387: return isNegative ? result : -result;
0388: }
0389:
0390: private static int parseIntText(Text csq, int radix, Cursor cursor) {
0391: // Parsing block identical for all CharSequences.
0392: final int start = (cursor != null) ? cursor.getIndex() : 0;
0393: final int end = (cursor != null) ? cursor.getEndIndex() : csq
0394: .length();
0395: boolean isNegative = false;
0396: int result = 0; // Accumulates negatively (avoid MIN_VALUE overflow).
0397: int i = start;
0398: for (; i < end; i++) {
0399: char c = csq.charAt(i);
0400: int digit = (c <= '9') ? c - '0'
0401: : ((c <= 'Z') && (c >= 'A')) ? c - 'A' + 10
0402: : ((c <= 'z') && (c >= 'a')) ? c - 'a' + 10
0403: : -1;
0404: if ((digit >= 0) && (digit < radix)) {
0405: int newResult = result * radix - digit;
0406: if (newResult > result)
0407: throw new NumberFormatException("Overflow");
0408: result = newResult;
0409: } else if ((c == '-') && (i == start)) {
0410: isNegative = true;
0411: } else if ((c == '+') && (i == start)) {
0412: // Ok.
0413: } else {
0414: if (cursor == null)
0415: throw new NumberFormatException(
0416: "Incomplete parsing");
0417: break; // Done.
0418: }
0419: }
0420: // Requires one valid digit character and checks for opposite overflow.
0421: if ((result == 0) && ((end == 0) || (csq.charAt(i - 1) != '0')))
0422: throw new NumberFormatException("Cannot parse " + csq
0423: + " as int");
0424: if ((result == Integer.MIN_VALUE) && !isNegative)
0425: throw new NumberFormatException("Overflow");
0426: if (cursor != null)
0427: cursor.setIndex(i);
0428: return isNegative ? result : -result;
0429: }
0430:
0431: private static int parseIntString(String csq, int radix,
0432: Cursor cursor) {
0433: // Parsing block identical for all CharSequences.
0434: final int start = (cursor != null) ? cursor.getIndex() : 0;
0435: final int end = (cursor != null) ? cursor.getEndIndex() : csq
0436: .length();
0437: boolean isNegative = false;
0438: int result = 0; // Accumulates negatively (avoid MIN_VALUE overflow).
0439: int i = start;
0440: for (; i < end; i++) {
0441: char c = csq.charAt(i);
0442: int digit = (c <= '9') ? c - '0'
0443: : ((c <= 'Z') && (c >= 'A')) ? c - 'A' + 10
0444: : ((c <= 'z') && (c >= 'a')) ? c - 'a' + 10
0445: : -1;
0446: if ((digit >= 0) && (digit < radix)) {
0447: int newResult = result * radix - digit;
0448: if (newResult > result)
0449: throw new NumberFormatException("Overflow");
0450: result = newResult;
0451: } else if ((c == '-') && (i == start)) {
0452: isNegative = true;
0453: } else if ((c == '+') && (i == start)) {
0454: // Ok.
0455: } else {
0456: if (cursor == null)
0457: throw new NumberFormatException(
0458: "Incomplete parsing");
0459: break; // Done.
0460: }
0461: }
0462: // Requires one valid digit character and checks for opposite overflow.
0463: if ((result == 0) && ((end == 0) || (csq.charAt(i - 1) != '0')))
0464: throw new NumberFormatException("Cannot parse " + csq
0465: + " as int");
0466: if ((result == Integer.MIN_VALUE) && !isNegative)
0467: throw new NumberFormatException("Overflow");
0468: if (cursor != null)
0469: cursor.setIndex(i);
0470: return isNegative ? result : -result;
0471: }
0472:
0473: private static int parseIntCharSequence(CharSequence csq,
0474: int radix, Cursor cursor) {
0475: // Parsing block identical for all CharSequences.
0476: final int start = (cursor != null) ? cursor.getIndex() : 0;
0477: final int end = (cursor != null) ? cursor.getEndIndex() : csq
0478: .length();
0479: boolean isNegative = false;
0480: int result = 0; // Accumulates negatively (avoid MIN_VALUE overflow).
0481: int i = start;
0482: for (; i < end; i++) {
0483: char c = csq.charAt(i);
0484: int digit = (c <= '9') ? c - '0'
0485: : ((c <= 'Z') && (c >= 'A')) ? c - 'A' + 10
0486: : ((c <= 'z') && (c >= 'a')) ? c - 'a' + 10
0487: : -1;
0488: if ((digit >= 0) && (digit < radix)) {
0489: int newResult = result * radix - digit;
0490: if (newResult > result)
0491: throw new NumberFormatException("Overflow");
0492: result = newResult;
0493: } else if ((c == '-') && (i == start)) {
0494: isNegative = true;
0495: } else if ((c == '+') && (i == start)) {
0496: // Ok.
0497: } else {
0498: if (cursor == null)
0499: throw new NumberFormatException(
0500: "Incomplete parsing");
0501: break; // Done.
0502: }
0503: }
0504: // Requires one valid digit character and checks for opposite overflow.
0505: if ((result == 0) && ((end == 0) || (csq.charAt(i - 1) != '0')))
0506: throw new NumberFormatException("Cannot parse " + csq
0507: + " as int");
0508: if ((result == Integer.MIN_VALUE) && !isNegative)
0509: throw new NumberFormatException("Overflow");
0510: if (cursor != null)
0511: cursor.setIndex(i);
0512: return isNegative ? result : -result;
0513: }
0514:
0515: /**
0516: * Parses the specified character sequence as a decimal <code>long</code>.
0517: *
0518: * @param csq the character sequence to parse.
0519: * @return <code>parseLong(csq, 10)</code>
0520: * @throws NumberFormatException if the specified character sequence
0521: * does not contain a parsable <code>long</code>.
0522: * @see #parseLong(CharSequence, int)
0523: */
0524: public static long parseLong(CharSequence csq) {
0525: return parseLong(csq, 10);
0526: }
0527:
0528: /**
0529: * Equivalent to {@link #parseLong(CharSequence)}
0530: * (for J2ME compatibility).
0531: */
0532: public static long parseLong(String str) {
0533: return parseLongString(str, 10, null);
0534: }
0535:
0536: /**
0537: * Parses the specified character sequence as a signed <code>long</code>
0538: * in the specified radix.
0539: *
0540: * @param csq the character sequence to parse.
0541: * @param radix the radix to be used while parsing.
0542: * @return the corresponding <code>long</code>.
0543: * @throws NumberFormatException if the specified character sequence
0544: * does not contain a parsable <code>long</code>.
0545: */
0546: public static long parseLong(CharSequence csq, int radix) {
0547: return parseLong(csq, radix, null);
0548: }
0549:
0550: /**
0551: * Equivalent to {@link #parseLong(CharSequence, int)}
0552: * (for J2ME compatibility).
0553: */
0554: public static long parseLong(String str, int radix) {
0555: return parseLongString(str, radix, null);
0556: }
0557:
0558: /**
0559: * Parses the specified character sequence from the specified position
0560: * as a signed <code>long</code> in the specified radix.
0561: *
0562: * @param csq the character sequence to parse.
0563: * @param radix the radix to be used while parsing.
0564: * @param cursor the current cursor position (being maintained) or
0565: * <code>null</code> if the whole character sequence is parsed.
0566: * @return the corresponding <code>long</code>.
0567: * @throws NumberFormatException if the specified character sequence
0568: * does not contain a parsable <code>long</code>.
0569: */
0570: public static long parseLong(CharSequence csq, int radix,
0571: Cursor cursor) {
0572: // Avoids dynamic cost of CharSequence.charAt
0573: if (csq instanceof CharArray)
0574: return parseLongCharArray((CharArray) csq, radix, cursor);
0575: if (csq instanceof TextBuilder)
0576: return parseLongTextBuilder((TextBuilder) csq, radix,
0577: cursor);
0578: if (csq instanceof Text)
0579: return parseLongText((Text) csq, radix, cursor);
0580: if (((Object) csq) instanceof String)
0581: return parseLongString((String) ((Object) csq), radix,
0582: cursor);
0583: return parseLongCharSequence(csq, radix, cursor);
0584: }
0585:
0586: private static long parseLongCharArray(CharArray csq, int radix,
0587: Cursor cursor) {
0588: // Parsing block identical for all CharSequences.
0589: final int start = (cursor != null) ? cursor.getIndex() : 0;
0590: final int end = (cursor != null) ? cursor.getEndIndex() : csq
0591: .length();
0592: boolean isNegative = false;
0593: long result = 0; // Accumulates negatively (avoid MIN_VALUE overflow).
0594: int i = start;
0595: for (; i < end; i++) {
0596: char c = csq.charAt(i);
0597: int digit = (c <= '9') ? c - '0'
0598: : ((c <= 'Z') && (c >= 'A')) ? c - 'A' + 10
0599: : ((c <= 'z') && (c >= 'a')) ? c - 'a' + 10
0600: : -1;
0601: if ((digit >= 0) && (digit < radix)) {
0602: long newResult = result * radix - digit;
0603: if (newResult > result)
0604: throw new NumberFormatException("Overflow");
0605: result = newResult;
0606: } else if ((c == '-') && (i == start)) {
0607: isNegative = true;
0608: } else if ((c == '+') && (i == start)) {
0609: // Ok.
0610: } else {
0611: if (cursor == null)
0612: throw new NumberFormatException(
0613: "Incomplete parsing");
0614: break; // Done.
0615: }
0616: }
0617: // Requires one valid digit character and checks for opposite overflow.
0618: if ((result == 0) && ((end == 0) || (csq.charAt(i - 1) != '0')))
0619: throw new NumberFormatException("Cannot parse " + csq
0620: + " as int");
0621: if ((result == Long.MIN_VALUE) && !isNegative)
0622: throw new NumberFormatException("Overflow");
0623: if (cursor != null)
0624: cursor.setIndex(i);
0625: return isNegative ? result : -result;
0626: }
0627:
0628: private static long parseLongTextBuilder(TextBuilder csq,
0629: int radix, Cursor cursor) {
0630: // Parsing block identical for all CharSequences.
0631: final int start = (cursor != null) ? cursor.getIndex() : 0;
0632: final int end = (cursor != null) ? cursor.getEndIndex() : csq
0633: .length();
0634: boolean isNegative = false;
0635: long result = 0; // Accumulates negatively (avoid MIN_VALUE overflow).
0636: int i = start;
0637: for (; i < end; i++) {
0638: char c = csq.charAt(i);
0639: int digit = (c <= '9') ? c - '0'
0640: : ((c <= 'Z') && (c >= 'A')) ? c - 'A' + 10
0641: : ((c <= 'z') && (c >= 'a')) ? c - 'a' + 10
0642: : -1;
0643: if ((digit >= 0) && (digit < radix)) {
0644: long newResult = result * radix - digit;
0645: if (newResult > result)
0646: throw new NumberFormatException("Overflow");
0647: result = newResult;
0648: } else if ((c == '-') && (i == start)) {
0649: isNegative = true;
0650: } else if ((c == '+') && (i == start)) {
0651: // Ok.
0652: } else {
0653: if (cursor == null)
0654: throw new NumberFormatException(
0655: "Incomplete parsing");
0656: break; // Done.
0657: }
0658: }
0659: // Requires one valid digit character and checks for opposite overflow.
0660: if ((result == 0) && ((end == 0) || (csq.charAt(i - 1) != '0')))
0661: throw new NumberFormatException("Cannot parse " + csq
0662: + " as int");
0663: if ((result == Long.MIN_VALUE) && !isNegative)
0664: throw new NumberFormatException("Overflow");
0665: if (cursor != null)
0666: cursor.setIndex(i);
0667: return isNegative ? result : -result;
0668: }
0669:
0670: private static long parseLongText(Text csq, int radix, Cursor cursor) {
0671: // Parsing block identical for all CharSequences.
0672: final int start = (cursor != null) ? cursor.getIndex() : 0;
0673: final int end = (cursor != null) ? cursor.getEndIndex() : csq
0674: .length();
0675: boolean isNegative = false;
0676: long result = 0; // Accumulates negatively (avoid MIN_VALUE overflow).
0677: int i = start;
0678: for (; i < end; i++) {
0679: char c = csq.charAt(i);
0680: int digit = (c <= '9') ? c - '0'
0681: : ((c <= 'Z') && (c >= 'A')) ? c - 'A' + 10
0682: : ((c <= 'z') && (c >= 'a')) ? c - 'a' + 10
0683: : -1;
0684: if ((digit >= 0) && (digit < radix)) {
0685: long newResult = result * radix - digit;
0686: if (newResult > result)
0687: throw new NumberFormatException("Overflow");
0688: result = newResult;
0689: } else if ((c == '-') && (i == start)) {
0690: isNegative = true;
0691: } else if ((c == '+') && (i == start)) {
0692: // Ok.
0693: } else {
0694: if (cursor == null)
0695: throw new NumberFormatException(
0696: "Incomplete parsing");
0697: break; // Done.
0698: }
0699: }
0700: // Requires one valid digit character and checks for opposite overflow.
0701: if ((result == 0) && ((end == 0) || (csq.charAt(i - 1) != '0')))
0702: throw new NumberFormatException("Cannot parse " + csq
0703: + " as int");
0704: if ((result == Long.MIN_VALUE) && !isNegative)
0705: throw new NumberFormatException("Overflow");
0706: if (cursor != null)
0707: cursor.setIndex(i);
0708: return isNegative ? result : -result;
0709: }
0710:
0711: private static long parseLongString(String csq, int radix,
0712: Cursor cursor) {
0713: // Parsing block identical for all CharSequences.
0714: final int start = (cursor != null) ? cursor.getIndex() : 0;
0715: final int end = (cursor != null) ? cursor.getEndIndex() : csq
0716: .length();
0717: boolean isNegative = false;
0718: long result = 0; // Accumulates negatively (avoid MIN_VALUE overflow).
0719: int i = start;
0720: for (; i < end; i++) {
0721: char c = csq.charAt(i);
0722: int digit = (c <= '9') ? c - '0'
0723: : ((c <= 'Z') && (c >= 'A')) ? c - 'A' + 10
0724: : ((c <= 'z') && (c >= 'a')) ? c - 'a' + 10
0725: : -1;
0726: if ((digit >= 0) && (digit < radix)) {
0727: long newResult = result * radix - digit;
0728: if (newResult > result)
0729: throw new NumberFormatException("Overflow");
0730: result = newResult;
0731: } else if ((c == '-') && (i == start)) {
0732: isNegative = true;
0733: } else if ((c == '+') && (i == start)) {
0734: // Ok.
0735: } else {
0736: if (cursor == null)
0737: throw new NumberFormatException(
0738: "Incomplete parsing");
0739: break; // Done.
0740: }
0741: }
0742: // Requires one valid digit character and checks for opposite overflow.
0743: if ((result == 0) && ((end == 0) || (csq.charAt(i - 1) != '0')))
0744: throw new NumberFormatException("Cannot parse " + csq
0745: + " as int");
0746: if ((result == Long.MIN_VALUE) && !isNegative)
0747: throw new NumberFormatException("Overflow");
0748: if (cursor != null)
0749: cursor.setIndex(i);
0750: return isNegative ? result : -result;
0751: }
0752:
0753: private static long parseLongCharSequence(CharSequence csq,
0754: int radix, Cursor cursor) {
0755: // Parsing block identical for all CharSequences.
0756: final int start = (cursor != null) ? cursor.getIndex() : 0;
0757: final int end = (cursor != null) ? cursor.getEndIndex() : csq
0758: .length();
0759: boolean isNegative = false;
0760: long result = 0; // Accumulates negatively (avoid MIN_VALUE overflow).
0761: int i = start;
0762: for (; i < end; i++) {
0763: char c = csq.charAt(i);
0764: int digit = (c <= '9') ? c - '0'
0765: : ((c <= 'Z') && (c >= 'A')) ? c - 'A' + 10
0766: : ((c <= 'z') && (c >= 'a')) ? c - 'a' + 10
0767: : -1;
0768: if ((digit >= 0) && (digit < radix)) {
0769: long newResult = result * radix - digit;
0770: if (newResult > result)
0771: throw new NumberFormatException("Overflow");
0772: result = newResult;
0773: } else if ((c == '-') && (i == start)) {
0774: isNegative = true;
0775: } else if ((c == '+') && (i == start)) {
0776: // Ok.
0777: } else {
0778: if (cursor == null)
0779: throw new NumberFormatException(
0780: "Incomplete parsing");
0781: break; // Done.
0782: }
0783: }
0784: // Requires one valid digit character and checks for opposite overflow.
0785: if ((result == 0) && ((end == 0) || (csq.charAt(i - 1) != '0')))
0786: throw new NumberFormatException("Cannot parse " + csq
0787: + " as int");
0788: if ((result == Long.MIN_VALUE) && !isNegative)
0789: throw new NumberFormatException("Overflow");
0790: if (cursor != null)
0791: cursor.setIndex(i);
0792: return isNegative ? result : -result;
0793: }
0794:
0795: /**
0796: * Parses the specified character sequence as a <code>float</code>.
0797: *
0798: * @param csq the character sequence to parse.
0799: * @return the float number represented by the specified character sequence.
0800: *@JVM-1.1+@
0801: public static float parseFloat(CharSequence csq) {
0802: return (float) parseDouble(csq);
0803: }
0804: /**/
0805:
0806: /**
0807: * Equivalent to {@link #parseFloat(CharSequence)}
0808: * (for J2ME compatibility).
0809: *@JVM-1.1+@
0810: public static float parseFloat(String str) {
0811: return (float) parseDoubleString(str, null);
0812: }
0813: /**/
0814:
0815: /**
0816: * Parses the specified character sequence from the specified position
0817: * as a <code>float</code>.
0818: *
0819: * @param csq the character sequence to parse.
0820: * @param cursor the current cursor position (being maintained).
0821: * @return the float number represented by the specified character sequence.
0822: *@JVM-1.1+@
0823: public static float parseFloat(CharSequence csq, Cursor cursor) {
0824: return (float) parseDouble(csq, cursor);
0825: }
0826: /**/
0827:
0828: /**
0829: * Parses the specified character sequence as a <code>double</code>.
0830: * The format must be of the form:<code>
0831: * <decimal>{'.'<fraction>}{'E|e'<exponent>}</code>.
0832: *
0833: * @param csq the character sequence to parse.
0834: * @return the double number represented by this character sequence.
0835: * @throws NumberFormatException if the character sequence does not contain
0836: * a parsable <code>double</code>.
0837: *@JVM-1.1+@
0838: public static double parseDouble(CharSequence csq)
0839: throws NumberFormatException {
0840: return parseDouble(csq, null);
0841: }
0842: /**/
0843:
0844: /**
0845: * Equivalent to {@link #parseDouble(CharSequence)}
0846: * (for J2ME compatibility).
0847: *@JVM-1.1+@
0848: public static double parseDouble(String str) {
0849: return parseDoubleString(str, null);
0850: }
0851: /**/
0852:
0853: /**
0854: * Parses the specified character sequence from the specified position
0855: * as a <code>double</code>.
0856: *
0857: * @param csq the character sequence to parse.
0858: * @param cursor the current cursor position (being maintained).
0859: * @return the double number represented by this character sequence.
0860: * @throws NumberFormatException if the character sequence does not contain
0861: * a parsable <code>double</code>.
0862: *@JVM-1.1+@
0863: public static double parseDouble(CharSequence csq, Cursor cursor)
0864: throws NumberFormatException {
0865: // Avoids dynamic cost of CharSequence.charAt
0866: if (csq instanceof CharArray)
0867: return parseDoubleCharArray((CharArray) csq, cursor);
0868: if (csq instanceof TextBuilder)
0869: return parseDoubleTextBuilder((TextBuilder) csq, cursor);
0870: if (csq instanceof Text)
0871: return parseDoubleText((Text) csq, cursor);
0872: if (((Object) csq) instanceof String)
0873: return parseDoubleString((String) ((Object) csq), cursor);
0874: return parseDoubleCharSequence(csq, cursor);
0875: }
0876:
0877: private static double parseDoubleCharArray(CharArray csq, Cursor cursor)
0878: throws NumberFormatException {
0879: // Parsing block identical for all CharSequences.
0880: final int start = (cursor != null) ? cursor.getIndex() : 0;
0881: final int length = (cursor != null) ? cursor.getEndIndex() : csq.length();
0882: int i = start;
0883: char c = csq.charAt(i);
0884:
0885: // Checks for NaN.
0886: if ((c == 'N') && match("NaN", csq, i, length)) {
0887: if (cursor != null) cursor.setIndex(i + 3);
0888: return Double.NaN;
0889: }
0890:
0891: // Reads sign.
0892: boolean isNegative = (c == '-');
0893: if ((isNegative || (c == '+')) && (++i < length)) {
0894: c = csq.charAt(i);
0895: }
0896:
0897: // Checks for Infinity.
0898: if ((c == 'I') && match("Infinity", csq, i, length)) {
0899: if (cursor != null) cursor.setIndex(i + 8);
0900: return isNegative ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY;
0901: }
0902:
0903: // Reads decimal and fraction (both merged to a long).
0904: long decimal = 0;
0905: int decimalPoint = -1;
0906: while (true) {
0907: int digit = c - '0';
0908: if ((digit >= 0) && (digit < 10)) {
0909: long tmp = decimal * 10 + digit;
0910: if (tmp < decimal)
0911: throw new NumberFormatException("Too many digits - Overflow");
0912: decimal = tmp;
0913: } else if ((c == '.') && (decimalPoint < 0)) {
0914: decimalPoint = i;
0915: } else {
0916: break; // Done.
0917: }
0918: if (++i >= length)
0919: break;
0920: c = csq.charAt(i);
0921: }
0922: if (isNegative) {
0923: decimal = - decimal;
0924: }
0925: int fractionLength = (decimalPoint >= 0) ? i - decimalPoint - 1 : 0;
0926:
0927: // Reads exponent.
0928: int exp = 0;
0929: if ((i < length) && ((c == 'E') || (c == 'e'))) {
0930: c = csq.charAt(++i);
0931: boolean isNegativeExp = (c == '-');
0932: if ((isNegativeExp || (c == '+')) && (++i < length)) {
0933: c = csq.charAt(i);
0934: }
0935: while (true) {
0936: int digit = c - '0';
0937: if ((digit >= 0) && (digit < 10)) {
0938: int tmp = exp * 10 + digit;
0939: if (tmp < exp)
0940: throw new NumberFormatException("Exponent Overflow");
0941: exp = tmp;
0942: } else {
0943: break; // Done.
0944: }
0945: if (++i >= length)
0946: break;
0947: c = csq.charAt(i);
0948: }
0949: if (isNegativeExp) {
0950: exp = -exp;
0951: }
0952: }
0953: if (cursor != null)
0954: cursor.setIndex(i);
0955: else if (i < length)
0956: throw new NumberFormatException("Incomplete parsing");
0957: return javolution.lang.MathLib.toDoublePow10(decimal, exp - fractionLength);
0958: }
0959:
0960: private static double parseDoubleTextBuilder(TextBuilder csq, Cursor cursor)
0961: throws NumberFormatException {
0962: // Parsing block identical for all CharSequences.
0963: final int start = (cursor != null) ? cursor.getIndex() : 0;
0964: final int length = (cursor != null) ? cursor.getEndIndex() : csq.length();
0965: int i = start;
0966: char c = csq.charAt(i);
0967:
0968: // Checks for NaN.
0969: if ((c == 'N') && match("NaN", csq, i, length)) {
0970: if (cursor != null) cursor.setIndex(i + 3);
0971: return Double.NaN;
0972: }
0973:
0974: // Reads sign.
0975: boolean isNegative = (c == '-');
0976: if ((isNegative || (c == '+')) && (++i < length)) {
0977: c = csq.charAt(i);
0978: }
0979:
0980: // Checks for Infinity.
0981: if ((c == 'I') && match("Infinity", csq, i, length)) {
0982: if (cursor != null) cursor.setIndex(i + 8);
0983: return isNegative ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY;
0984: }
0985:
0986: // Reads decimal and fraction (both merged to a long).
0987: long decimal = 0;
0988: int decimalPoint = -1;
0989: while (true) {
0990: int digit = c - '0';
0991: if ((digit >= 0) && (digit < 10)) {
0992: long tmp = decimal * 10 + digit;
0993: if (tmp < decimal)
0994: throw new NumberFormatException("Too many digits - Overflow");
0995: decimal = tmp;
0996: } else if ((c == '.') && (decimalPoint < 0)) {
0997: decimalPoint = i;
0998: } else {
0999: break; // Done.
1000: }
1001: if (++i >= length)
1002: break;
1003: c = csq.charAt(i);
1004: }
1005: if (isNegative) {
1006: decimal = - decimal;
1007: }
1008: int fractionLength = (decimalPoint >= 0) ? i - decimalPoint - 1 : 0;
1009:
1010: // Reads exponent.
1011: int exp = 0;
1012: if ((i < length) && ((c == 'E') || (c == 'e'))) {
1013: c = csq.charAt(++i);
1014: boolean isNegativeExp = (c == '-');
1015: if ((isNegativeExp || (c == '+')) && (++i < length)) {
1016: c = csq.charAt(i);
1017: }
1018: while (true) {
1019: int digit = c - '0';
1020: if ((digit >= 0) && (digit < 10)) {
1021: int tmp = exp * 10 + digit;
1022: if (tmp < exp)
1023: throw new NumberFormatException("Exponent Overflow");
1024: exp = tmp;
1025: } else {
1026: break; // Done.
1027: }
1028: if (++i >= length)
1029: break;
1030: c = csq.charAt(i);
1031: }
1032: if (isNegativeExp) {
1033: exp = -exp;
1034: }
1035: }
1036: if (cursor != null)
1037: cursor.setIndex(i);
1038: else if (i < length)
1039: throw new NumberFormatException("Incomplete parsing");
1040: return javolution.lang.MathLib.toDoublePow10(decimal, exp - fractionLength);
1041: }
1042:
1043: private static double parseDoubleText(Text csq, Cursor cursor)
1044: throws NumberFormatException {
1045: // Parsing block identical for all CharSequences.
1046: final int start = (cursor != null) ? cursor.getIndex() : 0;
1047: final int length = (cursor != null) ? cursor.getEndIndex() : csq.length();
1048: int i = start;
1049: char c = csq.charAt(i);
1050:
1051: // Checks for NaN.
1052: if ((c == 'N') && match("NaN", csq, i, length)) {
1053: if (cursor != null) cursor.setIndex(i + 3);
1054: return Double.NaN;
1055: }
1056:
1057: // Reads sign.
1058: boolean isNegative = (c == '-');
1059: if ((isNegative || (c == '+')) && (++i < length)) {
1060: c = csq.charAt(i);
1061: }
1062:
1063: // Checks for Infinity.
1064: if ((c == 'I') && match("Infinity", csq, i, length)) {
1065: if (cursor != null) cursor.setIndex(i + 8);
1066: return isNegative ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY;
1067: }
1068:
1069: // Reads decimal and fraction (both merged to a long).
1070: long decimal = 0;
1071: int decimalPoint = -1;
1072: while (true) {
1073: int digit = c - '0';
1074: if ((digit >= 0) && (digit < 10)) {
1075: long tmp = decimal * 10 + digit;
1076: if (tmp < decimal)
1077: throw new NumberFormatException("Too many digits - Overflow");
1078: decimal = tmp;
1079: } else if ((c == '.') && (decimalPoint < 0)) {
1080: decimalPoint = i;
1081: } else {
1082: break; // Done.
1083: }
1084: if (++i >= length)
1085: break;
1086: c = csq.charAt(i);
1087: }
1088: if (isNegative) {
1089: decimal = - decimal;
1090: }
1091: int fractionLength = (decimalPoint >= 0) ? i - decimalPoint - 1 : 0;
1092:
1093: // Reads exponent.
1094: int exp = 0;
1095: if ((i < length) && ((c == 'E') || (c == 'e'))) {
1096: c = csq.charAt(++i);
1097: boolean isNegativeExp = (c == '-');
1098: if ((isNegativeExp || (c == '+')) && (++i < length)) {
1099: c = csq.charAt(i);
1100: }
1101: while (true) {
1102: int digit = c - '0';
1103: if ((digit >= 0) && (digit < 10)) {
1104: int tmp = exp * 10 + digit;
1105: if (tmp < exp)
1106: throw new NumberFormatException("Exponent Overflow");
1107: exp = tmp;
1108: } else {
1109: break; // Done.
1110: }
1111: if (++i >= length)
1112: break;
1113: c = csq.charAt(i);
1114: }
1115: if (isNegativeExp) {
1116: exp = -exp;
1117: }
1118: }
1119: if (cursor != null)
1120: cursor.setIndex(i);
1121: else if (i < length)
1122: throw new NumberFormatException("Incomplete parsing");
1123: return javolution.lang.MathLib.toDoublePow10(decimal, exp - fractionLength);
1124: }
1125:
1126: private static double parseDoubleString(String csq, Cursor cursor)
1127: throws NumberFormatException {
1128: // Parsing block identical for all CharSequences.
1129: final int start = (cursor != null) ? cursor.getIndex() : 0;
1130: final int length = (cursor != null) ? cursor.getEndIndex() : csq.length();
1131: int i = start;
1132: char c = csq.charAt(i);
1133:
1134: // Checks for NaN.
1135: if ((c == 'N') && match("NaN", csq, i, length)) {
1136: if (cursor != null) cursor.setIndex(i + 3);
1137: return Double.NaN;
1138: }
1139:
1140: // Reads sign.
1141: boolean isNegative = (c == '-');
1142: if ((isNegative || (c == '+')) && (++i < length)) {
1143: c = csq.charAt(i);
1144: }
1145:
1146: // Checks for Infinity.
1147: if ((c == 'I') && match("Infinity", csq, i, length)) {
1148: if (cursor != null) cursor.setIndex(i + 8);
1149: return isNegative ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY;
1150: }
1151:
1152: // Reads decimal and fraction (both merged to a long).
1153: long decimal = 0;
1154: int decimalPoint = -1;
1155: while (true) {
1156: int digit = c - '0';
1157: if ((digit >= 0) && (digit < 10)) {
1158: long tmp = decimal * 10 + digit;
1159: if (tmp < decimal)
1160: throw new NumberFormatException("Too many digits - Overflow");
1161: decimal = tmp;
1162: } else if ((c == '.') && (decimalPoint < 0)) {
1163: decimalPoint = i;
1164: } else {
1165: break; // Done.
1166: }
1167: if (++i >= length)
1168: break;
1169: c = csq.charAt(i);
1170: }
1171: if (isNegative) {
1172: decimal = - decimal;
1173: }
1174: int fractionLength = (decimalPoint >= 0) ? i - decimalPoint - 1 : 0;
1175:
1176: // Reads exponent.
1177: int exp = 0;
1178: if ((i < length) && ((c == 'E') || (c == 'e'))) {
1179: c = csq.charAt(++i);
1180: boolean isNegativeExp = (c == '-');
1181: if ((isNegativeExp || (c == '+')) && (++i < length)) {
1182: c = csq.charAt(i);
1183: }
1184: while (true) {
1185: int digit = c - '0';
1186: if ((digit >= 0) && (digit < 10)) {
1187: int tmp = exp * 10 + digit;
1188: if (tmp < exp)
1189: throw new NumberFormatException("Exponent Overflow");
1190: exp = tmp;
1191: } else {
1192: break; // Done.
1193: }
1194: if (++i >= length)
1195: break;
1196: c = csq.charAt(i);
1197: }
1198: if (isNegativeExp) {
1199: exp = -exp;
1200: }
1201: }
1202: if (cursor != null)
1203: cursor.setIndex(i);
1204: else if (i < length)
1205: throw new NumberFormatException("Incomplete parsing");
1206: return javolution.lang.MathLib.toDoublePow10(decimal, exp - fractionLength);
1207: }
1208:
1209: private static double parseDoubleCharSequence(CharSequence csq, Cursor cursor)
1210: throws NumberFormatException {
1211: // Parsing block identical for all CharSequences.
1212: final int start = (cursor != null) ? cursor.getIndex() : 0;
1213: final int length = (cursor != null) ? cursor.getEndIndex() : csq.length();
1214: int i = start;
1215: char c = csq.charAt(i);
1216:
1217: // Checks for NaN.
1218: if ((c == 'N') && match("NaN", csq, i, length)) {
1219: if (cursor != null) cursor.setIndex(i + 3);
1220: return Double.NaN;
1221: }
1222:
1223: // Reads sign.
1224: boolean isNegative = (c == '-');
1225: if ((isNegative || (c == '+')) && (++i < length)) {
1226: c = csq.charAt(i);
1227: }
1228:
1229: // Checks for Infinity.
1230: if ((c == 'I') && match("Infinity", csq, i, length)) {
1231: if (cursor != null) cursor.setIndex(i + 8);
1232: return isNegative ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY;
1233: }
1234:
1235: // Reads decimal and fraction (both merged to a long).
1236: long decimal = 0;
1237: int decimalPoint = -1;
1238: while (true) {
1239: int digit = c - '0';
1240: if ((digit >= 0) && (digit < 10)) {
1241: long tmp = decimal * 10 + digit;
1242: if (tmp < decimal)
1243: throw new NumberFormatException("Too many digits - Overflow");
1244: decimal = tmp;
1245: } else if ((c == '.') && (decimalPoint < 0)) {
1246: decimalPoint = i;
1247: } else {
1248: break; // Done.
1249: }
1250: if (++i >= length)
1251: break;
1252: c = csq.charAt(i);
1253: }
1254: if (isNegative) {
1255: decimal = - decimal;
1256: }
1257: int fractionLength = (decimalPoint >= 0) ? i - decimalPoint - 1 : 0;
1258:
1259: // Reads exponent.
1260: int exp = 0;
1261: if ((i < length) && ((c == 'E') || (c == 'e'))) {
1262: c = csq.charAt(++i);
1263: boolean isNegativeExp = (c == '-');
1264: if ((isNegativeExp || (c == '+')) && (++i < length)) {
1265: c = csq.charAt(i);
1266: }
1267: while (true) {
1268: int digit = c - '0';
1269: if ((digit >= 0) && (digit < 10)) {
1270: int tmp = exp * 10 + digit;
1271: if (tmp < exp)
1272: throw new NumberFormatException("Exponent Overflow");
1273: exp = tmp;
1274: } else {
1275: break; // Done.
1276: }
1277: if (++i >= length)
1278: break;
1279: c = csq.charAt(i);
1280: }
1281: if (isNegativeExp) {
1282: exp = -exp;
1283: }
1284: }
1285: if (cursor != null)
1286: cursor.setIndex(i);
1287: else if (i < length)
1288: throw new NumberFormatException("Incomplete parsing");
1289: return javolution.lang.MathLib.toDoublePow10(decimal, exp - fractionLength);
1290: }
1291:
1292: static boolean match(String str, CharSequence csq, int start, int length) {
1293: for (int i = 0; i < str.length(); i++) {
1294: if ((start + i >= length)
1295: || csq.charAt(start + i) != str.charAt(i))
1296: return false;
1297: }
1298: return true;
1299: }
1300: static boolean match(String str, String csq, int start, int length) {
1301: for (int i = 0; i < str.length(); i++) {
1302: if ((start + i >= length)
1303: || csq.charAt(start + i) != str.charAt(i))
1304: return false;
1305: }
1306: return true;
1307: }
1308: /**/
1309:
1310: /**
1311: * Formats the specified <code>boolean</code> and appends the resulting
1312: * text to the <code>Appendable</code> argument.
1313: *
1314: * @param b a <code>boolean</code>.
1315: * @param a the <code>Appendable</code> to append.
1316: * @return the specified <code>StringBuffer</code> object.
1317: * @throws IOException if an I/O exception occurs.
1318: * @see #parseBoolean
1319: */
1320: public static Appendable format(boolean b, Appendable a)
1321: throws IOException {
1322: return b ? a.append('t').append('r').append('u').append('e')
1323: : a.append('f').append('a').append('l').append('s')
1324: .append('e');
1325: }
1326:
1327: /**
1328: * Formats the specified <code>int</code> and appends the resulting
1329: * text (decimal representation) to the <code>Appendable</code> argument.
1330: *
1331: * <p> Note: This method is preferred to <code>Appendable.append(int)
1332: * </code> as it does not create temporary <code>String</code>
1333: * objects (several times faster for small numbers).</p>
1334: *
1335: * @param i the <code>int</code> number.
1336: * @param a the <code>Appendable</code> to append.
1337: * @return the specified <code>Appendable</code> object.
1338: * @throws IOException if an I/O exception occurs.
1339: * @see #parseInt
1340: */
1341: public static Appendable format(int i, Appendable a)
1342: throws IOException {
1343: if (a instanceof TextBuilder)
1344: return ((TextBuilder) a).append(i);
1345: TextBuilder tmp = TextBuilder.newInstance();
1346: tmp.append(i);
1347: appendTo(a, tmp);
1348: TextBuilder.recycle(tmp);
1349: return a;
1350: }
1351:
1352: /**
1353: * Formats the specified <code>int</code> in the specified radix and appends
1354: * the resulting text to the <code>Appendable</code> argument.
1355: *
1356: * @param i the <code>int</code> number.
1357: * @param radix the radix.
1358: * @param a the <code>Appendable</code> to append.
1359: * @return the specified <code>Appendable</code> object.
1360: * @throws IllegalArgumentException if radix is not in [2 .. 36] range.
1361: * @throws IOException if an I/O exception occurs.
1362: * @see #parseInt(CharSequence, int)
1363: */
1364: public static Appendable format(int i, int radix, Appendable a)
1365: throws IOException {
1366: if (a instanceof TextBuilder)
1367: return ((TextBuilder) a).append(i, radix);
1368: TextBuilder tmp = TextBuilder.newInstance();
1369: tmp.append(i, radix);
1370: appendTo(a, tmp);
1371: TextBuilder.recycle(tmp);
1372: return a;
1373: }
1374:
1375: /**
1376: * Formats the specified <code>long</code> and appends the resulting
1377: * text (decimal representation) to the <code>Appendable</code> argument.
1378: *
1379: * <p> Note: This method is preferred to <code>Appendable.append(long)
1380: * </code> as it does not create temporary <code>String</code>
1381: * objects (several times faster for small numbers).</p>
1382: *
1383: * @param l the <code>long</code> number.
1384: * @param a the <code>Appendable</code> to append.
1385: * @return the specified <code>Appendable</code> object.
1386: * @throws IOException if an I/O exception occurs.
1387: * @see #parseLong
1388: */
1389: public static Appendable format(long l, Appendable a)
1390: throws IOException {
1391: if (a instanceof TextBuilder)
1392: return ((TextBuilder) a).append(l);
1393: TextBuilder tmp = TextBuilder.newInstance();
1394: tmp.append(l);
1395: appendTo(a, tmp);
1396: TextBuilder.recycle(tmp);
1397: return a;
1398: }
1399:
1400: /**
1401: * Formats the specified <code>long</code> in the specified radix and
1402: * appends the resulting text to the <code>Appendable</code> argument.
1403: *
1404: * @param l the <code>long</code> number.
1405: * @param radix the radix.
1406: * @param a the <code>Appendable</code> to append.
1407: * @return the specified <code>Appendable</code> object.
1408: * @throws IllegalArgumentException if radix is not in [2 .. 36] range.
1409: * @throws IOException if an I/O exception occurs.
1410: * @see #parseLong(CharSequence, int)
1411: */
1412: public static Appendable format(long l, int radix, Appendable a)
1413: throws IOException {
1414: if (a instanceof TextBuilder)
1415: return ((TextBuilder) a).append(l, radix);
1416: TextBuilder tmp = TextBuilder.newInstance();
1417: tmp.append(l, radix);
1418: appendTo(a, tmp);
1419: TextBuilder.recycle(tmp);
1420: return a;
1421: }
1422:
1423: /**
1424: * Formats the specified <code>float</code> value.
1425: *
1426: * @param f the <code>float</code> value.
1427: * @param a the <code>Appendable</code> to append.
1428: * @return the specified <code>Appendable</code> object.
1429: * @throws IOException if an I/O exception occurs.
1430: * @see TextBuilder#append(float)
1431: *@JVM-1.1+@
1432: public static Appendable format(float f, Appendable a)
1433: throws IOException {
1434: if (a instanceof TextBuilder)
1435: return ((TextBuilder) a).append(f);
1436: TextBuilder tmp = TextBuilder.newInstance();
1437: tmp.append(f);
1438: appendTo(a, tmp);
1439: TextBuilder.recycle(tmp);
1440: return a;
1441: }
1442: /**/
1443:
1444: /**
1445: * Formats the specified <code>double</code> value (16 or 17 digits output).
1446: *
1447: * @param d the <code>double</code> value.
1448: * @param a the <code>Appendable</code> to append.
1449: * @return the specified <code>Appendable</code> object.
1450: * @throws IOException if an I/O exception occurs.
1451: * @see TextBuilder#append(double)
1452: *@JVM-1.1+@
1453: public static Appendable format(double d, Appendable a)
1454: throws IOException {
1455: if (a instanceof TextBuilder)
1456: return ((TextBuilder) a).append(d);
1457: TextBuilder tmp = TextBuilder.newInstance();
1458: tmp.append(d);
1459: appendTo(a, tmp);
1460: TextBuilder.recycle(tmp);
1461: return a;
1462: }
1463: /**/
1464:
1465: /**
1466: * Formats the specified <code>double</code> value according to the
1467: * specified formatting arguments.
1468: *
1469: * @param d the <code>double</code> value.
1470: * @param digits the number of significative digits (excludes exponent) or
1471: * <code>-1</code> to mimic the standard library (16 or 17 digits).
1472: * @param scientific <code>true</code> to forces the use of the scientific
1473: * notation (e.g. <code>1.23E3</code>); <code>false</code>
1474: * otherwise.
1475: * @param showZero <code>true</code> if trailing fractional zeros are
1476: * represented; <code>false</code> otherwise.
1477: * @param a the <code>Appendable</code> to append.
1478: * @return the specified <code>Appendable</code> object.
1479: * @throws IllegalArgumentException if <code>(digits > 19)</code>)
1480: * @throws IOException if an I/O exception occurs.
1481: * @see TextBuilder#append(double, int, boolean, boolean)
1482: *@JVM-1.1+@
1483: public static Appendable format(double d, int digits,
1484: boolean scientific, boolean showZero, Appendable a) throws IOException {
1485: if (a instanceof TextBuilder)
1486: return ((TextBuilder) a).append(d, digits, scientific, showZero);
1487: TextBuilder tmp = TextBuilder.newInstance();
1488: tmp.append(d, digits, scientific, showZero);
1489: appendTo(a, tmp);
1490: TextBuilder.recycle(tmp);
1491: return a;
1492: }
1493: /**/
1494:
1495: /**
1496: * Appends to the specified appendable the text builder argument
1497: * (for text builder less than 32 characters).
1498: *
1499: * @param a the appendable.
1500: * @param txt the text to be append.
1501: * @throws IOException if an I/O exception occurs.
1502: */
1503: private static void appendTo(Object to, TextBuilder txt)
1504: throws IOException {
1505: if (to instanceof StringBuffer) {
1506: txt.appendTo((StringBuffer) to);
1507: /* @JVM-1.5+@
1508: } else if (to instanceof StringBuilder) {
1509: txt.appendTo((StringBuilder) to);
1510: /**/
1511: } else {
1512: ((Appendable) to).append(txt);
1513: }
1514: }
1515:
1516: }
|