From: <don...@is...> - 2003-12-06 20:04:23
|
I'm still trying to figure out how the test posted by Bruno works. Can someone explain? Below is a version that's improved for purposes of adding an entry to the test suite. See the comments therein. ;; no longer used (defun hash-table-keys (ht) (loop :for kk :being :each :hash-key :of ht :collect kk)) ;; no longer used - see next (defun check-hash-unique (ht) (let ((hash-ok t)) (do* ((keys (hash-table-keys ht) (cdr keys)) (key (car keys) (car keys)) (other-keys (cdr keys) (cdr keys))) ((null keys) hash-ok) (when (member key other-keys) (format t "ERROR! key ~s occurs multiple times!~%" key) (setf hash-ok nil))))) ;; if you really want to find the duplicate entries, this is much faster ;; if you just want to test it's not necessary (defun check-hash-unique2 (ht) (let ((h2 (make-hash-table :test 'equal))) (loop :for kk :being :each :hash-key :of ht do (if (gethash kk h2) (format t "ERROR! key ~s occurs multiple times!~%" kk) (setf (gethash kk h2) t))))) (defun do-hash-test (ht) (clrhash ht) (loop for countval upfrom 1 upto 15000 for key = (cons "HT" countval) ;; (format nil "HT-~D" countval) ;; same problem occurs with cons but a lot faster than format do ;;(gethash key ht) (setf (gethash key ht) t) (setf (gethash key ht) t) ;; was countval ;; The gethash seems unnecessary in the sense that the failure ;; occurs without it. Similarly, it occurs whether the two ;; assignments use the same value or not. ;; But two assignments are needed. ;; This part I don't understand. ;; Is the problem related to gc between the two? ;; I tried putting a gc between the two and the problem went away. ;; If there's no gc between the two then I'd expect the second ;; to be a noop. If the problem is a gc during one then why do ;; we need two? finally (format t "~A entries~%" (loop :for kk :being :each :hash-key :of ht :count t)) ;; as a test it suffices to count the entries (above) ;; (check-hash-unique2 ht) ;; only if you want to see the duplicates )) (loop :repeat 2 :do (loop :with ht = (make-hash-table :size 1000) ;; the size doesn't seem to matter ;; I get the bug with no size or 20000 or 100000 :for i :from 1 :to 10 :do (format t "~& --- ~d ---~%" i) (do-hash-test ht))) |