    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    }