001 package org.maltparser.core.symbol.trie;
002
003 import java.util.HashMap;
004
005 import org.maltparser.core.symbol.SymbolException;
006
007 /**
008
009 @author Johan Hall
010 @since 1.0
011 */
012 public class TrieNode {
013 /**
014 * Initial capacity of the hash maps.
015 */
016 private final static int INITIAL_CAPACITY = 2;
017 /**
018 * the character that corresponds to the trie node
019 */
020 private char character;
021 /**
022 * Maps a symbol table into an entry (if not cached)
023 */
024 private HashMap<TrieSymbolTable,TrieEntry> entries;
025 /**
026 * Maps a symbol table (cachedKeyEntry) into an entry (cachedValueEntry), caches only the first occurrence.
027 */
028 private TrieSymbolTable cachedKeyEntry;
029 private TrieEntry cachedValueEntry;
030
031 /**
032 * Maps a character into a child trie node (if not cached)
033 */
034 private HashMap<Character,TrieNode> children;
035 private char cachedKeyChar;
036 private TrieNode cachedValueTrieNode;
037
038 /**
039 * The parent trie node
040 */
041 private TrieNode parent;
042
043 /**
044 * Constructs a trie node
045 *
046 * @param character which character that the trie node belongs to
047 * @param parent the parent trie node
048 */
049 public TrieNode(char character, TrieNode parent) {
050 this.character = character;
051 this.parent = parent;
052 }
053
054 /**
055 * Adds and/or retrieve a child trie node. It only adds a entry if the parameter isWord is true.
056 *
057 * @param isWord true if it is a word (entry), otherwise false
058 * @param c the character to the child node
059 * @param table which symbol table to look in or add to
060 * @param code the integer representation of the string value
061 * @return the child trie node that corresponds to the character
062 * @throws SymbolException
063 */
064 public TrieNode getOrAddChild(boolean isWord, char c, TrieSymbolTable table, int code) throws SymbolException {
065 if (cachedValueTrieNode == null) {
066 cachedValueTrieNode = new TrieNode(c, this);
067 cachedKeyChar = c;
068 if (isWord) {
069 cachedValueTrieNode.addEntry(table, code);
070 }
071 return cachedValueTrieNode;
072 } else if (cachedKeyChar == c) {
073 if (isWord) {
074 cachedValueTrieNode.addEntry(table, code);
075 }
076 return cachedValueTrieNode;
077 } else {
078 TrieNode child = null; //table.getTrie().addTrieNodeChild(c, this);
079 if (children == null) {
080 children = new HashMap<Character, TrieNode>(INITIAL_CAPACITY);
081 child = new TrieNode(c, this);
082 children.put(c,child);
083 } else {
084 child = children.get(c);
085 if (child == null) {
086 child = new TrieNode(c, this);
087 children.put(c,child);
088 }
089 }
090 if (isWord) {
091 child.addEntry(table, code);
092 }
093 return child;
094 }
095 }
096
097 /**
098 * Adds an entry if it does not exist
099 *
100 * @param table which symbol table to add an entry
101 * @param code the integer representation of the string value
102 * @throws SymbolException
103 */
104 private void addEntry(TrieSymbolTable table, int code) throws SymbolException {
105 if (table == null) {
106 throw new SymbolException("Symbol table cannot be found. ");
107 }
108 if (cachedValueEntry == null) {
109 if (code != -1) {
110 cachedValueEntry = new TrieEntry(code,true);
111 table.updateValueCounter(code);
112 } else {
113 cachedValueEntry = new TrieEntry(table.increaseValueCounter(),false);
114 }
115 cachedKeyEntry = table;
116 } else if (!table.equals(cachedKeyEntry)) {
117 if (entries == null) {
118 entries = new HashMap<TrieSymbolTable, TrieEntry>(INITIAL_CAPACITY);
119 }
120 if (!entries.containsKey(table)) {
121 if (code != -1) {
122 entries.put(table, new TrieEntry(code,true));
123 table.updateValueCounter(code);
124 } else {
125 entries.put(table, new TrieEntry(table.increaseValueCounter(),false));
126 }
127 }
128 }
129 }
130
131 /**
132 * Returns the child node that corresponds to the character
133 *
134 * @param c the character of the child node
135 * @return the child node
136 */
137 public TrieNode getChild(char c) {
138 if (cachedKeyChar == c) {
139 return cachedValueTrieNode;
140 } else if (children != null) {
141 return children.get(c);
142 }
143 return null;
144 }
145
146
147
148 /**
149 * Returns the entry of the symbol table 'table'
150 *
151 * @param table which symbol table
152 * @return the entry of the symbol table 'table'
153 */
154 public TrieEntry getEntry(TrieSymbolTable table) {
155 if (table != null) {
156 if (table.equals(cachedKeyEntry)) {
157 return cachedValueEntry;
158 } else if (entries != null) {
159 return entries.get(table);
160 }
161 }
162 return null;
163 }
164
165 /**
166 * Returns the character of the trie node
167 *
168 * @return the character of the trie node
169 */
170 public char getCharacter() {
171 return character;
172 }
173
174 /**
175 * Returns the parent node
176 *
177 * @return the parent node
178 */
179 public TrieNode getParent() {
180 return parent;
181 }
182
183 public boolean equals(Object obj) {
184 return super.equals(obj);
185 }
186
187 public int hashCode() {
188 return super.hashCode();
189 }
190
191 public String toString() {
192 final StringBuilder sb = new StringBuilder();
193 sb.append(character);
194 return sb.toString();
195 }
196 }