Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
net.openhft.chronicle.values.ArrayFieldModel 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.MethodSpec;
import net.openhft.chronicle.core.Maths;
import org.jetbrains.annotations.NotNull;
import java.lang.reflect.Method;
import static net.openhft.chronicle.values.Utils.roundUp;
public class ArrayFieldModel extends FieldModel {
private final ScalarFieldModel elemModel;
Array array;
private MemberGenerator nativeGenerator;
public ArrayFieldModel(ScalarFieldModel elemModel) {
this.elemModel = elemModel;
}
@Override
void addLayoutInfo(Method m, MethodTemplate template) {
super.addLayoutInfo(m, template);
Array array = m.getAnnotation(Array.class);
if (array != null) {
if (this.array != null) {
throw new IllegalStateException("@Array should be specified only once for " + name +
" field. Specified " + this.array + " and " + array);
}
if (array.length() <= 1)
throw new IllegalStateException(array + ": length should be > 1, field " + name);
this.array = array;
int elementOffsetAlignment = array.elementOffsetAlignment();
if (elementOffsetAlignment == Align.DEFAULT && !(elemModel instanceof ValueFieldModel))
elementOffsetAlignment = Align.NO_ALIGNMENT;
elemModel.setOffsetAlignmentExplicitly(elementOffsetAlignment);
elemModel.dontCrossAlignment = array.elementDontCrossAlignment();
}
}
@Override
int sizeInBits() {
int elemSizeInBits = elemModel.sizeInBits();
int elemBitExtent = elemBitExtent();
int elemDontCrossBits = elemModel.dontCrossAlignmentInBits();
if (elemBitExtent <= elemDontCrossBits) {
// A power of 2, for fast index computation
int elemsInOneAlignment = 1 << Maths.intLog2(elemDontCrossBits / elemBitExtent);
return (array.length() / elemsInOneAlignment) * elemDontCrossBits +
((array.length() % elemsInOneAlignment) - 1) * elemBitExtent +
elemSizeInBits;
} else {
assert elemDontCrossBits == Align.NO_ALIGNMENT : "" + elemDontCrossBits;
return elemBitExtent * (array.length() - 1) + elemSizeInBits;
}
}
int elemBitExtent() {
return roundUp(elemModel.sizeInBits(), elemModel.offsetAlignmentInBits());
}
@Override
int offsetAlignmentInBytes() {
int elementAlignment = elemModel.maxAlignmentInBytes();
if (offsetAlignment == Align.DEFAULT) {
return elementAlignment;
}
if (offsetAlignment == 0 && elementAlignment > 0) {
// Special case, to avoid ISE below, because offset alignment of 1 of the element model
// could be implicit (element is CharSequence or another value)
return elementAlignment;
}
if (offsetAlignment < elementAlignment ||
(elementAlignment > 0 && offsetAlignment % elementAlignment != 0)) {
throw new IllegalStateException("Alignment of the array field " + name +
" " + offsetAlignment + " must be a multiple of it's element alignment " +
elementAlignment +
" (offset alignment is " + elemModel.offsetAlignmentInBytes() +
", dontCross alignment is " + elemModel.dontCrossAlignmentInBytes());
}
return offsetAlignment;
}
@Override
void postProcess() {
super.postProcess();
elemModel.postProcess();
}
@Override
void checkState() {
super.checkState();
elemModel.checkState();
}
@NotNull
private ArrayFieldModel self() {
return ArrayFieldModel.this;
}
@Override
MemberGenerator nativeGenerator() {
if (nativeGenerator == null)
nativeGenerator = new ArrayMemberGenerator(this, elemModel.nativeGenerator());
return nativeGenerator;
}
@Override
MemberGenerator createHeapGenerator() {
return new ArrayMemberGenerator(this, elemModel.heapGenerator());
}
void checkBounds(MethodSpec.Builder methodBuilder) {
methodBuilder.beginControlFlow("if (index < 0 || index >= $L)", array.length());
methodBuilder.addStatement("throw new $T(index + $S)",
ArrayIndexOutOfBoundsException.class,
" is out of bounds, array length " + array.length());
methodBuilder.endControlFlow();
}
public Array array() {
return array;
}
private class ArrayMemberGenerator extends MemberGenerator {
private final MemberGenerator elemGenerator;
private ArrayMemberGenerator(FieldModel fieldModel, MemberGenerator elemGenerator) {
super(fieldModel);
this.elemGenerator = elemGenerator;
}
@Override
public void generateFields(ValueBuilder valueBuilder) {
elemGenerator.generateArrayElementFields(self(), valueBuilder);
}
@Override
public void generateGet(ValueBuilder valueBuilder, MethodSpec.Builder methodBuilder) {
elemGenerator.generateArrayElementGet(self(), valueBuilder, methodBuilder);
}
@Override
public void generateGetVolatile(
ValueBuilder valueBuilder, MethodSpec.Builder methodBuilder) {
elemGenerator.generateArrayElementGetVolatile(self(), valueBuilder, methodBuilder);
}
@Override
public void generateGetUsing(ValueBuilder valueBuilder, MethodSpec.Builder methodBuilder) {
elemGenerator.generateArrayElementGetUsing(self(), valueBuilder, methodBuilder);
}
@Override
public void generateSet(ValueBuilder valueBuilder, MethodSpec.Builder methodBuilder) {
elemGenerator.generateArrayElementSet(self(), valueBuilder, methodBuilder);
}
@Override
public void generateSetVolatile(
ValueBuilder valueBuilder, MethodSpec.Builder methodBuilder) {
elemGenerator.generateArrayElementSetVolatile(self(), valueBuilder, methodBuilder);
}
@Override
public void generateSetOrdered(
ValueBuilder valueBuilder, MethodSpec.Builder methodBuilder) {
elemGenerator.generateArrayElementSetOrdered(self(), valueBuilder, methodBuilder);
}
@Override
public void generateAdd(ValueBuilder valueBuilder, MethodSpec.Builder methodBuilder) {
elemGenerator.generateArrayElementAdd(self(), valueBuilder, methodBuilder);
}
@Override
public void generateAddAtomic(ValueBuilder valueBuilder, MethodSpec.Builder methodBuilder) {
elemGenerator.generateArrayElementAddAtomic(self(), valueBuilder, methodBuilder);
}
@Override
public void generateCompareAndSwap(
ValueBuilder valueBuilder, MethodSpec.Builder methodBuilder) {
elemGenerator.generateArrayElementCompareAndSwap(self(), valueBuilder, methodBuilder);
}
@Override
public void generateCopyFrom(ValueBuilder valueBuilder, MethodSpec.Builder methodBuilder) {
beginLoop(methodBuilder);
elemGenerator.generateArrayElementCopyFrom(self(), valueBuilder, methodBuilder);
methodBuilder.endControlFlow();
}
private void beginLoop(MethodSpec.Builder methodBuilder) {
methodBuilder.beginControlFlow("for (int index = 0; index < $L; index++)",
array.length());
}
@Override
void generateWriteMarshallable(
ValueBuilder valueBuilder, MethodSpec.Builder methodBuilder) {
beginLoop(methodBuilder);
elemGenerator.generateArrayElementWriteMarshallable(
self(), valueBuilder, methodBuilder);
methodBuilder.endControlFlow();
}
@Override
void generateArrayElementWriteMarshallable(
ArrayFieldModel arrayFieldModel, ValueBuilder valueBuilder,
MethodSpec.Builder methodBuilder) {
throw new UnsupportedOperationException();
}
@Override
void generateReadMarshallable(ValueBuilder valueBuilder, MethodSpec.Builder methodBuilder) {
beginLoop(methodBuilder);
elemGenerator.generateArrayElementReadMarshallable(self(), valueBuilder, methodBuilder);
methodBuilder.endControlFlow();
}
@Override
void generateEquals(ValueBuilder valueBuilder, MethodSpec.Builder methodBuilder) {
beginLoop(methodBuilder);
elemGenerator.generateArrayElementEquals(self(), valueBuilder, methodBuilder);
methodBuilder.endControlFlow();
}
/**
* Copies google/auto value's strategy of hash code generation
*/
@Override
String generateHashCode(ValueBuilder valueBuilder, MethodSpec.Builder methodBuilder) {
String hashCodeVarName = varName() + "HashCode";
methodBuilder.addStatement("int $N = 1", hashCodeVarName);
beginLoop(methodBuilder);
methodBuilder.addStatement("$N *= 1000003", hashCodeVarName);
String elemHashCode = elemGenerator.generateArrayElementHashCode(
self(), valueBuilder, methodBuilder);
methodBuilder.addStatement("$N ^= $N", hashCodeVarName, elemHashCode);
methodBuilder.endControlFlow();
return hashCodeVarName;
}
@Override
void generateToString(ValueBuilder valueBuilder, MethodSpec.Builder methodBuilder) {
methodBuilder.addStatement("sb.append($S)", ", " + fieldModel.name + "=[");
beginLoop(methodBuilder);
elemGenerator.generateArrayElementToString(self(), valueBuilder, methodBuilder);
methodBuilder.endControlFlow();
methodBuilder.addStatement("sb.setCharAt(sb.length() - 2, ']')");
methodBuilder.addStatement("sb.setLength(sb.length() - 1)");
}
@Override
void generateArrayElementToString(
ArrayFieldModel arrayFieldModel, ValueBuilder valueBuilder,
MethodSpec.Builder methodBuilder) {
throw new UnsupportedOperationException();
}
}
}