Module: internal Author: Paul Haahr, Jonathan Bachrach, Scott McKay 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 /// classes define abstract primary class () slot range-from :: , required-init-keyword: from:; slot range-by :: , required-init-keyword: by:; end class ; define sealed class () end class ; define sealed class () sealed slot size :: type-union(, singleton(#f)), required-init-keyword: size:; end class ; define sealed class () sealed slot size :: , required-init-keyword: size:; end class ; define sealed class () end class ; define class () end; /// initialization define constant $empty-range-password :: = pair("empty-range", #()); define constant $empty-range :: = make(, from: 0, by: 0, password: $empty-range-password); define method make (class == , #key password, #all-keys) => (result :: ) if (password == $empty-range-password) next-method() else $empty-range end if; end method make; define method make (class == , #key from = 0, by = 1, to, below, above, size, #all-keys) => (result :: ) // constant ranges (by: 0) if (zero?(by)) if ((~above | (from > above)) & (~below | (from < below))) make(, from: from, by: 0, size: size) else $empty-range end if; else // convert above: or below: to to: if (by > 0) if (below & (~to | to < (below - by))) to := below - by end if; else if (above & (~to | to > (above - by))) to := above - by end if; end if; // infinite ranges if (~to & ~size) make(, from: from, by: by) else if (size) if (to) let new-to = from + by * (size + 1); if (new-to <= to) to := new-to else size := floor/(to + by - from, by); end if; else to := from + by * (size + 1); end if; else size := floor/(to + by - from, by); end if; if (size = 0) $empty-range else make(, from: from, by: by, size: size) end if; end if; end if; end method make; define constant range = method (#rest keys, #key from, by, to, below, above, size) => (range :: ) apply(make, , keys) end method; /// collection and sequence operations define sealed inline method type-for-copy (range :: ) => (result == ) end method type-for-copy; define method shallow-copy (range :: ) => (list :: ) for (e in range using backward-iteration-protocol, list = #() then pair(e, list)) finally list end end method shallow-copy; define method empty? (range :: ) => (result == #f) #f end method empty?; define sealed method empty? (range :: ) => (result == #t) #t end method empty?; define sealed method size (range :: ) => (result == 0) 0 end method size; define sealed method size (range :: ) => (result == #f) #f end method size; define sealed method element (range :: , key :: , #key default = unsupplied()) => (object) if (unsupplied?(default)) element-range-error(range, key) else default end if end method element; define sealed method element (range :: , key :: , #key default = unsupplied()) => (object) if (~range.size | key < range.size) range.range-from else if (unsupplied?(default)) element-range-error(range, key) else default end if end if; end method element; define sealed method element (range :: , key :: , #key default) => (object) range.range-from + key * range.range-by end method element; define sealed method element (range :: , key :: , #key default = unsupplied()) => (object) if (key >= 0 & key < range.size) range.range-from + key * range.range-by else if (unsupplied?(default)) element-range-error(range, key) else default end if end if; end method element; define sealed method last (range :: , #key default) => (object) error(make(, format-string: "Cannot apply 'last' to an unbounded range")) end method last; define sealed method last (range :: , #key default) => (object) range.range-from end method last; define sealed method last (range :: , #key default) => (object) range.range-from + range.range-by * (range.size - 1) end method last; define sealed method find-key-for-element (value, range :: ) #f end method find-key-for-element; define sealed method find-key-for-element (value, range :: ) if (value = range.range-from) 0 else #f end if end method find-key-for-element; define sealed method find-key-for-element (value, range :: ) let (key, rem) = truncate/(value - range.range-from, range.range-by); if (rem = 0 & 0 <= key) key else #f end if; end method find-key-for-element; define sealed method find-key-for-element (value, range :: ) let (key, rem) = truncate/(value - range.range-from, range.range-by); if (rem = 0 & 0 <= key & key < range.size) key else #f end if; end method find-key-for-element; define method as (class == , range :: ) => (result :: ) range end method as; define method \= (range-1 :: , range-2 :: ) => (result == #f) #f end method; define sealed method \= (range-1 :: , range-2 :: ) => (result == #t) #t end method; define sealed method \= (range-1 :: , range-2 :: ) => (result :: ) range-1.range-from = range-2.range-from & range-1.size = range-2.size end method; define sealed method \= (range-1 :: , range-2 :: ) => (result :: ) range-1.range-from = range-2.range-from & range-1.range-by = range-2.range-by end method; define sealed method \= (range-1 :: , range-2 :: ) => (result :: ) range-1.range-from = range-2.range-from & range-1.range-by = range-2.range-by & range-1.size = range-2.size end method; define method member? (value :: , range :: , #key test = \==) => (result :: ) if (test == \==) find-key-for-element(value, range) & #t else next-method() end if end method member?; define class () end; define method add! (range :: , elt) => (result :: ) error(make(, value: elt, type: )) end method add!; define method add (range :: , elt :: ) => (result :: ) add!(copy-sequence(range), elt) end method add; define sealed method add! (range :: , elt :: ) => (result :: ) make(, from: elt, size: 1) end method add!; define sealed method add! (range :: , elt :: ) => (result :: ) let prev = range.range-from - range.range-by; unless (elt = prev) error(make(, format-string: "You can't add %= to the infinite range %=", format-arguments: list(elt, range))) end unless; range.range-from := prev; range end method add!; define sealed method add! (range :: , elt :: ) => (result :: ) case (elt = range.range-from) => if (range.size) range.size := range.size + 1 end if; range; (range.size = 1) => make(, from: range.range-from, by: elt - range.range-from, size: 2); otherwise => add!(shallow-copy(range), elt); end case; end method add!; define sealed method add! (range :: , elt :: ) => (result :: ) case (elt = range.last + range.range-by) => range.size := range.size + 1; range; (elt = range.range-from - range.range-by) => range.size := range.size + 1; range.range-from := range.range-from - range.range-by; range; (range.size = 1) => if (elt = range.range-from) make(, from: elt, by: 0, size: 2); else range.size := range.size + 1; range.range-by := elt - range.range-from; range; end if; otherwise => add!(shallow-copy(range), elt); end case; end method add!; define method remove! (range :: , elt, #key test, count) => (result :: ) error(make(, value: elt, type: )) end method remove!; define method remove (range :: , elt :: , #key test, count) => (result :: ) remove!(copy-sequence(range), elt, test: test, count: count) end method remove; define sealed method remove! (range :: , elt :: , #key test, count) => (result :: ) range end method remove!; define sealed method remove! (range :: , elt :: , #key test, count) => (result :: ) //--- What about 'test'? unless (elt = range.range-from) error(make(, format-string: "You can't remove %= from the infinite range %=", format-arguments: list(elt, range))) end unless; if (~count | count > 0) let next = range.range-from + range.range-by; range.range-from := next; end if; range end method remove!; define sealed method remove! (range :: , elt :: , #key test, count) => (result :: ) //--- What about 'test'? if (~count | count > 0) case (elt = range.range-from) => if (range.size) range.size := range.size - 1 end if; range; (range.size = 1) => $empty-range; otherwise => if (member?(elt, range)) remove!(shallow-copy(range), elt, test: test, count: count) else range end if; end case; else range end if; end method remove!; define sealed method remove! (range :: , elt :: , #key test, count) => (result :: ) //--- What about 'test'? if (~count | count > 0) case (elt = range.last) => range.size := range.size - 1; range; (elt = range.range-from) => range.size := range.size - 1; range.range-from := range.range-from + range.range-by; range; (range.size = 1 & elt = range.range-from) => $empty-range; otherwise => if (count & count > 0 & member?(elt, range)) remove!(shallow-copy(range), elt, test: test, count: count) else range end if; end case; else range end if; end method remove!; define sealed method copy-sequence (range :: , #key start, end: endp) => (result :: ) $empty-range end method copy-sequence; define method copy-sequence (range :: , #key start = 0, end: endp = range.size) => (result :: ) let from = range[start]; let by = range.range-by; if (endp) let new-end = if (range.size & endp > range.size) range.size else endp end; make(, from: from, by: by, size: new-end - start) else make(, from: from, by: by) end if; end method copy-sequence; define method id?-intersection (r1 :: , r2 :: ) $empty-range end method id?-intersection; define method id?-intersection (r1 :: , r2 :: ) $empty-range end method id?-intersection; define method id?-intersection (r1 :: , r2 :: ) $empty-range end method id?-intersection; define method id?-intersection (r1 :: , r2 :: ) if (r1.range-from == r2.range-from) if (if (r1.size & r2.size) r1.size < r2.size else r1.size end) r1 else r2 end if; else $empty-range end if; end method id?-intersection; define constant id?-intersection-with-constant = method (value :: , range :: ) if (member?(value, range)) make(, from: value, size: 1) else $empty-range end if end method; define method id?-intersection (r1 :: , r2 :: ) id?-intersection-with-constant(r1.range-from, r2) end method id?-intersection; define method id?-intersection (r1 :: , r2 :: ) id?-intersection-with-constant(r1.range-from, r2) end method id?-intersection; define method id?-intersection (r1 :: , r2 :: ) id?-intersection-with-constant(r2.range-from, r1) end method id?-intersection; define method id?-intersection (r1 :: , r2 :: ) id?-intersection-with-constant(r2.range-from, r1) end method id?-intersection; define constant same-sign? // assumes x ~= 0 & y ~= 0 = method (x, y) (if (positive?(x)) positive? else negative? end)(y) end method; define constant first-intersection = method (from1, by1, from2, by2) if (by1 < 0) let neg = first-intersection(-from1, -by1, -from2, -by2); if (neg) -neg else #f end if; elseif (from1 < from2) first-intersection(from2, by2, from1, by1) else // assert(from1 >= from2 & by1 > 0 & by2 > 0) block (return) for (i from 0 below by2, n from from1 by by1) if (remainder(n - from2, by2) = 0) return(n) end if; finally #f end for end block end if end method; define constant ordered-finite-intersection // assumes by1 > 0 & by2 > 0 = method (lo1, by1, hi1, lo2, by2, hi2) if (hi1 < lo2 | hi2 < lo1) $empty-range else let from = first-intersection(lo1, by1, lo2, by2); if (from & from >= lo1 & from >= lo2) let to = first-intersection(hi1, -by1, hi2, -by2); if (to & to <= hi1 & to <= hi2) make(, from: from, to: to, by: lcm(by1, by2)) else $empty-range end if else $empty-range end if end if end method; define constant finite-intersection = method (from1, by1, to1, from2, by2, to2) if (by1.negative?) if (by2.negative?) ordered-finite-intersection(to1, -by1, from1, to2, -by2, from2) else ordered-finite-intersection(to1, -by1, from1, from2, by2, to2) end if else if (by2.negative?) ordered-finite-intersection(from1, by1, to1, to2, -by2, from2) else ordered-finite-intersection(from1, by1, to1, from2, by2, to2) end if end if end method; define constant last-of-in = method (of :: , in :: ) // |in| is either a finite range or an infinite range growing in // the opposite direction from |of| let bound = if (same-sign?(in.range-by, of.range-by)) in.last else in.range-from end if; let n = truncate/(bound - of.range-from, of.range-by); n * of.range-by + of.range-from end method; define method id?-intersection (r1 :: , r2 :: ) finite-intersection(r1.range-from, r1.range-by, r1.last, r2.range-from, r2.range-by, r2.last) end method id?-intersection; define method id?-intersection (r1 :: , r2 :: ) finite-intersection(r1.range-from, r1.range-by, r1.last, r2.range-from, r2.range-by, last-of-in(r2, r1)) end method id?-intersection; define method id?-intersection (r1 :: , r2 :: ) finite-intersection(r1.range-from, r1.range-by, last-of-in(r1, r2), r2.range-from, r2.range-by, r2.last) end method id?-intersection; define method id?-intersection (r1 :: , r2 :: ) let by1 = r1.range-by; let by2 = r2.range-by; let from1 = r1.range-from; let from2 = r2.range-from; if (same-sign?(by1, by2)) let from = first-intersection(from1, by1, from2, by2); if (from) make(, from: from, by: lcm(by1, by2)) else $empty-range end if else finite-intersection(from1, by1, last-of-in(r1, r2), from2, by2, last-of-in(r2, r1)) end if end method id?-intersection; define method intersection (range-1 :: , range-2 :: , #key test = \==) => (result :: ) if (test == \==) id?-intersection(range-1, range-2) else next-method() end if; end method intersection; define method reverse (range :: ) => (result :: ) reverse!(copy-sequence(range)) end method reverse; define sealed method reverse! (range :: ) => (result :: ) $empty-range end method reverse!; define sealed method reverse! (range :: ) => (result :: ) error(make(, format-string: "Cannot reverse! an infinite range")) end method reverse!; define sealed method reverse! (range :: ) => (result :: ) unless (range.size) error(make(, format-string: "Cannot reverse! an infinite range")) end unless; range end method reverse!; define sealed method reverse! (range :: ) => (result :: ) range.range-from := range.last; range.range-by := -range.range-by; range end method reverse!; //// ITERATION PROTOCOL define constant range-next-state = method (range :: , state :: ) => (result :: ) state + range.range-by end method; define constant range-previous-state = method (range :: , state :: ) => (result :: ) state - range.range-by end method; define constant empty-range-finished-state? = method (range :: , state, limit) => (result :: ); #t end method; define constant infinite-range-finished-state? = method (range :: , state, limit) => (result :: ); #f end method; define constant increasing-range-finished-state? = method (range :: , state, limit) => (result :: ); state > limit end method; define constant decreasing-range-finished-state? = method (range :: , state, limit) => (result :: ); state < limit end method; define constant range-current-key = method (range :: , state :: ) floor/(state - range.range-from, range.range-by) end method; define constant range-current-element = method (range :: , state :: ) state end method; define constant range-current-element-setter = method (new-value, range :: , state) => (will-never-return :: ) error(make(, format-string: "range %= is immutable", format-arguments: list(range))) end method; define constant constant-range-current-element = method (range :: , state :: ) range.range-from end method; define constant range-error = method (#rest ignored) => (will-never-return :: ) error("RANGE iteration protocol -- illegal operation") end method; define method forward-iteration-protocol (range :: ) => (initial-state, limit, next-state :: , finished-state? :: , current-key :: , current-element :: , current-element-setter :: , copy-state :: ) values(#f, #f, range-error, empty-range-finished-state?, range-error, range-error, range-current-element-setter, identity-copy-state) end method forward-iteration-protocol; define method backward-iteration-protocol (range :: ) => (final-state, limit, next-state :: , finished-state? :: , current-key :: , current-element :: , current-element-setter :: , copy-state :: ) forward-iteration-protocol(range) end method backward-iteration-protocol; define method forward-iteration-protocol (range :: ) => (final-state, limit, next-state :: , finished-state? :: , current-key :: , current-element :: , current-element-setter :: , copy-state :: ) values(range.range-from, #f, range-next-state, infinite-range-finished-state?, range-current-key, range-current-element, range-current-element-setter, identity-copy-state) end method forward-iteration-protocol; define method backward-iteration-protocol (range :: ) => (final-state, limit, next-state :: , finished-state? :: , current-key :: , current-element :: , current-element-setter :: , copy-state :: ) error(make(, format-string: "Cannot iterate backwards over an infinite range")) end method backward-iteration-protocol; define method forward-iteration-protocol (range :: ) => (initial-state, limit, next-state :: , finished-state? :: , current-key :: , current-element :: , current-element-setter :: , copy-state :: ) values(range.range-from, range.last, range-next-state, if (range.range-by.positive?) increasing-range-finished-state? else decreasing-range-finished-state? end if, range-current-key, range-current-element, range-current-element-setter, identity-copy-state) end method forward-iteration-protocol; define method backward-iteration-protocol (range :: ) => (final-state, limit, next-state :: , finished-state? :: , current-key :: , current-element :: , current-element-setter :: , copy-state :: ) values(range.last, range.range-from, range-previous-state, if (range.range-by.positive?) decreasing-range-finished-state? else increasing-range-finished-state? end if, range-current-key, range-current-element, range-current-element-setter, identity-copy-state) end method backward-iteration-protocol; define method forward-iteration-protocol (range :: ) => (initial-state, limit, next-state :: , finished-state? :: , current-key :: , current-element :: , current-element-setter :: , copy-state :: ) values(0, range.size, sequence-next-state, if (range.size) sequence-finished-state? else infinite-range-finished-state? end if, sequence-current-key, constant-range-current-element, range-current-element-setter, identity-copy-state) end method forward-iteration-protocol; define method backward-iteration-protocol (range :: ) => (final-state, limit, next-state :: , finished-state? :: , current-key :: , current-element :: , current-element-setter :: , copy-state :: ) unless (range.size) error(make(, format-string: "Cannot iterate backwards over an infinite range")) end unless; values(range.size - 1, -1, sequence-previous-state, sequence-finished-state?, sequence-current-key, constant-range-current-element, range-current-element-setter, identity-copy-state) end method backward-iteration-protocol; // NOT YET IMPLEMENTED define method limited (class == , #key of, #all-keys) => (type :: ) class end method; // Finally, if we have an infinite range as source then we had better // give up. define method map-as-one (type :: , function :: , collection :: ) => new-collection :: ; // actually :: type // TODO: make a proper error class error(make(, format-string: "Cannot map over an infinite range")) end method map-as-one; define inline copy-down-method map-as-one (type == , function :: , collection :: ) => (new-collection :: ); // actually :: type /* define method map-as-one (type == , function :: , collection :: ) => new-collection :: ; // actually :: type // TODO: make a proper error class error(make(, format-string: "Cannot map over an infinite range")) end method map-as-one; define method map-as-one (type == , function :: , collection :: ) => new-collection :: ; // actually :: type // TODO: make a proper error class error(make(, format-string: "Cannot map over an infinite range")) end method map-as-one; define method map-as-one (type == , function :: , collection :: ) => new-collection :: ; // actually :: type // TODO: make a proper error class error(make(, format-string: "Cannot map over an infinite range")) end method map-as-one; */ // eof