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 
  34         public FieldDescriptor(String name, Type type) {
  35             this.name = name;
  36             this.type = type;
  37         }
  38     }
  39 
  40     static Type[] typeArray;
  41     static String[] defaultArray;
  42     static int NB_TYPES = 9;
  43 
  44     static {
  45         typeArray = new Type[NB_TYPES];
  46         typeArray[0] = byte.class;
  47         typeArray[1] = short.class;
  48         typeArray[2] = int.class;
  49         typeArray[3] = long.class;
  50         typeArray[4] = char.class;
  51         typeArray[5] = float.class;
  52         typeArray[6] = double.class;
  53         typeArray[7] = boolean.class;
  54         typeArray[8] = Object.class;
  55 
  56     }
  57 
  58     static String defaultValue(Type t) {
  59         switch(t.getTypeName()) {
  60             case "byte": return "(byte)123";
  61             case "short": return "(short)32056";
  62             case "int": return "483647";
  63             case "long": return "922337203685477L";
  64             case "char": return "(char)65456";
  65             case "float": return "2.71828f";
  66             case "double": return "3.14159d";
  67             case "boolean": return "true";
  68             case "java.lang.Object": return "null";
  69             default:
  70                 throw new RuntimeException();
  71         }
  72     }
  73     static private String generateValueTypeInternal(Random random, String name, int nfields, int typeLimit) {
  74         // generate the fields
  75         FieldDescriptor[] fieldDescArray = new FieldDescriptor[nfields];
  76         for (int i = 0; i < nfields; i++) {
  77             int idx = random.nextInt(typeLimit);
  78             String fieldName = typeArray[idx].getTypeName()+"Field"+i;
  79             fieldDescArray[i] = new FieldDescriptor(fieldName, typeArray[idx]);
  80         }
  81 
  82         String source = generateSource(name, fieldDescArray);
  83         return source;
  84     }
  85 
  86     static public String generateValueType(Random random, String name, int nfields) {
  87         return generateValueTypeInternal(random, name, nfields, NB_TYPES);
  88     }
  89 
  90     static public String generateValueTypeNoObjectRef(Random random, String name, int nfields) {
  91         return generateValueTypeInternal(random, name, nfields, NB_TYPES - 1);
  92     }
  93 
  94     static String fieldsAsArgs(FieldDescriptor[] fields) {
  95         StringBuilder sb = new StringBuilder();
  96         for (int i = 0; i < fields.length; i++) {
  97             sb.append(fields[i].type).append(" ").append(fields[i].name);
  98             if (i != fields.length - 1) {
  99                 sb.append(", ");
 100             }
 101         }
 102         return sb.toString();
 103     }
 104 
 105     static String generateSource(String name, FieldDescriptor[] fields) {
 106         StringBuilder sb = new StringBuilder();
 107 
 108         // imports
 109         sb.append("import java.io.PrintStream;\n\n");
 110 
 111         // class declaration
 112         sb.append("public __ByValue final class ").append(name).append(" {\n");
 113 
 114         // field declarations
 115         for (FieldDescriptor f : fields) {
 116             sb.append("\tfinal public ").append(f.type).append(" ");
 117             sb.append(f.name).append(";\n");
 118         }
 119         sb.append("\n");
 120 
 121         // private constructor
 122         sb.append("\tprivate ").append(name).append("() {\n");
 123         for (int i = 0 ; i < fields.length; i++) {
 124             sb.append("\t\tthis.").append(fields[i].name).append(" = ").append(defaultValue(fields[i].type)).append(";\n");
 125         }
 126         sb.append("\t}\n");
 127         sb.append("\n");
 128 
 129         // factory
 130         sb.append("\t__ValueFactory static public ").append(name).append(" ").append("make").append(name).append("(");
 131         sb.append(fieldsAsArgs(fields));
 132         sb.append(") {\n");
 133         sb.append("\t\t").append(name).append(" v = ").append("__MakeDefault ").append(name).append("();\n");
 134         for (int i = 0 ; i < fields.length; i++) {
 135             sb.append("\t\tv.").append(fields[i].name).append(" = ").append(fields[i].name).append(";\n");
 136         }
 137         sb.append("\t\treturn v;\n");
 138         sb.append("\t};\n");
 139         sb.append("\n");
 140 
 141         // default factory
 142         sb.append("\t__ValueFactory static public ").append(name).append(" ").append("make").append(name).append("() {\n");
 143         sb.append("\t\t").append(name).append(" v = ").append("__MakeDefault ").append(name).append("();\n");
 144         for (int i = 0 ; i < fields.length; i++) {
 145             sb.append("\t\tv.").append(fields[i].name).append(" = ").append(defaultValue(fields[i].type)).append(";\n");
 146         }
 147         sb.append("\t\treturn v;\n");
 148         sb.append("\t}\n");
 149         sb.append("\n");
 150 
 151         // verify method
 152         sb.append("\tstatic public boolean verify(").append(name).append(" value) {\n");
 153         for (FieldDescriptor f : fields) {
 154             sb.append("\t\tif (value.").append(f.name).append(" != ").append(defaultValue(f.type)).append(") return false;\n");
 155         }
 156         sb.append("\t\treturn true;\n");
 157         sb.append("\t}\n");
 158 
 159         // printLayout method
 160         sb.append("\tstatic public void printLayout(PrintStream out) {\n");
 161         sb.append("\t\tout.println(\"").append(name).append(" fields: ");
 162         for (int i = 0; i < fields.length; i++) {
 163             sb.append(fields[i].type);
 164             if (i != fields.length - 1) {
 165                 sb.append(", ");
 166             }
 167         }
 168         sb.append("\");\n");
 169         sb.append("\t}\n");
 170 
 171         sb.append("}\n");
 172 
 173         return sb.toString();
 174     }
 175 }