/******************************************************************************* * Copyright (c) 2000, 2007 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * *******************************************************************************/ package org.eclipse.dltk.core.search.index; import java.util.regex.Pattern; import org.eclipse.dltk.compiler.CharOperation; import org.eclipse.dltk.compiler.util.HashtableOfObject; import org.eclipse.dltk.compiler.util.SimpleLookupTable; import org.eclipse.dltk.compiler.util.SimpleSet; import org.eclipse.dltk.core.search.SearchPattern; import org.eclipse.dltk.core.search.indexing.IIndexConstants; import org.eclipse.dltk.internal.core.util.SimpleWordSet; public class MemoryIndex { public int NUM_CHANGES = 500; // number of separate document changes... // used to decide when to merge SimpleLookupTable docsToReferences; // document paths -> // HashtableOfObject(category names -> // set of words) SimpleWordSet allWords; // save space by locally interning the referenced // words, since an indexer can generate numerous // duplicates String lastDocumentName; HashtableOfObject lastReferenceTable; MemoryIndex() { this.docsToReferences = new SimpleLookupTable(7); this.allWords = new SimpleWordSet(7); } void addDocumentNames(String substring, SimpleSet results) { // assumed the disk index already skipped over documents which have been // added/changed/deleted Object[] paths = this.docsToReferences.keyTable; Object[] referenceTables = this.docsToReferences.valueTable; if (substring == null) { // add all new/changed documents for (int i = 0, l = referenceTables.length; i < l; i++) if (referenceTables[i] != null) results.add(paths[i]); } else { for (int i = 0, l = referenceTables.length; i < l; i++) if (referenceTables[i] != null && ((String) paths[i]).startsWith(substring, 0)) results.add(paths[i]); } } void addIndexEntry(char[] category, char[] key, String documentName) { HashtableOfObject referenceTable; if (documentName.equals(this.lastDocumentName)) referenceTable = this.lastReferenceTable; else { // assumed a document was removed before its reindexed referenceTable = (HashtableOfObject) this.docsToReferences .get(documentName); if (referenceTable == null) this.docsToReferences.put(documentName, referenceTable = new HashtableOfObject(3)); this.lastDocumentName = documentName; this.lastReferenceTable = referenceTable; } SimpleWordSet existingWords = (SimpleWordSet) referenceTable .get(category); if (existingWords == null) referenceTable.put(category, existingWords = new SimpleWordSet(1)); existingWords.add(this.allWords.add(key)); } HashtableOfObject addQueryResults(char[][] categories, char[] key, int matchRule, HashtableOfObject results) { // assumed the disk index already skipped over documents which have been // added/changed/deleted // results maps a word -> EntryResult Object[] paths = this.docsToReferences.keyTable; Object[] referenceTables = this.docsToReferences.valueTable; if (matchRule == (SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE) && key != null) { nextPath: for (int i = 0, l = referenceTables.length; i < l; i++) { HashtableOfObject categoryToWords = (HashtableOfObject) referenceTables[i]; if (categoryToWords != null) { for (int j = 0, m = categories.length; j < m; j++) { SimpleWordSet wordSet = (SimpleWordSet) categoryToWords .get(categories[j]); if (wordSet != null && wordSet.includes(key)) { if (results == null) results = new HashtableOfObject(13); EntryResult result = (EntryResult) results.get(key); if (result == null) results.put(key, result = new EntryResult(key, null)); result.addDocumentName((String) paths[i]); continue nextPath; } } } } } else if ((matchRule & SearchPattern.R_REGEXP_MATCH) != 0) { Pattern regexpPattern = Pattern .compile( new String(key), (matchRule & SearchPattern.R_CASE_SENSITIVE) == 0 ? Pattern.CASE_INSENSITIVE : 0); for (int i = 0, l = referenceTables.length; i < l; i++) { HashtableOfObject categoryToWords = (HashtableOfObject) referenceTables[i]; if (categoryToWords != null) { for (int j = 0, m = categories.length; j < m; j++) { SimpleWordSet wordSet = (SimpleWordSet) categoryToWords .get(categories[j]); if (wordSet != null) { char[][] words = wordSet.words; for (int k = 0, n = words.length; k < n; k++) { char[] word = words[k]; if (word != null) { char decodedWord[]; int sep = CharOperation.indexOf( IIndexConstants.SEPARATOR, word); if (sep > 0) { decodedWord = CharOperation.subarray( word, 0, sep); } else { decodedWord = word; } if (regexpPattern.matcher( new String(decodedWord)).matches()) { if (results == null) results = new HashtableOfObject(13); EntryResult result = (EntryResult) results .get(word); if (result == null) results.put(word, result = new EntryResult( word, null)); result .addDocumentName((String) paths[i]); } } } } } } } } else { for (int i = 0, l = referenceTables.length; i < l; i++) { HashtableOfObject categoryToWords = (HashtableOfObject) referenceTables[i]; if (categoryToWords != null) { for (int j = 0, m = categories.length; j < m; j++) { SimpleWordSet wordSet = (SimpleWordSet) categoryToWords .get(categories[j]); if (wordSet != null) { char[][] words = wordSet.words; for (int k = 0, n = words.length; k < n; k++) { char[] word = words[k]; if (word != null && Index.isMatch(key, word, matchRule)) { if (results == null) results = new HashtableOfObject(13); EntryResult result = (EntryResult) results .get(word); if (result == null) results.put(word, result = new EntryResult(word, null)); result.addDocumentName((String) paths[i]); } } } } } } } return results; } boolean hasChanged() { return this.docsToReferences.elementSize > 0; } void remove(String documentName) { if (documentName.equals(this.lastDocumentName)) { this.lastDocumentName = null; this.lastReferenceTable = null; } this.docsToReferences.put(documentName, null); } boolean shouldMerge() { return this.docsToReferences.elementSize >= NUM_CHANGES; } }