PageRenderTime 50ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/jEdit/tags/jedit-4-2-pre4/org/gjt/sp/jedit/syntax/KeywordMap.java

#
Java | 256 lines | 135 code | 22 blank | 99 comment | 15 complexity | c431afa766c9bd17d058359fe36f2de5 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. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 1998, 2002 Slava Pestov
  7. * Copyright (C) 1999 Mike Dillon
  8. *
  9. * This program is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU General Public License
  11. * as published by the Free Software Foundation; either version 2
  12. * of the License, or any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, write to the Free Software
  21. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  22. */
  23. package org.gjt.sp.jedit.syntax;
  24. import javax.swing.text.Segment;
  25. import java.util.Vector;
  26. /**
  27. * A <code>KeywordMap</code> is similar to a hashtable in that it maps keys
  28. * to values. However, the `keys' are Swing segments. This allows lookups of
  29. * text substrings without the overhead of creating a new string object.
  30. *
  31. * @author Slava Pestov, Mike Dillon
  32. * @version $Id: KeywordMap.java 4759 2003-06-05 00:01:49Z spestov $
  33. */
  34. public class KeywordMap
  35. {
  36. //{{{ KeywordMap constructor
  37. /**
  38. * Creates a new <code>KeywordMap</code>.
  39. * @param ignoreCase True if keys are case insensitive
  40. */
  41. public KeywordMap(boolean ignoreCase)
  42. {
  43. this(ignoreCase, 52);
  44. this.ignoreCase = ignoreCase;
  45. noWordSep = new StringBuffer();
  46. } //}}}
  47. //{{{ KeywordMap constructor
  48. /**
  49. * Creates a new <code>KeywordMap</code>.
  50. * @param ignoreCase True if the keys are case insensitive
  51. * @param mapLength The number of `buckets' to create.
  52. * A value of 52 will give good performance for most maps.
  53. */
  54. public KeywordMap(boolean ignoreCase, int mapLength)
  55. {
  56. this.mapLength = mapLength;
  57. this.ignoreCase = ignoreCase;
  58. map = new Keyword[mapLength];
  59. } //}}}
  60. //{{{ lookup() method
  61. /**
  62. * Looks up a key.
  63. * @param text The text segment
  64. * @param offset The offset of the substring within the text segment
  65. * @param length 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,
  80. k.keyword))
  81. return k.id;
  82. k = k.next;
  83. }
  84. return Token.NULL;
  85. } //}}}
  86. //{{{ add() method
  87. /**
  88. * Adds a key-value mapping.
  89. * @param keyword The key
  90. * @param id The value
  91. */
  92. public void add(String keyword, byte id)
  93. {
  94. add(keyword.toCharArray(),id);
  95. } //}}}
  96. //{{{ add() method
  97. /**
  98. * Adds a key-value mapping.
  99. * @param keyword The key
  100. * @param id The value
  101. * @since jEdit 4.2pre3
  102. */
  103. public void add(char[] keyword, byte id)
  104. {
  105. int key = getStringMapKey(keyword);
  106. // complete-word command needs a list of all non-alphanumeric
  107. // characters used in a keyword map.
  108. loop: for(int i = 0; i < keyword.length; i++)
  109. {
  110. char ch = keyword[i];
  111. if(!Character.isLetterOrDigit(ch))
  112. {
  113. for(int j = 0; j < noWordSep.length(); j++)
  114. {
  115. if(noWordSep.charAt(j) == ch)
  116. continue loop;
  117. }
  118. noWordSep.append(ch);
  119. }
  120. }
  121. noWordSepStr = null;
  122. map[key] = new Keyword(keyword,id,map[key]);
  123. } //}}}
  124. //{{{ getNonAlphaNumericChars() method
  125. /**
  126. * Returns all non-alphanumeric characters that appear in the
  127. * keywords of this keyword map.
  128. * @since jEdit 4.0pre3
  129. */
  130. public String getNonAlphaNumericChars()
  131. {
  132. return noWordSep.toString();
  133. } //}}}
  134. //{{{ getKeywords() method
  135. /**
  136. * Returns an array containing all keywords in this keyword map.
  137. * @since jEdit 4.0pre3
  138. */
  139. public String[] getKeywords()
  140. {
  141. Vector vector = new Vector(100);
  142. for(int i = 0; i < map.length; i++)
  143. {
  144. Keyword keyword = map[i];
  145. while(keyword != null)
  146. {
  147. vector.addElement(new String(keyword.keyword));
  148. keyword = keyword.next;
  149. }
  150. }
  151. String[] retVal = new String[vector.size()];
  152. vector.copyInto(retVal);
  153. return retVal;
  154. } //}}}
  155. //{{{ getIgnoreCase() method
  156. /**
  157. * Returns true if the keyword map is set to be case insensitive,
  158. * false otherwise.
  159. */
  160. public boolean getIgnoreCase()
  161. {
  162. return ignoreCase;
  163. } //}}}
  164. //{{{ setIgnoreCase() method
  165. /**
  166. * Sets if the keyword map should be case insensitive.
  167. * @param ignoreCase True if the keyword map should be case
  168. * insensitive, false otherwise
  169. */
  170. public void setIgnoreCase(boolean ignoreCase)
  171. {
  172. this.ignoreCase = ignoreCase;
  173. } //}}}
  174. //{{{ add() method
  175. /**
  176. * Adds the content of another keyword map to this one.
  177. * @since jEdit 4.2pre3
  178. */
  179. public void add(KeywordMap map)
  180. {
  181. for(int i = 0; i < map.map.length; i++)
  182. {
  183. Keyword k = map.map[i];
  184. while(k != null)
  185. {
  186. add(k.keyword,k.id);
  187. k = k.next;
  188. }
  189. }
  190. } //}}}
  191. //{{{ Private members
  192. //{{{ Instance variables
  193. private int mapLength;
  194. private Keyword[] map;
  195. private boolean ignoreCase;
  196. private StringBuffer noWordSep;
  197. private String noWordSepStr;
  198. //}}}
  199. //{{{ getStringMapKey() method
  200. private int getStringMapKey(String s)
  201. {
  202. return (Character.toUpperCase(s.charAt(0)) +
  203. Character.toUpperCase(s.charAt(s.length()-1)))
  204. % mapLength;
  205. } //}}}
  206. //{{{ getStringMapKey() method
  207. private int getStringMapKey(char[] s)
  208. {
  209. return (Character.toUpperCase(s[0]) +
  210. Character.toUpperCase(s[s.length-1]))
  211. % mapLength;
  212. } //}}}
  213. //{{{ getSegmentMapKey() method
  214. protected int getSegmentMapKey(Segment s, int off, int len)
  215. {
  216. return (Character.toUpperCase(s.array[off]) +
  217. Character.toUpperCase(s.array[off + len - 1]))
  218. % mapLength;
  219. } //}}}
  220. //}}}
  221. //{{{ Keyword class
  222. class Keyword
  223. {
  224. public Keyword(char[] keyword, byte id, Keyword next)
  225. {
  226. this.keyword = keyword;
  227. this.id = id;
  228. this.next = next;
  229. }
  230. public char[] keyword;
  231. public byte id;
  232. public Keyword next;
  233. } //}}}
  234. }