1 /* 2 * Copyright (c) 2017, 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. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 import java.lang.reflect.Type; 25 import java.util.Random; 26 27 public class ValueTypeGenerator { 28 29 static class FieldDescriptor { 30 31 final public String name; 32 final public Type type; 33 final public String typeName; 34 35 public FieldDescriptor(String name, Type type) { 36 this.name = name; 37 this.type = type; 38 String s = type.getTypeName(); 39 if (s.startsWith("class")) { 40 s = s.substring(s.lastIndexOf(".")+1); 41 } 42 this.typeName = s; 43 } 44 } 45 46 static Type[] typeArray; 47 static String[] defaultArray; 48 static int NB_TYPES = 9; 49 50 static { 51 typeArray = new Type[NB_TYPES]; 52 typeArray[0] = byte.class; 53 typeArray[1] = short.class; 54 typeArray[2] = int.class; 55 typeArray[3] = long.class; 56 typeArray[4] = char.class; 57 typeArray[5] = float.class; 58 typeArray[6] = double.class; 59 typeArray[7] = boolean.class; 60 typeArray[8] = Object.class; 61 } 62 63 static String defaultValue(Type t) { 64 switch(t.getTypeName()) { 65 case "byte": return "(byte)123"; 66 case "short": return "(short)32056"; 67 case "int": return "483647"; 68 case "long": return "922337203685477L"; 69 case "char": return "(char)65456"; 70 case "float": return "2.71828f"; 71 case "double": return "3.14159d"; 72 case "boolean": return "true"; 73 case "java.lang.Object": return "new String(\"foo\")"; 74 default: 75 throw new RuntimeException(); 76 } 77 } 78 static private String generateValueTypeInternal(Random random, String name, int nfields, int typeLimit) { 79 // generate the fields 80 FieldDescriptor[] fieldDescArray = new FieldDescriptor[nfields]; 81 for (int i = 0; i < nfields; i++) { 82 int idx = random.nextInt(typeLimit); 83 String s = typeArray[idx].getTypeName(); 84 if (s.contains(".")) { 85 s = s.substring(s.lastIndexOf(".")+1); 86 } 87 String fieldName = s+"Field"+i; 88 fieldDescArray[i] = new FieldDescriptor(fieldName, typeArray[idx]); 89 } 90 91 String source = generateSource(name, fieldDescArray); 92 return source; 93 } 94 95 static public String generateValueType(Random random, String name, int nfields) { 96 return generateValueTypeInternal(random, name, nfields, NB_TYPES); 97 } 98 99 static public String generateValueTypeNoObjectRef(Random random, String name, int nfields) { 100 return generateValueTypeInternal(random, name, nfields, NB_TYPES - 1); 101 } 102 103 static String fieldsAsArgs(FieldDescriptor[] fields) { 104 StringBuilder sb = new StringBuilder(); 105 for (int i = 0; i < fields.length; i++) { 106 sb.append(fields[i].typeName).append(" ").append(fields[i].name); 107 if (i != fields.length - 1) { 108 sb.append(", "); 109 } 110 } 111 return sb.toString(); 112 } 113 114 static String generateSource(String name, FieldDescriptor[] fields) { 115 StringBuilder sb = new StringBuilder(); 116 117 // imports 118 sb.append("import java.io.PrintStream;\n\n"); 119 120 // class declaration 121 sb.append("public __ByValue final class ").append(name).append(" {\n"); 122 123 // field declarations 124 for (FieldDescriptor f : fields) { 125 sb.append("\tfinal public ").append(f.typeName).append(" "); 126 sb.append(f.name).append(";\n"); 127 } 128 sb.append("\n"); 129 130 // private constructor 131 sb.append("\tprivate ").append(name).append("() {\n"); 132 for (int i = 0 ; i < fields.length; i++) { 133 sb.append("\t\tthis.").append(fields[i].name).append(" = ").append(defaultValue(fields[i].type)).append(";\n"); 134 } 135 sb.append("\t}\n"); 136 sb.append("\n"); 137 138 // factory 139 sb.append("\t__ValueFactory static public ").append(name).append(" ").append("make").append(name).append("("); 140 sb.append(fieldsAsArgs(fields)); 141 sb.append(") {\n"); 142 sb.append("\t\t").append(name).append(" v = ").append("__MakeDefault ").append(name).append("();\n"); 143 for (int i = 0 ; i < fields.length; i++) { 144 sb.append("\t\tv.").append(fields[i].name).append(" = ").append(fields[i].name).append(";\n"); 145 } 146 sb.append("\t\treturn v;\n"); 147 sb.append("\t};\n"); 148 sb.append("\n"); 149 150 // default factory 151 sb.append("\t__ValueFactory static public ").append(name).append(" ").append("make").append(name).append("() {\n"); 152 sb.append("\t\t").append(name).append(" v = ").append("__MakeDefault ").append(name).append("();\n"); 153 for (int i = 0 ; i < fields.length; i++) { 154 sb.append("\t\tv.").append(fields[i].name).append(" = ").append(defaultValue(fields[i].type)).append(";\n"); 155 } 156 sb.append("\t\treturn v;\n"); 157 sb.append("\t}\n"); 158 sb.append("\n"); 159 160 // verify method 161 sb.append("\tstatic public boolean verify(").append(name).append(" value) {\n"); 162 for (FieldDescriptor f : fields) { 163 if (f.type.getTypeName().compareTo("java.lang.Object") == 0) { 164 sb.append("\t\tif (((String)value.").append(f.name).append(").compareTo(").append(defaultValue(f.type)).append(") != 0) return false;\n"); 165 } else { 166 sb.append("\t\tif (value.").append(f.name).append(" != ").append(defaultValue(f.type)).append(") return false;\n"); 167 } 168 } 169 sb.append("\t\treturn true;\n"); 170 sb.append("\t}\n"); 171 172 // printLayout method 173 sb.append("\tstatic public void printLayout(PrintStream out) {\n"); 174 sb.append("\t\tout.println(\"").append(name).append(" fields: "); 175 for (int i = 0; i < fields.length; i++) { 176 sb.append(fields[i].typeName); 177 if (i != fields.length - 1) { 178 sb.append(", "); 179 } 180 } 181 sb.append("\");\n"); 182 sb.append("\t}\n"); 183 184 sb.append("}\n"); 185 186 return sb.toString(); 187 } 188 }