summaryrefslogtreecommitdiff
path: root/modules/language/python/hash.scm
diff options
context:
space:
mode:
Diffstat (limited to 'modules/language/python/hash.scm')
-rw-r--r--modules/language/python/hash.scm48
1 files changed, 48 insertions, 0 deletions
diff --git a/modules/language/python/hash.scm b/modules/language/python/hash.scm
new file mode 100644
index 0000000..ca5e32e
--- /dev/null
+++ b/modules/language/python/hash.scm
@@ -0,0 +1,48 @@
+(define-module (language python hash)
+ #:use-module (oop goops)
+ #:use-module (oop pf-objects)
+ #:export (py-hash complexity xy pyhash-N))
+
+(define-syntax-rule (aif it p x y) (let ((it p)) (if it x y)))
+
+(define N #xefffffffffffffff)
+(define pyhash-N N)
+
+(define-inlinable (xy v seed)
+ (modulo
+ (logxor seed
+ (+ (py-hash v)
+ #x9e3779b9
+ (ash seed 6)
+ (ash seed -2)))
+ N))
+
+(define complexity 10)
+
+;; The default is to use guile's hash function
+(define-method (py-hash x) (hash x N))
+
+(define-method (py-hash (x <pair>))
+ (define i 0)
+ (let lp ((x x))
+ (if (< i complexity)
+ (begin
+ (set! i (+ i 1))
+ (if (pair? x)
+ (xy (lp (car x)) (lp (cdr x)))
+ (py-hash x)))
+ 0)))
+
+(define-method (py-hash (x <vector>))
+ (let ((n (min complexity (vector-length x))))
+ (let lp ((i 0) (s 0))
+ (if (< i n)
+ (lp (+ i 1)
+ (xy (py-hash (vector-ref x i)) s))
+ s))))
+
+(define-method (py-hash (x <p>))
+ (aif it (ref x '__hash__)
+ (it)
+ (hash x complexity)))
+