/*
* (c) Copyright 2010-2011 AgileBirds
*
* This file is part of OpenFlexo.
*
* OpenFlexo is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenFlexo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenFlexo. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.openflexo.jedit;
/*
* KeywordMap.java - Fast keyword->id map
* Copyright (C) 1998, 1999 Slava Pestov
* Copyright (C) 1999 Mike Dillon
*
* You may use and modify this package for any purpose. Redistribution is
* permitted, in both source and binary form, provided that this notice
* remains intact in all source distributions of this package.
*/
import javax.swing.text.Segment;
/**
* A <code>KeywordMap</code> is similar to a hashtable in that it maps keys to values. However, the `keys' are Swing segments. This allows
* lookups of text substrings without the overhead of creating a new string object.
* <p>
* This class is used by <code>CTokenMarker</code> to map keywords to ids.
*
* @author Slava Pestov, Mike Dillon
* @version $Id: KeywordMap.java,v 1.2 2011/09/12 11:47:09 gpolet Exp $
*/
public class KeywordMap {
/**
* Creates a new <code>KeywordMap</code>.
*
* @param ignoreCase
* True if keys are case insensitive
*/
public KeywordMap(boolean ignoreCase) {
this(ignoreCase, 52);
this.ignoreCase = ignoreCase;
}
/**
* Creates a new <code>KeywordMap</code>.
*
* @param ignoreCase
* True if the keys are case insensitive
* @param mapLength
* The number of `buckets' to create. A value of 52 will give good performance for most maps.
*/
public KeywordMap(boolean ignoreCase, int mapLength) {
this.mapLength = mapLength;
this.ignoreCase = ignoreCase;
map = new Keyword[mapLength];
}
/**
* Looks up a key.
*
* @param text
* The text segment
* @param offset
* The offset of the substring within the text segment
* @param length
* The length of the substring
*/
public byte lookup(Segment text, int offset, int length) {
if (length == 0) {
return Token.NULL;
}
Keyword k = map[getSegmentMapKey(text, offset, length)];
while (k != null) {
if (length != k.keyword.length) {
k = k.next;
continue;
}
if (SyntaxUtilities.regionMatches(ignoreCase, text, offset, k.keyword)) {
return k.id;
}
k = k.next;
}
return Token.NULL;
}
/**
* Adds a key-value mapping.
*
* @param keyword
* The key
* @Param id The value
*/
public void add(String keyword, byte id) {
int key = getStringMapKey(keyword);
map[key] = new Keyword(keyword.toCharArray(), id, map[key]);
}
/**
* Returns true if the keyword map is set to be case insensitive, false otherwise.
*/
public boolean getIgnoreCase() {
return ignoreCase;
}
/**
* Sets if the keyword map should be case insensitive.
*
* @param ignoreCase
* True if the keyword map should be case insensitive, false otherwise
*/
public void setIgnoreCase(boolean ignoreCase) {
this.ignoreCase = ignoreCase;
}
// protected members
protected int mapLength;
protected int getStringMapKey(String s) {
return (Character.toUpperCase(s.charAt(0)) + Character.toUpperCase(s.charAt(s.length() - 1))) % mapLength;
}
protected int getSegmentMapKey(Segment s, int off, int len) {
return (Character.toUpperCase(s.array[off]) + Character.toUpperCase(s.array[off + len - 1])) % mapLength;
}
// private members
class Keyword {
public Keyword(char[] keyword, byte id, Keyword next) {
this.keyword = keyword;
this.id = id;
this.next = next;
}
public char[] keyword;
public byte id;
public Keyword next;
}
private Keyword[] map;
private boolean ignoreCase;
}