# HG changeset patch # User sherman # Date 1408056844 25200 # Node ID 12bcf9a5994f8d1d98447db6fd23b8c23753c1a4 # Parent aa1e188ea8bffc7956af6e1b5171557c7c5f7d24 8055004: Reduce allocation overhead in java.time.Period/Duration parse methods Summary: To use the offset based new parse methods. Reviewed-by: sherman Contributed-by: claes.redestad@oracle.com diff -r aa1e188ea8bf -r 12bcf9a5994f jdk/src/share/classes/java/time/Duration.java --- a/jdk/src/share/classes/java/time/Duration.java Thu Aug 14 15:18:11 2014 +0200 +++ b/jdk/src/share/classes/java/time/Duration.java Thu Aug 14 15:54:04 2014 -0700 @@ -388,19 +388,21 @@ Matcher matcher = PATTERN.matcher(text); if (matcher.matches()) { // check for letter T but no time sections - if ("T".equals(matcher.group(3)) == false) { - boolean negate = "-".equals(matcher.group(1)); - String dayMatch = matcher.group(2); - String hourMatch = matcher.group(4); - String minuteMatch = matcher.group(5); - String secondMatch = matcher.group(6); - String fractionMatch = matcher.group(7); - if (dayMatch != null || hourMatch != null || minuteMatch != null || secondMatch != null) { - long daysAsSecs = parseNumber(text, dayMatch, SECONDS_PER_DAY, "days"); - long hoursAsSecs = parseNumber(text, hourMatch, SECONDS_PER_HOUR, "hours"); - long minsAsSecs = parseNumber(text, minuteMatch, SECONDS_PER_MINUTE, "minutes"); - long seconds = parseNumber(text, secondMatch, 1, "seconds"); - int nanos = parseFraction(text, fractionMatch, seconds < 0 ? -1 : 1); + if (!charMatch(text, matcher.start(3), matcher.end(3), 'T')) { + boolean negate = charMatch(text, matcher.start(1), matcher.end(1), '-'); + + int dayStart = matcher.start(2), dayEnd = matcher.end(2); + int hourStart = matcher.start(4), hourEnd = matcher.end(4); + int minuteStart = matcher.start(5), minuteEnd = matcher.end(5); + int secondStart = matcher.start(6), secondEnd = matcher.end(6); + int fractionStart = matcher.start(7), fractionEnd = matcher.end(7); + + if (dayStart >= 0 || hourStart >= 0 || minuteStart >= 0 || secondStart >= 0) { + long daysAsSecs = parseNumber(text, dayStart, dayEnd, SECONDS_PER_DAY, "days"); + long hoursAsSecs = parseNumber(text, hourStart, hourEnd, SECONDS_PER_HOUR, "hours"); + long minsAsSecs = parseNumber(text, minuteStart, minuteEnd, SECONDS_PER_MINUTE, "minutes"); + long seconds = parseNumber(text, secondStart, secondEnd, 1, "seconds"); + int nanos = parseFraction(text, fractionStart, fractionEnd, seconds < 0 ? -1 : 1); try { return create(negate, daysAsSecs, hoursAsSecs, minsAsSecs, seconds, nanos); } catch (ArithmeticException ex) { @@ -412,27 +414,37 @@ throw new DateTimeParseException("Text cannot be parsed to a Duration", text, 0); } - private static long parseNumber(CharSequence text, String parsed, int multiplier, String errorText) { + private static boolean charMatch(CharSequence text, int start, int end, char c) { + return (start >= 0 && end == start + 1 && text.charAt(start) == c); + } + + private static long parseNumber(CharSequence text, int start, int end, int multiplier, String errorText) { // regex limits to [-+]?[0-9]+ - if (parsed == null) { + if (start < 0 || end < 0) { return 0; } try { - long val = Long.parseLong(parsed); + long val = Long.parseLong(text, 10, start, end); return Math.multiplyExact(val, multiplier); } catch (NumberFormatException | ArithmeticException ex) { throw (DateTimeParseException) new DateTimeParseException("Text cannot be parsed to a Duration: " + errorText, text, 0).initCause(ex); } } - private static int parseFraction(CharSequence text, String parsed, int negate) { + private static int parseFraction(CharSequence text, int start, int end, int negate) { // regex limits to [0-9]{0,9} - if (parsed == null || parsed.length() == 0) { + if (start < 0 || end < 0 || end - start == 0) { return 0; } try { - parsed = (parsed + "000000000").substring(0, 9); - return Integer.parseInt(parsed) * negate; + int fraction = Integer.parseInt(text, 10, start, end); + + // for number strings smaller than 9 digits, interpret as if there + // were trailing zeros + for (int i = end - start; i < 9; i++) { + fraction *= 10; + } + return fraction * negate; } catch (NumberFormatException | ArithmeticException ex) { throw (DateTimeParseException) new DateTimeParseException("Text cannot be parsed to a Duration: fraction", text, 0).initCause(ex); } diff -r aa1e188ea8bf -r 12bcf9a5994f jdk/src/share/classes/java/time/Period.java --- a/jdk/src/share/classes/java/time/Period.java Thu Aug 14 15:18:11 2014 +0200 +++ b/jdk/src/share/classes/java/time/Period.java Thu Aug 14 15:54:04 2014 -0700 @@ -329,17 +329,17 @@ Objects.requireNonNull(text, "text"); Matcher matcher = PATTERN.matcher(text); if (matcher.matches()) { - int negate = ("-".equals(matcher.group(1)) ? -1 : 1); - String yearMatch = matcher.group(2); - String monthMatch = matcher.group(3); - String weekMatch = matcher.group(4); - String dayMatch = matcher.group(5); - if (yearMatch != null || monthMatch != null || dayMatch != null || weekMatch != null) { + int negate = (charMatch(text, matcher.start(1), matcher.end(1), '-') ? -1 : 1); + int yearStart = matcher.start(2), yearEnd = matcher.end(2); + int monthStart = matcher.start(3), monthEnd = matcher.end(3); + int weekStart = matcher.start(4), weekEnd = matcher.end(4); + int dayStart = matcher.start(5), dayEnd = matcher.end(5); + if (yearStart >= 0 || monthStart >= 0 || weekStart >= 0 || dayStart >= 0) { try { - int years = parseNumber(text, yearMatch, negate); - int months = parseNumber(text, monthMatch, negate); - int weeks = parseNumber(text, weekMatch, negate); - int days = parseNumber(text, dayMatch, negate); + int years = parseNumber(text, yearStart, yearEnd, negate); + int months = parseNumber(text, monthStart, monthEnd, negate); + int weeks = parseNumber(text, weekStart, weekEnd, negate); + int days = parseNumber(text, dayStart, dayEnd, negate); days = Math.addExact(days, Math.multiplyExact(weeks, 7)); return create(years, months, days); } catch (NumberFormatException ex) { @@ -350,11 +350,15 @@ throw new DateTimeParseException("Text cannot be parsed to a Period", text, 0); } - private static int parseNumber(CharSequence text, String str, int negate) { - if (str == null) { + private static boolean charMatch(CharSequence text, int start, int end, char c) { + return (start >= 0 && end == start + 1 && text.charAt(start) == c); + } + + private static int parseNumber(CharSequence text, int start, int end, int negate) { + if (start < 0 || end < 0) { return 0; } - int val = Integer.parseInt(str); + int val = Integer.parseInt(text, 10, start, end); try { return Math.multiplyExact(val, negate); } catch (ArithmeticException ex) {