/**
* Copyright 2014 National University of Ireland, Galway.
*
* This file is part of the SIREn project. Project and contact information:
*
* https://github.com/rdelbru/SIREn
*
* 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 org.sindice.siren.index.codecs.block;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
/**
* This class is used to generate {@link AForFrameDecompressor}.
*/
public class AForFrameDecompressorGenerator {
private FileWriter writer;
public static final int[] frameSizes = new int[99];
private final int[] MASK = { 0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000f, 0x0000001f, 0x0000003f,
0x0000007f, 0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff, 0x00001fff,
0x00003fff, 0x00007fff, 0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff, 0x000fffff,
0x001fffff, 0x003fffff, 0x007fffff, 0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff,
0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffff };
public AForFrameDecompressorGenerator() throws IOException {
this.generateFrameSizeTable();
}
protected void generateFrameSizeTable() throws IOException {
int frameSize = 0;
frameSizes[0] = 0;
for (int i = 1; i <= 32; i++) {
frameSize += 4;
frameSizes[i] = frameSize;
}
frameSizes[33] = 0;
frameSize = 0;
for (int i = 1; i <= 32; i++) {
frameSize += 2;
frameSizes[i+33] = frameSize;
}
frameSizes[66] = 0;
for (int i = 1; i <= 32; i++) {
frameSizes[i+66] = i;
}
}
public void generate(final File file) throws IOException {
writer = new FileWriter(file);
writer.append(FILE_HEADER); writer.append('\n');
this.generateClass();
writer.close();
}
protected void generateClass() throws IOException {
writer.append("/**\n");
writer.append(" * This class contains a lookup table of functors for decompressing fames.\n");
writer.append(" */\n");
writer.append("public class AForFrameDecompressor {\n\n");
this.generateTable();
this.generateAbstractInnerClass();
for (int i = 0; i < 99; i++) {
this.generateInnerClass(i);
}
writer.append("}\n");
}
protected void generateTable() throws IOException {
writer.append(" public static final FrameDecompressor[] decompressors = new FrameDecompressor[] {\n");
for (int i = 0; i < 99; i++) {
writer.append(" new FrameDecompressor"+i+"(),\n");
}
writer.append(" };\n\n");
}
protected void generateAbstractInnerClass() throws IOException {
writer.append(" static abstract class FrameDecompressor {\n");
writer.append(" public abstract void decompress(final BytesRef input, final IntsRef output);\n");
writer.append(" }\n\n");
}
protected void generateInnerClass(final int numFramebits) throws IOException {
writer.append(" static final class FrameDecompressor" + Integer.toString(numFramebits) + " extends FrameDecompressor {\n");
this.generateMethod(numFramebits);
writer.append(" }\n\n");
}
private void zeros(final int numFrameBits)
throws IOException {
final int nb;
if (numFrameBits <= 32)
nb = 32;
else if (numFrameBits <= 65)
nb = 16;
else
nb = 8;
writer.append(" ");
writer.append("final int[] unCompressedData = output.ints;\n");
writer.append(" ");
writer.append("final int outOffset = output.offset;\n");
for (int i = 0; i < nb; i++) {
writer.append(" ");
writer.append("unCompressedData[outOffset" + ((i == 0) ? "" : " + " +i) + "] = 0;\n");
}
writer.append(" output.offset += " + nb + ";\n");
writer.append(" input.offset += 1;\n");
writer.append(" }\n");
}
private void generate816Routines(final int numFrameBits) throws IOException {
for (int i = 0, j = 0; j < 16; ) {
if (i == 0)
writer.append(" unCompressedData[outOffset] = " + (numFrameBits == 8 ? "compressedArray[inOffset] & 0xFF" :
"((compressedArray[inOffset] & 0xFF) << 8) | (compressedArray[inOffset + 1] & 0xFF)") + ";\n");
else
writer.append(" unCompressedData[outOffset + " + j + "] = " + (numFrameBits == 8 ? "compressedArray[inOffset + " + i + "] & 0xFF" :
"((compressedArray[inOffset + " + i + "] & 0xFF) << 8) | (compressedArray[inOffset + " + (i+1) +"] & 0xFF)") + ";\n");
if (numFrameBits == 16)
i += 2;
else
i++;
j++;
}
this.generateMethodFooter(numFrameBits + 33);
writer.append(" }\n");
}
protected void generateMethod(final int numFrameBits) throws IOException {
writer.append(" public final void decompress(final BytesRef input, final IntsRef output) {\n");
// Zeros case
if (numFrameBits == 0 || numFrameBits == 33 || numFrameBits == 66) {
this.zeros(numFrameBits);
return;
}
this.generateMethodHeader(numFrameBits);
// for bits < 7, use byte variables
if (numFrameBits < 41 && numFrameBits > 33) {
this.generate1To7Routines(numFrameBits - 33);
writer.append(" }\n");
return;
}
// 8 and 16 BFS special case
if (numFrameBits == 41 || numFrameBits == 49) {
this.generate816Routines(numFrameBits - 33);
return;
}
if (numFrameBits <= 32)
this.generateIntValues(numFrameBits);
else if (numFrameBits <= 65)
this.generateShortValues(numFrameBits - 33);
else
this.generateByteValues(numFrameBits - 66);
if (numFrameBits <= 32)
this.generateInstructions32(numFrameBits);
else if (numFrameBits <= 65)
this.generateInstructions16(numFrameBits - 33);
else
this.generateInstructions8(numFrameBits - 66);
this.generateMethodFooter(numFrameBits);
writer.append(" }\n");
}
private void generate1To7Routines(final int numFrameBits)
throws IOException {
final int mask = (1 << numFrameBits) - 1;
int shift = 8;
int bytePtr = 0, intPtr = 0;
this.generateByteValues(numFrameBits*2);
while (intPtr != 16) { // while we didn't process 16 integers
while (shift >= numFrameBits) {
shift -= numFrameBits;
writer.append(" ");
if (shift == 0) {
writer.append("unCompressedData[outOffset + "+intPtr+"] = i"+bytePtr+" & "+mask+";\n");
}
else {
writer.append("unCompressedData[outOffset + "+intPtr+"] = (i"+bytePtr+" >>> "+shift+") & "+mask+";\n");
}
intPtr++;
}
if (shift > 0) {
writer.append(" ");
writer.append("unCompressedData[outOffset + "+intPtr+"] = ((i"+bytePtr+" & "+((1 << shift) - 1)+") << "+(numFrameBits - shift)+")");
bytePtr++;
shift = 8 - (numFrameBits - shift);
writer.append(" | (i"+bytePtr+" >>> "+shift+") & "+((1 << (8 - shift)) - 1)+";\n");
intPtr++;
}
else {
bytePtr++;
shift = 8;
}
}
this.generateMethodFooter(numFrameBits + 33);
}
protected void generateMethodFooter(final int numFrameBits) throws IOException {
writer.append(" ");
writer.append("input.offset += " + (1 + frameSizes[numFrameBits]) + ";\n");
writer.append(" ");
if (numFrameBits <= 32)
writer.append("output.offset += 32;\n");
else if (numFrameBits <= 65)
writer.append("output.offset += 16;\n");
else
writer.append("output.offset += 8;\n");
}
protected void generateMethodHeader(final int numFrameBits) throws IOException {
writer.append(" ");
writer.append("final int[] unCompressedData = output.ints;\n");
writer.append(" ");
writer.append("final byte[] compressedArray = input.bytes;\n");
writer.append(" ");
writer.append("final int inOffset = input.offset + 1;\n");
writer.append(" ");
writer.append("final int outOffset = output.offset;\n");
}
protected void generateIntValues(final int numFrameBits) throws IOException {
for (int i = 0, j = 0; i < numFrameBits; i++, j += 4) {
writer.append(" ");
writer.append("final int i"+i+" = ((compressedArray[inOffset + "+j+"] & 0xFF) << 24) | ");
writer.append("((compressedArray[inOffset + "+(j+1)+"] & 0xFF) << 16) | ");
writer.append("((compressedArray[inOffset + "+(j+2)+"] & 0xFF) << 8) | ");
writer.append("((compressedArray[inOffset + "+(j+3)+"] & 0xFF));\n");
}
writer.append("\n");
}
protected void generateByteValues(final int numFrameBits) throws IOException {
for (int i = 0; i < numFrameBits; i++) {
writer.append(" final byte i" + i + " = compressedArray[inOffset + " + i + "];\n");
}
writer.append("\n");
}
protected void generateShortValues( final int numFrameBits )
throws IOException
{
for ( int i = 0, j = 0; i < numFrameBits; i++, j += 2 )
{
writer.append( " " );
writer.append( "final short i" + i + " = (short) (((compressedArray[inOffset + " + j + "] & 0xFF) << 8) | " );
writer.append( "((compressedArray[inOffset + " + ( j + 1 ) + "] & 0xFF)));\n" );
}
writer.append( "\n" );
}
protected void generateInstructions32(final int numFrameBits) throws IOException {
final int mask = (1 << numFrameBits) - 1;
int shift = 32;
int bytePtr = 0, intPtr = 0;
while (intPtr != 32) { // while we didn't process 32 integers
while (shift >= numFrameBits) {
shift -= numFrameBits;
writer.append(" ");
if (shift == 0 && mask != 0) {
writer.append("unCompressedData[outOffset + "+intPtr+"] = i"+bytePtr+" & "+mask+";\n");
}
else if (shift == 0 && mask == 0) {
writer.append("unCompressedData[outOffset + "+intPtr+"] = i"+bytePtr+";\n");
}
else if (shift + numFrameBits == 32) {
writer.append("unCompressedData[outOffset + "+intPtr+"] = (i"+bytePtr+" >>> "+shift+");\n");
}
else {
writer.append("unCompressedData[outOffset + "+intPtr+"] = (i"+bytePtr+" >>> "+shift+") & "+mask+";\n");
}
intPtr++;
}
if (shift > 0) {
writer.append(" ");
// writer.append("unCompressedData[outOffset + "+intPtr+"] = ((i"+bytePtr+" & "+((1 << shift) - 1)+") << "+(numFrameBits - shift)+")");
writer.append("unCompressedData[outOffset + "+intPtr+"] = ((i"+bytePtr+" << "+(numFrameBits - shift)+")");
bytePtr++;
shift = 32 - (numFrameBits - shift);
// writer.append(" | (i"+bytePtr+" >>> "+shift+") & "+((1 << (32 - shift)) - 1)+";\n");
writer.append(" | (i"+bytePtr+" >>> "+shift+")) & "+mask+";\n");
intPtr++;
}
else {
bytePtr++;
shift = 32;
}
}
}
protected void generateInstructions8(final int numFrameBits) throws IOException {
final int mask = (1 << numFrameBits) - 1;
int shift = 8;
int bytePtr = 0, intPtr = 0;
while (intPtr < 8) {
while (shift >= numFrameBits) {
shift -= numFrameBits;
writer.append(" ");
if (shift == 0 && mask != 0) {
writer.append("unCompressedData[outOffset + " + intPtr + "] = i" + bytePtr + " & " + mask + ";\n");
} else if (shift == 0 && mask == 0) {
writer.append("unCompressedData[outOffset + " + intPtr + "] = i" + bytePtr + ";\n");
}
else {
writer.append("unCompressedData[outOffset + " + intPtr + "] = (i" + bytePtr + " >>> " + shift + ") & " + mask + ";\n");
}
intPtr++;
}
if (shift > 0) {
writer.append(" ");
writer.append("unCompressedData[outOffset + " + intPtr + "] = ((i" + bytePtr + " << " + (numFrameBits - shift) + ")");
bytePtr++;
shift = 8 - (numFrameBits - shift);
if (shift >= 0) {
if (mask == 0)
writer.append(" | (i" + bytePtr + " >>> " + shift + " & " + MASK[8 - shift] + "));\n");
else
writer.append(" | (i" + bytePtr + " >>> " + shift + " & " + MASK[8 - shift] + ")) & " + mask + ";\n");
}
else {
writer.append(" | (i" + bytePtr + " << " + (-shift) + " & " + MASK[8 - shift] + ")");
while (shift + 8 < 0) {
writer.append(" | (i" + (++bytePtr) + " << " + (-8 - shift) + " & " + MASK[-shift] + ")");
shift += 8;
}
if (mask == 0)
writer.append(" | (i" + (bytePtr + 1) + " >>> " + (8 + shift) + " & " + MASK[-shift] + "));\n");
else
writer.append(" | (i" + (bytePtr + 1) + " >>> " + (8 + shift) + " & " + MASK[-shift] + ")) & " + mask + ";\n");
}
intPtr++;
} else {
bytePtr++;
shift += 8;
}
}
}
protected void generateInstructions16(final int numFrameBits) throws IOException {
final int mask = ( 1 << numFrameBits ) - 1;
int shift = 16;
int bytePtr = 0, intPtr = 0;
while ( intPtr < 16 ) {
while ( shift >= numFrameBits ) {
shift -= numFrameBits;
writer.append( " " );
if ( shift == 0 && mask != 0 )
{
writer.append( "unCompressedData[outOffset + " + intPtr + "] = i" + bytePtr + " & " + mask + ";\n" );
}
else if ( shift == 0 && mask == 0 )
{
writer.append( "unCompressedData[outOffset + " + intPtr + "] = i" + bytePtr + ";\n" );
}
else {
writer.append( "unCompressedData[outOffset + " + intPtr + "] = (i" + bytePtr + " >>> " + shift + ") & " + mask + ";\n" );
}
intPtr++;
}
if ( shift > 0 ) {
writer.append( " " );
writer.append( "unCompressedData[outOffset + " + intPtr + "] = ((i" + bytePtr + " << " + ( numFrameBits - shift ) + ")" );
bytePtr++;
shift = 16 - ( numFrameBits - shift );
if ( shift >= 0 )
{
if ( mask == 0 )
writer.append( " | (i" + bytePtr + " >>> " + shift + " & " + MASK[16 - shift] + "));\n" );
else
writer.append( " | (i" + bytePtr + " >>> " + shift + " & " + MASK[16 - shift] + ")) & " + mask + ";\n" );
}
else {
if ( mask == 0 )
writer.append( " | (i" + bytePtr + " << " + ( -shift ) + " & " + MASK[16 - shift] + ") | (i" + ( bytePtr + 1 ) + " >>> " + ( 16 + shift ) + " & " + MASK[-shift] + "));\n" );
else
writer.append( " | (i" + bytePtr + " << " + ( -shift ) + " & " + MASK[16 - shift] + ") | (i" + ( bytePtr + 1 ) + " >>> " + ( 16 + shift ) + " & " + MASK[-shift] + ")) & " + mask + ";\n" );
}
intPtr++;
}
else {
bytePtr++;
shift += 16;
}
}
}
private static final String FILE_HEADER =
"/**\n" +
" * Copyright 2014 National University of Ireland, Galway.\n" +
" *\n" +
" * This file is part of the SIREn project. Project and contact information:\n" +
" *\n" +
" * https://github.com/rdelbru/SIREn\n" +
" *\n" +
" * Licensed under the Apache License, Version 2.0 (the \"License\");\n" +
" * you may not use this file except in compliance with the License.\n" +
" * You may obtain a copy of the License at\n" +
" *\n" +
" * http://www.apache.org/licenses/LICENSE-2.0\n" +
" *\n" +
" * Unless required by applicable law or agreed to in writing, software\n" +
" * distributed under the License is distributed on an \"AS IS\" BASIS,\n" +
" * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" +
" * See the License for the specific language governing permissions and\n" +
" * limitations under the License.\n" +
" */ \n" +
"/* This program is generated, do not modify. See AForFrameDecompressorGenerator.java */\n" +
"package org.sindice.siren.index.codecs.block;\n" +
"\n" +
"import org.apache.lucene.util.BytesRef;\n" +
"import org.apache.lucene.util.IntsRef;\n";
/**
* @param args
* @throws IOException
*/
public static void main(final String[] args) throws IOException {
final File file = new File("./src/main/java/org/sindice/siren/index/codecs/block", "AForFrameDecompressor.java");
final AForFrameDecompressorGenerator generator = new AForFrameDecompressorGenerator();
generator.generate(file);
}
}