package com.googlecode.totallylazy.collections; import com.googlecode.totallylazy.Arrays; import com.googlecode.totallylazy.Option; import com.googlecode.totallylazy.Value; import com.googlecode.totallylazy.annotations.tailrec; import static com.googlecode.totallylazy.Arrays.head; import static com.googlecode.totallylazy.Arrays.tail; import static com.googlecode.totallylazy.Option.none; import static com.googlecode.totallylazy.Option.option; public class ArrayTrie<K, V> implements Value<V> { private final Option<V> value; private final PersistentMap<K, ArrayTrie<K, V>> children; private ArrayTrie(Option<V> value, PersistentMap<K, ArrayTrie<K, V>> children) { this.value = value; this.children = children; } public static <K, V> ArrayTrie<K, V> trie() { return trie(Option.<V>none()); } public static <K, V> ArrayTrie<K, V> trie(Option<V> value) { return trie(value, ListMap.<K, ArrayTrie<K, V>>emptyListMap()); } public static <K, V> ArrayTrie<K, V> trie(Option<V> value, PersistentMap<K, ArrayTrie<K, V>> children) { return new ArrayTrie<K, V>(value, children); } @tailrec public boolean contains(K[] key) { if (Arrays.isEmpty(key)) return !value.isEmpty(); Option<ArrayTrie<K, V>> child = childFor(key); if (child.isEmpty()) return false; return child.get().contains(tail(key)); } @tailrec public Option<V> get(K[] key) { if (Arrays.isEmpty(key)) return value; Option<ArrayTrie<K, V>> child = childFor(key); if (child.isEmpty()) return none(); return child.get().get(tail(key)); } public ArrayTrie<K, V> put(K[] key, V value) { if (Arrays.isEmpty(key)) return trie(option(value), children); return trie(this.value, children.insert(head(key), childFor(key).getOrElse(ArrayTrie.<K, V>trie()).put(tail(key), value))); } public ArrayTrie<K, V> remove(K[] key) { return put(key, null); } public V value() { return value.get(); } public boolean isEmpty() { return value.isEmpty() && children.isEmpty(); } private Option<ArrayTrie<K, V>> childFor(K[] key) {return children.lookup(head(key));} }