mirror of
git://git.code.sf.net/p/sbcl/sbcl
synced 2026-09-10 07:26:40 -04:00
Use descriptor-hash32 only for a mixture of CASE key types
Otherwise, just CHAR-CODE or just SYMBOL-NAME-HASH may be enough.
This commit is contained in:
parent
aab89714af
commit
3d5139bef7
|
|
@ -3303,18 +3303,19 @@
|
|||
(return-from try-perfect-find/position-map conditional))
|
||||
(when (eq fun-name 'find) ; nothing to do. Wasted some time, no big deal
|
||||
(return-from try-perfect-find/position-map 'item))) ; transform arg is always named ITEM
|
||||
(flet ((hash (x) (if (symbolp x) (symbol-name-hash x) (descriptor-hash32 x))))
|
||||
(binding* ((hashes (map '(simple-array (unsigned-byte 32) (*)) #'hash keys))
|
||||
(n (length hashes))
|
||||
(pow2size (power-of-two-ceiling n))
|
||||
(binding* ((hashfn (prehash-function-for-mph-generator
|
||||
(minperfhash-key-universe-type keys)))
|
||||
(hashes (map '(simple-array (unsigned-byte 32) (*)) hashfn keys))
|
||||
(n (length hashes))
|
||||
(pow2size (power-of-two-ceiling n))
|
||||
;; FIXME: I messed up the minimal/non-minimal thing that was
|
||||
;; trying to simplify the calculation at the expense of a few extra cells.
|
||||
;; Minimal will always be right.
|
||||
(minimal t)
|
||||
(lambda (make-perfect-hash-lambda hashes items minimal) :exit-if-null)
|
||||
(keyspace-size (if minimal n pow2size))
|
||||
(domain (sb-xc:make-array keyspace-size :initial-element 0))
|
||||
(range
|
||||
(minimal t)
|
||||
(lambda (make-perfect-hash-lambda hashes items minimal) :exit-if-null)
|
||||
(keyspace-size (if minimal n pow2size))
|
||||
(domain (sb-xc:make-array keyspace-size :initial-element 0))
|
||||
(range
|
||||
(cond ((eq fun-name 'position)
|
||||
(sb-xc:make-array keyspace-size
|
||||
:element-type
|
||||
|
|
@ -3327,9 +3328,9 @@
|
|||
;; which the user wants (or seems to)
|
||||
((eq alistp t) domain)
|
||||
(t (sb-xc:make-array keyspace-size))))
|
||||
(phashfun (sb-c::compile-perfect-hash lambda hashes)))
|
||||
(phashfun (sb-c::compile-perfect-hash lambda hashes)))
|
||||
;; Iteration order doesn't matter here
|
||||
(maphash (lambda (key val &aux (phash (funcall phashfun (hash key))))
|
||||
(maphash (lambda (key val &aux (phash (funcall phashfun (funcall hashfn key))))
|
||||
(cond ((eq alistp t)
|
||||
(setf (aref domain phash) val)) ; VAL is the (key . val) pair
|
||||
(t
|
||||
|
|
@ -3375,7 +3376,7 @@
|
|||
(if minimal
|
||||
`(if (< phash ,n)
|
||||
,expr)
|
||||
expr)))))))))
|
||||
expr))))))))
|
||||
|
||||
(macrolet ((define-find-position (fun-name values-index)
|
||||
`(deftransform ,fun-name ((item sequence &key
|
||||
|
|
|
|||
|
|
@ -330,36 +330,69 @@
|
|||
(setf (info :function :compiler-macro-function 'uint32-modularly)
|
||||
#'sb-c::optimize-for-calc-phash)
|
||||
|
||||
;;; Decide what types are in OBJECTS and return {FIXNUM|SYMBOL|CHARACTER|T}.
|
||||
;;; Perhaps alternatively this could return an OR over types so the consumer
|
||||
;;; could decide to expand differently in various situations such as
|
||||
;;; (OR SYMBOL FIXNUM). Because maybe the hash function should be:
|
||||
;;; (if (symbolp x) (f x) (ldb (byte 32 0) (get-lisp-obj-address)))
|
||||
;;; which contains exactly 1 type test, and if not symbol, there is no
|
||||
;;; hazard in extracting low bits of a random descriptor.
|
||||
;;; On the other hand, that's pretty darn near what happens anyway.
|
||||
(defun minperfhash-key-universe-type (objects)
|
||||
(let ((types 0))
|
||||
(dolist (object objects (case types
|
||||
(#b001 'fixnum)
|
||||
(#b010 'symbol)
|
||||
(#b100 'character)
|
||||
(0 'nil) ; if OBJECTS is NIL
|
||||
(t 't)))
|
||||
(setq types (logior (typecase object
|
||||
(sb-xc:fixnum #b001)
|
||||
(symbol #b010)
|
||||
(character #b100)
|
||||
(t (return nil)))
|
||||
types)))))
|
||||
|
||||
;;; Construct a form which computes a 32-bit hash from OBJ whose value
|
||||
;;; should be - but might not be - one of the choices in KEYS.
|
||||
;;; If it is not, the expression's result should be irrelevant.
|
||||
;;; (Calling code has to do some kind of "hit" test)
|
||||
;;; TODO: consider putting in a "miss" label that this code bail out to
|
||||
;;; if there is an unexpected object type.
|
||||
;;; The 32-bit hash is then fed into a perfect hash expression.
|
||||
(defun prehash-expr-for-perfect-hash (obj keys)
|
||||
(if (notany #'symbolp keys)
|
||||
`(descriptor-hash32 ,obj)
|
||||
(multiple-value-bind (guard hashval)
|
||||
(if (vop-existsp :translate hash-as-if-symbol-name)
|
||||
(values `(pointerp ,obj) `(hash-as-if-symbol-name ,obj))
|
||||
;; NON-NULL-SYMBOL-P is the less expensive test as it omits the OR
|
||||
;; which accepts NIL along with OTHER-POINTER objects.
|
||||
(values `(,(if (member nil keys) 'symbolp 'non-null-symbol-p) ,obj)
|
||||
`(symbol-name-hash (truly-the symbol ,obj))))
|
||||
`(if ,guard
|
||||
,hashval
|
||||
,(if (every #'symbolp keys) 0 `(descriptor-hash32 ,obj))))))
|
||||
(let ((type (minperfhash-key-universe-type keys)))
|
||||
(ecase type
|
||||
((t symbol) ; most general hasher or just symbol
|
||||
(multiple-value-bind (guard hash)
|
||||
(if (vop-existsp :translate hash-as-if-symbol-name)
|
||||
(values `(pointerp ,obj) `(hash-as-if-symbol-name ,obj))
|
||||
;; NON-NULL-SYMBOL-P is the less expensive test as it omits the OR
|
||||
;; which accepts NIL along with OTHER-POINTER objects.
|
||||
(values `(,(if (member nil keys) 'symbolp 'non-null-symbol-p) ,obj)
|
||||
`(symbol-name-hash (truly-the symbol ,obj))))
|
||||
`(if ,guard ,hash ,(if (eq type 't) `(descriptor-hash32 ,obj) 0))))
|
||||
(character
|
||||
`(if (characterp ,obj) (char-code (truly-the character ,obj)) 0))
|
||||
(fixnum
|
||||
`(if (fixnump ,obj) (ldb (byte 32 0) (truly-the fixnum ,obj)) 0)))))
|
||||
;;; This is for use at compile-time, to build the array of uint32_t inputs
|
||||
;;; to the MPH generator after choosing the manner of prehashing.
|
||||
(defun prehash-function-for-mph-generator (type)
|
||||
(case type
|
||||
((t symbol) ; most general hasher or just symbol
|
||||
(lambda (x)
|
||||
(etypecase x
|
||||
(symbol (symbol-name-hash x))
|
||||
((or sb-xc:fixnum character) (descriptor-hash32 x)))))
|
||||
(character #'char-code)
|
||||
(t (lambda (x) (ldb (byte 32 0) (the sb-xc:fixnum x))))))
|
||||
|
||||
;;; The CASE macro can use this predicate to decide whether to expand in a way
|
||||
;;; that selects a clause via a perfect hash versus the customary expansion
|
||||
;;; as a sequence of IFs.
|
||||
(defun perfectly-hashable (objects)
|
||||
(flet ((hash (x) (if (symbolp x) (symbol-name-hash x) (descriptor-hash32 x))))
|
||||
(let* ((n (length objects))
|
||||
(hashes (make-array n :element-type '(unsigned-byte 32))))
|
||||
(loop for o in objects
|
||||
for i from 0
|
||||
do (let ((h (hash o)))
|
||||
(if h
|
||||
(setf (aref hashes i) h)
|
||||
(return-from perfectly-hashable nil))))
|
||||
(make-perfect-hash-lambda hashes objects))))
|
||||
(binding* ((type (minperfhash-key-universe-type objects) :exit-if-null)
|
||||
(hashfn (prehash-function-for-mph-generator type))
|
||||
(hashes (map '(simple-array (unsigned-byte 32) 1) hashfn objects)))
|
||||
(make-perfect-hash-lambda hashes objects)))
|
||||
|
|
|
|||
|
|
@ -74,6 +74,40 @@
|
|||
(let ((b (>> (<< val 28) 30)))
|
||||
(let ((a (& val #x3)))
|
||||
(^ a (aref tab b))))))")
|
||||
(#(A 3C 3F 5B 7B)
|
||||
"(#\\? #\\{ #\\[ #\\< #\\Newline)"
|
||||
"((let ((tab #a((4) (unsigned-byte 8) 5 0 0 0)))
|
||||
(let ((b (& val #x3)))
|
||||
(let ((a (>> (<< val 25) 30)))
|
||||
(^ a (aref tab b))))))")
|
||||
(#(23 27 2B 2C 2D 3A 40 56 76)
|
||||
"(#\\@ #\\: #\\, #\\' #\\# #\\V #\\v #\\- #\\+)"
|
||||
"((let ((tab #a((8) (unsigned-byte 8) 0 2 0 0 4 0 10 0)))
|
||||
(+= val #x1679e37f)
|
||||
(^= val (>> val 4))
|
||||
(let ((b (& val #x7)))
|
||||
(let ((a (>> (u32+ val (<< val 25)) 29)))
|
||||
(^ a (aref tab b))))))")
|
||||
(#(24 2F 41 42 43 44 45 46 47 4F 52 53 57 58)
|
||||
"#(#\\A #\\B #\\C #\\D #\\E #\\F #\\G #\\O #\\R #\\S #\\W #\\X #\\$ #\\/)"
|
||||
"((let ((tab #a((8) (unsigned-byte 8) 0 5 0 4 12 14 5 10)))
|
||||
(+= val #xa0fa272d)
|
||||
(^= val (>> val 4))
|
||||
(let ((b (& val #x7)))
|
||||
(let ((a (>> (u32+ val (<< val 26)) 29)))
|
||||
(^ a (aref tab b))))))")
|
||||
(#(25 26 28 29 3B 3E 49 54 5F 7C 7E)
|
||||
"#(#\\I #\\T #\\% #\\& #\\| #\\_ #\\( #\\) #\\; #\\> #\\~)"
|
||||
"((let ((tab #a((8) (unsigned-byte 8) 11 4 0 2 13 7 0 1)))
|
||||
(let ((b (& val #x7)))
|
||||
(let ((a (>> (<< val 25) 29)))
|
||||
(^ a (aref tab b))))))")
|
||||
(#(44 45 46 4C 52 53)
|
||||
"(#\\R #\\L #\\D #\\F #\\S #\\E)"
|
||||
"((let ((tab #a((4) (unsigned-byte 8) 4 3 0 3)))
|
||||
(let ((b (& val #x3)))
|
||||
(let ((a (>> (<< val 27) 30)))
|
||||
(^ a (aref tab b))))))")
|
||||
(#(8A 8E 92 96 9A 9E A2 A6 AA AE B2 B6 BA BE C2 C6 CA CE D2 D6)
|
||||
"(138 210 206 194 190 186 182 178 174 170 166 162 158 154 150 146 142 202 198 214)"
|
||||
"((let ((tab #a((16) (unsigned-byte 8) 0 13 0 13 0 13 0 13 15 21 3 21 21 11 7 21)))
|
||||
|
|
@ -117,43 +151,9 @@
|
|||
(#(13E 154 1BE 1D4)
|
||||
"(318 446 340 468)"
|
||||
"((& (>> val 6) 3))")
|
||||
(#(292 F12 FD2 16D2 1ED2)
|
||||
"(#\\? #\\{ #\\[ #\\< #\\Newline)"
|
||||
"((let ((tab #a((4) (unsigned-byte 8) 5 0 0 0)))
|
||||
(let ((b (& (>> val 6) #x3)))
|
||||
(let ((a (>> (<< val 19) 30)))
|
||||
(^ a (aref tab b))))))")
|
||||
(#(8D2 9D2 AD2 B12 B52 E92 1012 1592 1D92)
|
||||
"(#\\@ #\\: #\\, #\\' #\\# #\\V #\\v #\\- #\\+)"
|
||||
"((let ((tab #a((8) (unsigned-byte 8) 2 0 3 0 5 7 0 12)))
|
||||
(+= val #x746675d3)
|
||||
(^= val (>> val 4))
|
||||
(let ((b (& (>> val 2) #x7)))
|
||||
(let ((a (>> (u32+ val (<< val 16)) 29)))
|
||||
(^ a (aref tab b))))))")
|
||||
(#(912 BD2 1052 1092 10D2 1112 1152 1192 11D2 13D2 1492 14D2 15D2 1612)
|
||||
"#(#\\A #\\B #\\C #\\D #\\E #\\F #\\G #\\O #\\R #\\S #\\W #\\X #\\$ #\\/)"
|
||||
"((let ((tab #a((8) (unsigned-byte 8) 0 0 8 14 11 15 0 4)))
|
||||
(+= val #x9e67848b)
|
||||
(^= val (>> val 4))
|
||||
(let ((b (& (>> val 2) #x7)))
|
||||
(let ((a (>> (u32+ val (<< val 20)) 29)))
|
||||
(^ a (aref tab b))))))")
|
||||
(#(952 992 A12 A52 ED2 F92 1252 1512 17D2 1F12 1F92)
|
||||
"#(#\\I #\\T #\\% #\\& #\\| #\\_ #\\( #\\) #\\; #\\> #\\~)"
|
||||
"((let ((tab #a((8) (unsigned-byte 8) 11 4 0 2 13 7 0 1)))
|
||||
(let ((b (& (>> val 6) #x7)))
|
||||
(let ((a (>> (<< val 19) 29)))
|
||||
(^ a (aref tab b))))))")
|
||||
(#(1000 2000 4000 6000 8000 A000 C000)
|
||||
"(4096 40960 49152 32768 24576 16384 8192)"
|
||||
"((& (>> val 13) 7))")
|
||||
(#(1112 1152 1192 1312 1492 14D2)
|
||||
"(#\\R #\\L #\\D #\\F #\\S #\\E)"
|
||||
"((let ((tab #a((4) (unsigned-byte 8) 4 3 0 3)))
|
||||
(let ((b (& (>> val 6) #x3)))
|
||||
(let ((a (>> (<< val 21) 30)))
|
||||
(^ a (aref tab b))))))")
|
||||
(#(6641B 2D83FFB 3DD2F1F 166E98EA 18F3A192 19485E2B 1FF01E77)
|
||||
"(:ALLOW-OTHER-KEYS :SLOT-NAMES :METACLASS-CONSTRUCTOR :DD-TYPE :METACLASS-NAME :SUPERCLASS-NAME :CLASS-NAME)"
|
||||
"((& (^ (>> val 1) (>> val 20)) 7))")
|
||||
|
|
|
|||
|
|
@ -164,6 +164,32 @@
|
|||
"(8 16 32 64)"
|
||||
"((let ((b (& (>> val 5) 1)))
|
||||
(^ (& (>> val 3) 3) b (<< b 1))))")
|
||||
(#(A 3C 3F 5B 7B)
|
||||
"(#\\? #\\{ #\\[ #\\< #\\Newline)"
|
||||
"((let ((tab #a((4) (unsigned-byte 8) 5 0 0 0)))
|
||||
(let ((b (& val #x3)))
|
||||
(let ((a (>> (<< val 25) 30)))
|
||||
(^ a (aref tab b))))))")
|
||||
(#(23 27 2B 2C 2D 3A 40 56 76)
|
||||
"(#\\@ #\\: #\\, #\\' #\\# #\\V #\\v #\\- #\\+)"
|
||||
"((let ((tab #a((8) (unsigned-byte 8) 0 2 0 0 4 0 10 0)))
|
||||
(+= val #x1679e37f)
|
||||
(^= val (>> val 4))
|
||||
(let ((b (& val #x7)))
|
||||
(let ((a (>> (u32+ val (<< val 25)) 29)))
|
||||
(^ a (aref tab b))))))")
|
||||
(#(25 26 28 29 3B 3E 49 54 5F 7C 7E)
|
||||
"#(#\\I #\\T #\\% #\\& #\\| #\\_ #\\( #\\) #\\; #\\> #\\~)"
|
||||
"((let ((tab #a((8) (unsigned-byte 8) 11 4 0 2 13 7 0 1)))
|
||||
(let ((b (& val #x7)))
|
||||
(let ((a (>> (<< val 25) 29)))
|
||||
(^ a (aref tab b))))))")
|
||||
(#(44 45 46 4C 52 53)
|
||||
"(#\\R #\\L #\\D #\\F #\\S #\\E)"
|
||||
"((let ((tab #a((4) (unsigned-byte 8) 4 3 0 3)))
|
||||
(let ((b (& val #x3)))
|
||||
(let ((a (>> (<< val 27) 30)))
|
||||
(^ a (aref tab b))))))")
|
||||
(#(89 8D 91 95 99 9D A1 A5 A9 AD B1 B5 B9 BD C1 C5 C9 CD D1 D5 D9 DD E1 E5)
|
||||
"(137 221 217 205 201 197 193 189 185 181 177 173 169 165 161 157 153 149 145 141 213 209 229 225)"
|
||||
"((let ((tab #a((16) (unsigned-byte 8) 31 24 0 13 0 13 0 13 1 12 16 22 16 18 21 22)))
|
||||
|
|
@ -187,32 +213,6 @@
|
|||
(#(13E 154 1BE 1D4)
|
||||
"(318 446 340 468)"
|
||||
"((& (>> val 6) 3))")
|
||||
(#(14A 78A 7EA B6A F6A)
|
||||
"(#\\? #\\{ #\\[ #\\< #\\Newline)"
|
||||
"((let ((tab #a((4) (unsigned-byte 8) 5 0 0 0)))
|
||||
(let ((b (& (>> val 5) #x3)))
|
||||
(let ((a (>> (<< val 20) 30)))
|
||||
(^ a (aref tab b))))))")
|
||||
(#(46A 4EA 56A 58A 5AA 74A 80A ACA ECA)
|
||||
"(#\\@ #\\: #\\, #\\' #\\# #\\V #\\v #\\- #\\+)"
|
||||
"((let ((tab #a((8) (unsigned-byte 8) 13 5 0 4 7 0 6 0)))
|
||||
(+= val #xeb2f8376)
|
||||
(^= val (>> val 4))
|
||||
(let ((b (& (>> val 1) #x7)))
|
||||
(let ((a (>> (u32+ val (<< val 18)) 29)))
|
||||
(^ a (aref tab b))))))")
|
||||
(#(4AA 4CA 50A 52A 76A 7CA 92A A8A BEA F8A FCA)
|
||||
"#(#\\I #\\T #\\% #\\& #\\| #\\_ #\\( #\\) #\\; #\\> #\\~)"
|
||||
"((let ((tab #a((8) (unsigned-byte 8) 11 4 0 2 13 7 0 1)))
|
||||
(let ((b (& (>> val 5) #x7)))
|
||||
(let ((a (>> (<< val 20) 29)))
|
||||
(^ a (aref tab b))))))")
|
||||
(#(88A 8AA 8CA 98A A4A A6A)
|
||||
"(#\\R #\\L #\\D #\\F #\\S #\\E)"
|
||||
"((let ((tab #a((4) (unsigned-byte 8) 4 3 0 3)))
|
||||
(let ((b (& (>> val 5) #x3)))
|
||||
(let ((a (>> (<< val 22) 30)))
|
||||
(^ a (aref tab b))))))")
|
||||
(#(1000 2000 4000 6000 8000 A000 C000)
|
||||
"(4096 40960 49152 32768 24576 16384 8192)"
|
||||
"((& (>> val 13) 7))")
|
||||
|
|
|
|||
|
|
@ -212,6 +212,12 @@
|
|||
"(8 16 32 64)"
|
||||
"((let ((b (& (>> val 5) 1)))
|
||||
(^ (& (>> val 3) 3) b (<< b 1))))")
|
||||
(#(A 3C 3F 5B 7B)
|
||||
"(#\\? #\\{ #\\[ #\\< #\\Newline)"
|
||||
"((let ((tab #a((4) (unsigned-byte 8) 5 0 0 0)))
|
||||
(let ((b (& val #x3)))
|
||||
(let ((a (>> (<< val 25) 30)))
|
||||
(^ a (aref tab b))))))")
|
||||
(#(C D E 1C 1D 1E)
|
||||
"(28 12 30 29 14 13)"
|
||||
"((let ((tab #a((4) (unsigned-byte 8) 4 0 2 4)))
|
||||
|
|
@ -235,6 +241,26 @@
|
|||
(let ((b (& val #x3)))
|
||||
(let ((a (>> (<< val 26) 30)))
|
||||
(^ a (aref tab b))))))")
|
||||
(#(23 27 2B 2C 2D 3A 40 56 76)
|
||||
"(#\\@ #\\: #\\, #\\' #\\# #\\V #\\v #\\- #\\+)"
|
||||
"((let ((tab #a((8) (unsigned-byte 8) 0 2 0 0 4 0 10 0)))
|
||||
(+= val #x1679e37f)
|
||||
(^= val (>> val 4))
|
||||
(let ((b (& val #x7)))
|
||||
(let ((a (>> (u32+ val (<< val 25)) 29)))
|
||||
(^ a (aref tab b))))))")
|
||||
(#(25 26 28 29 3B 3E 49 54 5F 7C 7E)
|
||||
"#(#\\I #\\T #\\% #\\& #\\| #\\_ #\\( #\\) #\\; #\\> #\\~)"
|
||||
"((let ((tab #a((8) (unsigned-byte 8) 11 4 0 2 13 7 0 1)))
|
||||
(let ((b (& val #x7)))
|
||||
(let ((a (>> (<< val 25) 29)))
|
||||
(^ a (aref tab b))))))")
|
||||
(#(44 45 46 4C 52 53)
|
||||
"(#\\R #\\L #\\D #\\F #\\S #\\E)"
|
||||
"((let ((tab #a((4) (unsigned-byte 8) 4 3 0 3)))
|
||||
(let ((b (& val #x3)))
|
||||
(let ((a (>> (<< val 27) 30)))
|
||||
(^ a (aref tab b))))))")
|
||||
(#(64 65 66 67 F0 F2 F3)
|
||||
"(243 242 240 103 102 101 100)"
|
||||
"((& (^ val (>> val 3)) 7))")
|
||||
|
|
@ -261,35 +287,9 @@
|
|||
(#(13E 154 1BE 1D4)
|
||||
"(318 446 340 468)"
|
||||
"((& (>> val 6) 3))")
|
||||
(#(528 1E28 1FA8 2DA8 3DA8)
|
||||
"(#\\? #\\{ #\\[ #\\< #\\Newline)"
|
||||
"((let ((tab #a((4) (unsigned-byte 8) 5 0 0 0)))
|
||||
(let ((b (& (>> val 7) #x3)))
|
||||
(let ((a (>> (<< val 18) 30)))
|
||||
(^ a (aref tab b))))))")
|
||||
(#(1000 2000 4000 6000 8000 A000 C000)
|
||||
"(4096 40960 49152 32768 24576 16384 8192)"
|
||||
"((& (>> val 13) 7))")
|
||||
(#(11A8 13A8 15A8 1628 16A8 1D28 2028 2B28 3B28)
|
||||
"(#\\@ #\\: #\\, #\\' #\\# #\\V #\\v #\\- #\\+)"
|
||||
"((let ((tab #a((8) (unsigned-byte 8) 5 4 11 2 3 0 1 6)))
|
||||
(+= val #xebfb0b66)
|
||||
(^= val (>> val 4))
|
||||
(let ((b (& (>> val 7) #x7)))
|
||||
(let ((a (>> (u32+ val (<< val 13)) 29)))
|
||||
(^ a (aref tab b))))))")
|
||||
(#(12A8 1328 1428 14A8 1DA8 1F28 24A8 2A28 2FA8 3E28 3F28)
|
||||
"#(#\\I #\\T #\\% #\\& #\\| #\\_ #\\( #\\) #\\; #\\> #\\~)"
|
||||
"((let ((tab #a((8) (unsigned-byte 8) 11 4 0 2 13 7 0 1)))
|
||||
(let ((b (& (>> val 7) #x7)))
|
||||
(let ((a (>> (<< val 18) 29)))
|
||||
(^ a (aref tab b))))))")
|
||||
(#(2228 22A8 2328 2628 2928 29A8)
|
||||
"(#\\R #\\L #\\D #\\F #\\S #\\E)"
|
||||
"((let ((tab #a((4) (unsigned-byte 8) 4 3 0 3)))
|
||||
(let ((b (& (>> val 7) #x3)))
|
||||
(let ((a (>> (<< val 20) 30)))
|
||||
(^ a (aref tab b))))))")
|
||||
(#(D807 DA10 DA20 DA21 DCE8 DE82 DE83)
|
||||
"(55303 56963 56962 56552 55841 55840 55824)"
|
||||
"((let ((tab #a((4) (unsigned-byte 8) 6 0 2 7)))
|
||||
|
|
|
|||
Loading…
Reference in a new issue