shithub: mc

Download patch

ref: fb8e2abee34bebf7f8d1d0b2754894b838414bee
parent: b0b92f615f83d31f860044862592ea22cf925aaa
author: Ori Bernstein <[email protected]>
date: Fri Oct 18 13:15:03 EDT 2013

Add a hash table implementation.

--- a/libstd/Makefile
+++ b/libstd/Makefile
@@ -8,6 +8,7 @@
     error.myr \
     extremum.myr \
     fmt.myr \
+    htab.myr \
     intparse.myr \
     now.myr \
     option.myr \
--- /dev/null
+++ b/libstd/htab.myr
@@ -1,0 +1,158 @@
+use "alloc.use"
+use "option.use"
+use "types.use"
+
+pkg std =
+	type htab(@k, @v) = struct
+		hash	: (k : @k	-> uint32)
+		eq	: (a : @k, b : @k -> bool)
+
+		nelt	: size
+		keys	: @k[:]
+		vals	: @v[:]
+		hashes	: uint32[:]
+		dead	: bool[:]
+	;;
+
+	generic mkht	: (h : (k : @k -> uint32), eq : (a : @k, b : @k -> bool) -> htab(@k, @v)#)
+	generic htfree	: (ht : htab(@k, @v)# -> void)
+	generic htput	: (ht : htab(@k, @v)#, k : @k, v : @v -> void)
+	generic htget	: (ht : htab(@k, @v)#, k : @k -> option(@v))
+;;
+
+const Initsz = 32
+
+generic hash = {ht, k
+	var h
+
+	h = ht.hash(k)
+	if h == 0
+		-> 1
+	else
+		-> h
+	;;
+}
+
+generic grow = {ht
+	var oldk
+	var oldv
+	var oldh
+	var oldd
+	var sz
+	var i
+
+	oldk = ht.keys
+	oldv = ht.vals
+	oldh = ht.hashes
+	oldd = ht.dead
+	sz = 2*ht.keys.len
+
+	ht.nelt = 0
+	for i = 0; i < ht.keys.len; i++
+		if oldh[i] != 0 && !oldd[i]
+			htput(ht, oldk[i], oldv[i])
+		;;
+	;;
+	slfree(oldk)
+	slfree(oldv)
+	slfree(oldh)
+	slfree(oldd)
+}
+
+generic idx = {ht, k
+	var i
+	var h
+	var di
+
+	di = 0
+	h = hash(ht, k)
+	i = h & (ht.keys.len - 1)
+	while ht.hashes[i] != 0 && !ht.dead[i] && ht.hashes[i] != h
+:idxsearchmore
+		di++
+		i = (h + di) & (ht.keys.len - 1)
+	;;
+
+	if ht.hashes[i] == 0 || ht.dead[i]
+		-> `None
+	;;
+	if !ht.eq(ht.keys[i], k)
+		goto idxsearchmore /* collision */
+	;;
+	-> `Some i
+}
+
+generic mkht = {h, eq
+	var ht
+
+	ht = alloc()
+
+	ht.hash = h
+	ht.eq = eq
+
+	ht.nelt = 0
+	ht.keys = slalloc(Initsz)
+	ht.vals = slalloc(Initsz)
+	ht.hashes = slalloc(Initsz)
+	ht.dead = slalloc(Initsz)
+	-> ht
+}
+
+generic htfree = {ht
+	slfree(ht.keys)
+	slfree(ht.vals)
+	slfree(ht.hashes)
+	slfree(ht.dead)
+	free(ht)
+}
+
+generic htput = {ht, k, v
+	var i
+	var di
+	var h
+
+	di = 0
+	h = hash(ht, k)
+	i = h & (ht.keys.len - 1)
+	while ht.hashes[i] != 0 && !ht.dead[i]
+		/*
+		second insertion just overwrites first.
+		nb: comparing keys for dead values is bad.
+		*/
+		if ht.hashes[i] == h && (ht.dead[i] || ht.eq(ht.keys[i], k))
+			goto foundfreeslot
+		;;
+		di++
+		i = (h + di) & (ht.keys.len - 1)
+	;;
+:foundfreeslot
+	ht.hashes[i] = h
+	ht.keys[i] = k
+	ht.vals[i] = v
+	ht.dead[i] = false
+	ht.nelt++
+	if ht.keys.len < ht.nelt * 2
+		grow(ht)
+	;;
+}
+
+generic htdel = {ht, k
+	match idx(ht, k)
+	`Some i:	ht.dead[i] = true;;
+	_:	/* do nothing */;;
+	;;
+}
+
+generic htget = {ht, k
+	match idx(ht, k)
+	`Some i:	-> `Some ht.vals[i];;
+	`None:		-> `None;;
+	;;
+}
+
+generic hthas = {ht, k
+	match idx(ht, k)
+	`Some i:	-> true;;
+	`None:		-> false;;
+	;;
+}
--- a/libstd/types.myr
+++ b/libstd/types.myr
@@ -1,5 +1,6 @@
 pkg std =
 	type size	= uint64	/* spans entire address space */
+	type ssize	= int64		/* signed size */
 	type off	= uint64	/* file offsets */
 	type intptr	= uint64	/* can hold any pointer losslessly */
 	type time	= uint64	/* milliseconds since epoch */