/* * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package build.tools.generatecharacter; import java.lang.reflect.*; import java.util.*; /** Recovers and prints ranges for certain java.lang.Character properties. Useful for generating fast-path Latin-1 code. */ public class PrintCharacterRanges { static class BooleanRange { private int begin; private int end; BooleanRange(int begin, int end) { this.begin = begin; this.end = end; } int begin() { return begin; } int end() { return end; } } private static List recoverBooleanRanges(String methodName) throws Exception { List result = new ArrayList<>(); int currentRangeStart = -1; Method method = Character.class.getDeclaredMethod(methodName, new Class[] { Character.TYPE }); if (method == null) { throw new RuntimeException("No method \"" + methodName + "\"(C) found"); } for (int i = 0; i <= 255; i++) { boolean methodRes = ((Boolean) method.invoke(null, new Object[] { Character.valueOf((char) i) })).booleanValue(); if (methodRes) { if (currentRangeStart < 0) { currentRangeStart = i; } if (i == 255) { result.add(new BooleanRange(currentRangeStart, i)); } } else { if (currentRangeStart >= 0) { result.add(new BooleanRange(currentRangeStart, i - 1)); currentRangeStart = -1; } } } return result; } private static String describe(int num) { StringBuffer s = new StringBuffer(); s.append(num); s.append(" ('"); if (num > 32 && num < 123) { s.append((char) num); } else { s.append("\\u"); String hex = Long.toHexString(num).toUpperCase(); for (int i = 0; i < (4 - hex.length()); i++) { s.append('0'); } s.append(hex); } s.append("')"); return s.toString(); } private static void printBooleanRanges(List ranges, String methodName) { System.out.print(methodName + ":"); for (Iterator iter = ranges.iterator(); iter.hasNext();) { BooleanRange range = iter.next(); System.out.print(" [ " + describe(range.begin()) + ", " + describe(range.end()) + " ]"); } System.out.println(""); } private static void recoverAndPrintBooleanRanges(String methodName) throws Exception { List ranges = recoverBooleanRanges(methodName); printBooleanRanges(ranges, methodName); } static class ShiftRange { private int begin; private int end; private int offset; ShiftRange(int begin, int end, int offset) { this.begin = begin; this.end = end; this.offset = offset; } int begin() { return begin; } int end() { return end; } int offset() { return offset; } } private static List recoverShiftRanges(String methodName) throws Exception { List result = new ArrayList<>(); int currentRangeStart = -1; int currentRangeOffset = -1; Method method = Character.class.getDeclaredMethod(methodName, new Class[] { Character.TYPE }); if (method == null) { throw new RuntimeException("No method \"" + methodName + "\"(C) found"); } for (int i = 0; i <= 255; i++) { char methodRes = ((Character) method.invoke(null, new Object[] { Character.valueOf((char) i) })).charValue(); if (methodRes != i) { int offset = methodRes - i; if (currentRangeStart < 0) { currentRangeStart = i; } else if (offset != currentRangeOffset) { result.add(new ShiftRange(currentRangeStart, i - 1, currentRangeOffset)); currentRangeStart = i; } currentRangeOffset = offset; if (i == 255) { result.add(new ShiftRange(currentRangeStart, i, currentRangeOffset)); } } else { if (currentRangeStart >= 0) { result.add(new ShiftRange(currentRangeStart, i - 1, currentRangeOffset)); currentRangeStart = -1; } } } return result; } private static void printShiftRanges(List ranges, String methodName) { System.out.print(methodName + ":"); boolean isFirst = true; for (Iterator iter = ranges.iterator(); iter.hasNext();) { ShiftRange range = iter.next(); if (isFirst) { isFirst = false; } else { System.out.print(", "); } System.out.print(" [ " + describe(range.begin()) + ", " + describe(range.end()) + " ] -> [ " + describe((range.begin() + range.offset())) + ", " + describe((range.end() + range.offset())) + " ] (" + range.offset() + ")"); } System.out.println(""); } private static void recoverAndPrintShiftRanges(String methodName) throws Exception { List ranges = recoverShiftRanges(methodName); printShiftRanges(ranges, methodName); } public static void main(String[] args) { try { recoverAndPrintBooleanRanges("isDefined"); recoverAndPrintBooleanRanges("isDigit"); recoverAndPrintBooleanRanges("isIdentifierIgnorable"); recoverAndPrintBooleanRanges("isISOControl"); recoverAndPrintBooleanRanges("isJavaIdentifierPart"); recoverAndPrintBooleanRanges("isJavaIdentifierStart"); recoverAndPrintBooleanRanges("isLetter"); recoverAndPrintBooleanRanges("isLetterOrDigit"); recoverAndPrintBooleanRanges("isLowerCase"); recoverAndPrintBooleanRanges("isMirrored"); recoverAndPrintBooleanRanges("isSpaceChar"); recoverAndPrintBooleanRanges("isTitleCase"); recoverAndPrintBooleanRanges("isUnicodeIdentifierPart"); recoverAndPrintBooleanRanges("isUnicodeIdentifierStart"); recoverAndPrintBooleanRanges("isUpperCase"); recoverAndPrintBooleanRanges("isWhitespace"); recoverAndPrintShiftRanges("toUpperCase"); recoverAndPrintShiftRanges("toLowerCase"); } catch (Exception e) { e.printStackTrace(); } } }