/*
* JBoss, Home of Professional Open Source.
* Copyright 2015, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This 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 2.1 of
* the License, or (at your option) any later version.
*
* This software 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 software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.wildfly.clustering.marshalling.spi;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.wildfly.clustering.marshalling.Externalizer;
/**
* Various strategies for marshalling an array/collection index (i.e. an unsigned integer).
* @author Paul Ferraro
*/
public enum IndexExternalizer implements Externalizer<Integer> {
UNSIGNED_BYTE() {
@Override
public int readData(DataInput input) throws IOException {
return input.readUnsignedByte();
}
@Override
public void writeData(DataOutput output, int index) throws IOException {
if (index > (Byte.MAX_VALUE - Byte.MIN_VALUE)) {
throw new IndexOutOfBoundsException(Integer.toString(index));
}
output.writeByte(index);
}
},
UNSIGNED_SHORT() {
@Override
public int readData(DataInput input) throws IOException {
return input.readUnsignedShort();
}
@Override
public void writeData(DataOutput output, int index) throws IOException {
if (index > (Short.MAX_VALUE - Short.MIN_VALUE)) {
throw new IndexOutOfBoundsException(Integer.toString(index));
}
output.writeShort(index);
}
},
INTEGER() {
@Override
public int readData(DataInput input) throws IOException {
return input.readInt();
}
@Override
public void writeData(DataOutput output, int index) throws IOException {
output.writeInt(index);
}
},
/**
* Reads/write an unsigned integer using a variable-length format.
* Format requires between 1 and 5 bytes, depending on the index size.
* Smaller values require fewer bytes.
* Logic lifted directly from org.infinispan.commons.io.UnsignedNumeric.
* @author Manik Surtani
*/
VARIABLE() {
@Override
public int readData(DataInput input) throws IOException {
byte b = input.readByte();
int i = b & 0x7F;
for (int shift = 7; (b & 0x80) != 0; shift += 7) {
b = input.readByte();
i |= (b & 0x7FL) << shift;
}
return i;
}
@Override
public void writeData(DataOutput output, int index) throws IOException {
int i = index;
while ((i & ~0x7F) != 0) {
output.writeByte((byte) ((i & 0x7f) | 0x80));
i >>>= 7;
}
output.writeByte((byte) i);
}
},
;
/**
* Returns the most efficient externalizer for a given index size.
* @param size the size of the index
* @return an index externalizer
*/
public static final IndexExternalizer select(int size) {
if (size <= (Byte.MAX_VALUE - Byte.MIN_VALUE)) return UNSIGNED_BYTE;
if (size <= (Short.MAX_VALUE - Short.MIN_VALUE)) return UNSIGNED_SHORT;
return VARIABLE;
}
/**
* Read an index from the specified input stream.
* @param input a data input stream
* @return the index
* @throws IOException if an I/O error occurs
*/
public abstract int readData(DataInput input) throws IOException;
/**
* Writes the specified index to the specified output stream
* @param output the data output stream
* @param index the index
* @throws IOException if an I/O error occurs
*/
public abstract void writeData(DataOutput output, int index) throws IOException;
@Override
public Integer readObject(ObjectInput input) throws IOException {
return Integer.valueOf(this.readData(input));
}
@Override
public void writeObject(ObjectOutput output, Integer index) throws IOException {
assert index != null;
this.writeData(output, index.intValue());
}
@Override
public Class<Integer> getTargetClass() {
return Integer.class;
}
}