From 2cd43e5a217318c70097334b3598d2924f64b362 Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Wed, 20 Apr 2016 16:09:26 -0400 Subject: [PATCH] most of hash map - have to commit fix for unify type first --- stdlib/ast_transformation.krak | 5 +- stdlib/hash_map.krak | 108 ++++++++++++++++++++++++++++++++ stdlib/importer.krak | 1 - stdlib/parser.krak | 2 + stdlib/util.krak | 17 ++++- tests/test_map.expected_results | 12 ++++ tests/test_map.krak | 16 ++++- 7 files changed, 155 insertions(+), 6 deletions(-) create mode 100644 stdlib/hash_map.krak diff --git a/stdlib/ast_transformation.krak b/stdlib/ast_transformation.krak index 863a099..9fd4f79 100644 --- a/stdlib/ast_transformation.krak +++ b/stdlib/ast_transformation.krak @@ -1137,7 +1137,10 @@ fun unify_type(template_type: *tree, param_type: *type, new_map: *mapset(concat_symbol_tree(template_type), param_type) } } else if (get_node("\"\\*\"", template_type)) { - unify_type(template_type->children[1], param_type->clone_with_decreased_indirection(), new_map, template_replacements) + // only unify on decreased indirection if we're not already at 0 + if (param_type->indirection) + unify_type(template_type->children[1], param_type->clone_with_decreased_indirection(), new_map, template_replacements) + else return; } else if (get_node("template_inst", template_type)) { if (param_type->is_object()) { var enclosing_template = param_type->type_def->type_def.scope[string("~enclosing_scope")][0] diff --git a/stdlib/hash_map.krak b/stdlib/hash_map.krak new file mode 100644 index 0000000..f012b78 --- /dev/null +++ b/stdlib/hash_map.krak @@ -0,0 +1,108 @@ +import vector +import map +import io +import serialize +import util + +fun hash_map(): hash_map { + var toRet.construct(): hash_map + return toRet +} +fun hash_map(key:T, value:U): hash_map { + var toRet.construct(): hash_map + toRet.set(key, value) + return toRet +} + +obj hash_map (Object, Serializable) { + var data: vector::vector> + var size: int + + fun construct(): *hash_map { + data.construct() + data.add(map::map()) + size = 0 + return this + } + fun copy_construct(old: *hash_map) { + data.copy_construct(&old->data) + size = old->size + } + fun operator=(rhs: hash_map) { + destruct() + copy_construct(&rhs) + } + fun destruct() { + data.destruct() + } + fun serialize(): vector::vector { + return serialize::serialize(data) + serialize::serialize(size) + } + fun unserialize(it: ref vector::vector, pos: int): int { + pos = data.unserialize(it, pos) + util::unpack(size, pos) = serialize::unserialize(it, pos) + return pos + } + // the old unnecessary template to prevent generation + // if not used trick (in this case, changing out U with V) + fun operator==(other: ref hash_map): bool { + return data == other.data + } + fun set(key: T, value: U) { + var key_hash = util::hash(key) + if (!data[key_hash%data.size].contains_key(key)) + size++ + data[key_hash%data.size].set(key, value) + if (size > data.size) { + var new_data = vector::vector>() + for (var i = 0; i < size*2; i++;) + new_data.addEnd(map::map()) + for_each(fun(key: T, value: U) { + new_data[util::hash(key)%new_data.size].set(key, value) + }) + data = new_data + } + } + fun get(key: T): ref U { + return data[util::hash(key)%data.size].get(key) + } + fun contains_key(key: T): bool { + return data[util::hash(key)%data.size].contains_key(key) + } + fun contains_value(value: U): bool { + for (var i = 0; i < data.size; i++;) { + if (data[i].contains_value(value)) + return true + } + return false + } + fun reverse_get(value: U): ref T { + for (var i = 0; i < data.size; i++;) { + if (data[i].contains_value(value)) + return data[i].reverse_get(value) + } + io::println("trying to reverse get a value that is not in the hash_map") + } + fun remove(key: T) { + data[util::hash(key)%data.size].remove(key) + } + fun for_each(func: fun(T, U):void) { + for (var i = 0; i < data.size; i++;) + data[i].for_each(func) + } + fun operator[](key: T): ref U { + return get(key) + } + fun operator[]=(key: T, value: U) { + set(key,value) + } + fun get_with_default(key: T, default_val: ref U): ref U { + if (contains_key(key)) + return get(key) + return default_val + } + fun clear() { + data.clear() + } +} + diff --git a/stdlib/importer.krak b/stdlib/importer.krak index 80030e6..a5f61db 100644 --- a/stdlib/importer.krak +++ b/stdlib/importer.krak @@ -117,7 +117,6 @@ obj importer (Object) { remove_node(symbol("def_nonterm", false), parse_tree) remove_node(symbol("obj_nonterm", false), parse_tree) remove_node(symbol("adt_nonterm", false), parse_tree) - /*remove_node(symbol("\"\\|\"", true), parse_tree)*/ collapse_node(symbol("case_statement_list", false), parse_tree) collapse_node(symbol("opt_param_assign_list", false), parse_tree) diff --git a/stdlib/parser.krak b/stdlib/parser.krak index a6e8d85..b48b3c8 100644 --- a/stdlib/parser.krak +++ b/stdlib/parser.krak @@ -5,6 +5,7 @@ import tree:* import vector:* import stack:* import map:* +import hash_map:* import util:* import string:* import mem:* @@ -405,6 +406,7 @@ obj parser (Object) { obj gss (Object) { var data: vector>> var edges: map< pair<*tree, *tree>, *tree > + /*var edges: hash_map< pair<*tree, *tree>, *tree >*/ fun construct(): *gss { data.construct() diff --git a/stdlib/util.krak b/stdlib/util.krak index 4b9970c..a44b9b0 100644 --- a/stdlib/util.krak +++ b/stdlib/util.krak @@ -1,9 +1,11 @@ import mem +import io import set import map import vector import serialize + // maybe my favorite function fun do_nothing() {} @@ -25,6 +27,16 @@ fun min(a: T, b: T): T { return a; } +fun hash(item: T): int return item.hash() +fun hash(item: *T): int return (item) cast int +fun hash(item: int): int return item +fun hash(item: char): int return item +// default hash +fun hash(item: T): int { + io::println("using empty hash - please do not do!") + return 0 +} + fun make_pair(first: T, second: U): pair { var it.construct(first, second): pair return it @@ -46,7 +58,7 @@ obj unpack_dummy { } } -obj pair (Object, Serializable) { +obj pair (Object, Serializable, Hashable) { var first: T var second: U @@ -83,6 +95,9 @@ obj pair (Object, Serializable) { return second_pair.second } + /*fun hash():int return hash(first) ^ hash(second)*/ + fun hash():int return 0 + // the old unnecessary template to prevent generation // if not used trick (in this case, changing out U with V) fun operator==(other: ref pair): bool { diff --git a/tests/test_map.expected_results b/tests/test_map.expected_results index e77d4a3..33c0d3f 100644 --- a/tests/test_map.expected_results +++ b/tests/test_map.expected_results @@ -10,3 +10,15 @@ Lookie, a map! What I get for not testing different types key: 7, value: Lookie, a map! key: 30, value: we'll look for for_each too +3 +2 +1 +3 +20 +2 +30 +4 +Lookie, a map! +What I get for not testing different types +key: 30, value: we'll look for for_each too +key: 7, value: Lookie, a map! diff --git a/tests/test_map.krak b/tests/test_map.krak index a6bbfc6..11cb0b4 100644 --- a/tests/test_map.krak +++ b/tests/test_map.krak @@ -1,8 +1,8 @@ import io:* import map:* +import hash_map:* -fun main(): int { - var m = map(3,1) +fun test_map(m: ref T, mapEx: ref V) { m.set(2,2) m.set(1,3) println(m[1]) @@ -16,12 +16,22 @@ fun main(): int { println(m[2]) println(m[6]) println(m[3]) - var mapEx = map(7, "Lookie, a map!") mapEx[20] = "What I get for not testing different types" mapEx[30] = "we'll look for for_each too" println(mapEx[7]) println(mapEx[20]) mapEx.remove(20) mapEx.for_each(fun(key:int, value:*char) { print("key: "); print(key); print(", value: "); println(value); }) +} +fun main(): int { + var m1 = map(3,1) + var mapEx1 = map(7, "Lookie, a map!") + test_map(m1, mapEx1) + var m2 = hash_map(3,1) + var mapEx2 = hash_map(7, "Lookie, a map!") + test_map(m2, mapEx2) + /*println(m2.data.size)*/ + /*println(m2.data[1].keys.size)*/ + /*println(mapEx2.data.size)*/ return 0 }