8055004: Reduce allocation overhead in java.time.Period/Duration parse methods
authorsherman
Thu, 14 Aug 2014 15:54:04 -0700
changeset 25986 12bcf9a5994f
parent 25985 aa1e188ea8bf
child 25987 76e62811f63b
child 26213 e9545169177e
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
jdk/src/share/classes/java/time/Duration.java
jdk/src/share/classes/java/time/Period.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);
         }
--- 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) {