-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathfset-hacks.lisp
94 lines (80 loc) · 2.8 KB
/
fset-hacks.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
(in-package #:cloture)
(defconst int-length 32)
(defconst long-length 64)
(deftype int ()
'(signed-byte #.int-length))
(deftype long ()
'(signed-byte #.long-length))
(defsubst mask-signed-field (size int)
#+sbcl (sb-c::mask-signed-field size int)
#-sbcl
(cond ((zerop size)
0)
((logbitp (1- size) int)
(dpb int (byte size 0) -1))
(t
(ldb (byte size 0) int))))
(defsubst mask-int (int)
(mask-signed-field int-length int))
(defsubst mask-long (int)
(mask-signed-field long-length int))
(defpattern seq (&rest pats)
(with-unique-names (it)
`(guard1 (,it :type seq)
(typep ,it 'seq)
(size ,it) ,(length pats)
,@(loop for pat in pats
for i from 0
collect `(lookup ,it ,i)
collect pat))))
(defun murmurhash* (x)
(mask-int (murmurhash x)))
(defmethod murmurhash ((seq seq) &key (seed *default-seed*)
mix-only)
(mask-int
(murmurhash
(list* '%seq (size seq) (convert 'list seq))
:seed seed :mix-only mix-only)))
(defmethod murmurhash ((set set) &key (seed *default-seed*)
mix-only)
(mask-int
(murmurhash
(list* '%set (size set) (convert 'list set))
:seed seed :mix-only mix-only)))
(defmethod murmurhash ((map map) &key (seed *default-seed*)
mix-only)
(mask-int
(murmurhash
(list* '%set (size map) (map->alist map))
:seed seed :mix-only mix-only)))
;;; We want to be able to build on FSet's idea of equality, but we
;;; also need FSet to take into account Clojure's idea of equality (so
;;; that maps have the correct behavior). The following hack lets that
;;; work by detecting and breaking recursion.
(defmethod fset:compare (a b)
(handler-case
(without-recursion ()
(if (truthy? (|clojure.core|:|=| a b)) :equal :unequal))
(recursion-forbidden ()
(call-next-method))))
(defmethod fset:compare :around ((a symbol) (b symbol))
(flet ((compare-by-name (a b)
(let ((name1 (symbol-name a))
(name2 (symbol-name b)))
(eif (or (find #\/ name1)
(find #\/ name2))
(call-next-method)
(if (equal name1 name2)
:equal
(call-next-method))))))
(eif (keywordp a)
(call-next-method)
(eif (keywordp b)
(call-next-method)
(let ((package1 (symbol-package a)))
(eif (clojure-package? package1)
(let ((package2 (symbol-package b)))
(eif (clojure-package? package2)
(compare-by-name a b)
(call-next-method)))
(call-next-method)))))))