Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/make/src/classes/build/tools/hasher/Hasher.java
32287 views
/*1* Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package build.tools.hasher;2627import java.io.*;28import java.util.*;293031/**32* Reads a map in the form of a sequence of key/value-expression pairs from the33* standard input, attempts to construct a hash map that fits within the given34* table-size and chain-depth constraints, and, if successful, writes source35* code to the standard output for a subclass of sun.util.PreHashedMap that36* implements the map.37*38* @see sun.util.PreHashedMap39*40* @author Mark Reinhold41*/4243public class Hasher {4445// This class cannot, sadly, make use of 1.5 features since it must be46// compiled and run with the bootstrap JDK, which is 1.4.2.4748static final PrintStream out = System.out;49static final PrintStream err = System.err;5051boolean verbose = false;5253List<String> keys = new ArrayList<>(); // Key strings54List<String> values = new ArrayList<>(); // Value expressions55String pkg = null; // Package prefix for generated class56String cln = null; // Name of generated class57String vtype = "String"; // Value type58int maxBits = 11; // lg table size59int maxDepth = 3; // Max chain depth60boolean inner = false; // Generating an inner class?61boolean empty = false; // Generating an empty table?6263void usage() {64err.println("usage: java Hasher [options] [[pkgName.]ClassName]");65err.println("options:");66err.println(" -e generate empty table (ignores value exprs)");67err.println(" -i generate a static inner class");68err.println(" -md depth max chain depth (default 3)");69err.println(" -mb bits max index bits (lg of table size, default 10)");70err.println(" -t type value type (default String)");71err.println(" -v verbose");72err.println("Key/value-expression pairs are read from standard input");73err.println("If class name is given then source is written to standard output");74System.exit(1);75}7677Hasher(String[] args) {78List<String> as = Arrays.asList(args);79for (Iterator<String> i = as.iterator(); i.hasNext();) {80String a = i.next();81if (a.equals("-e")) {82empty = true;83} else if (a.equals("-i")) {84inner = true;85} else if (a.equals("-v")) {86verbose = true;87} else if (a.equals("-md")) {88if (!i.hasNext())89usage();90maxDepth = Integer.parseInt(i.next());91} else if (a.equals("-mb")) {92if (!i.hasNext())93usage();94maxBits = Integer.parseInt(i.next());95} else if (a.equals("-t")) {96if (!i.hasNext())97usage();98vtype = i.next();99} else if (a.startsWith("-")) {100usage();101} else {102int j = a.lastIndexOf('.');103if (j >= 0) {104pkg = a.substring(0, j);105cln = a.substring(j + 1);106} else {107cln = a;108}109}110}111if (verbose)112err.println("pkg=" + pkg + ", cln=" + cln);113}114115// Read keys and values116//117Hasher load() throws IOException {118BufferedReader br119= new BufferedReader(new InputStreamReader(System.in));120for (String ln; (ln = br.readLine()) != null;) {121String[] ws = ln.split(",?\\s+", 2);122String w = ws[0].replaceAll("\"", "");123if (keys.contains(w))124throw new RuntimeException("Duplicate word in input: " + w);125keys.add(w);126if (ws.length < 2)127throw new RuntimeException("Missing expression for key " + w);128values.add(ws[1]);129}130return this;131}132133Object[] ht; // Hash table itself134int nb; // Number of bits (lg table size)135int md; // Maximum chain depth136int mask; // Hash-code mask137int shift; // Hash-code shift size138139int hash(String w) {140return (w.hashCode() >> shift) & mask;141}142143// Build a hash table of size 2^nb, shifting the hash code by s bits144//145void build(int nb, int s) {146147this.nb = nb;148this.shift = s;149int n = 1 << nb;150this.mask = n - 1;151ht = new Object[n];152int nw = keys.size();153154for (int i = 0; i < nw; i++) {155String w = keys.get(i);156String v = values.get(i);157int h = hash(w);158if (ht[h] == null)159ht[h] = new Object[] { w, v };160else161ht[h] = new Object[] { w, v, ht[h] };162}163164this.md = 0;165for (int i = 0; i < n; i++) {166int d = 1;167for (Object[] a = (Object[])ht[i];168a != null && a.length > 2;169a = (Object[])a[2], d++);170this.md = Math.max(md, d);171}172173}174175Hasher build() {176// Iterate through acceptable table sizes177for (int nb = 2; nb < maxBits; nb++) {178// Iterate through possible shift sizes179for (int s = 0; s < (32 - nb); s++) {180build(nb, s);181if (verbose)182err.println("nb=" + nb + " s=" + s + " md=" + md);183if (md <= maxDepth) {184// Success185out.flush();186if (cln != null)187err.print(cln + ": ");188err.println("Table size " + (1 << nb) + " (" + nb + " bits)"189+ ", shift " + shift190+ ", max chain depth " + md);191return this;192}193}194}195throw new RuntimeException("Cannot find a suitable size"196+ " within given constraints");197}198199// Look for the given key in the hash table200//201String get(String k) {202int h = hash(k);203Object[] a = (Object[])ht[h];204for (;;) {205if (a[0].equals(k))206return (String)a[1];207if (a.length < 3)208return null;209a = (Object[])a[2];210}211}212213// Test that all input keys can be found in the table214//215Hasher test() {216if (verbose)217err.println();218for (int i = 0, n = keys.size(); i < n; i++) {219String w = keys.get(i);220String v = get(w);221if (verbose)222err.println(hash(w) + "\t" + w);223if (!v.equals(values.get(i)))224throw new Error("Incorrect value: " + w + " --> "225+ v + ", should be " + values.get(i));226}227return this;228}229230String ind = ""; // Indent prefix231232// Generate code for a single table entry233//234void genEntry(Object[] a, int depth, PrintWriter pw) {235Object v = empty ? null : a[1];236pw.print("new Object[] { \"" + a[0] + "\", " + v);237if (a.length < 3) {238pw.print(" }");239return;240}241pw.println(",");242pw.print(ind + " ");243for (int i = 0; i < depth; i++)244pw.print(" ");245genEntry((Object[])a[2], depth + 1, pw);246pw.print(" }");247}248249// Generate a PreHashedMap subclass from the computed hash table250//251Hasher generate() throws IOException {252if (cln == null)253return this;254PrintWriter pw255= new PrintWriter(new BufferedWriter(new OutputStreamWriter(out)));256257if (inner)258ind = " ";259260if (!inner && pkg != null) {261pw.println();262pw.println("package " + pkg + ";");263pw.println();264}265266if (inner) {267pw.println(ind + "private static final class " + cln);268} else {269pw.println();270pw.println("public final class " + cln);271}272pw.println(ind + " extends sun.util.PreHashedMap<" + vtype +">");273pw.println(ind + "{");274275pw.println();276pw.println(ind + " private static final int ROWS = "277+ ht.length + ";");278pw.println(ind + " private static final int SIZE = "279+ keys.size() + ";");280pw.println(ind + " private static final int SHIFT = "281+ shift + ";");282pw.println(ind + " private static final int MASK = 0x"283+ Integer.toHexString(mask) + ";");284pw.println();285286pw.println(ind + " " + (inner ? "private " : "public ")287+ cln + "() {");288pw.println(ind + " super(ROWS, SIZE, SHIFT, MASK);");289pw.println(ind + " }");290pw.println();291292pw.println(ind + " protected void init(Object[] ht) {");293for (int i = 0; i < ht.length; i++) {294if (ht[i] == null)295continue;296Object[] a = (Object[])ht[i];297pw.print(ind + " ht[" + i + "] = ");298genEntry(a, 0, pw);299pw.println(";");300}301pw.println(ind + " }");302pw.println();303304pw.println(ind + "}");305if (inner)306pw.println();307308pw.close();309return this;310}311312public static void main(String[] args) throws IOException {313new Hasher(args)314.load()315.build()316.test()317.generate();318}319320}321322323