// 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;
*() {}
*(B *value) {}
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));
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.children().put(subList(key, l(existingPrefix)), child);
branch.children.put(substring, newChild(value));
ret;
}
// case 3: no existing prefix, just add new child
if (children == null) children = new TreeMap;
children.put(string, newChild(value));
}
// returns TreeMap or ciMap
Map, B> asMap() {
Map, B> map = isCaseInsensitive() ? ciMap() : new TreeMap;
new StringBuilder buf;
collectMap(buf, map);
ret map;
}
private void collectMap(StringBuilder buf, Map, B> map) {
if (value != null) map.put(str(buf), value);
int n = l(buf);
for (L string, ListTrie child : children) {
buf.append(string);
child.collectMap(buf, map);
buf.setLength(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(quote(string));
child.toString(buf, indent);
}
}
private ListTrie newChild(B value) {
ret new ListTrie(comparator, value);
}
private TreeMap, ListTrie> children() {
if (children == null) children = new TreeMap(listComparator(comparator));
ret children;
}
Set> childStrings() { ret keys(children); }
ListTrie getChild(L string) { ret children.get(string); }
}