processing.app.syntax.KeywordMap Maven / Gradle / Ivy
/*
* 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.
*/
package processing.app.syntax;
import javax.swing.text.Segment;
/**
* A KeywordMap
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.
*
* This class is used by CTokenMarker
to map keywords to ids.
*
* @author Slava Pestov, Mike Dillon
* @version $Id$
*/
public class KeywordMap {
// private Keyword[] map;
// protected int mapLength;
private boolean ignoreCase;
private Keyword[] literalMap;
private Keyword[] parenMap;
// A value of 52 will give good performance for most maps.
static private int MAP_LENGTH = 52;
/**
* Creates a new KeywordMap
.
* @param ignoreCase True if keys are case insensitive
*/
public KeywordMap(boolean ignoreCase) {
// this(ignoreCase, 52);
this.ignoreCase = ignoreCase;
literalMap = new Keyword[MAP_LENGTH];
parenMap = new Keyword[MAP_LENGTH];
}
// /**
// * Creates a new KeywordMap
.
// * @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, boolean paren) {
if (length == 0) {
return Token.NULL;
}
int key = getSegmentMapKey(text, offset, length);
Keyword k = paren ? parenMap[key] : literalMap[key];
while (k != null) {
// if (length != k.keyword.length) {
// k = k.next;
// continue;
// }
if (length == k.keyword.length) {
if (regionMatches(ignoreCase, text, offset, k.keyword)) {
return k.id;
}
}
k = k.next;
}
return Token.NULL;
}
/**
* Checks if a subregion of a Segment
is equal to a
* character array.
* @param ignoreCase True if case should be ignored, false otherwise
* @param text The segment
* @param offset The offset into the segment
* @param match The character array to match
*/
static public boolean regionMatches(boolean ignoreCase, Segment text,
int offset, char[] match) {
int length = offset + match.length;
char[] textArray = text.array;
if (length > text.offset + text.count) {
return false;
}
for (int i = offset, j = 0; i < length; i++, j++) {
char c1 = textArray[i];
char c2 = match[j];
if (ignoreCase) {
c1 = Character.toUpperCase(c1);
c2 = Character.toUpperCase(c2);
}
if (c1 != c2) {
return false;
}
}
return true;
}
/**
* Adds a key-value mapping.
* @param keyword The key
* @param id The value
*/
public void add(String keyword, byte id, boolean paren) {
int key = getStringMapKey(keyword);
Keyword[] map = paren ? parenMap : literalMap;
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 int getStringMapKey(String s) {
return (Character.toUpperCase(s.charAt(0)) +
Character.toUpperCase(s.charAt(s.length()-1)))
% MAP_LENGTH;
}
protected int getSegmentMapKey(Segment s, int off, int len) {
return (Character.toUpperCase(s.array[off]) +
Character.toUpperCase(s.array[off + len - 1]))
% MAP_LENGTH;
}
// private members
private static class Keyword {
public final char[] keyword;
public final byte id;
public final Keyword next;
public Keyword(char[] keyword, byte id, Keyword next) {
this.keyword = keyword;
this.id = id;
this.next = next;
}
}
}