Skip to content

Introduce DecimalDigits.appendPair for efficient two-digit formatting and refactor DateTimeHelper #26911

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions src/java.base/share/classes/java/lang/AbstractStringBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -906,6 +906,31 @@ public AbstractStringBuilder append(char c) {
return this;
}

/**
* Appends the two-digit string representation of the {@code int}
* argument to this sequence.
* <p>
* The integer {@code i} is formatted as two decimal digits.
* If the value is between 0 and 9, it is formatted with a leading zero
* (e.g., 5 becomes "05"). If the value is outside the range 0-99,
* the behavior is unspecified and may result in unexpected output.
*
* @param i an {@code int} (should be between 0 and 99 inclusive).
* @throws IndexOutOfBoundsException if {@code i} is outside the range 0-99.
*/
void appendPair(int i) {
byte coder = this.coder;
int count = this.count;
byte[] value = ensureCapacitySameCoder(this.value, coder, count + 2);
if (isLatin1(coder)) {
DecimalDigits.uncheckedPutPairLatin1(value, count, i);
} else {
DecimalDigits.uncheckedPutPairUTF16(value, count, i);
}
this.value = value;
this.count = count + 2;
}

/**
* Appends the string representation of the {@code int}
* argument to this sequence.
Expand Down
4 changes: 4 additions & 0 deletions src/java.base/share/classes/java/lang/System.java
Original file line number Diff line number Diff line change
Expand Up @@ -2149,6 +2149,10 @@ public byte[] getBytesUTF8NoRepl(String s) {
return String.getBytesUTF8NoRepl(s);
}

public void appendPair(StringBuilder buf, int v) {
buf.appendPair(v);
}

public void inflateBytesToChars(byte[] src, int srcOff, char[] dst, int dstOff, int len) {
StringLatin1.inflate(src, srcOff, dst, dstOff, len);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,22 @@ public interface JavaLangAccess {
*/
void uncheckedPutCharUTF16(byte[] bytes, int index, int ch);

/**
* Appends the two-digit string representation of the {@code int}
* argument to the given {@code StringBuilder}.
* <p>
* This method is intended for internal use by {@code DecimalDigits.appendPair}.
* The integer {@code v} is formatted as two decimal digits.
* If the value is between 0 and 9, it is formatted with a leading zero
* (e.g., 5 becomes "05"). If the value is outside the range 0-99,
* the behavior is unspecified.
*
* @param buf the {@code StringBuilder} to append to.
* @param v the {@code int} value (should be between 0 and 99 inclusive).
* @see jdk.internal.util.DecimalDigits#appendPair(StringBuilder, int)
*/
void appendPair(StringBuilder buf, int v);

/**
* Encode the given string into a sequence of bytes using utf8.
*
Expand Down
29 changes: 15 additions & 14 deletions src/java.base/share/classes/jdk/internal/util/DateTimeHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,39 +49,40 @@ public static void formatTo(StringBuilder buf, LocalDateTime dateTime) {
* Requires extra capacity of 10 to avoid StringBuilder reallocation.
*/
public static void formatTo(StringBuilder buf, LocalDate date) {
int year = date.getYear(),
month = date.getMonthValue(),
day = date.getDayOfMonth();
int absYear = Math.abs(year);
int year = date.getYear(),
absYear = Math.abs(year);
if (absYear < 1000) {
if (year < 0) {
buf.append('-');
}
buf.repeat('0', absYear < 10 ? 3 : absYear < 100 ? 2 : 1);
buf.append(absYear);
int y01 = absYear / 100;
DecimalDigits.appendPair(buf, y01);
DecimalDigits.appendPair(buf, absYear - y01 * 100);
} else {
if (year > 9999) {
buf.append('+');
}
buf.append(year);
}
buf.append(month < 10 ? "-0" : "-").append(month)
.append(day < 10 ? "-0" : "-").append(day);
buf.append('-');
DecimalDigits.appendPair(buf, date.getMonthValue());
buf.append('-');
DecimalDigits.appendPair(buf, date.getDayOfMonth());
}

/**
* Prints the toString result to the given buf, avoiding extra string allocations.
* Requires extra capacity of 18 to avoid StringBuilder reallocation.
*/
public static void formatTo(StringBuilder buf, LocalTime time) {
int hour = time.getHour(),
minute = time.getMinute(),
second = time.getSecond(),
DecimalDigits.appendPair(buf, time.getHour());
buf.append(':');
DecimalDigits.appendPair(buf, time.getMinute());
int second = time.getSecond(),
nano = time.getNano();
buf.append(hour < 10 ? "0" : "").append(hour)
.append(minute < 10 ? ":0" : ":").append(minute);
if ((second | nano) > 0) {
buf.append(second < 10 ? ":0" : ":").append(second);
buf.append(':');
DecimalDigits.appendPair(buf, second);
if (nano > 0) {
buf.append('.');
int zeros = 9 - DecimalDigits.stringSize(nano);
Expand Down
19 changes: 19 additions & 0 deletions src/java.base/share/classes/jdk/internal/util/DecimalDigits.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

package jdk.internal.util;

import jdk.internal.access.SharedSecrets;
import jdk.internal.misc.Unsafe;
import jdk.internal.vm.annotation.Stable;

Expand Down Expand Up @@ -443,4 +444,22 @@ private static void uncheckedPutCharUTF16(byte[] buf, int charPos, int c) {
assert charPos >= 0 && charPos < (buf.length >> 1);
UNSAFE.putCharUnaligned(buf, ARRAY_BYTE_BASE_OFFSET + ((long) charPos << 1), (char) c);
}

/**
* Appends the two-digit string representation of the {@code int}
* argument to the given {@code StringBuilder}.
* <p>
* The integer {@code v} is formatted as two decimal digits.
* If the value is between 0 and 9, it is formatted with a leading zero
* (e.g., 5 becomes "05"). If the value is outside the range 0-99,
* the behavior is unspecified.
*
* @param buf the {@code StringBuilder} to append to.
* @param v the {@code int} value (should be between 0 and 99 inclusive).
* @see jdk.internal.access.JavaLangAccess#appendPair(StringBuilder, int)
*/
public static void appendPair(StringBuilder buf, int v) {
SharedSecrets.getJavaLangAccess()
.appendPair(buf, v);
}
}