PageRenderTime 46ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/jEdit/tags/jedit-4-0-pre5/org/gjt/sp/jedit/syntax/KeywordMap.java

#
Java | 202 lines | 113 code | 19 blank | 70 comment | 13 complexity | fd70b65718920b2decbf55292317bd0d MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, Apache-2.0, LGPL-2.0, LGPL-3.0, GPL-2.0, CC-BY-SA-3.0, LGPL-2.1, GPL-3.0, MPL-2.0-no-copyleft-exception, IPL-1.0
  1. /*
  2. * KeywordMap.java - Fast keyword->id map
  3. * Copyright (C) 1998, 1999 Slava Pestov
  4. * Copyright (C) 1999 Mike Dillon
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version 2
  9. * of the License, or any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  19. */
  20. package org.gjt.sp.jedit.syntax;
  21. import javax.swing.text.Segment;
  22. import java.util.Vector;
  23. import org.gjt.sp.jedit.TextUtilities;
  24. /**
  25. * A <code>KeywordMap</code> is similar to a hashtable in that it maps keys
  26. * to values. However, the `keys' are Swing segments. This allows lookups of
  27. * text substrings without the overhead of creating a new string object.
  28. *
  29. * @author Slava Pestov, Mike Dillon
  30. * @version $Id: KeywordMap.java 3931 2001-12-02 11:40:51Z spestov $
  31. */
  32. public class KeywordMap
  33. {
  34. /**
  35. * Creates a new <code>KeywordMap</code>.
  36. * @param ignoreCase True if keys are case insensitive
  37. */
  38. public KeywordMap(boolean ignoreCase)
  39. {
  40. this(ignoreCase, 52);
  41. this.ignoreCase = ignoreCase;
  42. noWordSep = new StringBuffer();
  43. }
  44. /**
  45. * Creates a new <code>KeywordMap</code>.
  46. * @param ignoreCase True if the keys are case insensitive
  47. * @param mapLength The number of `buckets' to create.
  48. * A value of 52 will give good 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. * Looks up a key.
  58. * @param text The text segment
  59. * @param offset The offset of the substring within the text segment
  60. * @param length The length of the substring
  61. */
  62. public byte lookup(Segment text, int offset, int length)
  63. {
  64. if(length == 0)
  65. return Token.NULL;
  66. Keyword k = map[getSegmentMapKey(text, offset, length)];
  67. while(k != null)
  68. {
  69. if(length != k.keyword.length)
  70. {
  71. k = k.next;
  72. continue;
  73. }
  74. if(TextUtilities.regionMatches(ignoreCase,text,offset,
  75. k.keyword))
  76. return k.id;
  77. k = k.next;
  78. }
  79. return Token.NULL;
  80. }
  81. /**
  82. * Adds a key-value mapping.
  83. * @param keyword The key
  84. * @param id The value
  85. */
  86. public void add(String keyword, byte id)
  87. {
  88. int key = getStringMapKey(keyword);
  89. char[] chars = keyword.toCharArray();
  90. // complete-word command needs a list of all non-alphanumeric
  91. // characters used in a keyword map.
  92. loop: for(int i = 0; i < chars.length; i++)
  93. {
  94. char ch = chars[i];
  95. if(!Character.isLetterOrDigit(ch))
  96. {
  97. for(int j = 0; j < noWordSep.length(); j++)
  98. {
  99. if(noWordSep.charAt(j) == ch)
  100. continue loop;
  101. }
  102. noWordSep.append(ch);
  103. }
  104. }
  105. map[key] = new Keyword(chars,id,map[key]);
  106. }
  107. /**
  108. * Returns all non-alphanumeric characters that appear in the
  109. * keywords of this keyword map.
  110. * @since jEdit 4.0pre3
  111. */
  112. public String getNonAlphaNumericChars()
  113. {
  114. return noWordSep.toString();
  115. }
  116. /**
  117. * Returns an array containing all keywords in this keyword map.
  118. * @since jEdit 4.0pre3
  119. */
  120. public String[] getKeywords()
  121. {
  122. Vector vector = new Vector(100);
  123. for(int i = 0; i < map.length; i++)
  124. {
  125. Keyword keyword = map[i];
  126. while(keyword != null)
  127. {
  128. vector.addElement(new String(keyword.keyword));
  129. keyword = keyword.next;
  130. }
  131. }
  132. String[] retVal = new String[vector.size()];
  133. vector.copyInto(retVal);
  134. return retVal;
  135. }
  136. /**
  137. * Returns true if the keyword map is set to be case insensitive,
  138. * false otherwise.
  139. */
  140. public boolean getIgnoreCase()
  141. {
  142. return ignoreCase;
  143. }
  144. /**
  145. * Sets if the keyword map should be case insensitive.
  146. * @param ignoreCase True if the keyword map should be case
  147. * insensitive, false otherwise
  148. */
  149. public void setIgnoreCase(boolean ignoreCase)
  150. {
  151. this.ignoreCase = ignoreCase;
  152. }
  153. // protected members
  154. protected int mapLength;
  155. protected int getStringMapKey(String s)
  156. {
  157. return (Character.toUpperCase(s.charAt(0)) +
  158. Character.toUpperCase(s.charAt(s.length()-1)))
  159. % mapLength;
  160. }
  161. protected int getSegmentMapKey(Segment s, int off, int len)
  162. {
  163. return (Character.toUpperCase(s.array[off]) +
  164. Character.toUpperCase(s.array[off + len - 1]))
  165. % mapLength;
  166. }
  167. // private members
  168. class Keyword
  169. {
  170. public Keyword(char[] keyword, byte id, Keyword next)
  171. {
  172. this.keyword = keyword;
  173. this.id = id;
  174. this.next = next;
  175. }
  176. public char[] keyword;
  177. public byte id;
  178. public Keyword next;
  179. }
  180. private Keyword[] map;
  181. private boolean ignoreCase;
  182. private StringBuffer noWordSep;
  183. }