// A = type of element in keys. // B = type of value in nodes. // Can be case-sensitive or case-insensitive // values can't be null sclass ListTrie { B value; Comparator comparator; TreeMap, ListTrie> children; *() {} *(Comparator *comparator) {} void add(L string, B value) { ifdef ListTrie_debug printFunctionCall("ListTrie add", string, value); endifdef // case 1: empty string if (empty(string)) ret with this.value = value; // case 2: some prefix of new string exists L existingPrefix = longestCommonPrefixOfNavigableSetAndList(string, navigableKeys(children), comparator); ifdef ListTrie_debug print(+existingPrefix); endifdef if (nempty(existingPrefix)) { ListTrie child = children.get(existingPrefix); L substring = subList(string, l(existingPrefix)); // case 2a: new string is complete suffix of existing child ifdef ListTrie_debug print(+child); endifdef if (child != null) ret with child.add(substring, value); // case 2b: make new branch ListTrie branch = newChild(null); Map.Entry, ListTrie> e = children.higherEntry(existingPrefix); L key = e.getKey(); child = e.getValue(); children.remove(e.getKey()); children.put(existingPrefix, branch); branch.makeChildren().put(subList(key, l(existingPrefix)), child); branch.children.put(substring, newChild(value)); ret; } // case 3: no existing prefix, just add new child makeChildren().put(string, newChild(value)); } Map, B> asMap() { Map, B> map = new TreeMap(listComparator(comparator)); new L buf; collectMap(buf, map); ret map; } private void collectMap(L buf, Map, B> map) { if (value != null) map.put(cloneList(buf), value); int n = l(buf); for (L string, ListTrie child : children) { buf.addAll(string); child.collectMap(buf, map); truncateList(buf, n); } } toString { new StringBuilder buf; if (value != null) { buf.append("\"\" => ").append(value).append("\n"); childrenToString(buf, 2); } else childrenToString(buf, 0); ret str(buf); } void toString(StringBuilder buf, int indent) { if (value != null) buf.append(" => ").append(value); buf.append("\n"); childrenToString(buf, indent+2); } void childrenToString(StringBuilder buf, int indent) { for (L string, ListTrie child : children) { buf.append(spaces(indent)).append(string); child.toString(buf, indent); } } private ListTrie newChild(B value) { ListTrie child = new(comparator); child.value = value; ret child; } private TreeMap, ListTrie> makeChildren() { if (children == null) children = new TreeMap(listComparator(comparator)); ret children; } Set> childStrings() { ret keys(children); } ListTrie getChild(L string) { ret children.get(string); } NavigableMap, ListTrie> children() { ret children; } }