All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opentcs.util.NumberParsers Maven / Gradle / Ivy

The newest version!
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.util;

import static java.util.Objects.requireNonNull;
import static org.opentcs.util.Assertions.checkInRange;

/**
 * Provides methods for optimized parsing of numbers from character sequences.
 */
public final class NumberParsers {

  /**
   * The number of characters used for Long.MAX_VALUE.
   */
  private static final int MAX_POSITIVE_LONG_CHARS = Long.toString(Long.MAX_VALUE).length();
  /**
   * The number of characters used for Long.MIN_VALUE.
   */
  private static final int MAX_NEGATIVE_LONG_CHARS = Long.toString(Long.MIN_VALUE).length();

  /**
   * Prevents creation of instances of this class.
   */
  private NumberParsers() {
  }

  /**
   * Parses a sequence of characters as a decimal number and returns the latter.
   *
   * @param source The character sequence to be parsed.
   * @return The decimal number represented by the given character sequence.
   * @throws NumberFormatException If the parsed sequence of characters does not
   * represent a decimal number.
   */
  public static long parsePureDecimalLong(CharSequence source)
      throws NumberFormatException {
    return parsePureDecimalLong(source, 0, source.length());
  }

  /**
   * Parses a (sub)sequence of characters as a decimal number and returns the
   * latter.
   *
   * @param source The character sequence to be parsed.
   * @param startIndex The position at which to start parsing.
   * @param length The number of characters to parse.
   * @return The decimal number represented by the given character sequence.
   * @throws NumberFormatException If the parsed sequence of characters does not
   * represent a decimal number.
   */
  public static long parsePureDecimalLong(
      CharSequence source,
      int startIndex,
      int length
  )
      throws NumberFormatException {
    requireNonNull(source, "source");
    checkInRange(startIndex, 0, source.length() - 1, "startIndex");
    checkInRange(length, 1, Integer.MAX_VALUE, "length");

    long result = 0;
    int index = 0;
    boolean negative;
    long limit;
    // Check if we have a negative number and initialize accordingly.
    if (source.charAt(startIndex) == '-') {
      if (length > MAX_NEGATIVE_LONG_CHARS) {
        throw new NumberFormatException("too long to be parsed");
      }
      negative = true;
      limit = Long.MIN_VALUE;
      index++;
    }
    else {
      if (length > MAX_POSITIVE_LONG_CHARS) {
        throw new NumberFormatException("too long to be parsed");
      }
      negative = false;
      limit = -Long.MAX_VALUE;
    }
    while (index < length) {
      int digit = source.charAt(startIndex + index) - '0';
      // If we've just read something other than a digit, throw an exception.
      if (digit < 0 || digit > 9) {
        throw new NumberFormatException(
            "not a decimal digit: " + source.charAt(startIndex + index)
        );
      }
      result *= 10;
      // Check if the next operation would overflow the result.
      if (result < limit + digit) {
        throw new NumberFormatException(
            "parsed number exceeds value boundaries"
        );
      }
      result -= digit;
      index++;
    }
    if (negative) {
      // If we did not parse at least one digit, throw an exception.
      if (index < 2) {
        throw new NumberFormatException("minus sign without succeeding digits");
      }
      return result;
    }
    else {
      return -result;
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy