Module: internal Author: Jonathan Bachrach 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 ; //////////// // INTERFACE //////////// define open generic pop (deque :: ) => object; define open generic pop-last (deque :: ) => object; define open generic push (deque :: , new-value) => (new-value :: ); define open generic push-last (deque :: , new-value) => (new-value :: ); ///////////////// // IMPLEMENTATION ///////////////// // // MAKE // define sealed inline method make (class == , #rest all-keys, #key size, fill) => (deque :: ) apply(make, , all-keys) end method make; // // AS // define method as (class == , object :: ) => (deque :: ) as(, object) end method as; define sealed inline method as (class == , deque :: ) => (deque :: ) deque end method as; // // ADD! // define method add! (deque :: , new-element) => (deque :: ) push(deque, new-element); deque end method add!; // // ADD // define method add (deque :: , new-element) => (new :: ) let new = deque.copy-sequence; push(new, new-element); new end method add; // // REMOVE // define method remove (deque :: , value, #key test = \==, count = deque.size) => (new :: ) remove!(deque.copy-sequence, value, test: test, count: count) end method remove; // // REVERSE // define method reverse (deque :: ) => (new :: ) reverse!(deque.copy-sequence) end method reverse; // // // define class (, ) slot representation :: , init-value: $empty-island-deque; end class ; define sealed domain element-type (); /// /// LIMITED DEQUES /// define method limited-deque (of :: ) => (type :: ) make(, class: , element-type: of, concrete-class: ); end method; define method limited (class == , #key of, #all-keys) => (type :: ) limited-deque(of) end method; /// TODO: COULD BE EXPENSIVE UNLESS TYPES ARE CACHED define sealed inline method type-for-copy (x :: ) => (type :: ) let elt-type = element-type(x); if (elt-type == ) object-class(x) else limited-deque(elt-type) end if end method type-for-copy; define constant $minimum-island-deque-data-size = 4; // Note that first-index > last-index when the queue is empty define class () slot first-index :: , init-value: 0; slot last-index :: , init-value: 0; repeated slot island-deque-element, init-keyword: fill:, init-value: #f, size-getter: size, size-init-keyword: size:, size-init-value: 0; end class ; define constant $empty-island-deque = make(, size: 0); // // INITIALIZE // define method initialize (deque :: , #key size = 0, fill) next-method(); check-nat(size); let data-size = max(size * 2, $minimum-island-deque-data-size); let rep = make(, size: data-size, fill: #f); let rep-first-index = truncate/(data-size, 2); let rep-last-index = rep-first-index + size - 1; if (fill) for (i :: from rep-first-index to rep-last-index) island-deque-element(rep, i) := fill end; end; rep.first-index := rep-first-index; rep.last-index := rep-last-index; deque.representation := rep; end method initialize; // // AS // define sealed method as (class == , object :: ) => (d :: ) let new-deque :: = make(); for (element in object) push-last(new-deque, element); end for; new-deque end method as; define sealed method as (class == , object :: ) => (d :: ) let new-deque :: = make(, size: object.size); let rep = new-deque.representation; for (i :: from rep.first-index, val in object) island-deque-element(rep, i) := val end for; new-deque end method as; define sealed method as (class == , object :: ) => (d :: ) object end method as; // // SIZE // define sealed inline method size (collection :: ) => (size :: ) let rep = collection.representation; (rep.last-index - rep.first-index) + 1 end method size; // // SIZE-SETTER // define sealed inline method trusted-size-setter (new-size :: , collection :: ) => (new-size :: ) // TODO: write a faster version of this method. let difference = new-size - collection.size; case difference < 0 => for (i :: from 0 below - difference) pop-last(collection) end; difference > 0 => for (i :: from 0 below difference) trusted-push-last(collection, #f) end; end case; new-size end method trusted-size-setter; define sealed method size-setter (new-size :: , collection :: ) => (new-size :: ) // TODO: write a faster version of this method. check-nat(new-size); let size = size(collection); unless (new-size <= size) // expected to fail when #f is incompatible with element-type check-type(#f, element-type(collection)) end unless; trusted-size(collection) := new-size; end method size-setter; // // EMPTY? // define sealed method empty? (collection :: ) => (result :: ) let rep = collection.representation; rep.last-index < rep.first-index end method empty?; // // ELEMENT // define sealed method element (collection :: , index :: , #key default = unsupplied()) => (object) let rep = collection.representation; let rep-first-index = rep.first-index; let rep-last-index = rep.last-index; let rep-size-minus-1 = rep-last-index - rep-first-index; if (index < 0 | index > rep-size-minus-1) if (unsupplied?(default)) element-range-error(collection, index) else check-type(default, element-type(collection)); default end if else // Even if multiple threads are running, and rep-first-index and // rep-last-index are incorrect, they should be within the bounds of // rep, and so if we get here the following should be within bounds. island-deque-element(rep, index + rep-first-index) end if end method element; // // ELEMENT-NO-BOUNDS-CHECK // // We can't trust skipping the bounds check because the deque might move under // our feet. define sealed inline method element-no-bounds-check (collection :: , index :: , #key default = unsupplied()) => (object) element(collection, index, default: default) end method element-no-bounds-check; // // ELEMENT-SETTER // define sealed method element-setter (new-value, collection :: , index :: ) => (object) check-type(new-value, element-type(collection)); let rep = collection.representation; let rep-first-index = rep.first-index; let rep-last-index = rep.last-index; let rep-size-minus-1 = rep-last-index - rep-first-index; if (index < 0) element-range-error(collection, index) end; if (index > rep-size-minus-1) if (collection.size = index) trusted-size(collection) := index + 1; else collection.size := index + 1; end if; collection[index] := new-value // Let's try again else // Even if multiple threads are running, and rep-first-index and // rep-last-index are incorrect, they should be within the bounds of // rep, and so if we get here the following should be within bounds. island-deque-element(rep, index + rep-first-index) := new-value; end if end method element-setter; // // ELEMENT-NO-BOUNDS-CHECK-SETTER // // We can't trust skipping the bounds check because the deque might move under // our feet. define inline sealed method element-no-bounds-check-setter (new-value, collection :: , index :: ) => (object) element-setter(new-value, collection, index) end method element-no-bounds-check-setter; // // REMOVE! // define sealed method remove! (deque :: , target, #key test = \==, count = deque.size) => (d :: ) let rep = deque.representation; let rep-first-index = rep.first-index; let rep-last-index = rep.last-index; iterate grovel (count :: = count, src-index :: = rep-first-index, dst-index :: = rep-first-index) if (src-index > rep-last-index) for (i :: from dst-index below src-index) island-deque-element(rep, i) := #f end; rep.last-index := dst-index - 1 else let item = island-deque-element(rep, src-index); case count > 0 & test(item, target) => grovel(count - 1, src-index + 1, dst-index); otherwise => island-deque-element(rep, dst-index) := item; grovel(count, src-index + 1, dst-index + 1) end case end if end iterate; deque end method remove!; // // REVERSE! // define sealed method reverse! (deque :: ) => (result :: ) let rep = deque.representation; let rep-first-index = rep.first-index; let rep-last-index = rep.last-index; let stopping-index = ceiling/(rep-first-index + rep-last-index, 2); for (i :: from rep-first-index below stopping-index, j :: from rep-last-index by -1) let tmp = island-deque-element(rep, i); island-deque-element(rep, i) := island-deque-element(rep, j); island-deque-element(rep, j) := tmp; end for; deque end method reverse!; // PRIVATE define method grow! (deque :: ) let old-rep = deque.representation; let old-rep-first-index = old-rep.first-index; let old-rep-last-index = old-rep.last-index; let old-rep-size = (old-rep-last-index - old-rep-first-index) + 1; let new-rep = make(, size: old-rep-size * 2, fill: #f); new-rep.first-index := truncate/(old-rep-size, 2); for (src-index :: from old-rep-first-index to old-rep-last-index, dst-index :: from new-rep.first-index) island-deque-element(new-rep, dst-index) := island-deque-element(old-rep, src-index); finally new-rep.last-index := dst-index - 1; end for; deque.representation := new-rep; deque end method grow!; define method make-room-at-first! (deque :: ) if (size(deque.representation) = deque.size) grow!(deque) end if; // assume grow leaves room at first let rep = deque.representation; let rep-first-index = rep.first-index; let rep-last-index = rep.last-index; let rep-size-minus-1 = rep.size - 1; let delta :: = rep-size-minus-1 - (rep-last-index - rep-first-index); unless ( rep-last-index = rep-size-minus-1 | delta < 0 /* i.e. thread problem */) // unlucky? for (dst-index :: from rep-size-minus-1 to delta by -1, src-index :: from (rep-size-minus-1 - delta) + rep-first-index by -1) island-deque-element(rep, dst-index) := island-deque-element(rep, src-index); end for; rep.first-index := delta; rep.last-index := rep-size-minus-1; end unless; values() end method make-room-at-first!; define method make-room-at-last! (deque :: ) if (size(deque.representation) = deque.size) grow!(deque) end if; // assume grow leaves room at last let rep = deque.representation; let rep-first-index = rep.first-index; let rep-last-index = rep.last-index; let new-last :: = rep-last-index - rep-first-index; unless (rep-first-index = 0 | new-last < -1 /* i.e. thread problem */) // unlucky? for (dst-index :: from 0 to new-last, src-index :: from rep-first-index) island-deque-element(rep, dst-index) := island-deque-element(rep, src-index); end for; rep.first-index := 0; rep.last-index := new-last end unless; values() end method make-room-at-last!; // // PUSH // define sealed method push (deque :: , new-element) => (new-element :: ) check-type(new-element, element-type(deque)); let rep = deque.representation; let rep-first-index = rep.first-index; while (rep-first-index = 0) // If threads are used properly this loop should // be executed at most once. make-room-at-first!(deque); rep := deque.representation; rep-first-index := rep.first-index; end while; rep.first-index := rep-first-index := rep-first-index - 1; island-deque-element(rep, rep-first-index) := new-element end method push; // // POP // define sealed method pop (deque :: ) => (object) let rep = deque.representation; let rep-first-index = rep.first-index; let rep-last-index = rep.last-index; if (rep-last-index < rep-first-index) error(make(, format-string: "POP empty deque %=", format-arguments: list(deque))) else let value = island-deque-element(rep, rep-first-index); island-deque-element(rep, rep-first-index) := #f; rep.first-index := rep-first-index + 1; value end if end method pop; // // PUSH-LAST // define sealed inline method trusted-push-last (deque :: , new-element) => (result :: ) let rep = deque.representation; let rep-last-index = rep.last-index; while (rep-last-index = (rep.size - 1)) // If threads are used properly this loop should // be executed at most once. make-room-at-last!(deque); rep := deque.representation; rep-last-index := rep.last-index; end while; rep.last-index := rep-last-index := rep-last-index + 1; island-deque-element(rep, rep-last-index) := new-element; deque end method trusted-push-last; define sealed method push-last (deque :: , new-element) => (result :: ) check-type(new-element, element-type(deque)); trusted-push-last(deque, new-element); end method push-last; // // POP-LAST // define sealed method pop-last (deque :: ) => (object) let rep = deque.representation; let rep-first-index = rep.first-index; let rep-last-index = rep.last-index; if (rep-last-index < rep-first-index) error(make(, format-string: "POP empty deque %=", format-arguments: list(deque))) else let value = island-deque-element(rep, rep-last-index); island-deque-element(rep, rep-last-index) := #f; rep.last-index := rep-last-index - 1; value end if end method pop-last; // // ITERATION PROTOCOL // // We assume that the underlying vector can only ever get bigger. If this // ceases to hold then the iteration code needs to be rethought. define inline function object-deque-current-key (deque :: , state :: ) state - deque.representation.first-index end function; define inline function object-deque-current-element (deque :: , state :: ) island-deque-element(deque.representation, state) end function; define inline function object-deque-current-element-setter (new-value, deque :: , state :: ) check-type(new-value, element-type(deque)); island-deque-element(deque.representation, state) := new-value end function; define inline method forward-iteration-protocol (deque :: ) => (initial-state, limit, next-state :: , finished-state? :: , current-key :: , current-element :: , current-element-setter :: , copy-state :: ) values(deque.representation.first-index, deque.representation.last-index + 1, sequence-next-state, sequence-finished-state?, object-deque-current-key, object-deque-current-element, object-deque-current-element-setter, identity-copy-state) end method forward-iteration-protocol; define inline method backward-iteration-protocol (deque :: ) => (final-state, limit, next-state :: , finished-state? :: , current-key :: , current-element :: , current-element-setter :: , copy-state :: ) values(deque.representation.last-index + 1, deque.representation.first-index, sequence-previous-state, sequence-finished-state?, sequence-current-key, object-deque-current-element, object-deque-current-element-setter, identity-copy-state) end method backward-iteration-protocol; // // COPY-SEQUENCE // define sealed method copy-sequence (source :: , #key start: first :: = 0, end: last = unsupplied()) => (result-sequence :: ); if (first ~= 0 | supplied?(last)) next-method() else let rep = source.representation; let rep-first-index = rep.first-index; let rep-last-index = rep.last-index; let deque-size = (rep-last-index - rep-first-index) + 1; let target = make(, size: deque-size, element-type: element-type(source)); let target-rep = target.representation; for (from :: from rep-first-index to rep-last-index, to :: from target-rep.first-index to target-rep.last-index) island-deque-element(target-rep, to) := island-deque-element(rep, from) end for; target end end copy-sequence; // // CONCATENATE-AS-TWO // define method concatenate-as-two (type == , first-seq :: , second-seq :: ) => result-seq :: ; case empty?(first-seq) => as(, second-seq); empty?(second-seq) => as(, first-seq); otherwise => let d = make(); for (val in first-seq) push-last(d, val) end; for (val in second-seq) push-last(d, val) end; d end end; define sealed domain make (singleton()); define sealed domain element-type (); define sealed method as (class == , v :: ) => (l :: ) let rep = v.representation; for (result = #() then pair(island-deque-element(rep, index), result), index :: from rep.last-index to rep.first-index by -1) finally result end end; /* ambiguity resolvers */ define copy-down-method map-as-one (type == , function :: , collection :: ) => (new-collection :: ); // actually :: type define copy-down-method map-as-one (type == , function :: , collection :: ) => (new-collection :: ); // actually :: type define copy-down-method map-as-one (type == , function :: , collection :: ) => (new-collection :: ); define copy-down-method map-as-one (type == , function :: , collection :: ) => (new-collection :: ); /* define method map-as-one (type == , function :: , collection :: ) => new-collection :: ; // actually :: type let acc = make(); for (e keyed-by k in collection) acc[k] := function(e) end for; convert-accumulator-as(type, acc) end method map-as-one; define method map-as-one (type == , function :: , collection :: ) => new-collection :: ; let acc = make(); for (e keyed-by k in collection) acc[k] := function(e) end for; convert-accumulator-as(type, acc) end method map-as-one; */ define inline method map-as-one (type == , function :: , collection :: ) => new-collection :: ; let result = make(); for (e in collection) push-last(result, function(e)) end for; result end method map-as-one; // markt, not quite a copy-down, because of == specializer above define inline method map-as-one (type == , function :: , collection :: ) => new-collection :: ; let result = make(); for (e in collection) push-last(result, function(e)) end for; result end method map-as-one; // eof