meaningless comment
[ephemerata.git] / KezvhLib / src-lib / net / kezvh / collections / text / TrieMap.java
blob554974159f2f78521d1ed93ab323cf9f32263a06
1 package net.kezvh.collections.text;
3 import java.util.AbstractMap;
4 import java.util.AbstractSet;
5 import java.util.ArrayList;
6 import java.util.Arrays;
7 import java.util.Collection;
8 import java.util.Comparator;
9 import java.util.Iterator;
10 import java.util.LinkedList;
11 import java.util.Map;
12 import java.util.NoSuchElementException;
13 import java.util.Set;
14 import java.util.SortedMap;
15 import java.util.SortedSet;
17 import net.kezvh.collections.TreeIterator;
18 import net.kezvh.collections.views.IteratorView;
19 import net.kezvh.development.UnimplementedException;
20 import net.kezvh.functional.lambda.L1;
22 /**
23 * @author afflux
24 * @param <T> COMMENT
26 public class TrieMap<T> extends AbstractMap<String, T> implements SortedMap<String, T> {
27 private final TreeIterator.ChildrenAccessor<TrieNode<T>> childrenAccessor = new TreeIterator.ChildrenAccessor<TrieNode<T>>() {
28 /**
29 * @see net.kezvh.collections.TreeIterator.ChildrenAccessor#getChildren(java.lang.Object)
30 * @param node COMMENT
31 * @return x
33 @Override
34 public Set<TrieNode<T>> getChildren(final TrieNode<T> node) {
35 return new AbstractSet<TrieNode<T>>() {
37 @Override
38 public Iterator<TrieNode<T>> iterator() {
39 return node.suffices.iterator();
42 @Override
43 public int size() {
44 return node.suffices.size();
51 private static final class TrieNode<V> {
52 private char[] keys = new char[] {};
53 private final ArrayList<TrieNode<V>> suffices = new ArrayList<TrieNode<V>>() {
54 /**
55 * @see java.util.AbstractList#iterator()
56 * @return x
58 @Override
59 public Iterator<TrieNode<V>> iterator() {
60 final Iterator<TrieNode<V>> iterator = super.iterator();
61 return new Iterator<TrieNode<V>>() {
62 /**
63 * @see java.util.Iterator#hasNext()
64 * @return x
66 @Override
67 public boolean hasNext() {
68 return iterator.hasNext();
71 /**
72 * @see java.util.Iterator#next()
73 * @return x
75 @Override
76 public TrieNode<V> next() {
77 return iterator.next();
80 /**
81 * @see java.util.Iterator#remove()
83 @Override
84 public void remove() {
85 iterator.remove();
86 throw new UnimplementedException("need to invoke remove on the TriENode"); // FIXME
91 private V value;
93 /**
94 * @param index COMMENT
95 * @return x
97 public char getSuffixKey(final int index) {
98 return this.keys[index];
102 * @param index COMMENT
103 * @return x
105 public TrieNode<V> getSuffixNode(final int index) {
106 return this.suffices.get(index);
110 * @param key COMMENT
111 * @return x
113 public TrieNode<V> find(final char key) {
114 return this.getSuffixNode(this.keyIndex(key));
118 * @param key COMMENT
119 * @return x
121 public int keyIndex(final char key) {
122 return Arrays.binarySearch(this.keys, key);
126 * @param key COMMENT
127 * @param newValue COMMENT
128 * @param insertionPoint COMMENT
130 public void insert(final char key, final TrieNode<V> newValue, final int insertionPoint) {
131 final char[] newKeys = new char[this.keys.length + 1];
132 System.arraycopy(this.keys, 0, newKeys, 0, insertionPoint);
133 newKeys[insertionPoint] = key;
134 System.arraycopy(this.keys, insertionPoint, newKeys, insertionPoint + 1, this.keys.length - insertionPoint);
135 this.keys = newKeys;
136 this.suffices.add(insertionPoint, newValue);
137 this.suffices.trimToSize();
141 * @return x
143 public int getNumKeys() {
144 return this.keys.length;
148 * @return your mom
150 public int getNumEntries() {
151 int numEntries = 0;
152 if (this.value != null)
153 numEntries++;
155 for (final TrieNode<V> t : this.suffices)
156 numEntries += t.getNumEntries();
157 return numEntries;
161 * @param key COMMENT
162 * @param newValue COMMENT
163 * @return x
165 public TrieNode<V> put(final char key, final TrieNode<V> newValue) {
166 final int index = this.keyIndex(key);
167 if (index >= 0)
168 return this.suffices.set(index, newValue);
170 final int insertionPoint = -(index + 1);
171 this.insert(key, newValue, insertionPoint);
172 return null;
176 * @return x
178 public boolean hasValue() {
179 return this.value != null;
183 * @return x
185 public V getValue() {
186 return this.value;
190 * @param value COMMENT
191 * @return x
193 public V setValue(final V value) {
194 try {
195 return this.value;
196 } finally {
197 this.value = value;
202 private final TrieNode<T> rootTrieNode = new TrieNode<T>();
205 * @see java.util.AbstractMap#put(java.lang.Object, java.lang.Object)
206 * @param key COMMENT
207 * @param value COMMENT
208 * @return x
210 @Override
211 public T put(final String key, final T value) {
212 // final long[] longs = TrieMap.getLongs(key);
213 final char[] chars = key.toCharArray();
214 TrieNode<T> t = this.rootTrieNode;
216 for (final char element : chars) {
217 final int index = t.keyIndex(element);
218 if (index >= 0)
219 t = t.getSuffixNode(index);
221 else {
222 final int insertionPoint = -(index + 1);
223 final TrieNode<T> tn = new TrieNode<T>();
224 t.insert(element, tn, insertionPoint);
225 t = tn;
229 return t.setValue(value);
233 * @see java.util.AbstractMap#containsKey(java.lang.Object)
234 * @param key COMMENT
235 * @return x
237 @Override
238 public boolean containsKey(final Object key) {
239 if (key == null || String.class != key.getClass())
240 return false;
242 final String string = (String) key;
243 // final long[] longs = TrieMap.getLongs(string);
244 final char[] chars = string.toCharArray();
245 TrieNode<T> t = this.rootTrieNode;
246 for (final char element : chars) {
247 final int index = t.keyIndex(element);
248 if (index >= 0)
249 t = t.getSuffixNode(index);
250 else
251 return false;
254 return t.hasValue();
258 * @see java.util.AbstractMap#get(java.lang.Object)
259 * @param key COMMENT
260 * @return x
262 @Override
263 public T get(final Object key) {
264 if (key == null || String.class != key.getClass())
265 return null;
267 final String string = (String) key;
268 // final long[] longs = TrieMap.getLongs(string);
269 final char[] chars = string.toCharArray();
270 TrieNode<T> t = this.rootTrieNode;
271 for (final char element : chars) {
272 final int index = t.keyIndex(element);
273 if (index >= 0)
274 t = t.getSuffixNode(index);
275 else
276 return null;
279 return t.getValue();
283 * TODO: this MUST implement SortedSet
285 * @author afflux
287 private final class EntrySet extends AbstractSet<Map.Entry<String, T>> implements SortedSet<Map.Entry<String, T>> {
289 private final L1<Map.Entry<String, T>, TrieNode<T>> map = new L1<Entry<String, T>, TrieNode<T>>() {
291 * @see L1
292 * @param param COMMENT
293 * @return x
295 @Override
296 public Entry<String, T> op(final TrieNode<T> param) {
297 return new Map.Entry<String, T>() {
299 * @see java.util.Map.Entry#getKey()
300 * @return x
302 @Override
303 public String getKey() {
305 throw new UnimplementedException();
306 // param
307 // AAAAAAAAAAAAARRRRRRRRRRRRRGGGGGGGGGGGGGGGGGHHHHHHHHHHHHHHH
308 // // FIXME
312 * @see java.util.Map.Entry#getValue()
313 * @return x
315 @Override
316 public T getValue() {
317 return param.getValue();
321 * @see java.util.Map.Entry#setValue(java.lang.Object)
322 * @param value COMMENT
323 * @return x
325 @Override
326 public T setValue(final T value) {
327 return param.setValue(value);
334 * @see java.util.AbstractCollection#iterator()
335 * @return x
337 @Override
338 public Iterator<java.util.Map.Entry<String, T>> iterator() {
339 return new IteratorView<TrieNode<T>, Entry<String, T>>(this.map, new TreeIterator<TrieNode<T>>(TrieMap.this.rootTrieNode, TrieMap.this.childrenAccessor));
343 * @see java.util.AbstractCollection#size()
344 * @return x
346 @Override
347 public int size() {
348 return TrieMap.this.size();
351 @Override
352 public Comparator<? super java.util.Map.Entry<String, T>> comparator() {
353 throw new UnimplementedException(); // FIXME
356 @Override
357 public java.util.Map.Entry<String, T> first() {
358 throw new UnimplementedException(); // FIXME
361 @Override
362 public SortedSet<java.util.Map.Entry<String, T>> headSet(final java.util.Map.Entry<String, T> toElement) {
363 throw new UnimplementedException(); // FIXME
366 @Override
367 public java.util.Map.Entry<String, T> last() {
368 throw new UnimplementedException(); // FIXME
371 @Override
372 public SortedSet<java.util.Map.Entry<String, T>> subSet(final java.util.Map.Entry<String, T> fromElement, final java.util.Map.Entry<String, T> toElement) {
373 throw new UnimplementedException(); // FIXME
376 @Override
377 public SortedSet<java.util.Map.Entry<String, T>> tailSet(final java.util.Map.Entry<String, T> fromElement) {
378 throw new UnimplementedException(); // FIXME
383 private EntrySet entrySet = null;
386 * @see java.util.AbstractMap#entrySet()
387 * @return x
389 @Override
390 public Set<java.util.Map.Entry<String, T>> entrySet() {
391 if (this.entrySet == null)
392 this.entrySet = new EntrySet();
393 return this.entrySet;
397 * @see java.util.SortedMap#comparator()
398 * @return x
400 public Comparator<? super String> comparator() {
401 return new Comparator<String>() {
403 * @see java.util.Comparator#compare(java.lang.Object,
404 * java.lang.Object)
405 * @param o1 COMMENT
406 * @param o2 COMMENT
407 * @return o1.compareTo(o2)
409 @Override
410 public int compare(final String o1, final String o2) {
411 return o1.compareTo(o2);
417 * @see java.util.SortedMap#firstKey()
418 * @return x
420 public String firstKey() {
421 if (this.isEmpty())
422 throw new NoSuchElementException();
424 return null;
428 * @see java.util.SortedMap#headMap(java.lang.Object)
429 * @param toKey COMMENT
430 * @return x
432 public SortedMap<String, T> headMap(final String toKey) {
433 return null;
437 * @see java.util.SortedMap#lastKey()
438 * @return x
440 public String lastKey() {
441 if (this.isEmpty())
442 throw new NoSuchElementException();
444 return null;
448 * @see java.util.SortedMap#subMap(java.lang.Object, java.lang.Object)
449 * @param fromKey COMMENT
450 * @param toKey COMMENT
451 * @return x
453 public SortedMap<String, T> subMap(final String fromKey, final String toKey) {
454 return null;
458 * @see java.util.SortedMap#tailMap(java.lang.Object)
459 * @param fromKey COMMENT
460 * @return x
462 public SortedMap<String, T> tailMap(final String fromKey) {
463 return null;
466 private boolean hasSuffix(final TrieNode<T> trieNode, final char[] chars, final int firstCharIndex) {
467 TrieNode<T> currentNode = trieNode;
468 for (int i = firstCharIndex; i < chars.length; i++) {
469 final int keyIndex = currentNode.keyIndex(chars[i]);
470 if (keyIndex >= 0)
471 currentNode = currentNode.getSuffixNode(keyIndex);
472 else
473 return false;
476 return currentNode.hasValue();
479 private ArrayList<TrieNode<T>> getTrieNodes(final char[] chars) {
480 TrieNode<T> currentTrieNode = this.rootTrieNode;
481 final ArrayList<TrieNode<T>> trieNodes = new ArrayList<TrieNode<T>>(chars.length + 1);
483 trieNodes.add(this.rootTrieNode);
485 for (final char element : chars) {
486 final TrieNode<T> nextTrieNode = currentTrieNode.find(element);
487 trieNodes.add(nextTrieNode);
488 currentTrieNode = nextTrieNode;
490 trieNodes.trimToSize();
491 return trieNodes;
494 private Collection<String> getSingleChars() {
495 final Collection<String> similar = new LinkedList<String>();
496 for (int i = 0; i < this.rootTrieNode.getNumKeys(); i++)
497 if (this.rootTrieNode.getSuffixNode(i).hasValue())
498 similar.add(String.valueOf(this.rootTrieNode.getSuffixKey(i)));
499 return similar;
503 * @param key COMMENT
504 * @return x
506 public Collection<String> getKeysSimilarTo(final String key) {
507 // FIXME refactor this nasty motherfucker.
508 final int len = key.length();
509 if (len == 0)
510 return this.getSingleChars();
511 final Collection<String> similar = new LinkedList<String>();
513 final StringBuffer add = new StringBuffer(key + 'X'); // add
514 final StringBuffer rem = new StringBuffer(key.subSequence(0, len - 1)); // remove
515 final StringBuffer del = new StringBuffer(key); // change
517 final char[] chars = key.toCharArray();
518 final ArrayList<TrieNode<T>> trieNodes = this.getTrieNodes(chars); // len
519 // +
520 // 1
521 // elements,
522 // 0
523 // is
524 // root
526 { // first iteration, last character, only care about adds
527 final TrieNode<T> lastNode = trieNodes.get(len);
528 for (int i = 0; i < lastNode.getNumKeys(); i++)
529 if (lastNode.getSuffixNode(i).hasValue()) {
530 add.setCharAt(len, lastNode.getSuffixKey(i));
531 similar.add(add.toString());
534 add.setCharAt(len, chars[len - 1]); // set last character of add
537 for (int k = len - 1; k >= 0; k--) {
538 final TrieNode<T> cur = trieNodes.get(k);
539 if (this.hasSuffix(cur, chars, k + 1)) // removes
540 similar.add(rem.toString());
542 for (int i = 0; i < cur.getNumKeys(); i++) {
543 final char c = cur.getSuffixKey(i);
545 if (chars[k] == c)
546 continue;
548 final TrieNode<T> node = cur.getSuffixNode(i);
550 if (this.hasSuffix(node, chars, k + 1)) { // changes
551 del.setCharAt(k, c);
552 similar.add(del.toString());
555 if (this.hasSuffix(node, chars, k)) { // adds
556 add.setCharAt(k, c);
557 similar.add(add.toString());
561 del.setCharAt(k, chars[k]);
562 if (k > 0) {
563 add.setCharAt(k, chars[k - 1]);
564 rem.setCharAt(k - 1, chars[k]);
568 return similar;