📄 srfi69.scm
字号:
; Copyright © Per Bothner (2005). All Rights Reserved.; (for Kawa-specific modifications and optimizations).; Copyright © Panu Kalliokoski (2005). All Rights Reserved.; Permission is hereby granted, free of charge, to any person; obtaining a copy of this software and associated documentation; files (the Software), to deal in the Software without restriction,; including without limitation the rights to use, copy, modify,; merge, publish, distribute, sublicense, and/or sell copies of the; Software, and to permit persons to whom the Software is furnished; to do so, subject to the following conditions:; The above copyright notice and this permission notice shall be; included in all copies or substantial portions of the Software.; THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND,; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS; BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN; ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN; CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE; SOFTWARE.(module-compile-options warn-undefined-variable: #t warn-invoke-unknown-method: #t)(provide 'srfi-69)(provide 'hash-table)(define *default-bound* #x100000000)(define (string-hash (s :: <string>) #!optional (bound :: <integer> #!null)) (let ((h :: <int> (*:hashCode s))) (if (eq? bound #!null) h (modulo h bound))))(define (string-ci-hash s #!optional (bound :: <integer> #!null)) ;; It would probably be more efficient to incrementally calculate ;; the hashCode rather than calling String.toLowerCase, but it's ;; tricky if we want to get the corner cases right, and it's ;; probably not worthwhile unless string-ci-hash gets used a lot. (let ((h :: <int> (*:hashCode (*:toLowerCase (*:toString s))))) (if (eq? bound #!null) h (modulo h bound))))(define (symbol-hash (s :: <symbol>) #!optional (bound :: <integer> #!null)) (let ((h :: <int> (*:hashCode s))) (if (eq? bound #!null) h (modulo h bound))))(define (hash obj #!optional (bound :: <integer> #!null)) (let ((h :: <int> (if (eq? obj #!null) 0 (*:hashCode obj)))) (if (eq? bound #!null) h (modulo h bound))))(define (hash-by-identity obj #!optional (bound :: <integer> #!null)) (let ((h :: <int> (java.lang.System:identityHashCode obj))) (if (eq? bound #!null) h (modulo h bound))))(define (vector-hash v #!optional (bound :: <integer> #!null)) (let ((h :: <int> (*:hashCode v))) (if (eq? bound #!null) h (modulo h bound))))(define *default-table-size* 64)(define-syntax hash-table-walk% (syntax-rules () ((hash-table-walk% hash-table node use-node) (let* ((table (*:.table hash-table)) (length ((primitive-array-length <gnu.kawa.util.HashNode>) table))) (do ((i :: <int> (- length 1) (- i 1))) ((< i 0) #!void) (do ((node :: <gnu.kawa.util.HashNode> ((primitive-array-get <gnu.kawa.util.HashNode>) table i) (invoke-static <gnu.kawa.util.GeneralHashTable> 'next node))) ((eq? node #!null) #!void) use-node))))))(define-simple-class <srfi-hash-table> (<gnu.kawa.util.GeneralHashTable>) (equivalenceFunction :: <procedure>) (hashFunction :: <procedure>) ((*init* (eq :: <procedure>) (h :: <procedure>) (sz :: <int>)) (invoke-special <gnu.kawa.util.GeneralHashTable> (this) '*init* sz) (set! equivalenceFunction eq) (set! hashFunction h)) ((hash key) :: <int> (hashFunction key)) ((matches value1 value2) :: <boolean> (equivalenceFunction value1 value2)) ((walk (proc :: <procedure>)) :: <void> (hash-table-walk% (this) node (proc (*:getKey node) (*:getValue node)))) ((fold (proc :: <procedure>) acc) (hash-table-walk% (this) node (set! acc (proc (*:getKey node) (*:getValue node) acc))) acc) ((toAlist) (let ((result '())) (hash-table-walk% (this) node (set! result (cons (cons (*:getKey node) (*:getValue node)) result))) result)) ((putAll (other :: <srfi-hash-table>)) :: <void> (hash-table-walk% other node (*:put (this) (*:getKey node) (*:getValue node)))) ((clone) (hash-table-copy (this))) )(define (hash-table? obj) :: <boolean> (instance? obj <srfi-hash-table>))(define (hash-table-size (hash-table :: <srfi-hash-table>)) :: <int> (*:size hash-table))(define (hash-table-equivalence-function (hash-table :: <srfi-hash-table>)) :: <procedure> (*:.equivalenceFunction hash-table))(define (hash-table-hash-function (hash-table :: <srfi-hash-table>)) :: <procedure> (*:.hashFunction hash-table))(define (appropriate-hash-function-for comparison) :: <procedure> (or (and (eq? comparison eq?) hash-by-identity) (and (eq? comparison string=?) string-hash) (and (eq? comparison string-ci=?) string-ci-hash) hash));; Optimize to use plain <GeneralHashTable> when defaults comparison/hash; since that is more efficient (no boxing/unboxing of hashes). FIXME(define (make-hash-table #!optional (comparison :: <procedure> equal?) (hash :: <procedure> (appropriate-hash-function-for comparison)) (size :: <int> *default-table-size*)) :: <srfi-hash-table> (make <srfi-hash-table> comparison hash size))#|;; Are these part of the specification? FIXME(define (make-hash-table-maker comp hash) (lambda args (apply make-hash-table (cons comp (cons hash args)))))(define make-symbol-hash-table (make-hash-table-maker eq? symbol-hash))(define make-string-hash-table (make-hash-table-maker string=? string-hash))(define make-string-ci-hash-table (make-hash-table-maker string-ci=? string-ci-hash))(define make-integer-hash-table (make-hash-table-maker = modulo))|#(define (hash-table-ref (hash-table :: <srfi-hash-table>) key #!optional default) (let ((node (*:getNode hash-table key))) (if (eq? node #!null) (if default (default) (error "hash-table-ref: no value associated with" key)) (*:getValue node))))(define (hash-table-ref/default (hash-table :: <srfi-hash-table>) key default) (*:get hash-table key default))(define (hash-table-set! (hash-table :: <srfi-hash-table>) key value) :: <void> (*:put hash-table key value))(define (hash-table-update! (hash-table :: <srfi-hash-table>) key function #!optional thunk) :: <void> (let ((node (*:getNode hash-table key))) (if (eq? node #!null) (if thunk (hash-table-set! hash-table key (function (thunk))) (error "hash-table-update!: no value exists for key" key)) (*:setValue node (function (*:getValue node))))))(define (hash-table-update!/default (hash-table :: <srfi-hash-table>) key function default) :: <void> (let ((node (*:getNode hash-table key))) (if (eq? node #!null) (hash-table-set! hash-table key (function default)) (*:setValue node (function (*:getValue node))))))(define (hash-table-delete! (hash-table :: <srfi-hash-table>) key) :: <void> (*:remove hash-table key))(define (hash-table-exists? (hash-table :: <srfi-hash-table>) key) :: <boolean> (not (eq? (*:getNode hash-table key) #!null)))(define (hash-table-walk (hash-table :: <srfi-hash-table>) (proc :: <procedure>)) :: <void> (*:walk hash-table proc)) (define (hash-table-fold (hash-table :: <srfi-hash-table>) (proc :: <procedure>) acc) (*:fold hash-table proc acc))(define (alist->hash-table alist #!optional (comparison equal?) (hash (appropriate-hash-function-for comparison)) (size (max *default-table-size* (* 2 (length alist))))) (let ((hash-table (make-hash-table comparison hash size))) (for-each (lambda (elem) (hash-table-update!/default hash-table (car elem) (lambda (x) x) (cdr elem))) alist) hash-table))(define (hash-table->alist (hash-table :: <srfi-hash-table>)) (*:toAlist hash-table))(define (hash-table-copy (hash-table :: <srfi-hash-table>)) :: <srfi-hash-table> (let* ((new (make-hash-table (hash-table-equivalence-function hash-table) (hash-table-hash-function hash-table) (max *default-table-size* (* 2 (hash-table-size hash-table)))))) (*:putAll new hash-table) new))(define (hash-table-merge! (hash-table1 :: <srfi-hash-table>) (hash-table2 :: <srfi-hash-table>)) :: <void> (*:putAll hash-table1 hash-table2) hash-table1)(define (hash-table-keys (hash-table :: <srfi-hash-table>)) (hash-table-fold hash-table (lambda (key val acc) (cons key acc)) '()))(define (hash-table-values (hash-table :: <srfi-hash-table>)) (hash-table-fold hash-table (lambda (key val acc) (cons val acc)) '()))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -