Commit 887ed7c5 authored by Adam Blank's avatar Adam Blank
Browse files

Merge branch 'backport-p2-changes' into 'master'

Backport p2 changes



See merge request !8
parents 706d120f 548c2d71
package cse332.datastructures.containers;
/**
* Simple class to hold a piece of data and its value.
*
* @param <K>
* type of the key
* @param <V>
* type of the value
*/
public class Item<K, V> {
/**
* The key whose value we are recording.
*/
public K key;
/**
* The value we are recording.
*/
public V value;
/**
* Create a data count.
*
* @param key
* the key we are recording.
* @param value
* the value of the key we are recording.
*/
public Item(K key, V value) {
this.key = key;
this.value = value;
}
public Item(Item<K, V> item) {
this(item.key, item.value);
}
@Override
public String toString() {
return this.key + "=" + this.value + "";
}
}
package cse332.interfaces.trie;
package cse332.interfaces.misc;
import java.lang.reflect.InvocationTargetException;
import java.util.Iterator;
......@@ -6,48 +6,52 @@ import java.util.Iterator;
import cse332.interfaces.worklists.FixedSizeFIFOWorkList;
import datastructures.worklists.CircularArrayFIFOQueue;
public abstract class BString<Alphabet> implements Iterable<Alphabet> {
public abstract class BString<Alphabet extends Comparable<Alphabet>> implements Iterable<Alphabet>, Comparable<BString<Alphabet>> {
protected FixedSizeFIFOWorkList<Alphabet> str;
public BString(Alphabet[] str) {
this.str = new CircularArrayFIFOQueue<Alphabet>(str.length);
for (int i = 0; i < str.length; i++) {
this.str.add(str[i]);
}
this.str = new CircularArrayFIFOQueue<Alphabet>(str.length);
for (int i = 0; i < str.length; i++) {
this.str.add(str[i]);
}
}
public BString(FixedSizeFIFOWorkList<Alphabet> q) {
this.str = q;
this.str = q;
}
@Override
public final Iterator<Alphabet> iterator() {
return str.iterator();
return this.str.iterator();
}
@SuppressWarnings("unchecked")
public static <A, X extends BString<A>> Class<A> getLetterType(Class<X> clz) {
public static <A extends Comparable<A>, X extends BString<A>> Class<A> getLetterType(Class<X> clz) {
try {
return (Class<A>) clz.getMethod("getLetterType", (Class<?>[])null).invoke(null, (Object[])null);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException
return (Class<A>) clz.getMethod("getLetterType", (Class<?>[]) null)
.invoke(null, (Object[]) null);
} catch (IllegalAccessException | IllegalArgumentException
| InvocationTargetException | NoSuchMethodException
| SecurityException e) {
e.printStackTrace();
e.printStackTrace();
System.err.println(clz.getName() + " does not have a getLetterType() method");
System.exit(1);
/* This is not reachable... */
return null;
}
}
public int size() {
return str.size();
return this.str.size();
}
public final boolean isEmpty() {
return str.size() == 0;
return this.str.size() == 0;
}
@Override
public String toString() {
StringBuilder build = new StringBuilder();
for (Alphabet chr : this) {
......@@ -62,7 +66,7 @@ public abstract class BString<Alphabet> implements Iterable<Alphabet> {
out[i] = arr[i];
}
return out;
}
}
protected static Byte[] wrap(byte[] arr) {
Byte[] out = new Byte[arr.length];
......@@ -71,4 +75,23 @@ public abstract class BString<Alphabet> implements Iterable<Alphabet> {
}
return out;
}
@Override
public int compareTo(BString<Alphabet> other) {
return this.str.compareTo(other.str);
}
@Override
public int hashCode() {
return this.str.hashCode();
}
@Override
@SuppressWarnings("unchecked")
public boolean equals(Object other) {
if (!(other instanceof BString)) {
return false;
}
return this.str.equals(((BString<Alphabet>) other).str);
}
}
......@@ -2,54 +2,66 @@ package cse332.interfaces.misc;
import java.util.Iterator;
import cse332.datastructures.containers.Item;
/**
* An object that maps keys to values.
* A Dictionary cannot contain duplicate keys; each key can map to at most one value.
*
* An object that maps keys to values. A Dictionary cannot contain duplicate
* keys; each key can map to at most one value.
*
* Dictionaries may not contain null keys or values.
*
* @param <K> the type of keys maintained by this map
* @param <V> the type of mapped values
* @param <K>
* the type of keys maintained by this map
* @param <V>
* the type of mapped values
*
* @author Adam Blank
* @author Adam Blank
*/
public abstract class Dictionary<K, V> implements Iterable<K> {
public abstract class Dictionary<K, V> implements Iterable<Item<K, V>> {
protected int size;
/**
* Associates the specified value with the specified key in this map.
* If the map previously contained a mapping for the key, the old
* value is replaced.
* Associates the specified value with the specified key in this map. If the
* map previously contained a mapping for the key, the old value is
* replaced.
*
* @param key key with which the specified value is to be associated
* @param value value to be associated with the specified key
* @return the previous value associated with <tt>key</tt>, or
* <tt>null</tt> if there was no mapping for <tt>key</tt>.
* @throws IllegalArgumentException if either key or value is null.
* @param key
* key with which the specified value is to be associated
* @param value
* value to be associated with the specified key
* @return the previous value associated with <tt>key</tt>, or <tt>null</tt>
* if there was no mapping for <tt>key</tt>.
* @throws IllegalArgumentException
* if either key or value is null.
*/
public abstract V insert(K key, V value);
/**
* Returns the value to which the specified key is mapped,
* or {@code null} if this map contains no mapping for the key.
* Returns the value to which the specified key is mapped, or {@code null}
* if this map contains no mapping for the key.
*
* @param key the key whose associated value is to be returned
* @return the value to which the specified key is mapped, or
* {@code null} if this map contains no mapping for the key
* @throws IllegalArgumentException if key is null.
* @param key
* the key whose associated value is to be returned
* @return the value to which the specified key is mapped, or {@code null}
* if this map contains no mapping for the key
* @throws IllegalArgumentException
* if key is null.
*/
public abstract V find(K key);
/**
* Removes the mapping for the specified key from this map if present.
*
* @param key key whose mapping is to be removed from the map
* @throws IllegalArgumentException if key is null.
*/
* @param key
* key whose mapping is to be removed from the map
* @throws IllegalArgumentException
* if key is null.
*/
public abstract void delete(K key);
/**
* Resets the state of this map to be the same as if the constructor were just called.
* Resets the state of this map to be the same as if the constructor were
* just called.
*/
public abstract void clear();
......@@ -74,10 +86,18 @@ public abstract class Dictionary<K, V> implements Iterable<K> {
/**
* An iterator over the keys of the map
*/
public abstract Iterator<K> iterator();
/**
* Subclasses *must* override toString()
*/
public abstract String toString();
@Override
public abstract Iterator<Item<K, V>> iterator();
@Override
public String toString() {
StringBuilder result = new StringBuilder();
for (Item<K, V> item : this) {
result.append(item + ", ");
}
if (result.length() > 0) {
result.delete(result.length() - 2, result.length());
}
return "{" + result.toString() + "}";
}
}
......@@ -2,12 +2,15 @@ package cse332.interfaces.misc;
import java.util.Iterator;
import cse332.datastructures.containers.Item;
public abstract class Set<E> implements Iterable<E> {
protected Dictionary<E, Boolean> map;
@SuppressWarnings("unused")
private Set(){}
private Set() {
}
protected Set(Dictionary<E, Boolean> backingMap) {
this.map = backingMap;
}
......@@ -23,7 +26,7 @@ public abstract class Set<E> implements Iterable<E> {
public final boolean contains(E e) {
return this.map.find(e) != null;
}
public final int size() {
return this.map.size();
}
......@@ -31,15 +34,31 @@ public abstract class Set<E> implements Iterable<E> {
public final boolean isEmpty() {
return this.size() == 0;
}
@Override
public Iterator<E> iterator() {
return this.map.iterator();
return new SetIterator();
}
private class SetIterator implements Iterator<E> {
private final Iterator<Item<E, Boolean>> mapIterator = Set.this.map.iterator();
@Override
public boolean hasNext() {
return this.mapIterator.hasNext();
}
@Override
public E next() {
return this.mapIterator.next().key;
}
}
public void clear() {
this.map.clear();
}
@Override
public String toString() {
return this.map.toString();
}
......
......@@ -5,6 +5,8 @@ import java.lang.reflect.InvocationTargetException;
import java.util.Iterator;
import java.util.Map.Entry;
import cse332.datastructures.containers.Item;
import cse332.interfaces.misc.BString;
import cse332.interfaces.misc.Dictionary;
import cse332.interfaces.misc.SimpleIterator;
import cse332.interfaces.worklists.LIFOWorkList;
......@@ -13,32 +15,40 @@ import datastructures.worklists.ArrayStack;
import datastructures.worklists.ListFIFOQueue;
/**
* An object that maps keys (made up of characters of a bounded type) to values.
* A TrieMap cannot contain duplicate keys; each key can map to at most one value.
*
* An object that maps keys (made up of characters of a bounded type) to values.
* A TrieMap cannot contain duplicate keys; each key can map to at most one
* value.
*
* TrieMaps may not contain null keys or values.
*
* @param <A> the type of the characters of the BString key type
* @param <K> the type of BString keys maintained by this map
* @param <V> the type of mapped values
* @param <A>
* the type of the characters of the BString key type
* @param <K>
* the type of BString keys maintained by this map
* @param <V>
* the type of mapped values
*
* @author Adam Blank
* @author Adam Blank
*/
public abstract class TrieMap<A, K extends BString<A>, V> extends Dictionary<K, V> {
public abstract class TrieMap<A extends Comparable<A>, K extends BString<A>, V> extends Dictionary<K, V> {
protected TrieNode<?, ?> root;
/**
* This variable is a hack to get the type of the key at runtime. It is initialized when the first key
* is inserted or removed from the map.
/**
* This variable is a hack to get the type of the key at runtime. It is
* initialized when the first key is inserted or removed from the map.
*/
protected Class<K> KClass;
/**
* The constructor for the TrieMap class must take an instance of the key class. Such a variable looks like
* <class name>.class and is necessary because Java's generics are implemented with type erasure. If you are
* really interested in why this is necessary, please come and talk to the instructor.
*
* @param KClass a reflection variable representing the key class for this particular instance of TrieMap
* The constructor for the TrieMap class must take an instance of the key
* class. Such a variable looks like <class name>.class and is necessary
* because Java's generics are implemented with type erasure. If you are
* really interested in why this is necessary, please come and talk to the
* instructor.
*
* @param KClass
* a reflection variable representing the key class for this
* particular instance of TrieMap
*/
public TrieMap(Class<K> KClass) {
this.KClass = KClass;
......@@ -48,26 +58,32 @@ public abstract class TrieMap<A, K extends BString<A>, V> extends Dictionary<K,
* Returns <tt>true</tt> if this map contains a mapping for which the key
* starts with the specified key prefix.
*
* @param keyPrefix The prefix of a key whose presence in this map is to be tested
* @return <tt>true</tt> if this map contains a mapping whose key starts with the specified
* key prefix.
* @throws IllegalArgumentException if either key is null.
* @param keyPrefix
* The prefix of a key whose presence in this map is to be tested
* @return <tt>true</tt> if this map contains a mapping whose key starts
* with the specified key prefix.
* @throws IllegalArgumentException
* if either key is null.
*/
public abstract boolean findPrefix(K keyPrefix);
/**
* This class represents a single node of the Trie. Crazy generics are necessary to make the alphebetic
* Strings as generic as possible.
*
* This class represents a single node of the Trie. Crazy generics are
* necessary to make the alphebetic Strings as generic as possible.
*
* @author Adam Blank
*
* @param <PType> the type of the pointers in the node
* @param <X> the type of the node itself
* @param <PType>
* the type of the pointers in the node
* @param <X>
* the type of the node itself
*/
protected abstract class TrieNode<PType, X extends TrieNode<PType, X>> implements Iterable<Entry<A, X>> {
protected abstract class TrieNode<PType, X extends TrieNode<PType, X>>
implements Iterable<Entry<A, X>> {
public PType pointers;
public V value;
@Override
public String toString() {
StringBuilder b = new StringBuilder();
if (this.value != null) {
......@@ -79,7 +95,8 @@ public abstract class TrieMap<A, K extends BString<A>, V> extends Dictionary<K,
this.toString(b, 0);
}
return b.toString();
}
}
private String spaces(int i) {
StringBuilder sp = new StringBuilder();
for (int x = 0; x < i; x++) {
......@@ -87,6 +104,7 @@ public abstract class TrieMap<A, K extends BString<A>, V> extends Dictionary<K,
}
return sp.toString();
}
protected boolean toString(StringBuilder s, int indent) {
WorkList<Entry<A, X>> entries = new ListFIFOQueue<Entry<A, X>>();
for (Entry<A, X> entry : this) {
......@@ -98,11 +116,11 @@ public abstract class TrieMap<A, K extends BString<A>, V> extends Dictionary<K,
for (Entry<A, X> entry : this) {
A idx = entry.getKey();
X node = entry.getValue();
if (node == null) {
continue;
}
V value = node.value;
s.append(spaces(indent) + idx + (value != null ? "[" + value + "]" : ""));
s.append("-> {\n");
......@@ -110,7 +128,7 @@ public abstract class TrieMap<A, K extends BString<A>, V> extends Dictionary<K,
if (!bc) {
s.append(spaces(indent) + "},\n");
}
else if (s.charAt(s.length() - 5) == '-'){
else if (s.charAt(s.length() - 5) == '-') {
s.delete(s.length() - 5, s.length());
s.append(",\n");
}
......@@ -125,43 +143,45 @@ public abstract class TrieMap<A, K extends BString<A>, V> extends Dictionary<K,
/**
* Removes the mapping for the specified key from this map if present.
*
* @param key key whose mapping is to be removed from the map
* @throws IllegalArgumentException if either key is null.
*/
* @param key
* key whose mapping is to be removed from the map
* @throws IllegalArgumentException
* if either key is null.
*/
public void delete(A[] key) {
delete(keyFromLetters(key));
}
private class TrieMapIterator extends SimpleIterator<K> {
private WorkList<K> keys;
private class TrieMapIterator extends SimpleIterator<Item<K, V>> {
private final WorkList<K> keys;
public TrieMapIterator() {
keys = new ListFIFOQueue<>();
initialize(new ArrayStack<>(), TrieMap.this.root);
this.keys = new ListFIFOQueue<>();
initialize(new ArrayStack<A>(), TrieMap.this.root);
}
@SuppressWarnings("unchecked")
protected K makeKeyFromLIFOWorkList(LIFOWorkList<A> list) {
A[] letters = (A[])Array.newInstance(BString.getLetterType(KClass), list.size());
A[] letters = (A[]) Array
.newInstance(BString.getLetterType(TrieMap.this.KClass), list.size());
int i = letters.length - 1;
while (list.hasWork()) {
letters[i--] = list.next();
}
for (i = 0; i < letters.length; i++) {
list.add(letters[i]);
}
return keyFromLetters(letters);
}
}
@SuppressWarnings("unchecked")
private void initialize(LIFOWorkList<A> acc, TrieNode<?, ?> current) {
if (current != null) {
if (current.value != null) {
keys.add(makeKeyFromLIFOWorkList(acc));
this.keys.add(makeKeyFromLIFOWorkList(acc));
}
for (Entry<A, ?> entry : current) {
if (entry != null) {
......@@ -174,8 +194,9 @@ public abstract class TrieMap<A, K extends BString<A>, V> extends Dictionary<K,
}
@Override
public K next() {
return this.keys.next();
public Item<K, V> next() {
K key = this.keys.next();
return new Item<K, V>(key, find(key));
}
@Override
......@@ -184,30 +205,26 @@ public abstract class TrieMap<A, K extends BString<A>, V> extends Dictionary<K,
}
}
public Iterator<K> iterator() {
@Override
public Iterator<Item<K, V>> iterator() {
return new TrieMapIterator();
}
/**
* Returns a new key instance from an array of letters instances
* @param letters the underlying array of the new key instance
*
* @param letters
* the underlying array of the new key instance
* @return a new key instance with the same letters as letters
*/
public K keyFromLetters(A[] letters) {
try {
return (K) KClass.getConstructor(letters.getClass()).newInstance((Object)letters);
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException
| SecurityException | NoSuchMethodException e) {
return this.KClass.getConstructor(letters.getClass())
.newInstance((Object) letters);
} catch (InstantiationException | IllegalAccessException
| IllegalArgumentException | InvocationTargetException | SecurityException
| NoSuchMethodException e) {
throw new RuntimeException("this should never happen!");
}
}
public String toString() {
if (this.root == null) {
return "null";
} else {
return this.root.toString();
}
}
}
package cse332.interfaces.trie;
import cse332.interfaces.misc.BString;
import cse332.interfaces.misc.Set;
public abstract class TrieSet<A, E extends BString<A>> extends Set<E> {
public abstract class TrieSet<A extends Comparable<A>, E extends BString<A>> extends Set<E> {
protected TrieSet(TrieMap<A, E, Boolean> backingMap) {
super(backingMap);