Dispensers are containers with access to only one entry, the "active entry". To access another entry the state of the dispenser must be changed. If for the same reason the dispenser must "be read out" the whole content can be copied into another container structure. Note that a dispenser can be only read from - that is exactly the opposite functionality of the other containers (lists and tables). This category of containers have four different dispensers being described by the following classes STACK_, QUEUE_, PRIORITY_QUEUE_, KEY_PRIORITY_QUEUE_. The effective dispensers are very simple. They differ mainly in the underlaying semantics. In any case functions 'list_of_elements' or 'table_of_elements' deliver the elements in the sequence they would be removed if this happened. The corresponding extracts from the short (a kind of) forms are put below.
indexing title: "The project-wide universal properties: the class is% %an ancestor to all the dispensers" deferred class interface SIMPLE_DISPENSER_[G] feature -- Operations remove -- deletes the "active entry" and sets 'item' and possibly 'key' -- to another entry (algorithms of selecting a new "active entry" -- differ in all dispensers) or - Void if there are no more -- entries require not_empty: not empty deferred feature -- Queries empty: BOOLEAN -- is the dispenser empty ? deferred item: G -- the "active entry" of the dispenser - in dispensers with two -- element entries attribute 'key' will be also considered as a -- part of the "active entry" invariant correct_emptiness: (empty implies item = Void) and then (item = Void implies empty); proper_tuning: (not empty implies item /= Void) and then (item /= Void implies not empty) end
indexing title: "Facilities for all the dispensers with one element entries" deferred class interface DISPENSER_[G] inherit CONTAINER_[G] export {NONE} make SIMPLE_DISPENSER_[G] feature -- Queries capacity: INTEGER -- gives the number of all the slots allocated in the dispenser -- (all the dispensers may have not only slots occupied by the -- entries already put into but unused ones also) count: INTEGER -- gives the number of entries in the dispenser or equally -- the number of the slots used for storing the entries list_of_elements: LIST_[G] -- delivers all the entries of the dispenser in the order in -- which they would be repeatedly removed if it really happened deferred ensure well_done: not empty implies Result /= Void end
indexing title: "Facilities for the dispensers with two element entries" deferred class interface KEYED_DISPENSER_[G, H] inherit KEYED_CONTAINER_[G, H] export {NONE} make SIMPLE_DISPENSER_[G] feature -- Queries key: H -- the other part of the "active entry" of the dispenser capacity: INTEGER -- gives the number of all the slots allocated in the dispenser -- (all the dispensers may have not only slots occupied by the -- entries already put into but unused ones also) count: INTEGER -- gives the number of entries in the dispenser or equally -- the number of the slots used for storing the entries table_of_elements: TABLE_[G, H] -- delivers all the entries of the dispenser in the order in -- which they would be repeatedly removing if it really happened deferred ensure well_done: not empty implies Result /= Void end
indexing title: "Stacks: dispensers implementing a last-in, first-out policy" class interface STACK_[G] inherit DISPENSER_[G] feature -- Operations put (x: G) -- adds the new entry into the dispenser which immediately after -- becomes the "active entry" of the dispenser require else valid_argument: x /= Void ensure then well_done: count = old count + 1 and then x = item remove -- deletes the "active entry" and sets 'item' to the one most -- recently put into if at least one entry exists after the -- removal - if it does not then 'item' is set to Void feature -- Queries list_of_elements: LIST_[G] -- delivers all the entries of the dispenser in the order in -- which they would be repeatedly removed if it really happened end
indexing title: "Queues: dispensers implementing a first-in, first-out policy" class interface QUEUE_[G] inherit DISPENSER_[G] feature -- Operations put (x: G) -- adds the new entry into the dispenser require else valid_argument: x /= Void ensure then well_done: count = old count + 1 remove -- deletes the "active entry" and sets 'item' to the one that has -- been in the dispenser for the longest time if there are no -- more entries after the removal - 'item' is set to Void ensure then well_done: count = old count - 1 feature -- Queries list_of_elements: LIST_[G] -- delivers all the entries of the dispenser in the order in -- which they would be repeatedly removed if it really happened end
indexing title: "Priority queues: dispensers with one element entries% %in which only the largest element is accessed" class interface PRIORITY_QUEUE_[G -> COMPARABLE] inherit DISPENSER_[G] feature -- Operations put (x: G) -- adds the new entry into the dispenser require else valid_argument: x /= Void ensure then well_done: count = old count + 1 remove -- deletes the "active entry" and sets 'item' to the largest one -- among those still existing in the dispenser after the removal; -- if there are no more entries then 'item' is set to Void ensure then well_done: count = old count - 1 feature -- Queries list_of_elements: LIST_[G] -- delivers all the entries of the dispenser in the order in -- which they would be repeatedly removed if it really happened end
indexing title: "Key priority queues: dispensers with two element entries% %in which only the entry with the largest key is accessed" class interface KEY_PRIORITY_QUEUE_[G, H -> COMPARABLE] inherit KEYED_DISPENSER_[G, H] feature -- Operations put (x: G; k: H) -- adds the new entry into the dispenser require else valid_item: x /= Void; valid_key: k /= Void ensure then well_done: count = old count + 1 remove -- deletes the "active entry" and sets 'item' to the element -- associated with the largest key among those still existing in -- the dispenser after the removal and 'key' to this key; if -- there are no more entries then 'item' and 'key' are both -- set to Void ensure then well_done: count = old count - 1 feature -- Queries table_of_elements: TABLE_[G, H] -- delivers all the entries of the dispenser in the order in -- which they would be repeatedly removed if it really happened end
As it was mentioned above the effective dispensers are very simple. They differ only in the underlying semantics. In any case the functions 'list_of_elements' or 'table_of_elements' deliver the elements (items) in the sequence they would be removed should this really happened. This means that the following program parts would be equivalent:
-- some common stuff ... x: DISPENSER; -- any real dispenser could be here: now -- it's only an example ... cs: CURSOR_; l: LIST_; !!x; -- -- putting some items into the dispenser ... -- -- The first version -- (note: the content of the dispenser is changed ...) from until x.empty loop io.print (x.item); x.remove end; ... -- The second version -- (note: the dispenser above remains unchanged ...) from l := x.list_of_elements; cs := l.cursor until cs.finish loop io.print (l.item_at (cs)); cs.forth end; ...