| /******************************************************************************* |
| * Copyright (c) 2000, 2003 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Common Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/cpl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.cdt.internal.core.index.impl; |
| |
| import java.io.UTFDataFormatException; |
| |
| /** |
| * Uses prefix coding on words, and gamma coding of document numbers differences. |
| */ |
| public class GammaCompressedIndexBlock extends IndexBlock { |
| CodeByteStream writeCodeStream= new CodeByteStream(); |
| CodeByteStream readCodeStream; |
| char[] prevWord= null; |
| int offset= 0; |
| |
| public GammaCompressedIndexBlock(int blockSize) { |
| super(blockSize); |
| readCodeStream= new CodeByteStream(field.buffer()); |
| } |
| /** |
| * @see IndexBlock#addEntry |
| */ |
| public boolean addEntry(WordEntry entry) { |
| writeCodeStream.reset(); |
| encodeEntry(entry, prevWord, writeCodeStream); |
| if (offset + writeCodeStream.byteLength() > this.blockSize - 2) { |
| return false; |
| } |
| byte[] bytes= writeCodeStream.toByteArray(); |
| field.put(offset, bytes); |
| offset += bytes.length; |
| prevWord= entry.getWord(); |
| return true; |
| } |
| protected void encodeEntry(WordEntry entry, char[] prevWord, CodeByteStream codeStream) { |
| char[] word= entry.getWord(); |
| int prefixLen= prevWord == null ? 0 : Util.prefixLength(prevWord, word); |
| codeStream.writeByte(prefixLen); |
| codeStream.writeUTF(word, prefixLen, word.length); |
| int n= entry.getNumRefs(); |
| codeStream.writeGamma(n); |
| int prevRef= 0; |
| for (int i= 0; i < n; ++i) { |
| int ref= entry.getRef(i); |
| if (ref <= prevRef) |
| throw new IllegalArgumentException(); |
| codeStream.writeGamma(ref - prevRef); |
| prevRef= ref; |
| } |
| } |
| /** |
| * @see IndexBlock#addEntry |
| */ |
| public boolean addIncludeEntry(IncludeEntry entry) { |
| writeCodeStream.reset(); |
| encodeEntry(entry, prevWord, writeCodeStream); |
| if (offset + writeCodeStream.byteLength() > this.blockSize - 2) { |
| return false; |
| } |
| byte[] bytes= writeCodeStream.toByteArray(); |
| field.put(offset, bytes); |
| offset += bytes.length; |
| prevWord= entry.getFile(); |
| return true; |
| } |
| /** |
| * @param entry |
| * @param prevWord |
| * @param writeCodeStream |
| */ |
| protected void encodeEntry(IncludeEntry entry, char[] prevWord, CodeByteStream codeStream) { |
| char[] file= entry.getFile(); |
| int prefixLen= prevWord == null ? 0 : Util.prefixLength(prevWord, file); |
| codeStream.writeByte(prefixLen); |
| codeStream.writeUTF(file, prefixLen, file.length); |
| int n= entry.getNumRefs(); |
| codeStream.writeGamma(n); |
| int prevRef= 0; |
| for (int i= 0; i < n; ++i) { |
| int ref= entry.getRef(i); |
| if (ref <= prevRef) |
| throw new IllegalArgumentException(); |
| codeStream.writeGamma(ref - prevRef); |
| prevRef= ref; |
| } |
| |
| } |
| /** |
| * @see IndexBlock#flush |
| */ |
| public void flush() { |
| if (offset > 0) { |
| field.putInt2(offset, 0); |
| offset= 0; |
| prevWord= null; |
| } |
| } |
| /** |
| * @see IndexBlock#isEmpty |
| */ |
| public boolean isEmpty() { |
| return offset == 0; |
| } |
| /** |
| * @see IndexBlock#nextEntry |
| */ |
| public boolean nextEntry(WordEntry entry) { |
| try { |
| readCodeStream.reset(field.buffer(), offset); |
| int prefixLength= readCodeStream.readByte(); |
| char[] word= readCodeStream.readUTF(); |
| if (prevWord != null && prefixLength > 0) { |
| char[] temp= new char[prefixLength + word.length]; |
| System.arraycopy(prevWord, 0, temp, 0, prefixLength); |
| System.arraycopy(word, 0, temp, prefixLength, word.length); |
| word= temp; |
| } |
| if (word.length == 0) { |
| return false; |
| } |
| entry.reset(word); |
| int n= readCodeStream.readGamma(); |
| int prevRef= 0; |
| for (int i= 0; i < n; ++i) { |
| int ref= prevRef + readCodeStream.readGamma(); |
| if (ref < prevRef) |
| throw new InternalError(); |
| entry.addRef(ref); |
| prevRef= ref; |
| } |
| offset= readCodeStream.byteLength(); |
| prevWord= word; |
| return true; |
| } catch (UTFDataFormatException e) { |
| return false; |
| } |
| } |
| /** |
| * @see IndexBlock#nextEntry |
| */ |
| public boolean nextEntry(IncludeEntry entry) { |
| try { |
| readCodeStream.reset(field.buffer(), offset); |
| int prefixLength= readCodeStream.readByte(); |
| char[] file= readCodeStream.readUTF(); |
| if (prevWord != null && prefixLength > 0) { |
| char[] temp= new char[prefixLength + file.length]; |
| System.arraycopy(prevWord, 0, temp, 0, prefixLength); |
| System.arraycopy(file, 0, temp, prefixLength, file.length); |
| file= temp; |
| } |
| if (file.length == 0) { |
| return false; |
| } |
| entry.reset(file); |
| int n= readCodeStream.readGamma(); |
| int prevRef= 0; |
| for (int i= 0; i < n; ++i) { |
| int ref= prevRef + readCodeStream.readGamma(); |
| if (ref < prevRef) |
| throw new InternalError(); |
| entry.addRef(ref); |
| prevRef= ref; |
| } |
| offset= readCodeStream.byteLength(); |
| prevWord= file; |
| return true; |
| } catch (UTFDataFormatException e) { |
| return false; |
| } |
| } |
| /** |
| * @see IndexBlock#reset |
| */ |
| public void reset() { |
| super.reset(); |
| offset= 0; |
| prevWord= null; |
| } |
| |
| } |
| |