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
    19   * to values. However, the `keys' are Swing segments. This allows lookups of
    20   * text 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  	 * @param ignoreCase True if keys are case insensitive
    32  	 */
    33  	public KeywordMap(boolean ignoreCase)
    34  	{
    35  		this(ignoreCase, 52);
    36  		this.ignoreCase = ignoreCase;
    37  	}
    38
    39  	/***
    40  	 * Creates a new <code>KeywordMap</code>.
    41  	 * @param ignoreCase True if the keys are case insensitive
    42  	 * @param mapLength The number of `buckets' to create.
    43  	 * A value of 52 will give good performance for most maps.
    44  	 */
    45  	public KeywordMap(boolean ignoreCase, int mapLength)
    46  	{
    47  		this.mapLength = mapLength;
    48  		this.ignoreCase = ignoreCase;
    49  		map = new Keyword[mapLength];
    50  	}
    51
    52  	/***
    53  	 * Looks up a key.
    54  	 * @param text The text segment
    55  	 * @param offset The offset of the substring within the text segment
    56  	 * @param length The length of the substring
    57  	 */
    58  	public byte lookup(Segment text, int offset, int length)
    59  	{
    60  		if(length == 0)
    61  			return Token.NULL;
    62  		Keyword k = map[getSegmentMapKey(text, offset, length)];
    63  		while(k != null)
    64  		{
    65  			if(length != k.keyword.length)
    66  			{
    67  				k = k.next;
    68  				continue;
    69  			}
    70  			if(SyntaxUtilities.regionMatches(ignoreCase,text,offset,
    71  				k.keyword))
    72  				return k.id;
    73  			k = k.next;
    74  		}
    75  		return Token.NULL;
    76  	}
    77
    78  	/***
    79  	 * Adds a key-value mapping.
    80  	 * @param keyword The key
    81  	 * @Param id The value
    82  	 */
    83  	public void add(String keyword, byte id)
    84  	{
    85  		int key = getStringMapKey(keyword);
    86  		map[key] = new Keyword(keyword.toCharArray(),id,map[key]);
    87  	}
    88
    89  	/***
    90  	 * Returns true if the keyword map is set to be case insensitive,
    91  	 * false otherwise.
    92  	 */
    93  	public boolean getIgnoreCase()
    94  	{
    95  		return ignoreCase;
    96  	}
    97
    98  	/***
    99  	 * Sets if the keyword map should be case insensitive.
    100 	 * @param ignoreCase True if the keyword map should be case
    101 	 * insensitive, false otherwise
    102 	 */
    103 	public void setIgnoreCase(boolean ignoreCase)
    104 	{
    105 		this.ignoreCase = ignoreCase;
    106 	}
    107
    108 	// protected members
    109 	protected int mapLength;
    110
    111 	protected int getStringMapKey(String s)
    112 	{
    113 		return (Character.toUpperCase(s.charAt(0)) +
    114 				Character.toUpperCase(s.charAt(s.length()-1)))
    115 				% mapLength;
    116 	}
    117
    118 	protected int getSegmentMapKey(Segment s, int off, int len)
    119 	{
    120 		return (Character.toUpperCase(s.array[off]) +
    121 				Character.toUpperCase(s.array[off + len - 1]))
    122 				% mapLength;
    123 	}
    124
    125 	// private members
    126 	class Keyword
    127 	{
    128 		public Keyword(char[] keyword, byte id, Keyword next)
    129 		{
    130 			this.keyword = keyword;
    131 			this.id = id;
    132 			this.next = next;
    133 		}
    134
    135 		public char[] keyword;
    136 		public byte id;
    137 		public Keyword next;
    138 	}
    139
    140 	private Keyword[] map;
    141 	private boolean ignoreCase;
    142 }