/* * $Id$ * * Copyright (c) 2004-2005 by the TeXlapse Team. * 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 net.sourceforge.texlipse.model; import java.util.Arrays; import java.util.List; /** * This class provides methods for retrieving partial matches from arrays. * Sorted arrays containing <code>AbstractEntry</code> -objects can be searched * for entries whose <code>key</code> starts with the given string. * * This class provides both a linear search algorithm (for a reference to test new * algorithms with) as well as a binary search algorithm. * * @author Oskar Ojala * @author Boris von Loesch */ public abstract class PartialRetriever { /** * Returns (if exist) the position of the entry with the given name in * the array * @param entryname Name of the wanted entry * @param entries Sorted List of AbstractEntry * @param lowerCase If true, entries must be sorted case insensitive * @return The position inside the list or -1 if the entry was not found */ public static int getEntry(String entryname, List<? extends AbstractEntry> entries, boolean lowerCase){ if (entries == null || entries.size() == 0) return -1; String lEntryname = entryname.toLowerCase(); int start = 0; int end = entries.size(); while (end - start > 1 && !entries.get((start + end)/2).getkey(lowerCase).equals(lEntryname)){ int c = entries.get((start + end)/2).getkey(lowerCase).compareTo(lEntryname); if (c < 0) start = (start + end)/2; else end = (start + end)/2; } if (lowerCase) { //This case is a bit more complicated since there could be different entries with the //same lower case letters int m = (start + end)/2; if (!entries.get(m).getkey(lowerCase).equals(lEntryname)) return -1; m--; while (m >= 0 && entries.get(m).getkey(lowerCase).equals(lEntryname)) m--; m++; while (m < entries.size() && entries.get(m).getkey(lowerCase).equals(lEntryname)) { if (entries.get(m).key.equals(entryname)) return m; m++; } return -1; } else { if (entries.get((start + end)/2).getkey(lowerCase).equals(lEntryname)) return (start + end)/2; else return -1; } } /** * Search the given (sorted) array of entries for all entries, * for which the start of the key matches the given search string. * * This version uses binary search for finding the lower and upper * bounds, resulting in O(log n) performance. * * @param start The start of the searchable string * @param entries The entries to search * @param lowerCase If true, entries must be sorted case insensitive * @return A two-element array with the lower (inclusive) and upper * (exclusive) bounds or {-1,-1} if no matching entries were found. */ protected int[] getCompletionsBin(String start, List<? extends AbstractEntry> entries, boolean lowerCase) { return this.getCompletionsBin(start, entries, new int[] {0, entries.size()}, lowerCase); } protected int[] getCompletionsBin(String start, AbstractEntry[] entries) { return this.getCompletionsBin(start, Arrays.asList(entries), new int[] {0, entries.length}, false); } /** * Search the given (sorted) list of entries for all entries, * for which the start of the key matches the given search string. * * This version uses binary search for finding the lower and upper * bounds, resulting in O(log n) performance. * * @param start The start of the searchable string * @param entries The entries to search * @param initBounds The initial lower and upper bounds to start the * search from * @param lowerCase If true, assumes that the list is sorted lower case and * @return A two-element array with the lower (inclusive) and upper * (exclusive) bounds or {-1,-1} if no matching entries were found. */ protected int[] getCompletionsBin(String start, List<? extends AbstractEntry> entries, int[] initBounds, boolean lowerCase) { int[] bounds = new int[] {-1,-1}; int left = initBounds[0], right = initBounds[1] - 1; int middle = right/2; if (left > right) return bounds; if (lowerCase) start = start.toLowerCase(); if (entries.get(left).getkey(lowerCase).startsWith(start)) right = middle = left; // get upper bound (inclusive) while (left < middle) { if (entries.get(middle).getkey(lowerCase).compareTo(start) >= 0) { right = middle; middle = (left + middle)/2; } else { left = middle; middle = (middle + right)/2; } } if (!entries.get(right).getkey(lowerCase).startsWith(start)) return bounds; bounds[0] = right; // get lower bound (exclusive) left = right; right = initBounds[1] - 1; if (entries.get(right).getkey(lowerCase).startsWith(start)) { bounds[1] = right + 1; return bounds; } middle = (left + right)/2; while (left < middle) { if (entries.get(middle).getkey(lowerCase).startsWith(start)) { left = middle; middle = (right + middle)/2; } else { right = middle; middle = (middle + left)/2; } } bounds[1] = right; return bounds; } }