< prev index next >

src/java.base/share/classes/java/lang/Runtime.java

Print this page
rev 15204 : 8162439: Runtime.Version.parse needs fast-path for major versions
Reviewed-by: psandoz, sdrach, iris


1095          * <a href="#verNum">version number</a> followed by pre-release and
1096          * build information.
1097          *
1098          * @param  s
1099          *         A string to interpret as a version
1100          *
1101          * @throws  IllegalArgumentException
1102          *          If the given string cannot be interpreted as a valid
1103          *          version
1104          *
1105          * @throws  NullPointerException
1106          *          If the given string is {@code null}
1107          *
1108          * @throws  NumberFormatException
1109          *          If an element of the version number or the build number
1110          *          cannot be represented as an {@link Integer}
1111          *
1112          * @return  The Version of the given string
1113          */
1114         public static Version parse(String s) {
1115             return VersionBuilder.parse(s);























































1116         }
1117 
1118         /**
1119          * Returns the <a href="#major">major</a> version number.
1120          *
1121          * @return  The major version number
1122          */
1123         public int major() {
1124             return version.get(0);
1125         }
1126 
1127         /**
1128          * Returns the <a href="#minor">minor</a> version number or zero if it
1129          * was not set.
1130          *
1131          * @return  The minor version number or zero if it was not set
1132          */
1133         public int minor() {
1134             return (version.size() > 1 ? version.get(1) : 0);
1135         }


1424          *
1425          * <p> This method satisfies the general contract of the {@link
1426          * Object#hashCode Object.hashCode} method.
1427          *
1428          * @return  The hashcode of this version
1429          */
1430         @Override
1431         public int hashCode() {
1432             int h = 1;
1433             int p = 17;
1434 
1435             h = p * h + version.hashCode();
1436             h = p * h + pre.hashCode();
1437             h = p * h + build.hashCode();
1438             h = p * h + optional.hashCode();
1439 
1440             return h;
1441         }
1442     }
1443 
1444     private static class VersionBuilder {
1445         // $VNUM(-$PRE)?(\+($BUILD)?(\-$OPT)?)?
1446         // RE limits the format of version strings
1447         // ([1-9][0-9]*(?:(?:\.0)*\.[1-9][0-9]*)*)(?:-([a-zA-Z0-9]+))?(?:(\+)(0|[1-9][0-9]*)?)?(?:-([-a-zA-Z0-9.]+))?
1448 
1449         private static final String VNUM
1450             = "(?<VNUM>[1-9][0-9]*(?:(?:\\.0)*\\.[1-9][0-9]*)*)";
1451         private static final String VNUM_GROUP  = "VNUM";
1452 
1453         private static final String PRE      = "(?:-(?<PRE>[a-zA-Z0-9]+))?";
1454         private static final String PRE_GROUP   = "PRE";
1455 
1456         private static final String BUILD
1457             = "(?:(?<PLUS>\\+)(?<BUILD>0|[1-9][0-9]*)?)?";
1458         private static final String PLUS_GROUP  = "PLUS";
1459         private static final String BUILD_GROUP = "BUILD";
1460 
1461         private static final String OPT      = "(?:-(?<OPT>[-a-zA-Z0-9.]+))?";
1462         private static final String OPT_GROUP   = "OPT";
1463 
1464         private static final String VSTR_FORMAT
1465             = "^" + VNUM + PRE + BUILD + OPT + "$";
1466         private static final Pattern VSTR_PATTERN = Pattern.compile(VSTR_FORMAT);
1467 
1468         /**
1469          * Constructs a valid <a href="verStr">version string</a> containing
1470          * a <a href="#verNum">version number</a> followed by pre-release and
1471          * build information.
1472          *
1473          * @param  s
1474          *         A string to be interpreted as a version
1475          *
1476          * @throws  IllegalArgumentException
1477          *          If the given string cannot be interpreted as a valid
1478          *          version
1479          *
1480          * @throws  NullPointerException
1481          *          If {@code s} is {@code null}
1482          *
1483          * @throws  NumberFormatException
1484          *          If an element of the version number or the build number
1485          *          cannot be represented as an {@link Integer}
1486          */
1487         static Version parse(String s) {
1488             if (s == null)
1489                 throw new NullPointerException();
1490 
1491             Matcher m = VSTR_PATTERN.matcher(s);
1492             if (!m.matches())
1493                 throw new IllegalArgumentException("Invalid version string: '"
1494                                                    + s + "'");
1495 
1496             // $VNUM is a dot-separated list of integers of arbitrary length
1497             List<Integer> version = new ArrayList<>();
1498             for (String i : m.group(VNUM_GROUP).split("\\."))
1499                 version.add(Integer.parseInt(i));
1500 
1501             Optional<String> pre = Optional.ofNullable(m.group(PRE_GROUP));
1502 
1503             String b = m.group(BUILD_GROUP);
1504             // $BUILD is an integer
1505             Optional<Integer> build = (b == null)
1506                 ? Optional.empty()
1507                 : Optional.of(Integer.parseInt(b));
1508 
1509             Optional<String> optional = Optional.ofNullable(m.group(OPT_GROUP));
1510 
1511             // empty '+'
1512             if ((m.group(PLUS_GROUP) != null) && !build.isPresent()) {
1513                 if (optional.isPresent()) {
1514                     if (pre.isPresent())
1515                         throw new IllegalArgumentException("'+' found with"
1516                             + " pre-release and optional components:'" + s
1517                             + "'");
1518                 } else {
1519                     throw new IllegalArgumentException("'+' found with neither"
1520                         + " build or optional components: '" + s + "'");
1521                 }
1522             }
1523             return new Version(version, pre, build, optional);
1524         }
1525     }
1526 }


