123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346 |
- % HCONS.SL - Hashing (unique) CONS and associated utilities.
- %
- % Author: William Galway
- % Symbolic Computation Group
- % Computer Science Dept.
- % University of Utah
- % Date: Wednesday, 2 June 1982
- % Copyright (c) 1982 University of Utah
- %
- (BothTimes % ?? Compile time may suffice.
- (load useful)
- (load fast-vector))
- % Summary of "user level" functions provided:
- % (DM Hcons (X) ...) % Nary hashed cons, right associative.
- % (DN Hlist (X) ...) % Hcons version of "list" function.
- % Hcons version of "copy" function. Note that unlike copy, this is not
- % guaranteed to create a new copy of a structure. (In fact, rather the
- % opposite.)
- % (DE Hcopy (lst) ...)
- % (DE Happend (U V) ...) % Hcons version of "append" function.
- % (DE Hreverse (U) ...) % Hcons version of "reverse" function.
- % Pairs for property list functions must be created by Hcons.
- % Get property of id or pair.
- % (DE extended-get (id-or-pair indicator) ...)
- % Put property of id or pair. Known to setf.
- % (DE extended-put (id-or-pair indicator val) ...)
- % Number of hash "slots" in table, should be a prime number to get an even
- % spread of hits (??). This package has been written so that it should be
- % possible to modify this size at runtime (I hope). So if the hash-tables
- % get too heavily loaded they can be copied to larger ones.
- (DefConst hcons-table-size 103)
- % Build the two tables (we switch from one to the other on each garbage
- % collection. Note that (MkVect 1) gives TWO locations.
- (setf hash-cons-tables (MkVect 1))
- (setf (IGetV hash-cons-tables 0)
- (MkVect (sub1 (const hcons-table-size))))
- (setf (IGetV hash-cons-tables 1)
- (MkVect (sub1 (const hcons-table-size))))
- % current-table-number switches between 0 and one at each garbage
- % collection--selecting the current table to use.
- (setf current-table-number 0)
- (DE next-table-number (table-number)
- (cond
- ((equal table-number 0) 1)
- (T 0)))
- % Should really use structs for this, but I'm unsure on the exact details
- % of how structs work, and it's very important to understand how much free
- % space will be demanded by any routines that are called.
- % Anyway, each location in a "hash table" is either NIL, or an "entry",
- % where an entry is implemented as a vector of
- % [ <dotted-pair> <property-list-for-pair> <next-entry-in-chain> ]
- % This should be done differently too.
- (DefConst entry-size 4) % The size of an entry in "heap units"??
- (DefConst pair-size 2) % Similarly for pairs.
- (DS create-hash-entry ()
- % Create a 3 element vector.
- (MkVect 2))
- (DS pair-info (ent)
- (IGetV ent 0))
- (DS prop-list-info (ent)
- (IGetV ent 1))
- (DS next-entry (ent)
- (IGetV ent 2))
- % Finds a location within a "hash table", for a pair (X,Y).
- % This version is very simpleminded!
- (DS hcons-hash-function (htable X Y)
- (remainder
- % Take absolute value to avoid sign problems with remainder.
- (abs (plus (Sys2Int X) (Sys2Int Y)))
- (add1 (ISizeV htable))))
- % Copy entries from one "hash cons table" to another, setting the source
- % table to all NILs. Return the dst-table, as well as copying into it.
- % This routine is used to place entries in their new locations after a
- % garbage collection. This routine MUST NOT allocate anything on the heap.
- (DE move-hcons-table (src-table dst-table)
- (prog (dst-index src-entry src-pair nxt-entry)
- (for (from src-index 0 (ISizeV src-table) 1)
- (do
- (progn
- (setf src-entry (IGetV src-table src-index))
- % Use GetV here, until "the bug" in IGetV gets fixed.
- (setf (GetV src-table src-index) NIL)
- (while src-entry
- (progn
- (setf src-pair (pair-info src-entry))
- (setf dst-index
- (hcons-hash-function
- dst-table
- (car src-pair) (cdr src-pair)))
- % Save the next entry in the the chain, and then relink the
- % current entry into its new location.
- (setf nxt-entry (next-entry src-entry))
- (setf (next-entry src-entry)
- (IGetV dst-table dst-index))
- (setf (IGetV dst-table dst-index) src-entry)
- % Move to next thing in chain.
- (setf src-entry nxt-entry))))))
- (return dst-table)))
- % Nary version of hashed cons.
- (DM Hcons (X)
- (RobustExpand (cdr X) 'hcons2 NIL))
- % Binary "hashed" cons of X and Y, returns pointer to previously
- % constructed pair if it can be found in the hash table.
- (DE Hcons2 (X Y)
- (prog (hashloc hitchain tmpchain newpair newentry)
- (setf hashloc (hcons-hash-function
- (IGetV hash-cons-tables current-table-number)
- X Y))
- % Get chain of entries at the appropriate hash location in the
- % appropriate table.
- (setf hitchain (IGetV
- (IGetV hash-cons-tables current-table-number)
- hashloc))
- % Search for a previously constructed pair, if any, with car and cdr
- % equal to X and Y respectively.
- % Note that tmpchain is not a list, but a "chain" of "entries".
- (setf tmpchain hitchain)
- (while (and tmpchain
- % Keep searching unless an exact match is found.
- (not (and
- % EqN test might be better, so that we handle numbers
- % intelligently? Probably have to worry about hash
- % code also.
- (eq X (car (setf newpair (pair-info tmpchain))))
- (eq Y (cdr newpair)))))
- % do
- (setf tmpchain (next-entry tmpchain)))
- (cond
- % If no entry was found, create a new one.
- ((null tmpchain)
- (progn
- % We need enough room for one new pair, plus one new entry. If
- % there isn't enough room on the heap then collect garbage (and
- % in the process move EVERYTHING around, switch hash tables,
- % etc.)
- (cond
- ((LessP
- (GtHeap NIL) % Returns free space in heap.
- (plus (const pair-size) (const entry-size)))
- (progn
- (reclaim)
- % Recalculate locations of everything.
- (setf hashloc
- (hcons-hash-function
- (IGetV hash-cons-tables current-table-number)
- X Y))
- % Get chain of entries at the appropriate hash location in
- % the appropriate table.
- (setf hitchain
- (IGetV
- (IGetV hash-cons-tables current-table-number)
- hashloc)))))
- % Allocate the new pair, store information into the appropriate
- % spot in appropriate table.
- (setf newpair (cons X Y))
- (setf newentry (create-hash-entry))
- (setf (pair-info newentry) newpair)
- (setf (prop-list-info newentry) NIL)
- (setf (next-entry newentry) hitchain)
- % Link the new entry into the front of the table.
- (setf
- (IGetV
- (IGetV hash-cons-tables current-table-number)
- hashloc)
- newentry))))
- % Return the pair (either newly constructed, or old).
- (return newpair)))
- % "hcons" version of "list" function.
- (DN Hlist (X)
- (do-hlist X))
- (DE do-hlist (X)
- (cond
- ((null X) NIL)
- (T (hcons (car X) (do-hlist (cdr X))))))
- % "hcons" version of copy. Note that unlike copy, this is not guaranteed
- % to create a new copy of a structure. (In fact, rather the opposite.)
- (DE Hcopy (lst)
- (cond
- ((not (pairp lst)) lst)
- (T (hcons (hcopy (car lst)) (hcopy (cdr lst))))))
- % "hcons" version of Append function.
- (DE Happend (U V)
- (cond
- % First arg is NIL, or some other non-pair.
- ((not (PairP U)) V)
- % else ...
- (T (hcons (car U) (Happend (cdr U) V)))))
- % Hcons version of Reverse.
- (DE Hreverse (U)
- (prog (V)
- (while (PairP U)
- (progn
- (setf V (hcons (car U) V))
- (setf U (cdr U))))
- (return V)))
- % Look up and return the entry for a pair, if any. Return NIL if argument
- % is not a pair.
- (DE entry-for-pair (p)
- (cond
- ((PairP p)
- (prog (hashloc ent)
- (setf hashloc
- (hcons-hash-function
- (IGetV hash-cons-tables current-table-number)
- (car p) (cdr p)))
- % Look at appropriate spot in hash table.
- (setf ent
- (IGetV (IGetV hash-cons-tables current-table-number) hashloc))
-
- % Search through chain for p.
- (while (and ent
- (not (eq (pair-info ent) p)))
- (setf ent (next-entry ent)))
- % Return the entry, or NIL if none found.
- (return ent)))))
- % Get a property for a pair or identifier. Only pairs stored in the hash
- % table have properties.
- (DE extended-get (id-or-pair indicator)
- (cond
- ((IdP id-or-pair) (get id-or-pair indicator))
- ((PairP id-or-pair)
- (prog (proplist prop-pair)
- (setf proplist (pair-property-list id-or-pair))
- (setf prop-pair (atsoc indicator proplist))
- (return
- (cond
- ((PairP prop-pair) (cdr prop-pair))))))))
- % Put function for pairs and identifiers. Only pairs in the hash table can
- % be given properties. (We are very sloppy about case when pair isn't in
- % table, but hopefully the code won't blow up.) "val" is returned in all
- % cases.
- (DE extended-put (id-or-pair indicator val)
- (cond
- ((IdP id-or-pair) (put id-or-pair indicator val))
- ((PairP id-or-pair)
- (prog (proplist prop-pair)
- (setf proplist (pair-property-list id-or-pair))
- % Get the information (if any) stored under the indicator.
- (setf prop-pair (Atsoc indicator proplist))
- (cond
- % Modify the information under the indicator, if any.
- ((PairP prop-pair)
- (setf (cdr prop-pair) val))
- % Otherwise (nothing found under indicator), create new
- % (indicator . value) pair.
- (T
- (progn
- % Note use of cons, not Hcons, WHICH IS RIGHT? (I think cons.)
- (setf prop-pair (cons indicator val))
- % Tack new (indicator . value) pair onto property list, and
- % store in entry for the pair who's property list is being
- % hacked.
- (set-pair-property-list
- id-or-pair (cons prop-pair proplist)))))
- % We return the value even if the pair isn't in the hash table.
- (return val)))))
- (PUT 'extended-get 'assign-op 'extended-put)
- (FLAG '(extended-get) 'SETF-SAFE)
- % Return the "property list" associated with a pair.
- (DE pair-property-list (p)
- (prog (ent)
- (setf ent (entry-for-pair p))
- (return
- (cond
- (ent (prop-list-info ent))
- (T NIL)))))
- % Set the "property list" cell for a pair, return the new "property list".
- (DE set-pair-property-list (p val)
- (prog (ent)
- (setf ent (entry-for-pair p))
- (return
- (cond
- (ent (setf (prop-list-info ent) val))
- (T NIL)))))
- % We redefine the garbage collector so that it rebuilds the hash table
- % after garbage collection has moved everything.
- (putd 'original-!%Reclaim (car (getd '!%Reclaim)) (cdr (getd '!%Reclaim)))
- % New version of !%reclaim--shuffles stuff in cons tables after collecting
- % garbage.
- (DE !%Reclaim ()
- (prog1
- (original-!%Reclaim)
- % Move the old table to the new one, shuffling everything into its
- % correct position.
- (move-hcons-table
- % Would use IGetV, but there appears to be a bug preventing it from
- % working.
- % Source
- (GetV hash-cons-tables current-table-number)
- % Destination
- (GetV hash-cons-tables
- (next-table-number current-table-number)))
- % Point to new "current-table".
- (setf current-table-number
- (next-table-number current-table-number))))
|