package jazz.unsafe;
///////////////////////////////////////////////////////////////////////////////
//
// Iimperative implementation of hashtables
//
// Keys should be either of a numeric type or a string. Elements can be of any
// type, and the static type of the elements returned by "get" is the empty
// type that can be cast into any type as needed. Type-safety therefore
// entirely relies on the user. Put and get operations must be explicitly
// serialized, otherwise put and get operations can occur in undefined order
// and results are undefined.
//
///////////////////////////////////////////////////////////////////////////////
public class Hashtable {
// Constructor
public static create(): Hashtable;
// Number of key/element pairs
public size(): int;
// Returns true if the table contains the elements
public contains<E>(element: E): boolean;
// Returns true if the table contains the key
public containsKey<K>(key: K): boolean;
// If the table contains the key, returns the associated elements, otherwise
// atomically associates the element to the key and returns the element. The
// second argument is only evaluated when the key is added to the table the
// first time.
public get<K, E>(key: K, element: E): E;
// Same thing, but returns a boolean indicating if the key has been added to
// the table.
public check<K, E>(key: K, element: E): boolean;
// Atomically associates the element to the key. This function is not
// compatible with the single-assignment semantics of the language (it is a
// pure side-effect) and should be used with great care. Whenever possible,
// the "get()" function should be used instead.
public put<K, E>(key: K, element: E): E;
// Associate each key to its matching element
public assoc<K, E>(n: int)(keys: K[n], elements: E[n]): ();
// Returns the array of keys of the table
public keys<K>(): K[size()];
// Returns the elements of the table
public elements<E>(): E[size()];
// Display
public static dynamic lbrace: String = "{";
public static dynamic arrow: String = " -> ";
public static dynamic separator: String = ", ";
public static dynamic rbrace: String = "}";
// Underlying native object
table: native;
getKey<K, E>(key: K): E;
}
///////////////////////////////////////////////////////////////////////////////
//
// Implementation
//
///////////////////////////////////////////////////////////////////////////////
Hashtable.create() =
new Hashtable(table = native("java.util.Hashtable()"));
size@Hashtable() = native("int java.util.Hashtable.size()", table);
// TEMPORARY (SHOULD BE ATOMIC)
getKey@Hashtable(key) =
native("java.lang.Object "
"java.util.Hashtable.get(java.lang.Object)", table, key);
// TEMPORARY (SHOULD BE ATOMIC)
get@Hashtable(key, element) = (containsKey(key) ?
getKey(key) : (table'; element))
{
table' = native("java.lang.Object "
"java.util.Hashtable.put(java.lang.Object,java.lang.Object)",
table, key, element);
}
// TEMPORARY (SHOULD BE ATOMIC)
check@Hashtable(key, element) = (containsKey(key) ? false : (put; true))
{
put = native("java.lang.Object "
"java.util.Hashtable.put(java.lang.Object,java.lang.Object)",
table, key, element);
}
// TEMPORARY (SHOULD BE ATOMIC)
put@Hashtable(key, element) = (table'; element)
{
table' = native("java.lang.Object "
"java.util.Hashtable.put(java.lang.Object,java.lang.Object)",
table, key, element);
}
contains@Hashtable(element) =
native("boolean java.util.Hashtable.contains(java.lang.Object)",
table, element);
containsKey@Hashtable(key) =
native("boolean java.util.Hashtable.containsKey(java.lang.Object)",
table, key);
keys@Hashtable() = elements
{
enum = native("java.util.Enumeration "
"java.util.Hashtable.keys()",
table);
fun next() = native("java.lang.Object "
"java.util.HashtableEnumerator.nextElement()",
enum);
elements = [next(), i -> (elements[i-1]; next())];
}
elements@Hashtable() = elements
{
enum = native("java.util.Enumeration "
"java.util.Hashtable.elements()",
table);
fun next() = native("java.lang.Object "
"java.util.HashtableEnumerator.nextElement()",
enum);
elements = [next(), i -> (elements[i-1]; next())];
}
toString@Hashtable() = format("%s%s%s",
lbrace,
size() == 0 ? "" : str[size() - 1],
rbrace)
{
ks = keys();
str = [format("%a%s%a", ks[0], arrow, getKey(ks[0])),
i -> format("%s%s%a%s%a",
str[i-1], separator, ks[i], arrow, getKey(ks[i]))];
}
assoc@Hashtable(n)(keys, elements) = b[n]
{
b = [(), i -> (b[i - 1]; put(keys[i-1], elements[i-1]); ())];
}