package org.eclipse.jdt.internal.core.index.impl; | |
/* | |
* (c) Copyright IBM Corp. 2000, 2001. | |
* All Rights Reserved. | |
*/ | |
import org.eclipse.jdt.internal.compiler.util.*; | |
import java.io.*; | |
import java.util.*; | |
/** | |
* An indexSummary is used when saving an index into a BlocksIndexOuput or | |
* reading it from a BlocksIndexInput. It contains basic informations about | |
* an index: first files/words in each block, number of files/words. | |
*/ | |
public class IndexSummary { | |
/** | |
* First file for each block. | |
*/ | |
protected Vector firstFilesInBlocks= new Vector(); | |
/** | |
* First word for each block. | |
*/ | |
protected Vector firstWordsInBlocks= new Vector(); | |
/** | |
* Number of files in the index. | |
*/ | |
protected int numFiles; | |
/** | |
* Number of words in the index. | |
*/ | |
protected int numWords; | |
static class FirstFileInBlock { | |
IndexedFile indexedFile; | |
int blockNum; | |
} | |
static class FirstWordInBlock { | |
char[] word; | |
int blockNum; | |
public String toString(){ | |
return "FirstWordInBlock: "/*nonNLS*/ + new String(word) + ", blockNum: "/*nonNLS*/ + blockNum; | |
} | |
} | |
protected int firstWordBlockNum; | |
protected boolean firstWordAdded= true; | |
/** | |
* Adds the given file as the first file for the given Block number. | |
*/ | |
public void addFirstFileInBlock(IndexedFile indexedFile, int blockNum) { | |
FirstFileInBlock entry= new FirstFileInBlock(); | |
entry.indexedFile= indexedFile; | |
entry.blockNum= blockNum; | |
firstFilesInBlocks.addElement(entry); | |
} | |
/** | |
* Adds the given word as the first word for the given Block number. | |
*/ | |
public void addFirstWordInBlock(char[] word, int blockNum) { | |
if (firstWordAdded) { | |
firstWordBlockNum= blockNum; | |
firstWordAdded= false; | |
} | |
FirstWordInBlock entry= new FirstWordInBlock(); | |
entry.word= word; | |
entry.blockNum= blockNum; | |
firstWordsInBlocks.addElement(entry); | |
} | |
/** | |
* Returns the numbers of all the blocks | |
*/ | |
public int[] getAllBlockNums() { | |
int max = firstWordsInBlocks.size(); | |
int[] blockNums = new int[max]; | |
for (int i = 0; i < max; i++){ | |
blockNums[i] = ((FirstWordInBlock)firstWordsInBlocks.elementAt(i)).blockNum; | |
} | |
return blockNums; | |
} | |
public int getBlockNum(int blockLocation) { | |
return ((FirstWordInBlock) firstWordsInBlocks.elementAt(blockLocation)).blockNum; | |
} | |
/** | |
* Returns the number of the Block containing the file with the given number. | |
*/ | |
public int getBlockNumForFileNum(int fileNum) { | |
int min= 0; | |
int max= firstFilesInBlocks.size() - 1; | |
while (min <= max) { | |
int mid= (min + max) / 2; | |
FirstFileInBlock entry= (FirstFileInBlock) firstFilesInBlocks.elementAt(mid); | |
int compare= fileNum - entry.indexedFile.getFileNumber(); | |
if (compare == 0) | |
return entry.blockNum; | |
if (compare < 0) | |
max= mid - 1; | |
else | |
min= mid + 1; | |
} | |
if (max < 0) | |
return -1; | |
FirstFileInBlock entry= (FirstFileInBlock) firstFilesInBlocks.elementAt(max); | |
return entry.blockNum; | |
} | |
/** | |
* Returns the number of the Block containing the given word. | |
*/ | |
public int getBlockNumForWord(char[] word) { | |
int min= 0; | |
int max= firstWordsInBlocks.size() - 1; | |
while (min <= max) { | |
int mid= (min + max) / 2; | |
FirstWordInBlock entry= (FirstWordInBlock) firstWordsInBlocks.elementAt(mid); | |
int compare= Util.compare(word, entry.word); | |
if (compare == 0) | |
return entry.blockNum; | |
if (compare < 0) | |
max= mid - 1; | |
else | |
min= mid + 1; | |
} | |
if (max < 0) | |
return -1; | |
FirstWordInBlock entry= (FirstWordInBlock) firstWordsInBlocks.elementAt(max); | |
return entry.blockNum; | |
} | |
public int[] getBlockNumsForPrefix(char[] prefix) { | |
int min= 0; | |
int size= firstWordsInBlocks.size(); | |
int max= size - 1; | |
int match= -1; | |
while (min <= max && match < 0) { | |
int mid= (min + max) / 2; | |
FirstWordInBlock entry= (FirstWordInBlock) firstWordsInBlocks.elementAt(mid); | |
int compare= Util.startsWith(entry.word, prefix); | |
if (compare == 0) { | |
match= mid; | |
break; | |
} | |
if (compare >= 0) | |
max= mid - 1; | |
else | |
min= mid + 1; | |
} | |
if (max < 0) | |
return new int[0]; | |
if (match < 0) | |
match= max; | |
int firstBlock= match - 1; | |
// Look if previous blocks are affected | |
for (; firstBlock >= 0; firstBlock--) { | |
FirstWordInBlock entry= (FirstWordInBlock) firstWordsInBlocks.elementAt(firstBlock); | |
if (!CharOperation.startsWith(entry.word, prefix)) | |
break; | |
} | |
if (firstBlock < 0) | |
firstBlock= 0; | |
// Look if next blocks are affected | |
int firstNotIncludedBlock= match + 1; | |
for (; firstNotIncludedBlock < size; firstNotIncludedBlock++) { | |
FirstWordInBlock entry= (FirstWordInBlock) firstWordsInBlocks.elementAt(firstNotIncludedBlock); | |
if (!CharOperation.startsWith(entry.word, prefix)) | |
break; | |
} | |
int numberOfBlocks= firstNotIncludedBlock - firstBlock; | |
int[] result= new int[numberOfBlocks]; | |
int pos= firstBlock; | |
for (int i= 0; i < numberOfBlocks; i++, pos++) { | |
FirstWordInBlock entry= (FirstWordInBlock) firstWordsInBlocks.elementAt(pos); | |
result[i]= entry.blockNum; | |
} | |
return result; | |
} | |
public int getFirstBlockLocationForPrefix(char[] prefix) { | |
int min = 0; | |
int size = firstWordsInBlocks.size(); | |
int max = size - 1; | |
int match = -1; | |
while (min <= max) { | |
int mid = (min + max) / 2; | |
FirstWordInBlock entry = (FirstWordInBlock) firstWordsInBlocks.elementAt(mid); | |
int compare = Util.startsWith(entry.word, prefix); | |
if (compare == 0) { | |
match = mid; | |
break; | |
} | |
if (compare >= 0) { | |
max = mid - 1; | |
} else { | |
match = mid; // not perfect match, but could be inside | |
min = mid + 1; | |
} | |
} | |
if (max < 0) return -1; | |
// no match at all, might be some matching entries inside max block | |
if (match < 0){ | |
match = max; | |
} else { | |
// look for possible matches inside previous blocks | |
while (match > 0){ | |
FirstWordInBlock entry = (FirstWordInBlock) firstWordsInBlocks.elementAt(match); | |
if (!CharOperation.startsWith(entry.word, prefix)){ | |
break; | |
} | |
match--; | |
} | |
} | |
return match; | |
} | |
/** | |
* Returns the number of the first IndexBlock (containing words). | |
*/ | |
public int getFirstWordBlockNum() { | |
return firstWordBlockNum; | |
} | |
/** | |
* Blocks are contiguous, so the next one is a potential candidate if its first word starts with | |
* the given prefix | |
*/ | |
public int getNextBlockLocationForPrefix(char[] prefix, int blockLoc) { | |
if (++blockLoc < firstWordsInBlocks.size()){ | |
FirstWordInBlock entry= (FirstWordInBlock) firstWordsInBlocks.elementAt(blockLoc); | |
if (CharOperation.startsWith(entry.word, prefix)) return blockLoc; | |
} | |
return -1; | |
} | |
/** | |
* Returns the number of files contained in the index. | |
*/ | |
public int getNumFiles() { | |
return numFiles; | |
} | |
/** | |
* Returns the number of words contained in the index. | |
*/ | |
public int getNumWords() { | |
return numWords; | |
} | |
/** | |
* Loads the summary in memory. | |
*/ | |
public void read(RandomAccessFile raf) throws IOException { | |
numFiles= raf.readInt(); | |
numWords= raf.readInt(); | |
firstWordBlockNum= raf.readInt(); | |
int numFirstFiles= raf.readInt(); | |
for (int i= 0; i < numFirstFiles; ++i) { | |
FirstFileInBlock entry= new FirstFileInBlock(); | |
String path= raf.readUTF(); | |
int fileNum= raf.readInt(); | |
entry.indexedFile= new IndexedFile(path, fileNum); | |
entry.blockNum= raf.readInt(); | |
firstFilesInBlocks.addElement(entry); | |
} | |
int numFirstWords= raf.readInt(); | |
for (int i= 0; i < numFirstWords; ++i) { | |
FirstWordInBlock entry= new FirstWordInBlock(); | |
entry.word= raf.readUTF().toCharArray(); | |
entry.blockNum= raf.readInt(); | |
firstWordsInBlocks.addElement(entry); | |
} | |
} | |
/** | |
* Sets the number of files of the index. | |
*/ | |
public void setNumFiles(int numFiles) { | |
this.numFiles= numFiles; | |
} | |
/** | |
* Sets the number of words of the index. | |
*/ | |
public void setNumWords(int numWords) { | |
this.numWords= numWords; | |
} | |
/** | |
* Saves the summary on the disk. | |
*/ | |
public void write(RandomAccessFile raf) throws IOException { | |
long fp= raf.getFilePointer(); | |
raf.writeInt(numFiles); | |
raf.writeInt(numWords); | |
raf.writeInt(firstWordBlockNum); | |
raf.writeInt(firstFilesInBlocks.size()); | |
for (int i= 0, size= firstFilesInBlocks.size(); i < size; ++i) { | |
FirstFileInBlock entry= (FirstFileInBlock) firstFilesInBlocks.elementAt(i); | |
raf.writeUTF(entry.indexedFile.getPath()); | |
raf.writeInt(entry.indexedFile.getFileNumber()); | |
raf.writeInt(entry.blockNum); | |
} | |
raf.writeInt(firstWordsInBlocks.size()); | |
for (int i= 0, size= firstWordsInBlocks.size(); i < size; ++i) { | |
FirstWordInBlock entry= (FirstWordInBlock) firstWordsInBlocks.elementAt(i); | |
raf.writeUTF(new String(entry.word)); | |
raf.writeInt(entry.blockNum); | |
} | |
} | |
} |