blob: 1d4753492e035883b3164130f920b344a0bb713a [file] [log] [blame]
/*******************************************************************************
* 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.IOException;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import org.eclipse.cdt.internal.core.CharOperation;
/**
* 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 ArrayList firstFilesInBlocks= new ArrayList();
/**
* First word for each block.
*/
protected ArrayList firstWordsInBlocks= new ArrayList();
/**
* First include for each block.
*/
protected ArrayList firstIncludesInBlocks= new ArrayList();
/**
* Number of files in the index.
*/
protected int numFiles;
/**
* Number of words in the index.
*/
protected int numWords;
/**
* Number of includes in the index.
*/
protected int numIncludes;
static class FirstFileInBlock {
IndexedFile indexedFile;
int blockNum;
}
static class FirstWordInBlock {
char[] word;
int blockNum;
public String toString(){
return "FirstWordInBlock: " + new String(word) + ", blockNum: " + blockNum; //$NON-NLS-1$ //$NON-NLS-2$
}
}
static class FirstIncludeInBlock {
char[] file;
int blockNum;
public String toString(){
return "FirstIncludeInBlock: " + new String(file) + ", blockNum: " + blockNum; //$NON-NLS-1$ //$NON-NLS-2$
}
}
protected int firstWordBlockNum;
protected boolean firstWordAdded= true;
protected int firstIncludeBlockNum;
protected boolean firstIncludeBlockAdded= 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.add(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.add(entry);
}
/**
* Adds the given include as the first include for the given Block number.
*/
public void addFirstIncludeInBlock(char[] file, int blockNum) {
if (firstIncludeBlockAdded) {
firstIncludeBlockNum= blockNum;
firstIncludeBlockAdded= false;
}
FirstIncludeInBlock entry= new FirstIncludeInBlock();
entry.file = file;
entry.blockNum= blockNum;
firstIncludesInBlocks.add(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.get(i)).blockNum;
}
return blockNums;
}
public int getBlockNum(int blockLocation) {
return ((FirstWordInBlock) firstWordsInBlocks.get(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.get(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.get(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.get(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.get(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.get(mid);
int compare= CharOperation.compareWith(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.get(firstBlock);
if (!CharOperation.prefixEquals(prefix, entry.word))
break;
}
if (firstBlock < 0)
firstBlock= 0;
// Look if next blocks are affected
int firstNotIncludedBlock= match + 1;
for (; firstNotIncludedBlock < size; firstNotIncludedBlock++) {
FirstWordInBlock entry= (FirstWordInBlock) firstWordsInBlocks.get(firstNotIncludedBlock);
if (!CharOperation.prefixEquals(prefix, entry.word))
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.get(pos);
result[i]= entry.blockNum;
}
return result;
}
public int[] getBlockNumsForIncludes() {
int max = firstIncludesInBlocks.size();
int[] blockNums = new int[max];
for (int i = 0; i < max; i++){
blockNums[i] = ((FirstIncludeInBlock)firstIncludesInBlocks.get(i)).blockNum;
}
return blockNums;
}
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.get(mid);
int compare = CharOperation.compareWith(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.get(match);
if (!CharOperation.prefixEquals(prefix, entry.word))
break;
match--;
}
}
return match;
}
/**
* Returns the number of the first IndexBlock (containing words).
*/
public int getFirstWordBlockNum() {
return firstWordBlockNum;
}
/**
* Returns the number of the first IndexBlock (containing words).
*/
public int getFirstIncludeBlockNum() {
return firstIncludeBlockNum;
}
/**
* 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.get(blockLoc);
if (CharOperation.prefixEquals(prefix, entry.word)) 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;
}
/**
* Returns the number of words contained in the index.
*/
public int getNumIncludes() {
return numIncludes;
}
/**
* Loads the summary in memory.
*/
public void read(RandomAccessFile raf) throws IOException {
numFiles= raf.readInt();
numWords= raf.readInt();
numIncludes= raf.readInt();
firstWordBlockNum= raf.readInt();
firstIncludeBlockNum= 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.add(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.add(entry);
}
int numIncludes = raf.readInt();
for (int i= 0; i < numIncludes; ++i) {
FirstIncludeInBlock entry= new FirstIncludeInBlock();
entry.file= raf.readUTF().toCharArray();
entry.blockNum= raf.readInt();
firstIncludesInBlocks.add(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;
}
/**
* Sets the number of includes of the index.
*/
public void setNumIncludes(int numIncs) {
this.numIncludes= numIncs;
}
/**
* Saves the summary on the disk.
*/
public void write(RandomAccessFile raf) throws IOException {
raf.writeInt(numFiles);
raf.writeInt(numWords);
raf.writeInt(numIncludes);
raf.writeInt(firstWordBlockNum);
raf.writeInt(firstIncludeBlockNum);
raf.writeInt(firstFilesInBlocks.size());
for (int i= 0, size= firstFilesInBlocks.size(); i < size; ++i) {
FirstFileInBlock entry= (FirstFileInBlock) firstFilesInBlocks.get(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.get(i);
raf.writeUTF(new String(entry.word));
raf.writeInt(entry.blockNum);
}
raf.writeInt(firstIncludesInBlocks.size());
for (int i= 0, size= firstIncludesInBlocks.size(); i < size; ++i) {
FirstIncludeInBlock entry= (FirstIncludeInBlock) firstIncludesInBlocks.get(i);
raf.writeUTF(new String(entry.file));
raf.writeInt(entry.blockNum);
}
}
}