/**
* Copyright (C) 2001-2017 by RapidMiner and the contributors
*
* Complete list of developers available at our web site:
*
* http://rapidminer.com
*
* This program is free software: you can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License as published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* This program 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License along with this program.
* If not, see http://www.gnu.org/licenses/.
*/
package com.rapidminer.gui.tools.syntax;
/*
* 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, Ingo Mierswa
*/
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
static 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;
}