hcons.sl 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. % HCONS.SL - Hashing (unique) CONS and associated utilities.
  2. %
  3. % Author: William Galway
  4. % Symbolic Computation Group
  5. % Computer Science Dept.
  6. % University of Utah
  7. % Date: Wednesday, 2 June 1982
  8. % Copyright (c) 1982 University of Utah
  9. %
  10. (BothTimes % ?? Compile time may suffice.
  11. (load useful)
  12. (load fast-vector))
  13. % Summary of "user level" functions provided:
  14. % (DM Hcons (X) ...) % Nary hashed cons, right associative.
  15. % (DN Hlist (X) ...) % Hcons version of "list" function.
  16. % Hcons version of "copy" function. Note that unlike copy, this is not
  17. % guaranteed to create a new copy of a structure. (In fact, rather the
  18. % opposite.)
  19. % (DE Hcopy (lst) ...)
  20. % (DE Happend (U V) ...) % Hcons version of "append" function.
  21. % (DE Hreverse (U) ...) % Hcons version of "reverse" function.
  22. % Pairs for property list functions must be created by Hcons.
  23. % Get property of id or pair.
  24. % (DE extended-get (id-or-pair indicator) ...)
  25. % Put property of id or pair. Known to setf.
  26. % (DE extended-put (id-or-pair indicator val) ...)
  27. % Number of hash "slots" in table, should be a prime number to get an even
  28. % spread of hits (??). This package has been written so that it should be
  29. % possible to modify this size at runtime (I hope). So if the hash-tables
  30. % get too heavily loaded they can be copied to larger ones.
  31. (DefConst hcons-table-size 103)
  32. % Build the two tables (we switch from one to the other on each garbage
  33. % collection. Note that (MkVect 1) gives TWO locations.
  34. (setf hash-cons-tables (MkVect 1))
  35. (setf (IGetV hash-cons-tables 0)
  36. (MkVect (sub1 (const hcons-table-size))))
  37. (setf (IGetV hash-cons-tables 1)
  38. (MkVect (sub1 (const hcons-table-size))))
  39. % current-table-number switches between 0 and one at each garbage
  40. % collection--selecting the current table to use.
  41. (setf current-table-number 0)
  42. (DE next-table-number (table-number)
  43. (cond
  44. ((equal table-number 0) 1)
  45. (T 0)))
  46. % Should really use structs for this, but I'm unsure on the exact details
  47. % of how structs work, and it's very important to understand how much free
  48. % space will be demanded by any routines that are called.
  49. % Anyway, each location in a "hash table" is either NIL, or an "entry",
  50. % where an entry is implemented as a vector of
  51. % [ <dotted-pair> <property-list-for-pair> <next-entry-in-chain> ]
  52. % This should be done differently too.
  53. (DefConst entry-size 4) % The size of an entry in "heap units"??
  54. (DefConst pair-size 2) % Similarly for pairs.
  55. (DS create-hash-entry ()
  56. % Create a 3 element vector.
  57. (MkVect 2))
  58. (DS pair-info (ent)
  59. (IGetV ent 0))
  60. (DS prop-list-info (ent)
  61. (IGetV ent 1))
  62. (DS next-entry (ent)
  63. (IGetV ent 2))
  64. % Finds a location within a "hash table", for a pair (X,Y).
  65. % This version is very simpleminded!
  66. (DS hcons-hash-function (htable X Y)
  67. (remainder
  68. % Take absolute value to avoid sign problems with remainder.
  69. (abs (plus (Sys2Int X) (Sys2Int Y)))
  70. (add1 (ISizeV htable))))
  71. % Copy entries from one "hash cons table" to another, setting the source
  72. % table to all NILs. Return the dst-table, as well as copying into it.
  73. % This routine is used to place entries in their new locations after a
  74. % garbage collection. This routine MUST NOT allocate anything on the heap.
  75. (DE move-hcons-table (src-table dst-table)
  76. (prog (dst-index src-entry src-pair nxt-entry)
  77. (for (from src-index 0 (ISizeV src-table) 1)
  78. (do
  79. (progn
  80. (setf src-entry (IGetV src-table src-index))
  81. % Use GetV here, until "the bug" in IGetV gets fixed.
  82. (setf (GetV src-table src-index) NIL)
  83. (while src-entry
  84. (progn
  85. (setf src-pair (pair-info src-entry))
  86. (setf dst-index
  87. (hcons-hash-function
  88. dst-table
  89. (car src-pair) (cdr src-pair)))
  90. % Save the next entry in the the chain, and then relink the
  91. % current entry into its new location.
  92. (setf nxt-entry (next-entry src-entry))
  93. (setf (next-entry src-entry)
  94. (IGetV dst-table dst-index))
  95. (setf (IGetV dst-table dst-index) src-entry)
  96. % Move to next thing in chain.
  97. (setf src-entry nxt-entry))))))
  98. (return dst-table)))
  99. % Nary version of hashed cons.
  100. (DM Hcons (X)
  101. (RobustExpand (cdr X) 'hcons2 NIL))
  102. % Binary "hashed" cons of X and Y, returns pointer to previously
  103. % constructed pair if it can be found in the hash table.
  104. (DE Hcons2 (X Y)
  105. (prog (hashloc hitchain tmpchain newpair newentry)
  106. (setf hashloc (hcons-hash-function
  107. (IGetV hash-cons-tables current-table-number)
  108. X Y))
  109. % Get chain of entries at the appropriate hash location in the
  110. % appropriate table.
  111. (setf hitchain (IGetV
  112. (IGetV hash-cons-tables current-table-number)
  113. hashloc))
  114. % Search for a previously constructed pair, if any, with car and cdr
  115. % equal to X and Y respectively.
  116. % Note that tmpchain is not a list, but a "chain" of "entries".
  117. (setf tmpchain hitchain)
  118. (while (and tmpchain
  119. % Keep searching unless an exact match is found.
  120. (not (and
  121. % EqN test might be better, so that we handle numbers
  122. % intelligently? Probably have to worry about hash
  123. % code also.
  124. (eq X (car (setf newpair (pair-info tmpchain))))
  125. (eq Y (cdr newpair)))))
  126. % do
  127. (setf tmpchain (next-entry tmpchain)))
  128. (cond
  129. % If no entry was found, create a new one.
  130. ((null tmpchain)
  131. (progn
  132. % We need enough room for one new pair, plus one new entry. If
  133. % there isn't enough room on the heap then collect garbage (and
  134. % in the process move EVERYTHING around, switch hash tables,
  135. % etc.)
  136. (cond
  137. ((LessP
  138. (GtHeap NIL) % Returns free space in heap.
  139. (plus (const pair-size) (const entry-size)))
  140. (progn
  141. (reclaim)
  142. % Recalculate locations of everything.
  143. (setf hashloc
  144. (hcons-hash-function
  145. (IGetV hash-cons-tables current-table-number)
  146. X Y))
  147. % Get chain of entries at the appropriate hash location in
  148. % the appropriate table.
  149. (setf hitchain
  150. (IGetV
  151. (IGetV hash-cons-tables current-table-number)
  152. hashloc)))))
  153. % Allocate the new pair, store information into the appropriate
  154. % spot in appropriate table.
  155. (setf newpair (cons X Y))
  156. (setf newentry (create-hash-entry))
  157. (setf (pair-info newentry) newpair)
  158. (setf (prop-list-info newentry) NIL)
  159. (setf (next-entry newentry) hitchain)
  160. % Link the new entry into the front of the table.
  161. (setf
  162. (IGetV
  163. (IGetV hash-cons-tables current-table-number)
  164. hashloc)
  165. newentry))))
  166. % Return the pair (either newly constructed, or old).
  167. (return newpair)))
  168. % "hcons" version of "list" function.
  169. (DN Hlist (X)
  170. (do-hlist X))
  171. (DE do-hlist (X)
  172. (cond
  173. ((null X) NIL)
  174. (T (hcons (car X) (do-hlist (cdr X))))))
  175. % "hcons" version of copy. Note that unlike copy, this is not guaranteed
  176. % to create a new copy of a structure. (In fact, rather the opposite.)
  177. (DE Hcopy (lst)
  178. (cond
  179. ((not (pairp lst)) lst)
  180. (T (hcons (hcopy (car lst)) (hcopy (cdr lst))))))
  181. % "hcons" version of Append function.
  182. (DE Happend (U V)
  183. (cond
  184. % First arg is NIL, or some other non-pair.
  185. ((not (PairP U)) V)
  186. % else ...
  187. (T (hcons (car U) (Happend (cdr U) V)))))
  188. % Hcons version of Reverse.
  189. (DE Hreverse (U)
  190. (prog (V)
  191. (while (PairP U)
  192. (progn
  193. (setf V (hcons (car U) V))
  194. (setf U (cdr U))))
  195. (return V)))
  196. % Look up and return the entry for a pair, if any. Return NIL if argument
  197. % is not a pair.
  198. (DE entry-for-pair (p)
  199. (cond
  200. ((PairP p)
  201. (prog (hashloc ent)
  202. (setf hashloc
  203. (hcons-hash-function
  204. (IGetV hash-cons-tables current-table-number)
  205. (car p) (cdr p)))
  206. % Look at appropriate spot in hash table.
  207. (setf ent
  208. (IGetV (IGetV hash-cons-tables current-table-number) hashloc))
  209. % Search through chain for p.
  210. (while (and ent
  211. (not (eq (pair-info ent) p)))
  212. (setf ent (next-entry ent)))
  213. % Return the entry, or NIL if none found.
  214. (return ent)))))
  215. % Get a property for a pair or identifier. Only pairs stored in the hash
  216. % table have properties.
  217. (DE extended-get (id-or-pair indicator)
  218. (cond
  219. ((IdP id-or-pair) (get id-or-pair indicator))
  220. ((PairP id-or-pair)
  221. (prog (proplist prop-pair)
  222. (setf proplist (pair-property-list id-or-pair))
  223. (setf prop-pair (atsoc indicator proplist))
  224. (return
  225. (cond
  226. ((PairP prop-pair) (cdr prop-pair))))))))
  227. % Put function for pairs and identifiers. Only pairs in the hash table can
  228. % be given properties. (We are very sloppy about case when pair isn't in
  229. % table, but hopefully the code won't blow up.) "val" is returned in all
  230. % cases.
  231. (DE extended-put (id-or-pair indicator val)
  232. (cond
  233. ((IdP id-or-pair) (put id-or-pair indicator val))
  234. ((PairP id-or-pair)
  235. (prog (proplist prop-pair)
  236. (setf proplist (pair-property-list id-or-pair))
  237. % Get the information (if any) stored under the indicator.
  238. (setf prop-pair (Atsoc indicator proplist))
  239. (cond
  240. % Modify the information under the indicator, if any.
  241. ((PairP prop-pair)
  242. (setf (cdr prop-pair) val))
  243. % Otherwise (nothing found under indicator), create new
  244. % (indicator . value) pair.
  245. (T
  246. (progn
  247. % Note use of cons, not Hcons, WHICH IS RIGHT? (I think cons.)
  248. (setf prop-pair (cons indicator val))
  249. % Tack new (indicator . value) pair onto property list, and
  250. % store in entry for the pair who's property list is being
  251. % hacked.
  252. (set-pair-property-list
  253. id-or-pair (cons prop-pair proplist)))))
  254. % We return the value even if the pair isn't in the hash table.
  255. (return val)))))
  256. (PUT 'extended-get 'assign-op 'extended-put)
  257. (FLAG '(extended-get) 'SETF-SAFE)
  258. % Return the "property list" associated with a pair.
  259. (DE pair-property-list (p)
  260. (prog (ent)
  261. (setf ent (entry-for-pair p))
  262. (return
  263. (cond
  264. (ent (prop-list-info ent))
  265. (T NIL)))))
  266. % Set the "property list" cell for a pair, return the new "property list".
  267. (DE set-pair-property-list (p val)
  268. (prog (ent)
  269. (setf ent (entry-for-pair p))
  270. (return
  271. (cond
  272. (ent (setf (prop-list-info ent) val))
  273. (T NIL)))))
  274. % We redefine the garbage collector so that it rebuilds the hash table
  275. % after garbage collection has moved everything.
  276. (putd 'original-!%Reclaim (car (getd '!%Reclaim)) (cdr (getd '!%Reclaim)))
  277. % New version of !%reclaim--shuffles stuff in cons tables after collecting
  278. % garbage.
  279. (DE !%Reclaim ()
  280. (prog1
  281. (original-!%Reclaim)
  282. % Move the old table to the new one, shuffling everything into its
  283. % correct position.
  284. (move-hcons-table
  285. % Would use IGetV, but there appears to be a bug preventing it from
  286. % working.
  287. % Source
  288. (GetV hash-cons-tables current-table-number)
  289. % Destination
  290. (GetV hash-cons-tables
  291. (next-table-number current-table-number)))
  292. % Point to new "current-table".
  293. (setf current-table-number
  294. (next-table-number current-table-number))))