view tests/automated/hash-table-tests.el @ 5013:ae48681c47fa

changes to VOID_TO_LISP et al. -------------------- ChangeLog entries follow: -------------------- src/ChangeLog addition: 2010-02-08 Ben Wing <ben@xemacs.org> * casetab.c (compute_canon_mapper): * casetab.c (initialize_identity_mapper): * casetab.c (compute_up_or_eqv_mapper): * casetab.c (recompute_case_table): * casetab.c (set_case_table): * chartab.c (copy_mapper): * chartab.c (copy_char_table_range): * chartab.c (get_range_char_table_1): * console.c (find_nonminibuffer_frame_not_on_console_predicate): * console.c (find_nonminibuffer_frame_not_on_console): * console.c (nuke_all_console_slots): * device.c: * device.c (find_nonminibuffer_frame_not_on_device_predicate): * device.c (find_nonminibuffer_frame_not_on_device): * dialog-msw.c (dialog_proc): * dialog-msw.c (handle_question_dialog_box): * dialog-x.c (maybe_run_dbox_text_callback): * eval.c: * eval.c (safe_run_hook_trapping_problems_1): * eval.c (safe_run_hook_trapping_problems): * event-msw.c: * event-msw.c (mswindows_wnd_proc): * event-msw.c (mswindows_find_frame): * faces.c (update_face_inheritance_mapper): * frame-msw.c (mswindows_init_frame_1): * frame-msw.c (mswindows_get_mouse_position): * frame-msw.c (mswindows_get_frame_parent): * glade.c (connector): * glade.c (Fglade_xml_signal_connect): * glade.c (Fglade_xml_signal_autoconnect): * glade.c (Fglade_xml_textdomain): * glyphs-msw.c (mswindows_subwindow_instantiate): * glyphs-msw.c (mswindows_widget_instantiate): * glyphs.c (check_instance_cache_mapper): * glyphs.c (check_window_subwindow_cache): * glyphs.c (check_image_instance_structure): * gui-x.c (snarf_widget_value_mapper): * gui-x.c (popup_selection_callback): * gui-x.c (button_item_to_widget_value): * keymap.c (map_keymap_mapper): * keymap.c (Fmap_keymap): * menubar-gtk.c (__torn_off_sir): * menubar-gtk.c (__activate_menu): * menubar-gtk.c (menu_convert): * menubar-gtk.c (__generic_button_callback): * menubar-gtk.c (menu_descriptor_to_widget_1): * menubar-msw.c: * menubar-msw.c (EMPTY_ITEM_ID): * menubar-x.c (menu_item_descriptor_to_widget_value_1): * menubar-x.c (pre_activate_callback): * menubar-x.c (command_builder_operate_menu_accelerator): * menubar-x.c (command_builder_find_menu_accelerator): * print.c (print_internal): * process-unix.c (close_process_descs_mapfun): * process.c (get_process_from_usid): * process.c (init_process_io_handles): * profile.c (sigprof_handler): * profile.c (get_profiling_info_timing_maphash): * profile.c (Fget_profiling_info): * profile.c (set_profiling_info_timing_maphash): * profile.c (mark_profiling_info_maphash): * scrollbar-msw.c (mswindows_create_scrollbar_instance): * scrollbar-msw.c (mswindows_free_scrollbar_instance): * scrollbar-msw.c (mswindows_handle_scrollbar_event): * specifier.c (recompute_cached_specifier_everywhere_mapfun): * specifier.c (recompute_cached_specifier_everywhere): * syntax.c (copy_to_mirrortab): * syntax.c (copy_if_not_already_present): * syntax.c (update_just_this_syntax_table): * text.c (new_dfc_convert_now_damn_it): * text.h (LISP_STRING_TO_EXTERNAL): * tooltalk.c: * tooltalk.c (tooltalk_message_callback): * tooltalk.c (tooltalk_pattern_callback): * tooltalk.c (Fcreate_tooltalk_message): * tooltalk.c (Fcreate_tooltalk_pattern): * ui-byhand.c (__generic_toolbar_callback): * ui-byhand.c (generic_toolbar_insert_item): * ui-byhand.c (__emacs_gtk_ctree_recurse_internal): * ui-byhand.c (Fgtk_ctree_recurse): * ui-gtk.c (__internal_callback_destroy): * ui-gtk.c (__internal_callback_marshal): * ui-gtk.c (Fgtk_signal_connect): * ui-gtk.c (gtk_type_to_lisp): * ui-gtk.c (lisp_to_gtk_type): * ui-gtk.c (lisp_to_gtk_ret_type): * lisp-disunion.h: * lisp-disunion.h (NON_LVALUE): * lisp-union.h: * lisp.h (LISP_HASH): Rename: LISP_TO_VOID -> STORE_LISP_IN_VOID VOID_TO_LISP -> GET_LISP_FROM_VOID These new names are meant to clearly identify that the Lisp object is the source and void the sink, and that they can't be used the other way around -- they aren't exact opposites despite the old names. The names are also important given the new functions created just below. Also, clarify comments in lisp-union.h and lisp-disunion.h about the use of the functions. * lisp.h: New functions STORE_VOID_IN_LISP and GET_VOID_FROM_LISP. These are different from the above in that the source is a void * (previously, you had to use make_opaque_ptr()). * eval.c (restore_lisp_object): * eval.c (record_unwind_protect_restoring_lisp_object): * eval.c (struct restore_int): * eval.c (restore_int): * eval.c (record_unwind_protect_restoring_int): * eval.c (free_pointer): * eval.c (record_unwind_protect_freeing): * eval.c (free_dynarr): * eval.c (record_unwind_protect_freeing_dynarr): * eval.c (unbind_to_1): Use STORE_VOID_IN_LISP and GET_VOID_FROM_LISP to eliminate the use of make_opaque_ptr() and mostly eliminate Lisp consing entirely in the use of these various record_unwind_protect_* functions as well as internal_bind_* (e.g. internal_bind_int). * tests.c: * tests.c (Ftest_store_void_in_lisp): * tests.c (syms_of_tests): * tests.c (vars_of_tests): Add an C-assert-style test to test STORE_VOID_IN_LISP and GET_VOID_FROM_LISP to make sure the same value comes back that was put in.
author Ben Wing <ben@xemacs.org>
date Mon, 08 Feb 2010 06:42:16 -0600
parents 189fb67ca31a
children 0f66906b6e37
line wrap: on
line source

