/* * Copyright (C) 2015, 2016 higherfrequencytrading.com * Copyright (C) 2016 Roman Leventov * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package net.openhft.chronicle.values; import com.squareup.javapoet.MethodSpec; import static java.lang.String.format; class BooleanFieldModel extends PrimitiveFieldModel { @Override int offsetAlignmentInBytes() { if (offsetAlignment == Align.DEFAULT) { throw new IllegalStateException("Default offset alignment doesn't make sense for " + "boolean field " + name); } return offsetAlignment; } @Override int dontCrossAlignmentInBytes() { if (dontCrossAlignment == Align.DEFAULT) { throw new IllegalStateException("Default dontCross alignment doesn't make sense for " + "boolean field " + name); } return dontCrossAlignment; } private MemberGenerator nativeGenerator = new MemberGenerator(BooleanFieldModel.this) { @Override void generateArrayElementFields( ArrayFieldModel arrayFieldModel, ValueBuilder valueBuilder) { // no fields } @Override void generateGet(ValueBuilder valueBuilder, MethodSpec.Builder methodBuilder) { get(valueBuilder, methodBuilder, ""); } private void get( ValueBuilder valueBuilder, MethodSpec.Builder methodBuilder, String readType) { int bitOffset = valueBuilder.model.fieldBitOffset(BooleanFieldModel.this); int byteOffset = bitOffset / 8; int bitShift = bitOffset & 7; methodBuilder.addStatement("return (bs.read$NByte(offset + $L) & (1 << $L)) != 0", readType, byteOffset, bitShift); } @Override void generateArrayElementGet( ArrayFieldModel arrayFieldModel, ValueBuilder valueBuilder, MethodSpec.Builder methodBuilder) { arrayElementGet(arrayFieldModel, valueBuilder, methodBuilder, ""); } private void arrayElementGet( ArrayFieldModel arrayFieldModel, ValueBuilder valueBuilder, MethodSpec.Builder methodBuilder, String readType) { arrayFieldModel.checkBounds(methodBuilder); int arrayBitOffset = valueBuilder.model.fieldBitOffset(arrayFieldModel); methodBuilder.addStatement("int bitOffset = $L + index", arrayBitOffset); methodBuilder.addStatement("int byteOffset = bitOffset / 8"); methodBuilder.addStatement("int bitShift = bitOffset & 7"); methodBuilder.addStatement( "return (bs.read$NByte(offset + byteOffset) & (1 << bitShift)) != 0", readType); } @Override void generateGetVolatile(ValueBuilder valueBuilder, MethodSpec.Builder methodBuilder) { get(valueBuilder, methodBuilder, "Volatile"); } @Override void generateArrayElementGetVolatile( ArrayFieldModel arrayFieldModel, ValueBuilder valueBuilder, MethodSpec.Builder methodBuilder) { arrayElementGet(arrayFieldModel, valueBuilder, methodBuilder, "Volatile"); } @Override void generateSet(ValueBuilder valueBuilder, MethodSpec.Builder methodBuilder) { set(valueBuilder, methodBuilder, "", ""); } private void set( ValueBuilder valueBuilder, MethodSpec.Builder methodBuilder, String readType, String writeType) { int bitOffset = valueBuilder.model.fieldBitOffset(BooleanFieldModel.this); int byteOffset = bitOffset / 8; int bitShift = bitOffset & 7; methodBuilder.addStatement("int b = bs.read$NByte(offset + $L)", readType, byteOffset); methodBuilder.beginControlFlow("if ($N)", varName()); methodBuilder.addStatement("b |= (1 << $L)", bitShift); methodBuilder.nextControlFlow("else"); methodBuilder.addStatement("b &= ~(1 << $L)", bitShift); methodBuilder.endControlFlow(); methodBuilder.addStatement("bs.write$NByte(offset + $L, (byte) b)", writeType, byteOffset); } @Override void generateArrayElementSet( ArrayFieldModel arrayFieldModel, ValueBuilder valueBuilder, MethodSpec.Builder methodBuilder) { arrayFieldModel.checkBounds(methodBuilder); arrayElementSet(arrayFieldModel, valueBuilder, methodBuilder, "", ""); } private void arrayElementSet (ArrayFieldModel arrayFieldModel, ValueBuilder valueBuilder, MethodSpec.Builder methodBuilder, String readType, String writeType) { int arrayBitOffset = valueBuilder.model.fieldBitOffset(arrayFieldModel); methodBuilder.addStatement("int bitOffset = $L + index", arrayBitOffset); methodBuilder.addStatement("int byteOffset = bitOffset / 8"); methodBuilder.addStatement("int bitShift = bitOffset & 7"); methodBuilder.addStatement("int b = bs.read$NByte(offset + byteOffset)", readType); methodBuilder.beginControlFlow("if ($N)", varName()); methodBuilder.addStatement("b |= (1 << bitShift)"); methodBuilder.nextControlFlow("else"); methodBuilder.addStatement("b &= ~(1 << bitShift)"); methodBuilder.endControlFlow(); methodBuilder.addStatement("bs.write$NByte(offset + byteOffset, (byte) b)", writeType); } @Override void generateSetVolatile(ValueBuilder valueBuilder, MethodSpec.Builder methodBuilder) { set(valueBuilder, methodBuilder, "Volatile", "Volatile"); } @Override void generateArrayElementSetVolatile( ArrayFieldModel arrayFieldModel, ValueBuilder valueBuilder, MethodSpec.Builder methodBuilder) { arrayFieldModel.checkBounds(methodBuilder); arrayElementSet(arrayFieldModel, valueBuilder, methodBuilder, "Volatile", "Volatile"); } @Override void generateSetOrdered(ValueBuilder valueBuilder, MethodSpec.Builder methodBuilder) { int bitOffset = valueBuilder.model.fieldBitOffset(BooleanFieldModel.this); int byteOffset = bitOffset / 8; methodBuilder.addStatement("long byteOffset = (offset + $L) & ~3L", byteOffset); methodBuilder.addStatement("int bitShift = (int) (((offset * 8) + $L) & 31)", bitOffset); endSetOrdered(methodBuilder); } private void endSetOrdered(MethodSpec.Builder methodBuilder) { methodBuilder.addStatement("int i = bs.readVolatileInt(byteOffset)"); methodBuilder.beginControlFlow("if ($N)", varName()); methodBuilder.addStatement("i |= (1 << bitShift)"); methodBuilder.nextControlFlow("else"); methodBuilder.addStatement("i &= ~(1 << bitShift)"); methodBuilder.endControlFlow(); methodBuilder.addStatement("bs.writeOrderedInt(byteOffset, i)"); } @Override void generateArrayElementSetOrdered( ArrayFieldModel arrayFieldModel, ValueBuilder valueBuilder, MethodSpec.Builder methodBuilder) { arrayFieldModel.checkBounds(methodBuilder); int arrayBitOffset = valueBuilder.model.fieldBitOffset(arrayFieldModel); methodBuilder.addStatement("long bitOffset = (offset * 8) + $L + index", arrayBitOffset); methodBuilder.addStatement("long byteOffset = (bitOffset / 32) * 4"); methodBuilder.addStatement("int bitShift = (int) ((bitOffset + $L) & 31)"); endSetOrdered(methodBuilder); } @Override void generateCompareAndSwap(ValueBuilder valueBuilder, MethodSpec.Builder methodBuilder) { int bitOffset = valueBuilder.model.fieldBitOffset(BooleanFieldModel.this); int byteOffset = bitOffset / 8; methodBuilder.addStatement("long byteOffset = (offset + $L) & ~3L", byteOffset); methodBuilder.addStatement("int bitShift = (int) (((offset * 8) + $L) & 31)", bitOffset); endCompareAndSwap(methodBuilder); } private void endCompareAndSwap(MethodSpec.Builder methodBuilder) { methodBuilder.addStatement("int i = bs.readVolatileInt(byteOffset), x"); methodBuilder.beginControlFlow("if ($N)", newName()); methodBuilder.addStatement("x = i | (1 << bitShift)"); methodBuilder.nextControlFlow("else"); methodBuilder.addStatement("x = i & ~(1 << bitShift)"); methodBuilder.endControlFlow(); methodBuilder.beginControlFlow("if ($N == $N)", oldName(), newName()); methodBuilder.addCode("if (i != x) return false;\n"); methodBuilder.nextControlFlow("else"); methodBuilder.addCode("if (i == x) return false;\n"); methodBuilder.endControlFlow(); methodBuilder.addStatement("return bs.compareAndSwapInt(byteOffset, i, x)"); } @Override void generateArrayElementCompareAndSwap( ArrayFieldModel arrayFieldModel, ValueBuilder valueBuilder, MethodSpec.Builder methodBuilder) { arrayFieldModel.checkBounds(methodBuilder); int arrayBitOffset = valueBuilder.model.fieldBitOffset(arrayFieldModel); methodBuilder.addStatement("long bitOffset = (offset * 8) + $L + index", arrayBitOffset); methodBuilder.addStatement("long byteOffset = (bitOffset / 32) * 4"); methodBuilder.addStatement("int bitShift = (int) ((bitOffset + $L) & 31)"); endCompareAndSwap(methodBuilder); } @Override void generateCopyFrom(ValueBuilder valueBuilder, MethodSpec.Builder methodBuilder) { String from = format("from.%s()", getOrGetVolatile().getName()); copyFrom(valueBuilder, methodBuilder, from); } private void copyFrom( ValueBuilder valueBuilder, MethodSpec.Builder methodBuilder, String from) { if (set != null) { methodBuilder.addStatement("$N($N)", set.getName(), from); } else { methodBuilder.addStatement("boolean $N = $N", varName(), from); set(valueBuilder, methodBuilder, "", ""); } } @Override void generateArrayElementCopyFrom( ArrayFieldModel arrayFieldModel, ValueBuilder valueBuilder, MethodSpec.Builder methodBuilder) { String from = format("from.%s(index)", arrayFieldModel.getOrGetVolatile().getName()); arrayElementCopyFrom(arrayFieldModel, valueBuilder, methodBuilder, from); } private void arrayElementCopyFrom( ArrayFieldModel arrayFieldModel, ValueBuilder valueBuilder, MethodSpec.Builder methodBuilder, String from) { if (arrayFieldModel.set != null) { methodBuilder.addStatement("$N(index, $N)", arrayFieldModel.set.getName(), from); } else { methodBuilder.addStatement("boolean $N = $N", varName(), from); arrayElementSet(arrayFieldModel, valueBuilder, methodBuilder, "", ""); } } @Override void generateReadMarshallable(ValueBuilder valueBuilder, MethodSpec.Builder methodBuilder) { copyFrom(valueBuilder, methodBuilder, "bytes.readBoolean()"); } @Override void generateArrayElementReadMarshallable( ArrayFieldModel arrayFieldModel, ValueBuilder valueBuilder, MethodSpec.Builder methodBuilder) { arrayElementCopyFrom(arrayFieldModel, valueBuilder, methodBuilder, "bytes.readBoolean()"); } @Override void generateEquals(ValueBuilder valueBuilder, MethodSpec.Builder methodBuilder) { methodBuilder.addCode("if ($N() != other.$N()) return false;\n", getOrGetVolatile().getName(), getOrGetVolatile().getName()); } @Override void generateArrayElementEquals( ArrayFieldModel arrayFieldModel, ValueBuilder valueBuilder, MethodSpec.Builder methodBuilder) { String get = arrayFieldModel.getOrGetVolatile().getName(); methodBuilder.addCode("if ($N(index) != other.$N(index)) return false;\n", get, get); } @Override String generateHashCode(ValueBuilder valueBuilder, MethodSpec.Builder methodBuilder) { return format("Boolean.hashCode(%s())", getOrGetVolatile().getName()); } @Override String generateArrayElementHashCode( ArrayFieldModel arrayFieldModel, ValueBuilder valueBuilder, MethodSpec.Builder methodBuilder) { return format("Boolean.hashCode(%s(index))", arrayFieldModel.getOrGetVolatile().getName()); } }; @Override MemberGenerator nativeGenerator() { return nativeGenerator; } @Override MemberGenerator createHeapGenerator() { return new PrimitiveBackedHeapMemberGenerator(this) { }; } }