1/*
2 * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package build.tools.generatecharacter;
27
28import java.lang.reflect.*;
29import java.util.*;
30
31/** Recovers and prints ranges for certain java.lang.Character
32    properties. Useful for generating fast-path Latin-1 code. */
33
34public class PrintCharacterRanges {
35  static class BooleanRange {
36    private int begin;
37    private int end;
38
39    BooleanRange(int begin, int end) {
40      this.begin = begin;
41      this.end   = end;
42    }
43
44    int begin() { return begin; }
45    int end()   { return end;   }
46  }
47
48  private static List/*<BooleanRange>*/ recoverBooleanRanges(String methodName) throws Exception {
49    List result = new ArrayList();
50    int currentRangeStart = -1;
51    Method method = Character.class.getDeclaredMethod(methodName, new Class[] { Character.TYPE });
52    if (method == null) {
53      throw new RuntimeException("No method \"" + methodName + "\"(C) found");
54    }
55
56    for (int i = 0; i <= 255; i++) {
57      boolean methodRes = ((Boolean) method.invoke(null, new Object[] { new Character((char) i) })).booleanValue();
58      if (methodRes) {
59        if (currentRangeStart < 0) {
60          currentRangeStart = i;
61        }
62        if (i == 255) {
63          result.add(new BooleanRange(currentRangeStart, i));
64        }
65      } else {
66        if (currentRangeStart >= 0) {
67          result.add(new BooleanRange(currentRangeStart, i - 1));
68          currentRangeStart = -1;
69        }
70      }
71    }
72
73    return result;
74  }
75
76  private static String describe(int num) {
77    StringBuffer s = new StringBuffer();
78    s.append(num);
79    s.append(" ('");
80    if (num > 32 && num < 123) {
81      s.append((char) num);
82    } else {
83      s.append("\\u");
84      String hex = Long.toHexString(num).toUpperCase();
85      for (int i = 0; i < (4 - hex.length()); i++) {
86        s.append('0');
87      }
88      s.append(hex);
89    }
90    s.append("')");
91    return s.toString();
92  }
93
94  private static void printBooleanRanges(List/*<BooleanRange>*/ ranges, String methodName) {
95    System.out.print(methodName + ":");
96    for (Iterator iter = ranges.iterator(); iter.hasNext();) {
97      BooleanRange range = (BooleanRange) iter.next();
98      System.out.print(" [ " + describe(range.begin()) + ", " + describe(range.end()) + " ]");
99    }
100    System.out.println("");
101  }
102
103  private static void recoverAndPrintBooleanRanges(String methodName) throws Exception {
104    List ranges = recoverBooleanRanges(methodName);
105    printBooleanRanges(ranges, methodName);
106  }
107
108  static class ShiftRange {
109    private int begin;
110    private int end;
111    private int offset;
112
113    ShiftRange(int begin, int end, int offset) {
114      this.begin  = begin;
115      this.end    = end;
116      this.offset = offset;
117    }
118
119    int begin()  { return begin;  }
120    int end()    { return end;    }
121    int offset() { return offset; }
122  }
123
124  private static List/*<ShiftRange>*/ recoverShiftRanges(String methodName) throws Exception {
125    List result = new ArrayList();
126    int currentRangeStart = -1;
127    int currentRangeOffset = -1;
128    Method method = Character.class.getDeclaredMethod(methodName, new Class[] { Character.TYPE });
129    if (method == null) {
130      throw new RuntimeException("No method \"" + methodName + "\"(C) found");
131    }
132
133    for (int i = 0; i <= 255; i++) {
134      char methodRes = ((Character) method.invoke(null, new Object[] { new Character((char) i) })).charValue();
135      if (methodRes != i) {
136        int offset = methodRes - i;
137        if (currentRangeStart < 0) {
138          currentRangeStart = i;
139        } else if (offset != currentRangeOffset) {
140          result.add(new ShiftRange(currentRangeStart, i - 1, currentRangeOffset));
141          currentRangeStart = i;
142        }
143        currentRangeOffset = offset;
144        if (i == 255) {
145          result.add(new ShiftRange(currentRangeStart, i, currentRangeOffset));
146        }
147      } else {
148        if (currentRangeStart >= 0) {
149          result.add(new ShiftRange(currentRangeStart, i - 1, currentRangeOffset));
150          currentRangeStart = -1;
151        }
152      }
153    }
154
155    return result;
156  }
157
158  private static void printShiftRanges(List/*<ShiftRange>*/ ranges, String methodName) {
159    System.out.print(methodName + ":");
160    boolean isFirst = true;
161    for (Iterator iter = ranges.iterator(); iter.hasNext();) {
162      ShiftRange range = (ShiftRange) iter.next();
163      if (isFirst) {
164        isFirst = false;
165      } else {
166        System.out.print(", ");
167      }
168      System.out.print(" [ " + describe(range.begin()) + ", " + describe(range.end()) + " ] -> [ " +
169                       describe((range.begin() + range.offset())) + ", " + describe((range.end() + range.offset())) + " ] (" +
170                       range.offset() + ")");
171    }
172    System.out.println("");
173  }
174
175  private static void recoverAndPrintShiftRanges(String methodName) throws Exception {
176    List ranges = recoverShiftRanges(methodName);
177    printShiftRanges(ranges, methodName);
178  }
179
180  public static void main(String[] args) {
181    try {
182      recoverAndPrintBooleanRanges("isDefined");
183      recoverAndPrintBooleanRanges("isDigit");
184      recoverAndPrintBooleanRanges("isIdentifierIgnorable");
185      recoverAndPrintBooleanRanges("isISOControl");
186      recoverAndPrintBooleanRanges("isJavaIdentifierPart");
187      recoverAndPrintBooleanRanges("isJavaIdentifierStart");
188      recoverAndPrintBooleanRanges("isLetter");
189      recoverAndPrintBooleanRanges("isLetterOrDigit");
190      recoverAndPrintBooleanRanges("isLowerCase");
191      recoverAndPrintBooleanRanges("isMirrored");
192      recoverAndPrintBooleanRanges("isSpaceChar");
193      recoverAndPrintBooleanRanges("isTitleCase");
194      recoverAndPrintBooleanRanges("isUnicodeIdentifierPart");
195      recoverAndPrintBooleanRanges("isUnicodeIdentifierStart");
196      recoverAndPrintBooleanRanges("isUpperCase");
197      recoverAndPrintBooleanRanges("isWhitespace");
198
199      recoverAndPrintShiftRanges("toUpperCase");
200      recoverAndPrintShiftRanges("toLowerCase");
201    } catch (Exception e) {
202      e.printStackTrace();
203    }
204  }
205}
206