module: internal Copyright: Original Code is Copyright (c) 1995-2004 Functional Objects, Inc. All rights reserved. License: Functional Objects Library Public License Version 1.0 Dual-license: GNU Lesser General Public License Warranty: Distributed WITHOUT WARRANTY OF ANY KIND define open abstract class () end class ; define sealed inline method make (class == , #rest all-keys, #key) => (object) apply(make, , all-keys) end method make; //// //// //// define constant $empty-table-set-elements = make(, size: 0); define sealed class () slot set-elements :: , init-value: $empty-table-set-elements; end class ; define sealed domain make (singleton()); define sealed method initialize (set :: , #key size = unsupplied()) next-method(); set.set-elements := if (size.supplied?) make(, size: size, values?: #f) else make(, values?: #f) end; end method initialize; // // SIZE // define sealed inline method size (set :: ) => (size :: ) set.set-elements.size end method size; // This is a simplified version of gethash. Read the comments in table.dylan // for further explanation of how this works. define sealed method member? (object, set :: , #key test) => (bool :: ) let table :: = set.set-elements; let tv = table-vector(table); let token = rehash-token(tv); // Ensure token fetched before computing hash code. sequence-point(); // Don't need hash state here. let id = hash-for-lookup(tv, object); let (index, table-key) = search(tv, object, id); if (table-key ~== $table-entry-empty) sequence-point(); if (rehash-token-valid?(tv, token)) #t else // Rehash has been initiated. // rehash-table(table, tv, #f); // Why do this? with-table-vector-locked (tv) end; // Just wait on lock instead. member?(object, set); // try again end if; elseif (needs-rehash?(tv, token)) rehash-table(table, tv, #f); member?(object, set); // try again else #f end if; end method member?; // This is a simplified version of puthash. Read the comments in table.dylan // for further explanation of how this works. define sealed method add! (set :: , key) => (set :: ) let table :: = set.set-elements; let tv = table-vector(table); let token = rehash-token(tv); // Ensure that the above occurs before computing the hash code. sequence-point(); let (id, hstate) = hash(tv, key); let (index, fkey) = search(tv, key, id); let success? = if (fkey ~== $table-entry-empty) #t else with-table-vector-locked (tv) merge-hash-state!(hash-state(tv), hstate); let keys = entry-keys(tv); if (entry-key(keys, index) == $table-entry-empty & ~full?(tv) & rehash-token-valid?(tv, token) & ~is-stale?(tv.hash-state)) additions(tv) := additions(tv) + 1; entry-key(keys, index) := key; #t; // success flag else #f; // failure flag end if; end with-table-vector-locked; end if; if (success?) set else // Store failed for some reason. Rehash if needed and retry. if (needs-rehash?(tv, token)) rehash-table(table, tv, full?(tv)); elseif (full?(tv)) rehash-table(table, tv, #t); end; add!(set, key); // try again end if; end method add!; define sealed method remove! (set :: , object, #key test, count) => (set :: ) remove-key!(set.set-elements, object); set end method remove!; define sealed method remove-all-keys! (set :: ) remove-all-keys!(set.set-elements) end method; define sealed method element (set :: , key, #key default = unsupplied()) => (key-or-default-or-error :: ) if (member?(key, set)) key elseif (supplied?(default)) default else error(make(, format-string: "No such element %= in %=", format-arguments: list(key, set))) end end method element; // element-setter for sets, given that a set's key-sequence is a vector // of its elements. element-setter(o, s, o) adds o if not already present. // element-setter(o, s, m) replaces m by o if m already present, otherwise // adds o. (yuk - who decided on this spec?) define sealed method element-setter (object, set :: , key) => (object) if (key == object) add!(set, object) else if (member?(key, set)) remove!(set, key) end if; add!(set, object) end if; object end method element-setter; define sealed method key-test (set :: ) => test :: ; \== end method key-test; //// //// iteration protocol //// define inline function set-finished-state? (set, state :: , limit) => finished? :: ; // ignore(set, limit); finished-state-index?(state-index(state)) end; define sealed inline method forward-iteration-protocol (set :: ) => (initial-state :: , limit :: , next-state :: , finished-state? :: , current-key :: , current-element :: , current-element-setter :: , copy-state :: ); let (initial, limit, next, finished, current-key, current-element, current-element-setter, copy-state) = set.set-elements.forward-iteration-protocol; values(initial, #f, next, set-finished-state?, current-key, current-key, method (value, table, state :: ) error(make(, format-string: "Cannot update current element of a set during iteration.")) end, copy-state) end method forward-iteration-protocol; /// /// LIMITED TABLES /// define method limited-set (of :: , size :: false-or()) => (type :: ) make(, class: , element-type: of, concrete-class: , size: size); end method; /// TODO: COULD BE EXPENSIVE UNLESS TYPES ARE CACHED define inline method type-for-copy (x :: ) => (type :: ) let elt-type = element-type(x); if (elt-type == ) object-class(x) else limited-set(element-type(x), #f) end if end method type-for-copy; // eof