View Javadoc

1   /*
2    * KeywordMap.java - Fast keyword->id map
3    * Copyright (C) 1998, 1999 Slava Pestov
4    * Copyright (C) 1999 Mike Dillon
5    *
6    * You may use and modify this package for any purpose. Redistribution is
7    * permitted, in both source and binary form, provided that this notice
8    * remains intact in all source distributions of this package.
9    */
10  
11  package org.syntax.jedit;
12  
13  import javax.swing.text.Segment;
14  
15  import org.syntax.jedit.tokenmarker.Token;
16  
17  /***
18   * A <code>KeywordMap</code> is similar to a hashtable in that it maps keys to
19   * values. However, the `keys' are Swing segments. This allows lookups of text
20   * substrings without the overhead of creating a new string object.
21   * <p>
22   * This class is used by <code>CTokenMarker</code> to map keywords to ids.
23   * 
24   * @author Slava Pestov, Mike Dillon
25   * @version $Id$
26   */
27  public class KeywordMap
28  {
29  	/***
30  	 * Creates a new <code>KeywordMap</code>.
31  	 * 
32  	 * @param ignoreCase
33  	 *           True if keys are case insensitive
34  	 */
35  	public KeywordMap( boolean ignoreCase )
36  	{
37  		this( ignoreCase, 52 );
38  		this.ignoreCase = ignoreCase;
39  	}
40  
41  	/***
42  	 * Creates a new <code>KeywordMap</code>.
43  	 * 
44  	 * @param ignoreCase
45  	 *           True if the keys are case insensitive
46  	 * @param mapLength
47  	 *           The number of `buckets' to create. A value of 52 will give good
48  	 *           performance for most maps.
49  	 */
50  	public KeywordMap( boolean ignoreCase, int mapLength )
51  	{
52  		this.mapLength = mapLength;
53  		this.ignoreCase = ignoreCase;
54  		map = new Keyword[mapLength];
55  	}
56  
57  	/***
58  	 * Looks up a key.
59  	 * 
60  	 * @param text
61  	 *           The text segment
62  	 * @param offset
63  	 *           The offset of the substring within the text segment
64  	 * @param length
65  	 *           The length of the substring
66  	 */
67  	public byte lookup( Segment text, int offset, int length )
68  	{
69  		if( length == 0 )
70  			return Token.NULL;
71  		Keyword k = map[getSegmentMapKey( text, offset, length )];
72  		while( k != null )
73  		{
74  			if( length != k.keyword.length )
75  			{
76  				k = k.next;
77  				continue;
78  			}
79  			if( SyntaxUtilities.regionMatches( ignoreCase, text, offset, k.keyword ) )
80  				return k.id;
81  			k = k.next;
82  		}
83  		return Token.NULL;
84  	}
85  
86  	/***
87  	 * Adds a key-value mapping.
88  	 * 
89  	 * @param keyword
90  	 *           The key
91  	 * @Param id The value
92  	 */
93  	public void add( String keyword, byte id )
94  	{
95  		int key = getStringMapKey( keyword );
96  		map[key] = new Keyword( keyword.toCharArray(), id, map[key] );
97  	}
98  
99  	/***
100 	 * Returns true if the keyword map is set to be case insensitive, false
101 	 * otherwise.
102 	 */
103 	public boolean getIgnoreCase()
104 	{
105 		return ignoreCase;
106 	}
107 
108 	/***
109 	 * Sets if the keyword map should be case insensitive.
110 	 * 
111 	 * @param ignoreCase
112 	 *           True if the keyword map should be case insensitive, false
113 	 *           otherwise
114 	 */
115 	public void setIgnoreCase( boolean ignoreCase )
116 	{
117 		this.ignoreCase = ignoreCase;
118 	}
119 
120 	// protected members
121 	protected int mapLength;
122 
123 	protected int getStringMapKey( String s )
124 	{
125 		return ( Character.toUpperCase( s.charAt( 0 ) ) + Character.toUpperCase( s.charAt( s.length() - 1 ) ) )
126 				% mapLength;
127 	}
128 
129 	protected int getSegmentMapKey( Segment s, int off, int len )
130 	{
131 		return ( Character.toUpperCase( s.array[off] ) + Character.toUpperCase( s.array[off + len - 1] ) ) % mapLength;
132 	}
133 
134 	// private members
135 	class Keyword
136 	{
137 		public Keyword( char[] keyword, byte id, Keyword next )
138 		{
139 			this.keyword = keyword;
140 			this.id = id;
141 			this.next = next;
142 		}
143 
144 		public char[] keyword;
145 		public byte id;
146 		public Keyword next;
147 	}
148 
149 	private Keyword[] map;
150 	private boolean ignoreCase;
151 }