001: /*
002: * Copyright (C) 2005 - 2008 JasperSoft Corporation. All rights reserved.
003: * http://www.jaspersoft.com.
004: *
005: * Unless you have purchased a commercial license agreement from JasperSoft,
006: * the following license terms apply:
007: *
008: * This program is free software; you can redistribute it and/or modify
009: * it under the terms of the GNU General Public License version 2 as published by
010: * the Free Software Foundation.
011: *
012: * This program is distributed WITHOUT ANY WARRANTY; and without the
013: * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
014: * See the GNU General Public License for more details.
015: *
016: * You should have received a copy of the GNU General Public License
017: * along with this program; if not, see http://www.gnu.org/licenses/gpl.txt
018: * or write to:
019: *
020: * Free Software Foundation, Inc.,
021: * 59 Temple Place - Suite 330,
022: * Boston, MA USA 02111-1307
023: *
024: *
025: *
026: *
027: * KeywordMap.java
028: *
029: */
030:
031: package org.syntax.jedit;
032:
033: import org.syntax.jedit.tokenmarker.*;
034: import javax.swing.text.Segment;
035:
036: /**
037: * A <code>KeywordMap</code> is similar to a hashtable in that it maps keys
038: * to values. However, the `keys' are Swing segments. This allows lookups of
039: * text substrings without the overhead of creating a new string object.
040: * <p>
041: * This class is used by <code>CTokenMarker</code> to map keywords to ids.
042: *
043: * @author Slava Pestov, Mike Dillon
044: * @version $Id: KeywordMap.java 1167 2008-01-15 18:49:05Z gtoffoli $
045: */
046: public class KeywordMap {
047: /**
048: * Creates a new <code>KeywordMap</code>.
049: * @param ignoreCase True if keys are case insensitive
050: */
051: public KeywordMap(boolean ignoreCase) {
052: this (ignoreCase, 52);
053: this .ignoreCase = ignoreCase;
054: }
055:
056: /**
057: * Creates a new <code>KeywordMap</code>.
058: * @param ignoreCase True if the keys are case insensitive
059: * @param mapLength The number of `buckets' to create.
060: * A value of 52 will give good performance for most maps.
061: */
062: public KeywordMap(boolean ignoreCase, int mapLength) {
063: this .mapLength = mapLength;
064: this .ignoreCase = ignoreCase;
065: map = new Keyword[mapLength];
066: }
067:
068: /**
069: * Looks up a key.
070: * @param text The text segment
071: * @param offset The offset of the substring within the text segment
072: * @param length The length of the substring
073: */
074: public byte lookup(Segment text, int offset, int length) {
075: if (length == 0)
076: return Token.NULL;
077: Keyword k = map[getSegmentMapKey(text, offset, length)];
078: while (k != null) {
079: if (length != k.keyword.length) {
080: k = k.next;
081: continue;
082: }
083: if (SyntaxUtilities.regionMatches(ignoreCase, text, offset,
084: k.keyword))
085: return k.id;
086: k = k.next;
087: }
088: return Token.NULL;
089: }
090:
091: /**
092: * Adds a key-value mapping.
093: * @param keyword The key
094: * @Param id The value
095: */
096: public void add(String keyword, byte id) {
097: int key = getStringMapKey(keyword);
098: map[key] = new Keyword(keyword.toCharArray(), id, map[key]);
099: }
100:
101: /**
102: * Returns true if the keyword map is set to be case insensitive,
103: * false otherwise.
104: */
105: public boolean getIgnoreCase() {
106: return ignoreCase;
107: }
108:
109: /**
110: * Sets if the keyword map should be case insensitive.
111: * @param ignoreCase True if the keyword map should be case
112: * insensitive, false otherwise
113: */
114: public void setIgnoreCase(boolean ignoreCase) {
115: this .ignoreCase = ignoreCase;
116: }
117:
118: // protected members
119: protected int mapLength;
120:
121: protected int getStringMapKey(String s) {
122: return (Character.toUpperCase(s.charAt(0)) + Character
123: .toUpperCase(s.charAt(s.length() - 1)))
124: % mapLength;
125: }
126:
127: protected int getSegmentMapKey(Segment s, int off, int len) {
128: return (Character.toUpperCase(s.array[off]) + Character
129: .toUpperCase(s.array[off + len - 1]))
130: % mapLength;
131: }
132:
133: // private members
134: class Keyword {
135: public Keyword(char[] keyword, byte id, Keyword next) {
136: this .keyword = keyword;
137: this .id = id;
138: this .next = next;
139: }
140:
141: public char[] keyword;
142: public byte id;
143: public Keyword next;
144: }
145:
146: private Keyword[] map;
147: private boolean ignoreCase;
148: }
|