1095          * <a href="#verNum">version number</a> followed by pre-release and
1096          * build information.
1097          *
1098          * @param  s
1099          *         A string to interpret as a version
1100          *
1101          * @throws  IllegalArgumentException
1102          *          If the given string cannot be interpreted as a valid
1103          *          version
1104          *
1105          * @throws  NullPointerException
1106          *          If the given string is {@code null}
1107          *
1108          * @throws  NumberFormatException
1109          *          If an element of the version number or the build number
1110          *          cannot be represented as an {@link Integer}
1111          *
1112          * @return  The Version of the given string
1113          */
1114         public static Version parse(String s) {
1115             if (s == null)
1116                 throw new NullPointerException();
1117 
1118             // Shortcut to avoid initializing VersionPattern when creating
1119             // major version constants during startup
1120             if (isSimpleNumber(s)) {
1121                 return new Version(List.of(Integer.parseInt(s)),
1122                         Optional.empty(), Optional.empty(), Optional.empty());
1123             }
1124             Matcher m = VersionPattern.VSTR_PATTERN.matcher(s);
1125             if (!m.matches())
1126                 throw new IllegalArgumentException("Invalid version string: '"
1127                                                    + s + "'");
1128 
1129             // $VNUM is a dot-separated list of integers of arbitrary length
1130             List<Integer> version = new ArrayList<>();
1131             for (String i : m.group(VersionPattern.VNUM_GROUP).split("\\."))
1132                 version.add(Integer.parseInt(i));
1133 
1134             Optional<String> pre = Optional.ofNullable(
1135                     m.group(VersionPattern.PRE_GROUP));
1136 
1137             String b = m.group(VersionPattern.BUILD_GROUP);
1138             // $BUILD is an integer
1139             Optional<Integer> build = (b == null)
1140                 ? Optional.empty()
1141                 : Optional.of(Integer.parseInt(b));
1142 
1143             Optional<String> optional = Optional.ofNullable(
1144                     m.group(VersionPattern.OPT_GROUP));
1145 
1146             // empty '+'
1147             if ((m.group(VersionPattern.PLUS_GROUP) != null)
1148                     && !build.isPresent()) {
1149                 if (optional.isPresent()) {
1150                     if (pre.isPresent())
1151                         throw new IllegalArgumentException("'+' found with"
1152                             + " pre-release and optional components:'" + s
1153                             + "'");
1154                 } else {
1155                     throw new IllegalArgumentException("'+' found with neither"
1156                         + " build or optional components: '" + s + "'");
1157                 }
1158             }
1159             return new Version(version, pre, build, optional);
1160         }
1161 
1162         private static boolean isSimpleNumber(String s) {
1163             for (int i = 0; i < s.length(); i++) {
1164                 char c = s.charAt(i);
1165                 char lowerBound = (i > 0) ? '0' : '1';
1166                 if (c < lowerBound || c > '9') {
1167                     return false;
1168                 }
1169             }
1170             return true;
1171         }
1172 
1173         /**
1174          * Returns the <a href="#major">major</a> version number.
1175          *
1176          * @return  The major version number
1177          */
1178         public int major() {
1179             return version.get(0);
1180         }
1181 
1182         /**
1183          * Returns the <a href="#minor">minor</a> version number or zero if it
1184          * was not set.
1185          *
1186          * @return  The minor version number or zero if it was not set
1187          */
1188         public int minor() {
1189             return (version.size() > 1 ? version.get(1) : 0);
1190         }


1479          *
1480          * <p> This method satisfies the general contract of the {@link
1481          * Object#hashCode Object.hashCode} method.
1482          *
1483          * @return  The hashcode of this version
1484          */
1485         @Override
1486         public int hashCode() {
1487             int h = 1;
1488             int p = 17;
1489 
1490             h = p * h + version.hashCode();
1491             h = p * h + pre.hashCode();
1492             h = p * h + build.hashCode();
1493             h = p * h + optional.hashCode();
1494 
1495             return h;
1496         }
1497     }
1498 
1499     private static class VersionPattern {
1500         // $VNUM(-$PRE)?(\+($BUILD)?(\-$OPT)?)?
1501         // RE limits the format of version strings
1502         // ([1-9][0-9]*(?:(?:\.0)*\.[1-9][0-9]*)*)(?:-([a-zA-Z0-9]+))?(?:(\+)(0|[1-9][0-9]*)?)?(?:-([-a-zA-Z0-9.]+))?
1503 
1504         private static final String VNUM
1505             = "(?<VNUM>[1-9][0-9]*(?:(?:\\.0)*\\.[1-9][0-9]*)*)";


1506         private static final String PRE      = "(?:-(?<PRE>[a-zA-Z0-9]+))?";


1507         private static final String BUILD
1508             = "(?:(?<PLUS>\\+)(?<BUILD>0|[1-9][0-9]*)?)?";



1509         private static final String OPT      = "(?:-(?<OPT>[-a-zA-Z0-9.]+))?";


1510         private static final String VSTR_FORMAT
1511             = "^" + VNUM + PRE + BUILD + OPT + "$";


































1512 
1513         static final Pattern VSTR_PATTERN = Pattern.compile(VSTR_FORMAT);
1514 
1515         static final String VNUM_GROUP  = "VNUM";
1516         static final String PRE_GROUP   = "PRE";
1517         static final String PLUS_GROUP  = "PLUS";
1518         static final String BUILD_GROUP = "BUILD";
1519         static final String OPT_GROUP   = "OPT";

















1520     }
1521 }
< prev index next >