-- Copyright 1993-1998, by the Cecil Project -- Department of Computer Science and Engineering, University of Washington -- See the LICENSE file for license information. --DOC `identity_assoc_table' is an implementation of tables based on a --DOC linked-list of key/value associations. It uses object identity --DOC (`==') to compare keys. template object identity_assoc[Key,Value] isa comparable[identity_assoc[Key,Value]]; field key(@:identity_assoc[`Key,`Value]):Key; var field value(@:identity_assoc[`Key,`Value]):Value; method =(l@:identity_assoc[`Key1,`Value1], r@:identity_assoc[`Key2,`Value2]):bool { l == r | { l.key == r.key } } method print_string(a@:identity_assoc[`Key,`Value]):string { a.key.print_string || " -> " || a.value.print_string } method new_identity_assoc[Key,Value](k:Key, v:Value ):identity_assoc[Key,Value] { concrete object isa identity_assoc[Key,Value] { key := k, value := v } } method copy(a@:identity_assoc[`Key,`Value]):identity_assoc[Key,Value] { new_identity_assoc[Key,Value](a.key, a.value) } template object identity_assoc_table[Key,Value] isa m_removable_table[Key,Value]; private field assocs(@:identity_assoc_table[`Key,`Value] ):m_list[identity_assoc[Key,Value]] := new_m_list[identity_assoc[Key,Value]](); method length(t@:identity_assoc_table[`Key,`Value]):int { t.assocs.length } method is_empty(t@:identity_assoc_table[`Key,`Value]):bool { t.assocs.is_empty } method do_associations(t@:identity_assoc_table[`Key,`Value], c:&(Key,Value):void):void { do(t.assocs, &(a:identity_assoc[Key,Value]){ eval(c, a.key, a.value); }); } method fetch(t@:identity_assoc_table[`Key,`Value], key:Key, if_absent:&():Value):Value { t.do_associations(&(k:Key, v:Value){ if(key == k, { ^ v }); }); eval(if_absent) } method store(t@:identity_assoc_table[`Key,`Value], key:Key, value:Value, if_absent:&():void):void { do(t.assocs, &(a:identity_assoc[Key,Value]){ if(key == a.key, { a.value := value; ^ }); }); add(t.assocs, new_identity_assoc[Key,Value](key, value)); if(warn_for_long_assoc_tables & { t.length = 11 }, { print_line("\a** warning: identity_assoc_table " || t.print_string || " grew to more than 10 entries"); }); } method remove_key(t@:identity_assoc_table[`Key,`Value], key:Key, if_absent:&():`Else):Value|Else { t.assocs.remove_and_return_one( &(x:identity_assoc[Key,Value]){ x.key == key }, { ^ eval(if_absent) }).value } method remove_keys_if(t@:identity_assoc_table[`Key,`Value], pred:&(Key):bool):int { t.assocs.remove_if( &(a:identity_assoc[Key,Value]){ eval(pred, a.key); }); } method remove_all(t@:identity_assoc_table[`Key,`Value]):void { t.assocs.remove_all; } method new_identity_assoc_table[Key,Value]():identity_assoc_table[Key,Value] { concrete object isa identity_assoc_table[Key,Value] } method copy_empty(t@:identity_assoc_table[`Key,`Value] ):identity_assoc_table[Key,Value] { new_identity_assoc_table[Key,Value]() } method copy(t@:identity_assoc_table[`Key,`Value] ):identity_assoc_table[Key,Value] { let c:identity_assoc_table[Key,Value] := t.copy_empty; t.assocs.do(&(a:identity_assoc[Key,Value]){ c.assocs.add(a.copy); }); c } -- -- table data structure with different printing behavior -- template object identity_assoc_CR_table[Key,Value] isa identity_assoc_table[Key,Value]; method elem_separator(t@:identity_assoc_CR_table[`Key,`Value]):string { "\n" } method new_identity_assoc_CR_table[Key,Value]() :identity_assoc_CR_table[Key,Value] { concrete object isa identity_assoc_CR_table[Key,Value] } method copy_empty(c@:identity_assoc_CR_table[`Key,`Value] ):identity_assoc_CR_table[Key,Value] { new_identity_assoc_CR_table[Key,Value]() }