mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-05-11 00:00:49 +02:00
153 lines
4.3 KiB
Scheme
153 lines
4.3 KiB
Scheme
; "hash.scm", hashing functions for Scheme.
|
|
; Copyright (c) 1992, 1993, 1995 Aubrey Jaffer
|
|
;
|
|
;Permission to copy this software, to redistribute it, and to use it
|
|
;for any purpose is granted, subject to the following restrictions and
|
|
;understandings.
|
|
;
|
|
;1. Any copy made of this software must include this copyright notice
|
|
;in full.
|
|
;
|
|
;2. I have made no warrantee or representation that the operation of
|
|
;this software will be error-free, and I am under no obligation to
|
|
;provide any services, by way of maintenance, update, or otherwise.
|
|
;
|
|
;3. In conjunction with products arising from the use of this
|
|
;material, there shall be no use of my name in any advertising,
|
|
;promotional, or sales literature without prior written consent in
|
|
;each case.
|
|
|
|
(define (hash:hash-char-ci char n)
|
|
(modulo (char->integer (char-downcase char)) n))
|
|
|
|
(define hash:hash-char hash:hash-char-ci)
|
|
|
|
(define (hash:hash-symbol sym n)
|
|
(hash:hash-string (symbol->string sym) n))
|
|
|
|
;;; This can overflow on implemenatations where inexacts have a larger
|
|
;;; range than exact integers.
|
|
(define hash:hash-number
|
|
(if (provided? 'inexact)
|
|
(lambda (num n)
|
|
(if (integer? num)
|
|
(modulo (if (exact? num) num (inexact->exact num)) n)
|
|
(hash:hash-string-ci
|
|
(number->string (if (exact? num) (exact->inexact num) num))
|
|
n)))
|
|
(lambda (num n)
|
|
(if (integer? num)
|
|
(modulo num n)
|
|
(hash:hash-string-ci (number->string num) n)))))
|
|
|
|
(define (hash:hash-string-ci str n)
|
|
(let ((len (string-length str)))
|
|
(if (> len 5)
|
|
(let loop ((h (modulo 264 n)) (i 5))
|
|
(if (positive? i)
|
|
(loop (modulo (+ (* h 256)
|
|
(char->integer
|
|
(char-downcase
|
|
(string-ref str (modulo h len)))))
|
|
n)
|
|
(- i 1))
|
|
h))
|
|
(let loop ((h 0) (i (- len 1)))
|
|
(if (>= i 0)
|
|
(loop (modulo (+ (* h 256)
|
|
(char->integer
|
|
(char-downcase (string-ref str i))))
|
|
n)
|
|
(- i 1))
|
|
h)))))
|
|
|
|
(define hash:hash-string hash:hash-string-ci)
|
|
|
|
(define (hash:hash obj n)
|
|
(let hs ((d 10) (obj obj))
|
|
(cond
|
|
((number? obj) (hash:hash-number obj n))
|
|
((char? obj) (modulo (char->integer (char-downcase obj)) n))
|
|
((symbol? obj) (hash:hash-symbol obj n))
|
|
((string? obj) (hash:hash-string obj n))
|
|
((vector? obj)
|
|
(let ((len (vector-length obj)))
|
|
(if (> len 5)
|
|
(let lp ((h 1) (i (quotient d 2)))
|
|
(if (positive? i)
|
|
(lp (modulo (+ (* h 256)
|
|
(hs 2 (vector-ref obj (modulo h len))))
|
|
n)
|
|
(- i 1))
|
|
h))
|
|
(let loop ((h (- n 1)) (i (- len 1)))
|
|
(if (>= i 0)
|
|
(loop (modulo (+ (* h 256) (hs (quotient d len)
|
|
(vector-ref obj i)))
|
|
n)
|
|
(- i 1))
|
|
h)))))
|
|
((pair? obj)
|
|
(if (positive? d) (modulo (+ (hs (quotient d 2) (car obj))
|
|
(hs (quotient d 2) (cdr obj)))
|
|
n)
|
|
1))
|
|
(else
|
|
(modulo
|
|
(cond
|
|
((null? obj) 256)
|
|
((boolean? obj) (if obj 257 258))
|
|
((eof-object? obj) 259)
|
|
((input-port? obj) 260)
|
|
((output-port? obj) 261)
|
|
((procedure? obj) 262)
|
|
((and (provided? 'RECORD) (record? obj))
|
|
(let* ((rtd (record-type-descriptor obj))
|
|
(fns (record-type-field-names rtd))
|
|
(len (length fns)))
|
|
(if (> len 5)
|
|
(let lp ((h (modulo 266 n)) (i (quotient d 2)))
|
|
(if (positive? i)
|
|
(lp (modulo
|
|
(+ (* h 256)
|
|
(hs 2 ((record-accessor
|
|
rtd (list-ref fns (modulo h len)))
|
|
obj)))
|
|
n)
|
|
(- i 1))
|
|
h))
|
|
(let loop ((h (- n 1)) (i (- len 1)))
|
|
(if (>= i 0)
|
|
(loop (modulo
|
|
(+ (* h 256)
|
|
(hs (quotient d len)
|
|
((record-accessor
|
|
rtd (list-ref fns (modulo h len)))
|
|
obj)))
|
|
n)
|
|
(- i 1))
|
|
h)))))
|
|
(else 263))
|
|
n)))))
|
|
|
|
(define hash hash:hash)
|
|
(define hashv hash:hash)
|
|
|
|
;;; Object-hash is somewhat expensive on copying GC systems (like
|
|
;;; PC-Scheme and MITScheme). We use it only on strings, pairs,
|
|
;;; vectors, and records. This also allows us to use it for both
|
|
;;; hashq and hashv.
|
|
|
|
(if (provided? 'object-hash)
|
|
(set! hashv
|
|
(if (provided? 'record)
|
|
(lambda (obj k)
|
|
(if (or (string? obj) (pair? obj) (vector? obj) (record? obj))
|
|
(modulo (object-hash obj) k)
|
|
(hash:hash obj k)))
|
|
(lambda (obj k)
|
|
(if (or (string? obj) (pair? obj) (vector? obj))
|
|
(modulo (object-hash obj) k)
|
|
(hash:hash obj k))))))
|
|
|
|
(define hashq hashv)
|