hashtable-utils.scm 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. ;;; Copyright (C) 2024, 2025 David Thompson <dave@spritely.institute>
  2. ;;; Copyright (C) 2023, 2024 Robin Templeton
  3. ;;;
  4. ;;; Licensed under the Apache License, Version 2.0 (the "License");
  5. ;;; you may not use this file except in compliance with the License.
  6. ;;; You may obtain a copy of the License at
  7. ;;;
  8. ;;; http://www.apache.org/licenses/LICENSE-2.0
  9. ;;;
  10. ;;; Unless required by applicable law or agreed to in writing, software
  11. ;;; distributed under the License is distributed on an "AS IS" BASIS,
  12. ;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. ;;; See the License for the specific language governing permissions and
  14. ;;; limitations under the License.
  15. ;;; Commentary:
  16. ;;;
  17. ;;; Hashtable tests.
  18. ;;;
  19. ;;; Code:
  20. (define-module (test hashtable-utils)
  21. #:use-module (srfi srfi-64)
  22. #:use-module (test utils)
  23. #:export (test-hashtable-impl))
  24. (define-syntax-rule (test-hashtable-impl make-hashtable
  25. make-eq-hashtable
  26. make-eqv-hashtable
  27. hashtable?
  28. hashtable-hash
  29. hashtable-equiv
  30. hashtable-size
  31. hashtable-ref
  32. hashtable-set!
  33. hashtable-delete!
  34. hashtable-clear!
  35. hashtable-contains?
  36. hashtable-copy
  37. hashtable-keys
  38. hashtable-values
  39. hashtable-for-each
  40. hashtable-fold)
  41. (begin
  42. ;; Ref hit
  43. (test-call "b"
  44. (lambda ()
  45. (let ((ht (make-eq-hashtable)))
  46. (hashtable-set! ht 'a 'b)
  47. (hashtable-ref ht 'a))))
  48. ;; Ref miss
  49. (test-call "#f"
  50. (lambda ()
  51. (let ((ht (make-eq-hashtable)))
  52. (hashtable-set! ht 'x 'y)
  53. (hashtable-ref ht 'a))))
  54. ;; Ref miss with default
  55. (test-call "b"
  56. (lambda ()
  57. (let ((ht (make-eq-hashtable)))
  58. (hashtable-set! ht 'x 'y)
  59. (hashtable-ref ht 'a 'b))))
  60. ;; Key insertion increases size
  61. (test-call "1"
  62. (lambda ()
  63. (let ((ht (make-eq-hashtable)))
  64. (hashtable-set! ht 'a 'b)
  65. (hashtable-size ht))))
  66. ;; Key deletion
  67. (test-call "#f"
  68. (lambda ()
  69. (let ((ht (make-eq-hashtable)))
  70. (hashtable-set! ht 'a 'b)
  71. (hashtable-delete! ht 'a)
  72. (hashtable-contains? ht 'a))))
  73. ;; Key deletion decrements size
  74. (test-call "0"
  75. (lambda ()
  76. (let ((ht (make-eq-hashtable)))
  77. (hashtable-set! ht 'a 'b)
  78. (hashtable-delete! ht 'a)
  79. (hashtable-size ht))))
  80. ;; Key deletion miss does not decrement size
  81. (test-call "1"
  82. (lambda ()
  83. (let ((ht (make-eq-hashtable)))
  84. (hashtable-set! ht 'a 'b)
  85. (hashtable-delete! ht 'c)
  86. (hashtable-size ht))))
  87. ;; Check for existing key
  88. (test-call "#t"
  89. (lambda ()
  90. (let ((ht (make-eq-hashtable)))
  91. (hashtable-set! ht 'a 'b)
  92. (hashtable-contains? ht 'a))))
  93. ;; Overwrite value for key
  94. (test-call "c"
  95. (lambda ()
  96. (let ((ht (make-eq-hashtable)))
  97. (hashtable-set! ht 'a 'b)
  98. (hashtable-set! ht 'a 'c)
  99. (hashtable-ref ht 'a))))
  100. ;; Copy
  101. (test-call "(2 b d)"
  102. (lambda ()
  103. (let ((ht (make-eq-hashtable)))
  104. (hashtable-set! ht 'a 'b)
  105. (hashtable-set! ht 'c 'd)
  106. (let ((ht* (hashtable-copy ht)))
  107. (list (hashtable-size ht*)
  108. (hashtable-ref ht* 'a)
  109. (hashtable-ref ht* 'c))))))
  110. ;; Clear sets size to 0
  111. (test-call "0"
  112. (lambda ()
  113. (let ((ht (make-eq-hashtable)))
  114. (hashtable-set! ht 'a 'b)
  115. (hashtable-clear! ht)
  116. (hashtable-size ht))))
  117. ;; Clear removes all associations
  118. (test-call "#f"
  119. (lambda ()
  120. (let ((ht (make-eq-hashtable)))
  121. (hashtable-set! ht 'a 'b)
  122. (hashtable-clear! ht)
  123. (hashtable-contains? ht 'a))))
  124. ;; Keys of an empty table
  125. (test-call "()"
  126. (lambda ()
  127. (hashtable-keys (make-eq-hashtable))))
  128. ;; Keys of a populated table
  129. (test-call "(a)"
  130. (lambda ()
  131. (let ((ht (make-eq-hashtable)))
  132. (hashtable-set! ht 'a 'b)
  133. (hashtable-keys ht))))
  134. ;; Values of an empty table
  135. (test-call "()"
  136. (lambda ()
  137. (hashtable-values (make-eq-hashtable))))
  138. ;; Values of a populated table
  139. (test-call "(b)"
  140. (lambda ()
  141. (let ((ht (make-eq-hashtable)))
  142. (hashtable-set! ht 'a 'b)
  143. (hashtable-values ht))))
  144. ;; For each iteration
  145. (test-call "(a b)"
  146. (lambda ()
  147. (let ((ht (make-eq-hashtable))
  148. (result #f))
  149. (hashtable-set! ht 'a 'b)
  150. (hashtable-for-each (lambda (k v)
  151. (set! result (list k v)))
  152. ht)
  153. result)))
  154. ;; Fold (result order is technically unspecified but we know what it
  155. ;; will be)
  156. (test-call "((a . b) (c . d))"
  157. (lambda ()
  158. (let ((ht (make-eq-hashtable))
  159. (result #f))
  160. (hashtable-set! ht 'a 'b)
  161. (hashtable-set! ht 'c 'd)
  162. (hashtable-fold (lambda (k v prev)
  163. (cons (cons k v) prev))
  164. '()
  165. ht))))
  166. ;; Grow/shrink
  167. (with-additional-imports ((only (hoot numbers) 1+))
  168. (test-call "100"
  169. (lambda ()
  170. (let ((ht (make-eq-hashtable)))
  171. (do ((i 0 (1+ i)))
  172. ((= i 100))
  173. (hashtable-set! ht i i))
  174. (do ((i 0 (1+ i)))
  175. ((= i 100))
  176. (hashtable-delete! ht i))
  177. (do ((i 0 (1+ i)))
  178. ((= i 100))
  179. (hashtable-set! ht i i))
  180. (hashtable-size ht)))))))