FastLongFormatter.java
- /* Copyright 2022-2025 Thales Alenia Space
- * Licensed to CS GROUP (CS) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * CS licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package org.orekit.utils.formatting;
- import org.hipparchus.util.FastMath;
- import org.orekit.errors.OrekitInternalError;
- import java.io.IOException;
- import java.util.Arrays;
- /** Formatter for long integers with low overhead.
- * <p>
- * This class is intended to be used when formatting large amounts of data with
- * fixed formats like, for example, large ephemeris or measurement files.
- * </p>
- * <p>
- * Building the formatter is done once, and the formatter
- * {@link #appendTo(Appendable, long)} or {@link #toString(long)} methods can be
- * called hundreds of thousands of times, without incurring the overhead that
- * would occur with {@code String.format()}. Some tests showed this formatter is
- * about 10 times faster than {@code String.format()} with {@code %{width}d} format.
- * </p>
- * <p>
- * Instances of this class are immutable
- * </p>
- * @author Luc Maisonobe
- * @since 13.0.3
- */
- public class FastLongFormatter {
- /** Digits. */
- private static final char[] DIGITS = {
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
- };
- /** Number of characters to output. */
- private final int width;
- /** Zero padding indicator. */
- private final boolean zeroPadding;
- /** Size of the conversion array. */
- private final int size;
- /** Simple constructor.
- * <p>
- * This constructor is equivalent to either {@link java.util.Formatter Formatter}
- * integer format {@code %{width}d} or {@code %0{width}d}
- * </p>
- * @param width number of characters to output
- * @param zeroPadding if true, the result is left padded with '0' until it matches width
- */
- public FastLongFormatter(final int width, final boolean zeroPadding) {
- this.width = width;
- this.zeroPadding = zeroPadding;
- this.size = FastMath.max(width, 20);
- }
- /** Get the width.
- * @return width
- */
- public int getWidth() {
- return width;
- }
- /** Check if left padding uses '0' characters.
- * @return true if left padding uses '0' characters
- */
- public boolean hasZeroPadding() {
- return zeroPadding;
- }
- /** Append one formatted value to an {@code Appendable}.
- * @param appendable to append value to
- * @param value value to format
- * @exception IOException if an I/O error occurs
- */
- public void appendTo(final Appendable appendable, final long value) throws IOException {
- // initialize conversion loop
- final char[] digits = new char[size];
- int index = 0;
- long remaining;
- if (value == Long.MIN_VALUE) {
- // special case for value -9223372036854775808L that has no representable opposite
- digits[0] = '8';
- index = 1;
- remaining = 922337203685477580L;
- } else {
- remaining = FastMath.abs(value);
- }
- // convert to decimal string
- do {
- digits[index++] = DIGITS[(int) (remaining % 10L)];
- remaining /= 10L;
- } while (remaining > 0L);
- // manage sign and padding
- if (zeroPadding) {
- if (value < 0L) {
- // zero padding a negative value occurs between the minus sign and the most significant digit
- if (index < width - 1) {
- Arrays.fill(digits, index, width - 1, '0');
- index = width - 1;
- }
- digits[index++] = '-';
- }
- else {
- if (index < width) {
- Arrays.fill(digits, index, width, '0');
- index = width;
- }
- }
- } else {
- if (value < 0L) {
- // space padding a negative value is before minus sign
- digits[index++] = '-';
- }
- if (index < width) {
- Arrays.fill(digits, index, width, ' ');
- index = width;
- }
- }
- // fill up string
- while (index > 0) {
- appendable.append(digits[--index]);
- }
- }
- /** Format one value.
- * @param value value to format
- * @return formatted string
- */
- public String toString(final long value) {
- try {
- final StringBuilder builder = new StringBuilder();
- appendTo(builder, value);
- return builder.toString();
- } catch (IOException ioe) {
- // this should never happen
- throw new OrekitInternalError(ioe);
- }
- }
- }