private static byte[] createBitCompactedArray( ShortArray type, Object array, int offsetBytes ) { Class<?> componentType = array.getClass().getComponentType(); boolean isPrimitiveByteArray = componentType.equals( Byte.TYPE ); boolean isByteArray = componentType.equals( Byte.class ) || isPrimitiveByteArray; int arrayLength = Array.getLength( array ); int requiredBits = isByteArray ? Byte.SIZE : type.calculateRequiredBitsForArray( array, arrayLength ); int totalBits = requiredBits * arrayLength; int bitsUsedInLastByte = totalBits % 8; bitsUsedInLastByte = bitsUsedInLastByte == 0 ? 8 : bitsUsedInLastByte; if ( isByteArray ) { return createBitCompactedByteArray( type, isPrimitiveByteArray, array, bitsUsedInLastByte, requiredBits, offsetBytes ); } else { int numberOfBytes = (totalBits - 1) / 8 + 1; numberOfBytes += NUMBER_HEADER_SIZE; // type + rest + requiredBits header. TODO no need to use full bytes Bits bits = Bits.bits( numberOfBytes ); bits.put( (byte) type.intValue() ); bits.put( (byte) bitsUsedInLastByte ); bits.put( (byte) requiredBits ); type.writeAll( array, arrayLength, requiredBits, bits ); return bits.asBytes( offsetBytes ); } }
public static Long readOwnerFromDynamicLabelsRecord( DynamicRecord record ) { byte[] data = record.getData(); byte[] header = PropertyType.ARRAY.readDynamicRecordHeader( data ); byte[] array = Arrays.copyOfRange( data, header.length, data.length ); int requiredBits = header[2]; if ( requiredBits == 0 ) { return null; } Bits bits = Bits.bitsFromBytes( array ); return bits.getLong( requiredBits ); }
public static Value decode( Bits bits ) { // [][][ ,bbbb][bbll,llll][yyyy,tttt][kkkk,kkkk][kkkk,kkkk][kkkk,kkkk] bits.getInt( 24 ); // Get rid of key bits.getByte( 4 ); // Get rid of short array type int typeId = bits.getByte( 4 ); int arrayLength = bits.getByte(6); int requiredBits = bits.getByte( 6 ); /* * So, it can be the case that values require 64 bits to store. However, you cannot encode this * value with 6 bits. calculateRequiredBitsForArray never returns 0, because even for an array of * all 0s one bit is required for every value. So when writing, we let it overflow and write out * 0. When we are reading back, we just have to make sure that reading in 0 means 64. */ if ( requiredBits == 0 ) { requiredBits = 64; } ShortArray type = typeOf( (byte)typeId ); return type.createArray(arrayLength, bits, requiredBits); }
public Bits put( byte value ) { return put( value, Byte.SIZE ); }
@Test public void doubleAsBytes() { double[] array1 = new double[] { 1.0, 2.0, 3.0, 4.0, 5.0 }; Bits bits = Bits.bits( array1.length * 8 ); for ( double value : array1 ) { bits.put( Double.doubleToRawLongBits( value ) ); } String first = bits.toString(); byte[] asBytes = bits.asBytes(); String other = Bits.bitsFromBytes( asBytes ).toString(); assertEquals( first, other ); }
@Test public void writeAndRead() { for ( int b = 5; b <= 8; b++ ) { Bits bits = Bits.bits( 16 ); for ( byte value = 0; value < 16; value++ ) { bits.put( value, b ); } for ( byte expected = 0; bits.available(); expected++ ) { assertEquals( expected, bits.getByte( b ) ); } } for ( byte value = Byte.MIN_VALUE; value < Byte.MAX_VALUE; value++ ) { Bits bits = Bits.bits( 8 ); bits.put( value ); assertEquals( value, bits.getByte() ); } }
public static long versionStringToLong( String storeVersion ) { if ( CommonAbstractStore.UNKNOWN_VERSION.equals( storeVersion ) ) { return -1; } Bits bits = Bits.bits( 8 ); int length = storeVersion.length(); if ( length == 0 || length > 7 ) { throw new IllegalArgumentException( format( "The given string %s is not of proper size for a store version string", storeVersion ) ); } bits.put( length, 8 ); for ( int i = 0; i < length; i++ ) { char c = storeVersion.charAt( i ); if ( c >= 256 ) { throw new IllegalArgumentException( format( "Store version strings should be encode-able as Latin1 - %s is not", storeVersion ) ); } bits.put( c, 8 ); // Just the lower byte } return bits.getLong(); }
putClient.labelBits.clear( true ); putClient.labelBits.put( labelIds.length, bitsPerLabel ); for ( long labelId : labelIds ) putClient.labelBits.put( (int) labelId, bitsPerLabel ); int longsInUse = putClient.labelBits.longsInUse(); assert longsInUse > 0 : "Uhm"; if ( longsInUse == 1 ) putClient.fieldBits.clear( true ); putClient.fieldBits.put( labelIds.length, bitsPerLabel ); putClient.fieldBits.put( spillOverIndex, Long.SIZE - bitsPerLabel ); cache.set( nodeId, putClient.fieldBits.getLongs()[0] );
if ( Bits.requiredLongs( numberOfBytes ) > PropertyType.getPayloadSizeLongs() ) Bits result = Bits.bits( numberOfBytes ); target.setValueBlocks( result.getLongs() ); return true;
private static boolean encodeUTF8( int keyId, String string, PropertyBlock target, int payloadSize ) { byte[] bytes = string.getBytes( StandardCharsets.UTF_8 ); final int length = bytes.length; if ( length > payloadSize - 3/*key*/ - 2/*enc+len*/ ) { return false; } Bits bits = newBitsForStep8(length); writeHeader( bits, keyId, ENCODING_UTF8, length); // In this case it isn't the string length, but the number of bytes for ( byte value : bytes ) { bits.put( value ); } target.setValueBlocks( bits.getLongs() ); return true; }
static boolean tryInlineInNodeRecord( NodeRecord node, long[] ids, Collection<DynamicRecord> changedDynamicRecords ) { // We reserve the high header bit for future extensions of the format of the in-lined label bits // i.e. the 0-valued high header bit can allow for 0-7 in-lined labels in the bit-packed format. if ( ids.length > 7 ) { return false; } byte bitsPerLabel = (byte) (ids.length > 0 ? (LABEL_BITS / ids.length) : LABEL_BITS); Bits bits = bits( 5 ); if ( !inlineValues( ids, bitsPerLabel, bits ) ) { return false; } node.setLabelField( combineLabelCountAndLabelStorage( (byte) ids.length, bits.getLongs()[0] ), changedDynamicRecords ); return true; }
private static boolean encodeLatin1( int keyId, String string, PropertyBlock target ) { int length = string.length(); Bits bits = newBitsForStep8(length); writeHeader( bits, keyId, ENCODING_LATIN1, length ); if ( !writeLatin1Characters( string, bits ) ) { return false; } target.setValueBlocks( bits.getLongs() ); return true; }
private static Bits newBitsForStep8( int length ) { return Bits.bits(calculateNumberOfBlocksUsedForStep8(length) << 3 ); //*8 }
public int getInt( int steps ) { return (int) getLong( steps ); }
public byte getByte() { return getByte( Byte.SIZE ); }
client.fieldBits.clear( false ); client.fieldScratch[0] = cache.get( nodeId ); if ( client.fieldScratch[0] == 0 ) int length = client.fieldBits.getInt( bitsPerLabel ); int longsInUse = ((bitsPerLabel * (length + 1)) - 1) / Long.SIZE + 1; target = ensureCapacity( target, length ); long spillOverIndex = client.fieldBits.getLong( Long.SIZE - bitsPerLabel ); client.labelBits.clear( false ); for ( int i = 0; i < longsInUse; i++ ) client.labelBits.getInt( bitsPerLabel ); // first one ignored, since it's just the length decode( client.labelBits, length, target );
public static Bits bitsFromBytes( byte[] bytes ) { return bitsFromBytes( bytes, 0 ); }
public static long[] parseInlined( long labelField ) { byte numberOfLabels = labelCount( labelField ); if ( numberOfLabels == 0 ) { return EMPTY_LONG_ARRAY; } long existingLabelsField = parseLabelsBody( labelField ); byte bitsPerLabel = (byte) (LABEL_BITS / numberOfLabels); Bits bits = bitsFromLongs( new long[]{existingLabelsField} ); long[] result = new long[numberOfLabels]; for ( int i = 0; i < result.length; i++ ) { result[i] = bits.getLong( bitsPerLabel ); } return result; }