;; Copyright (C) 1998 Free Software Foundation, Inc.

;; Author: Martin Buchholz <martin@xemacs.org>
;; Maintainer: Martin Buchholz <martin@xemacs.org>
;; Created: 1998
;; Keywords: tests, database

;; This file is part of XEmacs.

;; XEmacs is free software; you can redistribute it and/or modify it
;; under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.

;; XEmacs is distributed in the hope that it will be useful, but
;; WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
;; General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with XEmacs; see the file COPYING.  If not, write to the Free
;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
;; 02111-1307, USA.

;;; Synched up with: Not in FSF.

;;; Commentary:

;;; Test hash tables implementation
;;; See test-harness.el

(condition-case err
    (require 'test-harness)
  (file-error
   (when (and (boundp 'load-file-name) (stringp load-file-name))
     (push (file-name-directory load-file-name) load-path)
     (require 'test-harness))))

;; Test all combinations of make-hash-table keywords
(dolist (test '(eq eql equal))
  (dolist (size '(0 1 100))
    (dolist (rehash-size '(1.1 9.9))
      (dolist (rehash-threshold '(0.2 .9))
	(dolist (weakness '(nil key value key-or-value key-and-value))
	  (dolist (data '(() (1 2) (1 2 3 4)))
	    (let ((ht (make-hash-table
		       :test test
		       :size size
		       :rehash-size rehash-size
		       :rehash-threshold rehash-threshold
		       :weakness weakness)))
	      (Assert-equal ht (car (let ((print-readably t))
				       (read-from-string (prin1-to-string ht)))))
	      (Assert-eq test (hash-table-test ht))
	      (Assert (<= size (hash-table-size ht)))
	      (Assert-eql rehash-size (hash-table-rehash-size ht))
	      (Assert-eql rehash-threshold (hash-table-rehash-threshold ht))
	      (Assert-eq weakness (hash-table-weakness ht)))))))))

(loop for (fun weakness) in '((make-hashtable nil)
			      (make-weak-hashtable key-and-value)
			      (make-key-weak-hashtable key)
			      (make-value-weak-hashtable value))
  do (Assert-eq weakness (hash-table-weakness (funcall fun 10))))

(loop for (type weakness) in '((non-weak nil)
			       (weak key-and-value)
			       (key-weak key)
			       (value-weak value))
  do (Assert-equal (make-hash-table :type type)
		    (make-hash-table :weakness weakness)))

(Assert (not (equal (make-hash-table :weakness nil)
		    (make-hash-table :weakness t))))

(let ((ht (make-hash-table :size 20 :rehash-threshold .75 :test 'eq))
      (size 80))
  (Assert (hashtablep ht))
  (Assert (hash-table-p ht))
  (Assert-eq 'eq (hash-table-test ht))
  (Assert-eq 'non-weak (hash-table-type ht))
  (Assert-eq 'non-weak (hashtable-type ht))
  (Assert-eq 'nil (hash-table-weakness ht))
  (dotimes (j size)
    (puthash j (- j) ht)
    (Assert-eq (gethash j ht) (- j))
    (Assert= (hash-table-count ht) (1+ j))
    (Assert= (hashtable-fullness ht) (hash-table-count ht))
    (puthash j j ht)
    (Assert-eq (gethash j ht 'foo) j)
    (Assert= (hash-table-count ht) (1+ j))
    (setf (gethash j ht) (- j))
    (Assert-eq (gethash j ht) (- j))
    (Assert= (hash-table-count ht) (1+ j)))

  (clrhash ht)
  (Assert= 0 (hash-table-count ht))

  (dotimes (j size)
    (puthash j (- j) ht)
    (Assert-eq (gethash j ht) (- j))
    (Assert= (hash-table-count ht) (1+ j)))

  (let ((k-sum 0) (v-sum 0))
    (maphash #'(lambda (k v) (incf k-sum k) (incf v-sum v)) ht)
    (Assert= k-sum (/ (* size (- size 1)) 2))
    (Assert= v-sum (- k-sum)))

  (let ((count size))
    (dotimes (j size)
      (remhash j ht)
      (Assert-eq (gethash j ht) nil)
      (Assert-eq (gethash j ht 'foo) 'foo)
      (Assert= (hash-table-count ht) (decf count)))))

(let ((ht (make-hash-table :size 30 :rehash-threshold .25 :test 'equal))
      (size 70))
  (Assert (hashtablep ht))
  (Assert (hash-table-p ht))
  (Assert (>= (hash-table-size ht) (/ 30 .25)))
  (Assert-eql .25 (hash-table-rehash-threshold ht))
  (Assert-eq 'equal (hash-table-test ht))
  (Assert-eq (hash-table-test ht) (hashtable-test-function ht))
  (Assert-eq 'non-weak (hash-table-type ht))
  (dotimes (j size)
    (puthash (int-to-string j) (- j) ht)
    (Assert-eq (gethash (int-to-string j) ht) (- j))
    (Assert= (hash-table-count ht) (1+ j))
    (puthash (int-to-string j) j ht)
    (Assert-eq (gethash (int-to-string j) ht 'foo) j)
    (Assert= (hash-table-count ht) (1+ j)))

  (clrhash ht)
  (Assert= 0 (hash-table-count ht))
  (Assert-equal ht (copy-hash-table ht))

  (dotimes (j size)
    (setf (gethash (int-to-string j) ht) (- j))
    (Assert-eq (gethash (int-to-string j) ht) (- j))
    (Assert= (hash-table-count ht) (1+ j)))

  (let ((count size))
    (dotimes (j size)
      (remhash (int-to-string j) ht)
      (Assert-eq (gethash (int-to-string j) ht) nil)
      (Assert-eq (gethash (int-to-string j) ht 'foo) 'foo)
      (Assert= (hash-table-count ht) (decf count)))))

(let ((iterations 5) (one 1.0) (two 2.0))
  (flet ((check-copy
	  (ht)
	  (let ((copy-of-ht (copy-hash-table ht)))
	    (Assert-equal ht copy-of-ht)
	    (Assert (not (eq ht copy-of-ht)))
	    (Assert-eq  (hash-table-count ht) (hash-table-count copy-of-ht))
	    (Assert-eq  (hash-table-type  ht) (hash-table-type  copy-of-ht))
	    (Assert-eq  (hash-table-size  ht) (hash-table-size  copy-of-ht))
	    (Assert-eql (hash-table-rehash-size ht) (hash-table-rehash-size copy-of-ht))
	    (Assert-eql (hash-table-rehash-threshold ht) (hash-table-rehash-threshold copy-of-ht)))))

  (let ((ht (make-hash-table :size 100 :rehash-threshold .6 :test 'eq)))
    (dotimes (j iterations)
      (puthash (+ one 0.0) t ht)
      (puthash (+ two 0.0) t ht)
      (puthash (cons 1 2) t ht)
      (puthash (cons 3 4) t ht))
    (Assert-eq (hashtable-test-function ht) 'eq)
    (Assert-eq (hash-table-test ht) 'eq)
    (Assert= (* iterations 4) (hash-table-count ht))
    (Assert-eq nil (gethash 1.0 ht))
    (Assert-eq nil (gethash '(1 . 2) ht))
    (check-copy ht)
    )

  (let ((ht (make-hash-table :size 100 :rehash-threshold .6 :test 'eql)))
    (dotimes (j iterations)
      (puthash (+ one 0.0) t ht)
      (puthash (+ two 0.0) t ht)
      (puthash (cons 1 2) t ht)
      (puthash (cons 3 4) t ht))
    (Assert-eq (hashtable-test-function ht) 'eql)
    (Assert-eq (hash-table-test ht) 'eql)
    (Assert= (+ 2 (* 2 iterations)) (hash-table-count ht))
    (Assert-eq t (gethash 1.0 ht))
    (Assert-eq nil (gethash '(1 . 2) ht))
    (check-copy ht)
    )

  (let ((ht (make-hash-table :size 100 :rehash-threshold .6 :test 'equal)))
    (dotimes (j iterations)
      (puthash (+ one 0.0) t ht)
      (puthash (+ two 0.0) t ht)
      (puthash (cons 1 2) t ht)
      (puthash (cons 3 4) t ht))
    (Assert-eq (hashtable-test-function ht) 'equal)
    (Assert-eq (hash-table-test ht) 'equal)
    (Assert= 4 (hash-table-count ht))
    (Assert-eq t (gethash 1.0 ht))
    (Assert-eq t (gethash '(1 . 2) ht))
    (check-copy ht)
    )

  ))

;; Test that weak hash-tables are properly handled
(loop for (weakness expected-count expected-k-sum expected-v-sum) in
  '((nil 6 38 25)
    (t 3 6 9)
    (key 4 38 9)
    (value 4 6 25))
  do
  (let* ((ht (make-hash-table :weakness weakness))
       (my-obj (cons ht ht)))
  (garbage-collect)
  (puthash my-obj 1 ht)
  (puthash 2 my-obj ht)
  (puthash 4 8 ht)
  (puthash (cons ht ht) 16 ht)
  (puthash 32 (cons ht ht) ht)
  (puthash (cons ht ht) (cons ht ht) ht)
  (let ((k-sum 0) (v-sum 0))
    (maphash #'(lambda (k v)
		 (when (integerp k) (incf k-sum k))
		 (when (integerp v) (incf v-sum v)))
	     ht)
    (Assert-eq 38 k-sum)
    (Assert-eq 25 v-sum))
  (Assert-eq 6 (hash-table-count ht))
  (garbage-collect)
  (Assert-eq expected-count (hash-table-count ht))
  (let ((k-sum 0) (v-sum 0))
    (maphash #'(lambda (k v)
		 (when (integerp k) (incf k-sum k))
		 (when (integerp v) (incf v-sum v)))
	     ht)
    (Assert-eq expected-k-sum k-sum)
    (Assert-eq expected-v-sum v-sum))))

;;; Test the ability to puthash and remhash the current elt of a maphash
(let ((ht (make-hash-table :test 'eql)))
  (dotimes (j 100) (setf (gethash j ht) (- j)))
  (maphash #'(lambda (k v)
	       (if (oddp k) (remhash k ht) (puthash k (- v) ht)))
	   ht)
  (let ((k-sum 0) (v-sum 0))
    (maphash #'(lambda (k v) (incf k-sum k) (incf v-sum v)) ht)
    (Assert= (* 50 49) k-sum)
    (Assert= v-sum k-sum)))

;;; Test reading and printing of hash-table objects
(let ((h1 #s(hashtable  weakness t rehash-size 3.0 rehash-threshold .2 test eq data (1 2 3 4)))
      (h2 #s(hash-table weakness t rehash-size 3.0 rehash-threshold .2 test eq data (1 2 3 4)))
      (h3 (make-hash-table :weakness t :rehash-size 3.0 :rehash-threshold .2 :test 'eq)))
  (Assert-equal h1 h2)
  (Assert (not (equal h1 h3)))
  (puthash 1 2 h3)
  (puthash 3 4 h3)
  (Assert-equal h1 h3))

;;; Testing equality of hash tables
(Assert-equal (make-hash-table :test 'eql :size 300 :rehash-threshold .9 :rehash-size 3.0)
	       (make-hash-table :test 'eql))
(Assert (not (equal (make-hash-table :test 'eq)
		    (make-hash-table :test 'equal))))
(let ((h1 (make-hash-table))
      (h2 (make-hash-table)))
  (Assert-equal h1 h2)
  (Assert (not (eq h1 h2)))
  (puthash 1 2 h1)
  (Assert (not (equal h1 h2)))
  (puthash 1 2 h2)
  (Assert-equal h1 h2)
  (puthash 1 3 h2)
  (Assert (not (equal h1 h2)))
  (clrhash h1)
  (Assert (not (equal h1 h2)))
  (clrhash h2)
  (Assert-equal h1 h2)
  )

;;; Test sxhash
(Assert= (sxhash "foo") (sxhash "foo"))
(Assert= (sxhash '(1 2 3)) (sxhash '(1 2 3)))
(Assert (/= (sxhash '(1 2 3)) (sxhash '(3 2 1))))