import Type
import FiniteLinearAggregate
)abbrev category A1AGG OneDimensionalArrayAggregate
++ Author: Michael Monagan; revised by Manuel Bronstein and Richard Jenks
++ Date Created: August 87 through August 88
++ Date Last Updated: April 1991
++ Basic Operations:
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ References:
++ Description:
++ One-dimensional-array aggregates serves as models for one-dimensional arrays.
++ Categorically, these aggregates are finite linear aggregates
++ with the shallowly mutable property, that is, any component of
++ the array may be changed without affecting the
++ identity of the overall array.
++ Array data structures are typically represented by a fixed area in storage and
++ therefore cannot efficiently grow or shrink on demand as can list structures
++ (see however \spadtype{FlexibleArray} for a data structure which
++ is a cross between a list and an array).
++ Iteration over, and access to, elements of arrays is extremely fast
++ (and often can be optimized to open-code).
++ Insertion and deletion however is generally slow since an entirely new
++ data structure must be created for the result.
OneDimensionalArrayAggregate(S:Type): Category ==
Join(FiniteLinearAggregate S,ShallowlyMutableAggregate S)
add
members x == [qelt(x, i) for i in minIndex x .. maxIndex x]
sort!(f, a) == quickSort(f, a)$FiniteLinearAggregateSort(S, %)
any?(f, a) ==
for i in minIndex a .. maxIndex a repeat
f qelt(a, i) => return true
false
every?(f, a) ==
for i in minIndex a .. maxIndex a repeat
not(f qelt(a, i)) => return false
true
position(f:S -> Boolean, a:%) ==
for i in minIndex a .. maxIndex a repeat
f qelt(a, i) => return i
minIndex(a) - 1
find(f, a) ==
for i in minIndex a .. maxIndex a repeat
f qelt(a, i) => return qelt(a, i)
"failed"
count(f:S->Boolean, a:%) ==
n:NonNegativeInteger := 0
for i in minIndex a .. maxIndex a repeat
if f(qelt(a, i)) then n := n+1
n
map!(f, a) ==
for i in minIndex a .. maxIndex a repeat
qsetelt!(a, i, f qelt(a, i))
a
setelt(a:%, s:UniversalSegment(Integer), x:S) ==
l := lo s; h := if hasHi s then hi s else maxIndex a
l < minIndex a or h > maxIndex a => error "index out of range"
for k in l..h repeat qsetelt!(a, k, x)
x
reduce(f, a) ==
empty? a => error "cannot reduce an empty aggregate"
r := qelt(a, m := minIndex a)
for k in m+1 .. maxIndex a repeat r := f(r, qelt(a, k))
r
reduce(f, a, identity) ==
for k in minIndex a .. maxIndex a repeat
identity := f(identity, qelt(a, k))
identity
if S has BasicType then
reduce(f, a, identity,absorber) ==
for k in minIndex a .. maxIndex a while identity ~= absorber
repeat identity := f(identity, qelt(a, k))
identity
-- this is necessary since new has disappeared.
stupidnew: (NonNegativeInteger, %, %) -> %
stupidget: List % -> S
-- a and b are not both empty if n > 0
stupidnew(n, a, b) ==
zero? n => empty()
new(n, (empty? a => qelt(b, minIndex b); qelt(a, minIndex a)))
-- at least one element of l must be non-empty
stupidget l ==
for a in l repeat
not empty? a => return first a
error "Should not happen"
map(f, a, b) ==
m := max(minIndex a, minIndex b)
n := min(maxIndex a, maxIndex b)
l := max(0, n - m + 1)::NonNegativeInteger
c := stupidnew(l, a, b)
for i in minIndex(c).. for j in m..n repeat
qsetelt!(c, i, f(qelt(a, j), qelt(b, j)))
c
-- map(f, a, b, x) ==
-- m := min(minIndex a, minIndex b)
-- n := max(maxIndex a, maxIndex b)
-- l := (n - m + 1)::NonNegativeInteger
-- c := new l
-- for i in minIndex(c).. for j in m..n repeat
-- qsetelt!(c, i, f(a(j, x), b(j, x)))
-- c
merge(f, a, b) ==
r := stupidnew(#a + #b, a, b)
i := minIndex a
m := maxIndex a
j := minIndex b
n := maxIndex b
k := minIndex(r)
while i <= m and j <= n repeat
if f(qelt(a, i), qelt(b, j)) then
qsetelt!(r, k, qelt(a, i))
i := i+1
else
qsetelt!(r, k, qelt(b, j))
j := j+1
k := k + 1
while i <= m repeat
qsetelt!(r, k, elt(a, i))
k := k + 1
i := i + 1
while j <= n repeat
qsetelt!(r, k, elt(b, j))
k := k + 1
j := j + 1
r
elt(a:%, s:UniversalSegment(Integer)) ==
l := lo s
h := if hasHi s then hi s else maxIndex a
l < minIndex a or h > maxIndex a => error "index out of range"
r := stupidnew(max(0, h - l + 1)::NonNegativeInteger, a, a)
for k in minIndex r.. for i in l..h repeat
qsetelt!(r, k, qelt(a, i))
r
insert(a:%, b:%, i:Integer) ==
m := minIndex b
n := maxIndex b
i < m or i > n => error "index out of range"
y := stupidnew(#a + #b, a, b)
k := minIndex y
for j in m..i-1 repeat
qsetelt!(y, k, qelt(b, j))
k := k + 1
for j in minIndex a .. maxIndex a repeat
qsetelt!(y, k, qelt(a, j))
k := k + 1
for j in i..n repeat
qsetelt!(y, k, qelt(b, j))
k := k + 1
y
copy x ==
y := stupidnew(#x, x, x)
for i in minIndex x .. maxIndex x for j in minIndex y .. repeat
qsetelt!(y, j, qelt(x, i))
y
copyInto!(y, x, s) ==
s < minIndex y or s + #x > maxIndex y + 1 =>
error "index out of range"
for i in minIndex x .. maxIndex x for j in s.. repeat
qsetelt!(y, j, qelt(x, i))
y
construct l ==
-- a := new(#l)
empty? l => empty()
a := new(#l, first l)
for i in minIndex(a).. for x in l repeat qsetelt!(a, i, x)
a
delete(a:%, s:UniversalSegment(Integer)) ==
l := lo s; h := if hasHi s then hi s else maxIndex a
l < minIndex a or h > maxIndex a => error "index out of range"
h < l => copy a
r := stupidnew((#a - h + l - 1)::NonNegativeInteger, a, a)
k := minIndex(r)
for i in minIndex a..l-1 repeat
qsetelt!(r, k, qelt(a, i))
k := k + 1
for i in h+1 .. maxIndex a repeat
qsetelt!(r, k, qelt(a, i))
k := k + 1
r
delete(x:%, i:Integer) ==
i < minIndex x or i > maxIndex x => error "index out of range"
y := stupidnew((#x - 1)::NonNegativeInteger, x, x)
k := minIndex y
for j in minIndex x..i-1 repeat
qsetelt!(y, k, qelt(x, j))
k := k + 1
for j in i+1 .. maxIndex x repeat
qsetelt!(y, k, qelt(x, j))
k := k + 1
y
reverse! x ==
m := minIndex x
n := maxIndex x
for i in 0..((n-m) quo 2) repeat swap!(x, m+i, n-i)
x
concat l ==
empty? l => empty()
n := +/[#a for a in l]
i := minIndex(r := new(n, stupidget l))
for a in l repeat
copyInto!(r, a, i)
i := i + #a
r
sorted?(f, a) ==
for i in minIndex(a)..maxIndex(a)-1 repeat
not f(qelt(a, i), qelt(a, i + 1)) => return false
true
concat(x:%, y:%) ==
z := stupidnew(#x + #y, x, y)
copyInto!(z, x, i := minIndex z)
copyInto!(z, y, i + #x)
z
if S has CoercibleTo(OutputForm) then
coerce(r:%):OutputForm ==
bracket commaSeparate
[qelt(r, k)::OutputForm for k in minIndex r .. maxIndex r]
if S has BasicType then
x = y ==
#x ~= #y => false
for i in minIndex x .. maxIndex x repeat
not(qelt(x, i) = qelt(y, i)) => return false
true
position(x:S, t:%, s:Integer) ==
n := maxIndex t
s < minIndex t or s > n => error "index out of range"
for k in s..n repeat
qelt(t, k) = x => return k
minIndex(t) - 1
if S has OrderedSet then
a < b ==
for i in minIndex a .. maxIndex a
for j in minIndex b .. maxIndex b repeat
qelt(a, i) ~= qelt(b, j) => return a.i < b.j
#a < #b