![JAR search and dependency download from the Maven repository](/logo.png)
net.openhft.chronicle.values.Generators Maven / Gradle / Ivy
/*
* Copyright 2016-2021 chronicle.software
*
* https://chronicle.software
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.openhft.chronicle.values;
import com.squareup.javapoet.*;
import net.openhft.chronicle.bytes.*;
import net.openhft.chronicle.core.Jvm;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.List;
import static java.lang.String.format;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static javax.lang.model.element.Modifier.PRIVATE;
import static javax.lang.model.element.Modifier.PUBLIC;
final class Generators {
private Generators() {
}
static String generateNativeClass(ValueModel model, String nativeClassName) {
TypeSpec.Builder typeBuilder = TypeSpec.classBuilder(nativeClassName);
typeBuilder.addModifiers(PUBLIC);
ValueBuilder valueBuilder = new ValueBuilder(model, nativeClassName, typeBuilder);
model.fields().forEach(f -> f.generateNativeMembers(valueBuilder));
generateNativeCommons(valueBuilder);
valueBuilder.closeConstructorsAndInitializationBlocks();
TypeSpec nativeType = typeBuilder.build();
String result = JavaFile
.builder(model.valueType.getPackage().getName(), nativeType)
.build()
.toString();
if (Jvm.getBoolean("chronicle.values.dumpCode"))
System.out.println(result);
return result;
}
private static void generateNativeCommons(ValueBuilder valueBuilder) {
generateValueCommons(valueBuilder, ImplType.NATIVE);
ValueModel model = valueBuilder.model;
valueBuilder.typeBuilder
.addSuperinterface(Byteable.class)
.addField(BytesStore.class, "bs", PRIVATE)
.addField(long.class, "offset", PRIVATE)
.addMethod(bytesStoreMethod(model))
.addMethod(bytesStoreGetterMethod())
.addMethod(offsetMethod())
.addMethod(maxSizeMethod(model));
}
private static MethodSpec bytesStoreMethod(ValueModel model) {
try {
Method bytesStoreReflectMethod = Byteable.class
.getMethod("bytesStore", BytesStore.class, long.class, long.class);
return methodBuilder(bytesStoreReflectMethod, asList("bytesStore", "offset", "length"))
.beginControlFlow("if (length != maxSize())")
.addStatement("throw new $T($S + length)",
IllegalArgumentException.class,
format("Constant size is %d, given length is ", model.sizeInBytes()))
.endControlFlow()
.addStatement("this.bs = bytesStore")
.addStatement(" if (offset + length > bytesStore.capacity())\n" +
" throw new AssertionError()")
.addStatement("this.offset = offset")
.build();
} catch (NoSuchMethodException e) {
throw new AssertionError(e);
}
}
private static MethodSpec bytesStoreGetterMethod() {
try {
Method bytesStoreReflectMethod = Byteable.class.getMethod("bytesStore");
return methodBuilder(bytesStoreReflectMethod, emptyList())
.addStatement("return bs")
.build();
} catch (NoSuchMethodException e) {
throw new AssertionError(e);
}
}
private static MethodSpec offsetMethod() {
try {
return methodBuilder(Byteable.class.getMethod("offset"), emptyList())
.addStatement("return offset")
.build();
} catch (NoSuchMethodException e) {
throw new AssertionError(e);
}
}
private static MethodSpec maxSizeMethod(ValueModel model) {
try {
return methodBuilder(Byteable.class.getMethod("maxSize"), emptyList())
.addStatement("return $L", model.sizeInBytes())
.build();
} catch (NoSuchMethodException e) {
throw new AssertionError(e);
}
}
private static void generateValueCommons(ValueBuilder valueBuilder, ImplType implType) {
Class> valueType = valueBuilder.model.valueType;
valueBuilder.typeBuilder
.addSuperinterface(valueType)
.addSuperinterface(ParameterizedTypeName.get(Copyable.class, valueType))
.addSuperinterface(BytesMarshallable.class);
valueBuilder.typeBuilder
.addMethod(copyFromMethod(valueBuilder, implType))
.addMethod(writeMarshallableMethod(valueBuilder, implType))
.addMethod(readMarshallableMethod(valueBuilder, implType))
.addMethod(equalsMethod(valueBuilder, implType))
.addMethod(hashCodeMethod(valueBuilder, implType));
// .addMethod(toStringMethod(valueBuilder, implType));
}
private static MethodSpec copyFromMethod(ValueBuilder valueBuilder, ImplType implType) {
MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder("copyFrom")
.addAnnotation(Override.class)
.addModifiers(PUBLIC)
.addParameter(valueBuilder.model.valueType, "from");
if (implType == ImplType.NATIVE) {
ClassName nativeClassName = valueBuilder.className();
methodBuilder.beginControlFlow("if (from instanceof $T)", nativeClassName);
{
methodBuilder.addStatement(
"bs.write(offset, (($T) from).bytesStore(), (($T) from).offset(), $L)",
nativeClassName, nativeClassName, valueBuilder.model.sizeInBytes());
}
methodBuilder.nextControlFlow("else");
}
valueBuilder.model.fields()
.forEach(f -> {
// plain java blocks to isolate variable namespaces
methodBuilder.beginControlFlow("");
implType.getMemberGenerator(f).generateCopyFrom(valueBuilder, methodBuilder);
methodBuilder.endControlFlow();
});
if (implType == ImplType.NATIVE) {
methodBuilder.endControlFlow();
}
return methodBuilder.build();
}
private static MethodSpec readMarshallableMethod(ValueBuilder valueBuilder, ImplType implType) {
MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder("readMarshallable")
.addAnnotation(Override.class)
.addModifiers(PUBLIC)
.addParameter(BytesIn.class, "bytes");
valueBuilder.model.fields()
.forEach(f -> {
// plain java blocks to isolate variable namespaces
methodBuilder.beginControlFlow("");
implType.getMemberGenerator(f)
.generateReadMarshallable(valueBuilder, methodBuilder);
methodBuilder.endControlFlow();
});
return methodBuilder.build();
}
private static MethodSpec writeMarshallableMethod(
ValueBuilder valueBuilder, ImplType implType) {
MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder("writeMarshallable")
.addAnnotation(Override.class)
.addModifiers(PUBLIC)
.addParameter(BytesOut.class, "bytes");
valueBuilder.model.fields()
.forEach(f -> {
// plain java blocks to isolate variable namespaces
methodBuilder.beginControlFlow("");
implType.getMemberGenerator(f)
.generateWriteMarshallable(valueBuilder, methodBuilder);
methodBuilder.endControlFlow();
});
return methodBuilder.build();
}
private static MethodSpec equalsMethod(ValueBuilder valueBuilder, ImplType implType) {
MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder("equals")
.addParameter(Object.class, "obj")
.addAnnotation(Override.class)
.addModifiers(PUBLIC)
.returns(boolean.class);
Class> valueType = valueBuilder.model.valueType;
methodBuilder.addCode("if (!(obj instanceof $T)) return false;\n",
valueType);
methodBuilder.addStatement("$T other = ($T) obj", valueType, valueType);
valueBuilder.model.fields().forEach(f -> {
// plain java blocks to isolate variable namespaces
methodBuilder.beginControlFlow("");
implType.getMemberGenerator(f).generateEquals(valueBuilder, methodBuilder);
methodBuilder.endControlFlow();
});
methodBuilder.addStatement("return true");
return methodBuilder.build();
}
/**
* Copies google/auto value's strategy of hash code generation
*/
private static MethodSpec hashCodeMethod(ValueBuilder valueBuilder, ImplType implType) {
MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder("hashCode")
.addAnnotation(Override.class)
.addModifiers(PUBLIC)
.returns(int.class);
methodBuilder.addStatement("int hashCode = 1");
valueBuilder.model.fields().forEach(f -> {
methodBuilder.addStatement("hashCode *= 1000003");
// plain java blocks to isolate variable namespaces
methodBuilder.beginControlFlow("");
String fieldHashCode =
implType.getMemberGenerator(f).generateHashCode(valueBuilder, methodBuilder);
methodBuilder.addStatement("hashCode ^= $N", fieldHashCode);
methodBuilder.endControlFlow();
});
methodBuilder.addStatement("return hashCode");
return methodBuilder.build();
}
private static MethodSpec toStringMethod(ValueBuilder valueBuilder, ImplType implType) {
MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder("toString")
.addAnnotation(Override.class)
.addModifiers(PUBLIC)
.returns(String.class);
// check it's valid
methodBuilder.addStatement("$T sb = new $T()", StringBuilder.class, StringBuilder.class);
String modelName = valueBuilder.model.simpleName();
methodBuilder.addStatement("sb.append($S)", modelName);
valueBuilder.model.fields().forEach(f -> {
// plain java blocks to isolate variable namespaces
methodBuilder.beginControlFlow("");
implType.getMemberGenerator(f).generateToString(valueBuilder, methodBuilder);
methodBuilder.endControlFlow();
});
methodBuilder.addStatement("sb.setCharAt($L, '{')", modelName.length());
methodBuilder.addStatement("sb.append(' ').append('}')");
methodBuilder.addStatement("return sb.toString()");
return methodBuilder.build();
}
static String generateHeapClass(ValueModel model, String heapClassName) {
TypeSpec.Builder typeBuilder = TypeSpec.classBuilder(heapClassName);
typeBuilder.addModifiers(PUBLIC);
ValueBuilder valueBuilder = new ValueBuilder(model, heapClassName, typeBuilder);
model.fields().forEach(f -> f.generateHeapMembers(valueBuilder));
generateValueCommons(valueBuilder, ImplType.HEAP);
if (Byteable.class.isAssignableFrom(model.valueType))
typeBuilder.addSuperinterface(HeapByteable.class);
valueBuilder.closeConstructorsAndInitializationBlocks();
TypeSpec heapType = typeBuilder.build();
String result = JavaFile
.builder(model.valueType.getPackage().getName(), heapType)
.build()
.toString();
if (Jvm.getBoolean("chronicle.values.dumpCode"))
System.out.println(result);
return result;
}
static MethodSpec.Builder methodBuilder(Method m, List paramNames) {
MethodSpec.Builder builder = MethodSpec.methodBuilder(m.getName())
.addAnnotation(Override.class)
.addModifiers(PUBLIC);
builder.returns(m.getReturnType());
Parameter[] parameters = m.getParameters();
for (int i = 0; i < parameters.length; i++) {
Parameter p = parameters[i];
builder.addParameter(ParameterSpec.builder(p.getType(), paramNames.get(i)).build());
}
return builder;
}
private enum ImplType {
HEAP {
@Override
MemberGenerator getMemberGenerator(FieldModel fieldModel) {
return fieldModel.heapGenerator();
}
},
NATIVE {
@Override
MemberGenerator getMemberGenerator(FieldModel fieldModel) {
return fieldModel.nativeGenerator();
}
};
abstract MemberGenerator getMemberGenerator(FieldModel fieldModel);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy