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 // BOOTED: define ... class ... end; // BOOTED: define ... class ... end; // BOOTED: define ... class ... end; //////////// // INTERFACE //////////// // Functions on define inline function vector (#rest arguments) => (vector :: ) arguments end function; // this is just a marker for optimization, to say that the vector can be // constant-folded define not-inline function immutable-vector (#rest arguments) => (vector :: ) arguments end function; // this is just a marker for optimization, to say that the vector can be // constant-folded define not-upgrade not-inline function immutable-type-vector (#rest types) => (vector :: ) for (type in types) check-type(type, ) end for; types end function; // // LIMITED-VECTOR // define open generic limited-vector (of :: false-or(), size :: false-or()) => (type :: ); ///////////////// // IMPLEMENTATION ///////////////// // // Specialized inherited generic methods // // // MAKE // define sealed inline method make (class == , #key size = 0, fill) => (vector :: ) make(, size: size, fill: fill) end method make; // // AS // define open method as (class == , collection :: ) => (vector :: ) collection end method as; // // SHALLOW-COPY // define inline method shallow-copy (vector :: ) => (result :: ) vector.copy-sequence end method shallow-copy; // // TYPE-FOR-COPY // define inline method type-for-copy (vector :: ) => (type :: ) end method type-for-copy; // // EMPTY? // define inline method empty? (vector :: ) => (b :: ) vector.size = 0 end method empty?; // // EMPTY // define open generic empty (class :: ) => (res :: ); define inline method empty (class :: ) => (res :: ) empty() end method empty; // // DIMENSIONS // define inline method dimensions (vector :: ) => (l :: ) list(vector.size) end method dimensions; // // ADD // define method add (vector :: , object) => (v :: ) let new-vector :: = make(vector.type-for-copy, size: vector.size + 1, fill: object); without-bounds-checks for (i :: from 0 below vector.size) new-vector[i] := vector[i] end; new-vector[vector.size] := object; end without-bounds-checks; new-vector end method add; // // REVERSE! // define method reverse! (vector :: ) => (v :: ) let stopping-index = floor/(vector.size, 2); without-bounds-checks for (index :: from 0 below stopping-index, size-index :: from vector.size - 1 by -1) let tmp = vector[index]; vector[index] := vector[size-index]; vector[size-index] := tmp; end for end without-bounds-checks; vector end method reverse!; // // REVERSE // define method reverse (vector :: ) => (v :: ) let size = size(vector); if (size = 0) make(vector.type-for-copy, size: 0) else let new-vector :: = make(vector.type-for-copy, size: size, fill: vector[0]); without-bounds-checks for (from :: from 0, to from size - 1 to 0 by -1) new-vector[to] := vector[from] end end without-bounds-checks; new-vector end if end method reverse; // // ROW-MAJOR-INDEX // define method row-major-index (vector :: , #rest indices) => (i :: ) unless (indices.size = 1) error(make(, format-string: "Number of subscripts %= not equal to " "rank of array %=", format-arguments: list(indices, vector))) end unless; indices.first end method row-major-index; // // REPLACE-ELEMENTS! // define method replace-elements!(vector :: , predicate :: , new_value_fn :: , #key count: count = #f) => vec :: ; let count :: = count | vector.size; without-bounds-checks for (key :: from 0 below vector.size, until: count = 0) let this_element = vector[key]; if (predicate(this_element)) vector[key] := new_value_fn(this_element); count := count - 1; end if; end for end without-bounds-checks; vector; end method replace-elements!; // // AREF // define method aref (vector :: , #rest indices) => elt :: ; if (indices.size == 1) vector[indices[0]]; else error(make(, format-string: "Invalid number of indices for %=. " "Expected 1, got %d", format-arguments: list(vector, indices.size))) end; end; // // AREF-SETTER // define method aref-setter (new, vector :: , #rest indices) => new :: ; if (indices.size == 1) vector[indices[0]] := new; else error(make(, format-string: "Invalid number of indices for %=. " "Expected 1, got %d", format-arguments: list(vector, indices.size))) end; end; // // COPY-SEQUENCE // define sealed method copy-sequence (source :: , #key start: first :: = 0, end: last = unsupplied()) => (result-sequence :: ); let last :: = check-start-compute-end(source, first, last); let sz = last - first; if (sz <= 0) make(type-for-copy(source), size: 0) else let fill = source[0]; let result :: = make(type-for-copy(source), size: sz, fill: fill); without-bounds-checks for (j :: from 0 below sz, i :: from first) result[j] := source[i]; end for; end without-bounds-checks; result end if end method; // // SUBSEQUENCE-POSITION // define method subsequence-position (big :: , pat :: , #key test :: = \==, count :: = 1) => (index :: false-or()); let sz = size(big); let pat-sz = size(pat); without-bounds-checks select (pat-sz) 0 => count - 1; 1 => let ch = pat[0]; for (key :: from 0 below sz, until: test(big[key], ch) & (count := count - 1) <= 0) finally if (key < sz) key end if; end for; 2 => let ch1 = pat[0]; let ch2 = pat[1]; for (key :: from 0 below sz - 1, until: test(big[key], ch1) & test(big[key + 1], ch2) & (count := count - 1) <= 0) finally if (key < (sz - 1)) key end if; end for; otherwise => local method search(index, big-key, pat-key, count) case pat-key >= pat-sz => if (count = 1) index else search(index + 1, index + 1, 0, count - 1); end if; big-key = sz => #f; test(big[big-key], pat[pat-key]) => search(index, big-key + 1, pat-key + 1, count); otherwise => search(index + 1, index + 1, 0, count); end case; end method search; search(0, 0, 0, count); end select; end without-bounds-checks end method subsequence-position; // // SORT // define method sort (sequence :: , #key test = \<, stable: stable) => new-seq :: ; sort!(copy-sequence(sequence), test: test, stable: stable); end method sort; // // MEMBER // define method member? (value, collection :: , #key test = \==) => (boolean :: ) (without-bounds-checks let n :: = collection.size; if (test == \== & ~(value-object?(value))) iterate grovel (index :: = 0) if (index = n) #f elseif (pointer-id?(collection[index], value)) #t else grovel(index + 1) end end iterate else iterate grovel (index :: = 0) unless (index = collection.size) (test(value, element(collection, index)) & #t) | grovel(index + 1) end unless end iterate end if end without-bounds-checks); end method member?; // // ADD-NEW // define method add-new (vector :: , new-element, #key test :: = \==) => (new-vector :: ); if (any? (method (el) test(el, new-element) end, vector)) vector else add(vector, new-element) end if end method add-new; // // ADD-NEW! // define method add-new! (vector :: , new-element, #key test :: = \==) => (new-vector :: ); if (any? (method (el) test(el, new-element) end, vector)) vector else add!(vector, new-element) end if end method add-new!; // // AS // define constant = type-union(subclass(), ); define method as (class :: , collection :: ) => (vector :: ) if (collection.object-class == class) collection else let new-size = collection.size; without-bounds-checks if (new-size = 0) make(class, size: new-size) else let new-vector = with-fip-of collection let fill = current-element(collection, initial-state); make(class, size: new-size, fill: fill); end with-fip-of; for (index :: from 0 below new-size, item in collection) element(new-vector, index) := item; end for; new-vector end if end without-bounds-checks; end if end method as; // // CONCATENATE-AS // define method concatenate-as (type :: , vector :: , #rest more-vectors) => (result :: ) block (return) let total-sz :: = vector.size; let num-non-empty :: = if (total-sz = 0) 0 else 1 end; let fill = unsupplied(); for (v in more-vectors) unless (instance?(v, type)) return(next-method()) end unless; let sz :: = v.size; unless (sz = 0) total-sz := total-sz + sz; num-non-empty := num-non-empty + 1; when (unsupplied?(fill)) fill := v[0]; end when; end unless; end for; without-bounds-checks select (num-non-empty) 0 => make(type); 1 => if (vector.size > 0) as(type, vector) else for (i :: from 0 below more-vectors.size, while: more-vectors[i].size = 0) finally as(type, more-vectors[i]) end for end; otherwise => let result = make(type, size: total-sz, fill: fill); for (i :: from 0 below size(vector)) result[i] := vector[i]; finally let result-index :: = i; for (v :: in more-vectors) for (i :: from 0 below size(v), j :: from result-index) result[j] := v[i]; end for; result-index := result-index + size(v); end for; end for; result; end select; end without-bounds-checks; end block end method concatenate-as; // // REDUCE1 // define inline method reduce1 (fn :: , collection :: ) => (object) if (empty?(collection)) // Is there a more informative error class that's appropriate here? error(make(, format-string: "Reduce1 undefined for empty collections")) else without-bounds-checks for (index :: from 1 below collection.size, result = collection[0] then fn(result, collection[index])) finally result end for end without-bounds-checks end end method reduce1; // // REPLACE-SUBSEQUENCE! // define method replace-subsequence! (target :: , insert :: , #key start :: = 0, end: last = unsupplied()) => (result-sequence :: ); let target-size :: = target.size; let insert-size :: = insert.size; let last :: = check-start-compute-end(target, start, last); let delete-size :: = last - start; without-bounds-checks if (delete-size = insert-size) for (index :: from start below last, e in insert) target[index] := e end for; target else let new-size :: = target-size - delete-size + insert-size; let new-target = make(target.type-for-copy, size: new-size); let new-end :: = start + insert-size; for (index :: from 0 below start) new-target[index] := target[index] end; for (index :: from start below new-end, e in insert) new-target[index] := e end; for (from :: from last below target-size, to from new-end below new-size) new-target[to] := target[from] end; new-target end if; end without-bounds-checks end method; /// NEED /// CONCATENATE-AS /// FILL! // // // // // MAKE // define sealed inline method make (class == , #key size = 0, fill) => (vector :: ) make(, size: size, fill: fill) end method make; // // TYPE-FOR-COPY // define inline method type-for-copy (vector :: ) => (type :: ) object-class(vector) end method type-for-copy; /// /// LIMITED VECTOR /// define macro limited-vector-shared-definer { define limited-vector-shared "<" ## ?:name ## ">" } => { define inline sealed method element-no-bounds-check (vector :: "", index :: , #key default) => (object :: "<" ## ?name ## ">") ?name ## "-vector-element"(vector, index) end method element-no-bounds-check; define inline sealed method element-no-bounds-check-setter (new-value :: "<" ## ?name ## ">", vector :: "", index :: ) => (object) ?name ## "-vector-element"(vector, index) := new-value; new-value end method element-no-bounds-check-setter; define inline function ?name ## "-vector-current-element" (vector :: "", state :: ) => (res :: "<" ## ?name ## ">") ?name ## "-vector-element"(vector, state) end function; define inline function ?name ## "-vector-current-element-setter" (new-value :: "<" ## ?name ## ">", vector :: "", state :: ) ?name ## "-vector-element"(vector, state) := new-value end function; define sealed inline method forward-iteration-protocol (sequence :: "") => (initial-state :: , limit :: , next-state :: , finished-state? :: , current-key :: , current-element :: , current-element-setter :: , copy-state :: ) values(0, sequence.size, sequence-next-state, sequence-finished-state?, sequence-current-key, ?name ## "-vector-current-element", ?name ## "-vector-current-element-setter", identity-copy-state) end method forward-iteration-protocol; define sealed inline method backward-iteration-protocol (sequence :: "") => (final-state :: , limit :: , previous-state :: , finished-state? :: , current-key :: , current-element :: , current-element-setter :: , copy-state :: ) values(sequence.size - 1, -1, sequence-previous-state, sequence-finished-state?, sequence-current-key, ?name ## "-vector-current-element", ?name ## "-vector-current-element-setter", identity-copy-state) end method backward-iteration-protocol; /// SEALED DOMAINS define sealed domain make (singleton("")); define sealed domain initialize (""); define sealed domain type-for-copy (""); define sealed domain shallow-copy (""); define sealed domain size (""); define sealed domain element-type (""); define sealed domain empty? (""); define sealed domain add ("", ); define sealed domain add! ("", ); define sealed domain add-new ("", ); define sealed domain add-new! ("", ); define sealed domain member? (, ""); define sealed domain fill! (""); define sealed domain remove ("", ); define sealed domain remove! ("", ); define sealed domain sort (""); define sealed domain sort! (""); define sealed domain copy-sequence (""); define sealed domain reduce (, , ""); define sealed domain reduce1 (, ""); define sealed domain choose (, ""); define sealed domain replace-subsequence! ("", ""); define sealed domain subsequence-position ("", ""); define sealed domain as (singleton(""), ); define sealed domain concatenate-as (singleton(""), ""); } end macro; define macro limited-vector-element-setter-definer { define limited-vector-element-setter "<" ## ?:name ## ">" } => { define inline sealed method element-setter (new-value :: "<" ## ?name ## ">", vector :: "", index :: ) => (object :: "<" ## ?name ## ">") if (element-range-check(index, size(vector))) element-no-bounds-check(vector, index) := new-value else element-range-error(vector, index) end if end method element-setter; } end macro; define macro limited-vector-shared+element-setter-definer { define limited-vector-shared+element-setter "<" ## ?:name ## ">" } => { define limited-vector-shared "<" ## ?name ## ">"; define limited-vector-element-setter "<" ## ?name ## ">"; } end macro; define macro limited-vector-minus-constructor-definer { define limited-vector-minus-constructor "<" ## ?:name ## ">" (?superclasses:*) (#key ?fill:expression) } => { define limited-vector-shared "<" ## ?name ## ">"; define sealed concrete primary class "" (?superclasses) repeated sealed inline slot ?name ## "-vector-element" :: "<" ## ?name ## ">", init-value: ?fill, init-keyword: fill:, size-getter: size, size-init-keyword: size:, size-init-value: 0; end class; define inline sealed method element (vector :: "", index :: , #key default = unsupplied()) => (object :: "<" ## ?name ## ">") if (element-range-check(index, size(vector))) element-no-bounds-check(vector, index) else if (unsupplied?(default)) element-range-error(vector, index) else check-type(default, element-type(vector)); default end if end if end method element; } end macro; define macro limited-vector-minus-selector-definer { define limited-vector-minus-selector "<" ## ?:name ## ">" (?superclasses:*) (#key ?fill:expression) } => { define limited-vector-minus-constructor "<" ## ?name ## ">" (?superclasses) (fill: ?fill); define limited-vector-element-setter "<" ## ?name ## ">"; define constant "$empty-" = system-allocate-repeated-instance ("", "<" ## ?name ## ">", unbound(), 0, ?fill); define sealed inline method empty (class == "") => (res :: "") "$empty-" end method empty; define sealed inline method element-type (t :: "") => (type :: ) "<" ## ?name ## ">" end method; define method make (class == "", #key fill :: "<" ## ?name ## ">" = ?fill, size :: = 0) => (vector :: "") if (size = 0) empty(class) else system-allocate-repeated-instance ("", "<" ## ?name ## ">", unbound(), size, fill); end if end method; } end macro; define macro limited-vector-definer { define limited-vector "<" ## ?:name ## ">" (#key ?fill:expression) } => { define limited-vector-minus-selector "<" ## ?name ## ">" () (fill: ?fill); define sealed inline method concrete-limited-vector-class (of == "<" ## ?name ## ">") => (type :: singleton("")) "" end method; } end macro; define limited-vector-shared+element-setter ; define constant object-vector-element = vector-element; define constant object-vector-element-setter = vector-element-setter; define inline method concrete-limited-vector-class (of :: ) => (res :: ) end method; define method limited-vector (of :: , size :: false-or()) => (type :: ) let concrete-class = concrete-limited-vector-class(of); let default-concrete-class = ; if (size | concrete-class == default-concrete-class) make(, class: , element-type: of, concrete-class: concrete-class, size: size) else concrete-class end if; end method; // // // // // MAKE // // COULD BE A COPY-DOWN define sealed method make (class == , #key fill = #f, size :: = 0) => (vector :: ) if (size = 0) #[] // canonicalize empty vector else system-allocate-repeated-object-instance (, unbound(), size, fill); end if end method; // // LIMITED-VECTOR // define method limited-vector (of == , size :: false-or()) => (res :: ) end method; // // ELEMENT // define /* inline */ sealed method element (vector :: , index :: , #key default = unsupplied()) => (object) if (element-range-check(index, size(vector))) vector-element(vector, index) else if (unsupplied?(default)) element-range-error(vector, index) else default end if end if end method element; // // EMPTY // define inline method empty (class == ) => (res :: ) #[] end method empty; // // AS // define inline sealed method as (class == , collection :: ) => (vector :: ) collection end method as; // // FILL! // define method fill! (target :: , value, #key start :: = 0, end: last = unsupplied()) => (target :: ) let last :: = check-start-compute-end(target, start, last); primitive-fill! (target, primitive-repeated-slot-offset(target), integer-as-raw(start), integer-as-raw(last - start), value); target end; // // CONCATENATE-AS // define sealed method concatenate-as (class == , vector :: , #rest more-vectors) => (result :: ) block (return) let total-sz :: = vector.size; let num-non-empty :: = if (total-sz = 0) 0 else 1 end; for (v in more-vectors) if (~instance?(v, )) return(next-method()) end; let sz :: = v.size; if (sz ~= 0) total-sz := total-sz + sz; num-non-empty := num-non-empty + 1; end; end for; select (num-non-empty) 0 => #[]; 1 => if (vector.size > 0) vector else for (i :: from 0 below more-vectors.size, while: more-vectors[i].size = 0) finally more-vectors[i] end end; otherwise => let result = make(, size: total-sz); let sz :: = integer-as-raw(vector.size); primitive-replace! (result, primitive-repeated-slot-offset(result), integer-as-raw(0), vector, primitive-repeated-slot-offset(vector), integer-as-raw(0), sz); let result-index :: = sz; for (v :: in more-vectors) let vsz :: = integer-as-raw(v.size); primitive-replace! (result, primitive-repeated-slot-offset(result), result-index, v, primitive-repeated-slot-offset(v), integer-as-raw(0), vsz); result-index := primitive-machine-word-add(result-index, vsz); end; result end select; end block end method concatenate-as; // // COPY-SEQUENCE // define sealed method copy-sequence (source :: , #key start: first :: = 0, end: last = unsupplied()) => (result-sequence :: ); let last :: = check-start-compute-end(source, first, last); let sz = last - first; let result :: = make(, size: sz); primitive-replace! (result, primitive-repeated-slot-offset(result), integer-as-raw(0), source, primitive-repeated-slot-offset(source), integer-as-raw(first), integer-as-raw(sz)); result end method; // eof