Collection.st
author Claus Gittinger <cg@exept.de>
Tue, 22 Aug 2000 15:57:33 +0200
changeset 5557 f5f8d236027c
parent 5532 c1b11318aba3
child 5607 94c690ba0dea
permissions -rw-r--r--
category change

"
 COPYRIGHT (c) 1989 by Claus Gittinger
	      All Rights Reserved

 This software is furnished under a license and may be used
 only in accordance with the terms of that license and with the
 inclusion of the above copyright notice.   This software may not
 be provided or otherwise made available to, or used by, any
 other person.  No title to or ownership of the software is
 hereby transferred.
"

"{ Package: 'stx:libbasic' }"

Object subclass:#Collection
	instanceVariableNames:''
	classVariableNames:'InvalidKeySignal EmptyCollectionSignal ValueNotFoundSignal
		NotEnoughElementsSignal RecursiveCollectionStoreStringSignal'
	poolDictionaries:''
	category:'Collections-Abstract'
!

!Collection class methodsFor:'documentation'!

copyright
"
 COPYRIGHT (c) 1989 by Claus Gittinger
	      All Rights Reserved

 This software is furnished under a license and may be used
 only in accordance with the terms of that license and with the
 inclusion of the above copyright notice.   This software may not
 be provided or otherwise made available to, or used by, any
 other person.  No title to or ownership of the software is
 hereby transferred.
"
!

documentation
"
    Abstract superclass for all collections.
    This abstract class provides functionality common to all collections,
    without knowing how the concrete class implements things. Thus, all
    methods found here depend on some basic mechanisms to be defined in the
    concrete class. 
    These basic methods are usually defined as #subclassResponsibility here.
    Some methods are also redefined for better performance.

    Subclasses should at least implement:
        do:     - enumerate elements

    they should implement one of the following set of access messages:
    keyed collections:
        at:ifAbsent:            - fetching an element
        at:                     - fetching an element
        at:put:                 - storing an element

    unkeyed collections:
        add:                    - add an element
        remove:ifAbsent:        - remove an element


    [author:]
        Claus Gittinger
"
! !

!Collection class methodsFor:'initialization'!

initialize
    "setup the signal"

    InvalidKeySignal isNil ifTrue:[
        InvalidKeySignal := ErrorSignal newSignalMayProceed:true.
        InvalidKeySignal nameClass:self message:#invalidKeySignal.
        InvalidKeySignal notifierString:'invalid key:'.

        ValueNotFoundSignal := NotFoundSignal newSignalMayProceed:true.
        ValueNotFoundSignal nameClass:self message:#valueNotFoundSignal.
        ValueNotFoundSignal notifierString:'value not found:'.

        NotEnoughElementsSignal := NotFoundSignal newSignalMayProceed:true.
        NotEnoughElementsSignal nameClass:self message:#notEnoughElementsSignal.
        NotEnoughElementsSignal notifierString:'not enough elements in collection'.

        EmptyCollectionSignal := NotEnoughElementsSignal newSignalMayProceed:true.
        EmptyCollectionSignal nameClass:self message:#emptyCollectionSignal.
        EmptyCollectionSignal notifierString:'operation not allowed for empty collections'.
    ]

    "Modified: / 8.11.1997 / 19:18:17 / cg"
! !

!Collection class methodsFor:'instance creation'!

new:size withAll:element
    "return a new COllection of size, where all elements are
     initialized to element"

    |newCollection|

    newCollection := self new:size.
    size timesRepeat:[newCollection add:element]
!

with:anObject
    "return a new Collection with one element:anObject"

    |newCollection|

    newCollection := self new.
    newCollection add:anObject.
    ^ newCollection
!

with:firstObject with:secondObject
    "return a new Collection with two elements:firstObject and secondObject"

    |newCollection|

    newCollection := self new.
    newCollection add:firstObject; add:secondObject.
    ^ newCollection
!

with:firstObject with:secondObject with:thirdObject
    "return a new Collection with three elements"

    |newCollection|

    newCollection := self new.
    newCollection add:firstObject; add:secondObject; add:thirdObject.
    ^ newCollection
!

with:firstObject with:secondObject with:thirdObject with:fourthObject
    "return a new Collection with four elements"

    |newCollection|

    newCollection := self new.
    newCollection add:firstObject; add:secondObject; add:thirdObject; add:fourthObject.
    ^ newCollection
!

with:a1 with:a2 with:a3 with:a4 with:a5
    "return a new Collection with five elements"

    |newCollection|

    newCollection := self new.
    newCollection add:a1; add:a2; add:a3; add:a4; add:a5.
    ^ newCollection

    "Modified: 22.1.1997 / 19:34:01 / cg"
!

with:a1 with:a2 with:a3 with:a4 with:a5 with:a6
    "return a new Collection with size elements"

    |newCollection|

    newCollection := self new.
    newCollection add:a1; add:a2; add:a3; add:a4; add:a5; add:a6.
    ^ newCollection

    "Created: 22.1.1997 / 19:34:14 / cg"
!

with:a1 with:a2 with:a3 with:a4 with:a5 with:a6 with:a7
    "return a new Collection with seven elements"

    |newCollection|

    newCollection := self new.
    newCollection add:a1; add:a2; add:a3; add:a4; add:a5; add:a6; add:a7.
    ^ newCollection

    "Created: 22.1.1997 / 19:34:24 / cg"
!

with:a1 with:a2 with:a3 with:a4 with:a5 with:a6 with:a7 with:a8
    "return a new Collection with eight elements"

    |newCollection|

    newCollection := self new.
    newCollection add:a1; add:a2; add:a3; add:a4; add:a5; add:a6; add:a7; add:a8.
    ^ newCollection

    "Created: 22.1.1997 / 19:34:34 / cg"
!

withAll:aCollection
    "return a new Collection with all elements taken from the argument,
     aCollection"

    |newCollection|

    newCollection := self new.
    newCollection addAll:aCollection.
    ^newCollection
! !

!Collection class methodsFor:'Signal constants'!

emptyCollectionSignal
    "return the signal used to report non-allowed operation on empty collections"

    ^ EmptyCollectionSignal
!

invalidKeySignal
    "return the signal used to report bad key usage"

    ^ InvalidKeySignal
!

notEnoughElementsSignal
    "return the signal used to report attempts for an operation, for which
     there are not enough elements in the collection"

    ^ NotEnoughElementsSignal
!

valueNotFoundSignal
    "return the signal used to report a nonexisting element."

    ^ ValueNotFoundSignal
! !

!Collection class methodsFor:'queries'!

growIsCheap
    "return true, if this collection can easily grow
     (i.e. without a need for become:).
     Returns true here; this method is redefined in fix-size
     collections"

    ^ true
! !

!Collection methodsFor:'accessing'!

anElement
    "return any element from the collection, or nil if there is none"

    self do: [:each | ^ each].
    ^ nil
!

atAll:indexCollection put:anObject
    "put anObject into all indexes from indexCollection in the receiver.
     This abstract implementation requires that the receiver supports
     access via a key (and indexCollection contains valid keys).

     Notice: This operation modifies the receiver, NOT a copy;
     therefore the change may affect all others referencing the receiver."

    indexCollection do:[:index | self at:index put:anObject]

    "
     args:    indexCollection : <Collection of keys<object> >
     returns: self
    "

    "
     (Array new:10) atAll:(1 to:5) put:0
     (Array new:10) atAll:#(1 5 6 9) put:0
     (Dictionary new) atAll:#(foo bar baz) put:'hello' 

    raises an error:
     (Set new) atAll:#(foo bar baz) put:'hello' 
    "

    "Modified: / 20.5.1998 / 14:50:46 / cg"
!

fifth
    "return the fifth element of the collection.
     For unordered collections, this simply returns the fifth
     element when enumerating them.
     This should be redefined in subclasses."

    ^ self nth:5

    "
     #(1 2 3 4 5) fifth
    "
!

first
    "return the first element of the collection.
     For unordered collections, this simply returns the first
     element when enumerating them.
     This should be redefined in subclasses."

    self do:[:e | ^ e].

    "error if collection is empty"
    ^ self emptyCollectionError
!

firstIfEmpty:exceptionValue
    "return the first element of the collection.
     If its empty, return the excveptionValue.
     (i.e. dont trigger an error as done in #first)"

    self isEmpty ifTrue:[^ exceptionValue value].
    ^  self first

    "Modified: 6.2.1996 / 15:27:17 / cg"
!

fourth
    "return the fourth element of the collection.
     For unordered collections, this simply returns the fourth
     element when enumerating them.
     This should be redefined in subclasses."

    ^ self nth:4

    "
     #(1 2 3 4) fourth
    "
!

last
    "return the last element of the collection.
     This should be redefined in subclasses."

    |theLastOne any|

    any := false.
    self do:[:e | any := true. theLastOne := e].
    any ifTrue:[
	^ theLastOne
    ].

    "error if collection is empty"
    ^ self emptyCollectionError
!

lastIfEmpty:exceptionValue
    "return the last element of the collection.
     If its empty, return the exceptionValue.
     (i.e. dont trigger an error as done in #last)"

    self isEmpty ifTrue:[^ exceptionValue value].
    ^ self last

    "Modified: 6.2.1996 / 15:27:17 / cg"
    "Created: 6.2.1996 / 15:27:49 / cg"
!

nth:n
    "return the nth element of the collection.
     For unordered collections, this simply returns the nth
     element when enumerating them.
     This should be redefined in subclasses."

    |count|

    count := 1.
    self do:[:e | 
        count == n ifTrue:[^ e].
        count := count + 1
    ].

    "error if collection is smaller"
    ^ self notEnoughElementsError

    "
     #(1 2 3 4) nth:3
     #(1 2 3 4) nth:5

     #(1 2 3 4) asSet nth:3  
     #(1 2 3 4) asSet nth:5
    "
!

second
    "return the second element of the collection.
     For unordered collections, this simply returns the second
     element when enumerating them.
     This should be redefined in subclasses."

    |count|

    count := 1.
    self do:[:e | 
        count == 2 ifTrue:[^ e].
        count := count + 1
    ].

    "error if collection is smaller"
    ^ self notEnoughElementsError

    "
     #(1 2 3) second
    "

!

sixth
    "return the sixth element of the collection.
     For unordered collections, this simply returns the sixth
     element when enumerating them.
     This should be redefined in subclasses."

    ^ self nth:6

    "
     #(1 2 3 4 5 6 7) sixth
    "
!

third
    "return the third element of the collection.
     For unordered collections, this simply returns the third
     element when enumerating them.
     This should be redefined in subclasses."

    ^ self nth:3


    "
     #(1 2 3) third
    "
! !

!Collection methodsFor:'adding & removing'!

add:anObject
    "add the argument, anObject to the receiver.
     If the receiver is ordered, the position of the new element is undefined
     (i.e. dont depend on where it will be put).
     An error is raised here - it is to be implemented by a concrete subclass."

    ^ self subclassResponsibility

    "Modified: 1.2.1997 / 11:57:08 / cg"
!

add:newObject withOccurrences:anInteger
    "add the argument, anObject anInteger times to the receiver.
     Returns the object."

    anInteger timesRepeat:[self add:newObject].
    ^ newObject

    "Created: 11.5.1996 / 12:13:48 / cg"
!

addAll:aCollection
    "add all elements of the argument, aCollection to the receiver.
     Returns the argument, aCollection."

    aCollection do:[:element |
        self add:element
    ].
    ^ aCollection

    "
     #(1 2 3 4) copy addAll:#(5 6 7 8)
     #(1 2 3 4) asOrderedCollection addAll:#(5 6 7 8)
    "

    "Modified: 12.4.1996 / 13:29:20 / cg"
!

addAllFirst:aCollection
    "insert all elements of the argument, aCollection at the beginning
     of the receiver. Returns the argument, aCollection."

    aCollection reverseDo:[:element | 
        self addFirst:element 
    ].
    ^ aCollection

    "
     |c|
     c := #(4 3 2 1) asOrderedCollection.
     c addAllFirst:#(9 8 7 6 5).
     c   
    "

    "Modified: 12.4.1996 / 13:30:10 / cg"
!

addAllLast:aCollection
    "add all elements of the argument, aCollection to the receiver.
     Returns the argument, aCollection."

    aCollection do:[:element | 
        self addLast:element 
    ].
    ^ aCollection

    "
     |c|
     c := #(4 3 2 1) asOrderedCollection.
     c addAllLast:#(9 8 7 6 5)
    "

    "Modified: 12.4.1996 / 13:30:54 / cg"
!

addFirst:anObject
    "add the argument, anObject to the receiver.
     If the receiver is ordered, the new element will be added at the beginning.
     An error is raised here - it is to be implemented by a concrete subclass."

    ^ self subclassResponsibility

    "Modified: 1.2.1997 / 11:57:19 / cg"
!

addLast:anObject
    "add the argument, anObject to the receiver. 
     If the receiver is ordered, the new element will be added at the end.
     Return the argument, anObject."

    ^ self add:anObject

    "Modified: 12.4.1996 / 13:31:12 / cg"
!

contents:aCollection
    "set my contents from aCollection
     - this may be redefined in a concrete subclass for more performance"

    self removeAll.
    aCollection notNil ifTrue:[
        self addAll:aCollection
    ]

    "Modified: / 17.8.1998 / 10:18:43 / cg"
!

remove:anObject
    "search for the first element, which is equal to anObject;
     if found, remove and return it.
     If not found, report a 'value not found'-error.
     Uses equality compare (=) to search for the occurrence."

    ^ self remove:anObject ifAbsent:[self errorValueNotFound:anObject]

    "Modified: 1.2.1997 / 11:58:48 / cg"
!

remove:anObject ifAbsent:exceptionBlock
    "search for the first element, which is equal to anObject;
     if found, remove and return it.
     If not found, return the the value of the exceptionBlock.
     Uses equality compare (=) to search for the occurrence.
     An error is raised here - it is to be implemented by a concrete subclass."

    ^ self subclassResponsibility

    "Modified: 1.2.1997 / 11:56:53 / cg"
!

removeAll
    "remove all elements from the receiver. Returns the receiver.
     This should be reimplemented in subclasses for better
     performance."

    [self isEmpty] whileFalse:[
        self removeFirst
    ].

    "Modified: 12.2.1997 / 12:40:29 / cg"
!

removeAll:aCollection
    "remove all elements of the argument, aCollection from the receiver.
     Return the argument, aCollection.
     Raises an error, if some element-to-remove is not in the receiver.
     (see also: #removeAllFoundIn:, which does not raise an error).

     Notice: for some collections (those not tuned for
             resizing themself) this may be very slow.
             If the number of removed elements is big compared to to
             the receivers size, it may be better to copy the
             ones which are not to be removed into a new collection."

    aCollection do:[:element | self remove:element].
    ^ aCollection

    "
     |coll|

     coll := #(1 2 3 4 5 6) asSet.
     coll removeAll:#(4 5 6).
     coll
    "

    "raises an error:
     |coll|

     coll := #(1 2 3 4 5 6) asSet.
     coll removeAll:#(4 5 6 7 8).
     coll
    "

    "no error raised:
     |coll|

     coll := #(1 2 3 4 5 6) asSet.
     coll removeAllFoundIn:#(4 5 6 7 8).
     coll
    "


!

removeAllFoundIn:aCollection 
    "Remove each element of aCollection, which is present in the receiver
     from the receiver.
     No error is raised, if some element-to-remove is not in the receiver.
     (see also: #removeAll:, which does raise an error)."

    aCollection do:[:each | self remove:each ifAbsent:[]].
    ^ aCollection

    "
     |coll|

     coll := #(1 2 3 4 5 6) asSet.
     coll removeAllFoundIn:#(4 5 6 7 8).
     coll
    "

    "raises an error:
     |coll|

     coll := #(1 2 3 4 5 6) asSet.
     coll removeAll:#(4 5 6 7 8).
     coll
    "

!

removeAllSuchThat:aBlock
    "Apply the condition to each element and remove it if the condition is true.  
     Return a collection of removed elements.
     First elements-to-remove are collected, then removed in one operation."

    |removedElements|

    removedElements := OrderedCollection new.
    self do:[:element |
        (aBlock value:element) ifTrue: [
            removedElements add:element
        ]
    ].
    self removeAll:removedElements.
    ^ removedElements

    "
     |coll|

     coll := #(1 2 3 4 5 6 7 8 9 10) asOrderedCollection.
     coll removeAllSuchThat:[:el | el even].
     coll     
    "
    "
     |coll|

     coll := #(1 2 3 4 5 6 7 8 9 10) asSet.
     coll removeAllSuchThat:[:el | el even].
     coll     
    "

!

removeFirst
    "remove the first element from the receiver.
     Return the removed element."

    self do:[:element |
        self remove:element.
        ^ element.
    ].
    ^ self emptyCollectionError

    "
     (Set with:3 with:2 with:1) removeFirst 
    "

    "Modified: 28.6.1996 / 18:55:33 / cg"
!

removeFirst:n
    "remove the first n elements from the receiver.
     Return a collection of removed elements.
     Notice: for some collections (those not tuned for
             resizing themself) this may be very slow."

    |ret|

    self size < n ifTrue:[
        ^ self notEnoughElementsError
    ].
    ret := Array new:n.
    1 to:n do:[:i |
        ret at:i put:(self removeFirst).
    ].
    ^ ret
!

removeIdentical:anObject
    "search for the first element, which is identical to anObject;
     if found, remove and return it.
     If not found, report a 'value not found'-error.
     Uses identity compare (==) to search for the occurrence."

    ^ self removeIdentical:anObject ifAbsent:[self errorValueNotFound:anObject]

    "Modified: 12.4.1996 / 13:33:30 / cg"
    "Created: 1.2.1997 / 11:59:10 / cg"
!

removeIdentical:anObject ifAbsent:exceptionBlock
    "search for the first element, which is identical to anObject;
     if found, remove and return it.
     If not found, return the the value of the exceptionBlock.
     Uses identity compare (==) to search for the occurrence.
     An error is raised here - it is to be implemented by a concrete subclass."

    ^ self subclassResponsibility

    "Created: 1.2.1997 / 11:56:01 / cg"
    "Modified: 1.2.1997 / 11:56:59 / cg"
!

removeLast
    "remove the last element from the receiver.
     Return the removed element.
     An error is raised here - it is to be implemented by a concrete subclass."

    ^ self subclassResponsibility

    "Modified: 1.2.1997 / 11:57:53 / cg"
!

removeLast:n
    "remove the last n elements from the receiver.
     Return a collection of removed elements.
     Notice: for some collections (those not tuned for
             resizing themself) this may be very slow."

    |ret|

    self size < n ifTrue:[
        ^ self notEnoughElementsError
    ].
    ret := Array new:n.
    n to:1 by:-1 do:[:i |
        ret at:i put:(self removeLast).
    ].
    ^ ret
! !

!Collection methodsFor:'converting'!

asArray
    "return a new Array with the collections elements"

    |anArray 
     index "{ Class: SmallInteger }" |

    anArray := Array new:(self size).
    index := 1.
    self do:[:each |
	anArray at:index put:each.
	index := index + 1
    ].
    ^ anArray
!

asBag
    "return a new Bag with the receiver collections elements"

    ^ self addAllTo:(Bag new)
!

asByteArray
    "return a new ByteArray with the collections elements
     (which must convert to integers in the range 0..255)."

    |aByteArray 
     index "{ Class: SmallInteger }" |

    aByteArray := ByteArray new:(self size).
    index := 1.
    self do:[:each |
	aByteArray at:index put:each asInteger.
	index := index + 1
    ].
    ^ aByteArray
!

asDoubleArray
    "return a new DoubleArray with the collections elements
     (which must convert to floats)."

    |aDoubleArray
     index "{ Class: SmallInteger }" |

    aDoubleArray := DoubleArray new:(self size).
    index := 1.
    self do:[:each |
	aDoubleArray at:index put:each asFloat.
	index := index + 1
    ].
    ^ aDoubleArray
!

asFloatArray
    "return a new FloatArray with the collections elements
     (which must convert to floats)."

    |aFloatArray
     index "{ Class: SmallInteger }" |

    aFloatArray := FloatArray new:(self size).
    index := 1.
    self do:[:each |
	aFloatArray at:index put:each asFloat.
	index := index + 1
    ].
    ^ aFloatArray
!

asIdentitySet
    "return a new IdentitySet with the receiver collections elements"

    ^ self addAllTo:(IdentitySet new:self size)
!

asList
    "return a new List with the receiver collections elements"

    ^ self addAllTo:(List new:self size)

    "Created: 14.2.1997 / 16:25:23 / cg"
!

asOrderedCollection
    "return a new OrderedCollection with the receiver collections elements"

    ^ self addAllTo:(OrderedCollection new:self size)
!

asRunArray
    "return a new RunArray with the collections elements"

    ^ RunArray from:self.

"/    |runs lastElement occurrences|
"/
"/    runs := RunArray new.
"/    occurrences := 0.
"/    self do:[:each |
"/        each == lastElement ifTrue:[
"/            occurrences := occurrences + 1
"/        ] ifFalse:[
"/            runs add:lastElement withOccurrences:occurrences.
"/            occurrences := 1.
"/            lastElement := each
"/        ].
"/    ].
"/    occurrences ~~ 0 ifTrue:[
"/        runs add:lastElement withOccurrences:occurrences
"/    ].
"/    ^ runs

    "
     #(1 2 3 3 3 4 4 4 4 5 6 7) asRunArray 
    "

    "Modified: / 7.4.1998 / 09:50:54 / cg"
!

asSet
    "return a new Set with the receiver collections elements"

    ^ self addAllTo:(Set new:self size)
!

asSortedCollection
    "return a new SortedCollection with the receiver collections elements"

    |aSortedCollection|

    aSortedCollection := SortedCollection new:self size.
    aSortedCollection addAll:self.
    ^ aSortedCollection
!

asSortedCollection:sortBlock
    "return a new SortedCollection with the receiver collections elements,
     using sortBlock for comparing"

    |aSortedCollection|

    aSortedCollection := SortedCollection sortBlock:sortBlock.
    aSortedCollection addAll:self.
    ^ aSortedCollection
!

asSortedStrings
    "Create & return a SortedCollection that sorts the receivers
     elements according to the locales collating policy.
     This is currently not really support - strings are sorted
     without caring for the locale."

    |aSortedCollection|

    aSortedCollection := SortedCollection forStrings:self size.
    aSortedCollection addAll:self.
    ^ aSortedCollection

    "Created: 13.9.1997 / 09:36:22 / cg"
    "Modified: 13.9.1997 / 09:43:00 / cg"
!

asSortedStrings:sortBlock
    "Create & return a SortedCollection that sorts the receivers
     elements using sortBlock and according to the locales collating policy,
     which is passed as first arg to sortBlock.
     This is currently not really support - strings are sorted
     without caring for the locale."

    |aSortedCollection|

    aSortedCollection := SortedCollection forStrings:self size.
    aSortedCollection sortBlock:sortBlock.
    aSortedCollection addAll:self.
    ^ aSortedCollection

    "Created: / 13.9.1997 / 09:36:45 / cg"
    "Modified: / 27.10.1997 / 16:39:48 / cg"
!

asSortedStrings:sortBlock with:aCollationPolicy
    "Create & return a SortedCollection that sorts the receivers
     elements using sortBlock and according to the specified locales collating policy.
     This is currently not really support - strings are sorted
     without caring for the locale."

    |aSortedCollection|

    aSortedCollection := SortedCollection forStrings:self size collatedBy:aCollationPolicy.
    aSortedCollection sortBlock:sortBlock.
    aSortedCollection addAll:self.
    ^ aSortedCollection

    "Created: 13.9.1997 / 09:37:21 / cg"
    "Modified: 13.9.1997 / 09:45:27 / cg"
!

asSortedStringsWith: aCollationPolicy
    "Create & return a SortedCollection that sorts the receivers
     elements according to the specified locales collating policy.
     This is currently not really support - strings are sorted
     without caring for the locale."

    |aSortedCollection|

    aSortedCollection := SortedCollection forStrings:self size collatedBy:aCollationPolicy.
    aSortedCollection addAll:self.
    ^ aSortedCollection

    "Created: 13.9.1997 / 09:37:50 / cg"
    "Modified: 13.9.1997 / 09:44:08 / cg"
!

asString
    "return a String with the collections elements 
     (which must convert to characters)"

    |aString 
     index "{ Class: SmallInteger }" |

    aString := String new:(self size).
    index := 1.
    self do:[:each |
	aString at:index put:each asCharacter.
	index := index + 1
    ].
    ^ aString
!

asStringCollection
    "return a new string collection containing the elements;
     these ought to be strings. (i.e. String or Text instances)"

    ^ self addAllTo:(StringCollection new)

    "Modified: 18.5.1996 / 13:54:34 / cg"
!

asText
    "return a Text-object (collection of lines) from myself.
     BIG warning: asText is totally misnamed here 
     - ST/X's asText has nothing to do with PP's asText.
     Therefore it will be removed/renamed soon. 
     Please use #asStringCollection."

    self obsoleteMethodWarning:'use #asStringCollection; #asText will change its meaning'.

    ^ self asStringCollection
!

readStream
    "return a stream for reading from the receiver"

    ^ ReadStream on:self

    "
     |s|

     s := 'hello world' readStream.
     s next:5.
     s next.
     (s next:5) inspect
    "
!

writeStream
    "return a stream for writing onto the receiver"

    ^ WriteStream on:self

    "
     |s|

     s := #() copy writeStream.
     s nextPut:1.
     s nextPut:2.
     s nextPut:3.
     s contents inspect
    "

    "
     |s|

     s := OrderedCollection new writeStream.
     s nextPut:1.
     s nextPut:2.
     s nextPut:3.
     s contents inspect
    "
! !

!Collection methodsFor:'copying'!

copy
    "return a copy of the receiver.
     Redefined to pass the original as argument to tyhe postCopyFrom method."

    ^ self shallowCopy postCopyFrom:self

    "Created: / 19.4.1998 / 20:02:53 / cg"
!

copyEmpty
    "return a copy of the receiver with no elements.
     This is used by copying and enumeration methods
     to get a new instance which is similar to the receiver."

    ^ self species new
!

copyEmpty:size
    "return a copy of the receiver with no elements, but space for
     size elements. This is used by copying and enumeration methods
     to get a new instance which is similar to the receiver.
     This method should be redefined in subclasses with instance
     variables, which should be put into the copy too.
     For example, SortedCollection has to copy its sortBlock into the
     new collection."

    ^ self species new:size
!

copyEmptyAndGrow:size
    "return a copy of the receiver with size nil elements.
     This is used by copying and enumeration methods
     to get a new instance which is similar to the receiver."

    ^ (self copyEmpty:size) grow:size
!

postCopyFrom:original
    "sent to a freshly copied object to give it a chance to adjust things.
     Notice, that for Sets/Dicts etc. a rehash is not needed, since the copy
     will have the same hash key as the receiver (as long as ST/X provides the 
     setHash: functionality)."

    "for ST-80 compatibility, we try postCopy here ..."
    ^ self postCopy

    "Created: / 19.4.1998 / 19:59:42 / cg"
    "Modified: / 19.4.1998 / 20:03:57 / cg"
! !

!Collection methodsFor:'enumerating'!

addAllTo:aCollection
    "add all elements of the receiver, to aCollection.
     Return aCollection."

    self do:[:each | aCollection add:each].
    ^ aCollection

    "
     #(1 2 3 4 5 1 2 3 4 5) addAllTo:Set new
    "

    "Modified: / 11.2.2000 / 11:22:14 / cg"
!

allSatisfy:aBlock 
    "evaluate aBlock for each of the receiver's elements. 
     Return true, if aBlock returns true for all elements, false otherwise
     (i.e. false if any element fails to satisfy the block-condition).
     This is an ANSI renomer of #donform:"

    ^ self conform:aBlock.

    "
     #(1 2 3 4 5) allSatisfy:[:el | el odd]   
     #(2 4 6 8 10) allSatisfy:[:el | el odd]  
     #(2 4 6 8 10) allSatisfy:[:el | el even]  
    "

!

anySatisfy:aBlock 
    "evaluate aBlock for each of the receiver's elements. 
     Return true, if aBlock ever returns true, false otherwise
     (i.e. if any element satisfies the block-condition).
     This is an ANSI renomer of #contains:"

    ^ self contains:aBlock.

    "
     #(1 2 3 4 5) anySatisfy:[:el | el odd]   
     #(2 4 6 8 10) anySatisfy:[:el | el odd]  
    "

!

collect:aBlock
    "for each element in the receiver, evaluate the argument, aBlock
     and return a new collection with the results"

    |newCollection|

    newCollection := self species new.
    self do:[:element | newCollection add:(aBlock value:element)].
    ^ newCollection

    "
     #(1 2 3 4) collect:[:n | n * 2]  
    "
!

collect:collectBlock thenSelect:selectBlock
    "combination of collect followed by select.
     May be redefined by some subclasses for optimal performance
     (avoidong the creation of intermediate garbage)"

    ^ (self collect:collectBlock) select:selectBlock

    "
     #(1 2 3 4 5 6 7) collect:[:i | i * 2] thenSelect:[:i | i < 10]
    "

!

conform:aBlock
    "return true, if every element conforms to some condition.
     I.e. return false, if aBlock returns false for any element;
     true otherwise."

    self do:[:element | (aBlock value:element) ifFalse:[^ false]].
    ^ true
!

contains:aBlock 
    "evaluate aBlock for each of the receiver's elements. 
     Return true, if aBlock ever returns true, false otherwise."

    self detect:aBlock ifNone:[^ false].
    ^ true

    "
     #(1 2 3 4 5) contains:[:el | el odd]  
     #(2 4 6 8 10) contains:[:el | el odd]  
    "

    "Modified: 26.5.1997 / 17:38:57 / cg"
!

count:aBlock
    "count elements, for which aBlock returns true.
     Return the sum."

    ^ self inject:0 into:[:sumSoFar :element |
	    (aBlock value:element) ifTrue:[sumSoFar + 1]
				   ifFalse:[sumSoFar]
      ]

    "
     #(1 2 3 4 6 8 10) count:[:a | a even]     
     #(1 nil nil nil 2 3 nil 4 5) count:[:a | a isNil] 
    "
!

detect:aBlock
    "evaluate the argument, aBlock for each element in the receiver until
     the block returns true; in this case return the element which caused
     the true evaluation.
     If none of the evaluations returns true, report an error"

    ^ self detect:aBlock ifNone:[self errorNotFound]

    "
     #(1 2 3 4) detect:[:n | n odd]   
     #(2 4 6 8) detect:[:n | n odd]  
    "
!

detect:aBlock ifNone:exceptionBlock
    "evaluate the argument, aBlock for each element in the receiver until
     the block returns true; in this case return the element which caused
     the true evaluation.
     If none of the evaluations returns true, return the result of the
     evaluation of the exceptionBlock"

    self do:[:each | 
	(aBlock value:each) ifTrue:[^ each].
    ].
    ^ exceptionBlock value

    "
     #(1 2 3 4) detect:[:n | n odd] ifNone:['sorry']    
     #(2 4 6 8) detect:[:n | n odd] ifNone:['sorry']     
    "
!

detectLast:aBlock
    "evaluate the argument, aBlock for each element in the receiver until
     the block returns true; in this case return the element which caused
     the true evaluation. The elements are processed in reverse order.
     If none of the evaluations returns true, report an error"

    ^ self detectLast:aBlock ifNone:[self errorNotFound]

    "
     #(1 2 3 4) detectLast:[:n | n odd]   
     #(2 4 6 8) detectLast:[:n | n odd]  
    "
!

detectLast:aBlock ifNone:exceptionBlock
    "evaluate the argument, aBlock for each element in the receiver until
     the block returns true; in this case return the element which caused
     the true evaluation. The elements are processed in reverse order.
     If none of the evaluations returns true, return the result of the
     evaluation of the exceptionBlock"

    self reverseDo:[:each | 
	(aBlock value:each) ifTrue:[^ each].
    ].
    ^ exceptionBlock value

    "
     #(1 2 3 4) detectLast:[:n | n odd] ifNone:['sorry']    
     #(2 4 6 8) detectLast:[:n | n odd] ifNone:['sorry']     
    "
!

do:aBlock
    "evaluate the argument, aBlock for each element"

    ^ self subclassResponsibility
!

do:aBlock inBetweenDo:betweenBlock
    "evaluate the argument, aBlock for each element.
     Between elements (i.e. after each except for the last),
     evaluate betweenBlock.
     This is a utility helper for collection printers
     (for example, to print a space between elements)."

    |first|

    first := true.
    self do:[:element |
        first ifTrue:[
            first := false
        ] ifFalse:[
            betweenBlock value.
        ].
        aBlock value:element
    ].

    "
     #(1 2 3 4) do:[:el | Transcript show:el]
                inBetweenDo:[ Transcript show:'-']
    "

    "Modified: / 11.2.2000 / 11:23:15 / cg"
!

doWithExit:aBlock
    "evaluate the argument, aBlock for each element.
     Passes an additional exit object, which can be used to leave
     the loop early, by sending it a #value: message.
     Returns nil or the value passed to the exit>>value: message.

     Notice, that this is different to a return from the block, which
     returns from the enclosed method, NOT only from the block."

    ^ [:exit |
        self do:[:el |
            aBlock value:el value:exit
        ].
        nil
    ] valueWithExit.

    "Example:
     search for the first element which is >= 99; return it.
     remaining elements are not processed:

     #(1 2 3 4 999 5 6 7 8 9) 
        doWithExit:[:element :exit |
            Transcript showCR:element.
            element >= 99 ifTrue:[exit value:element]]

     #(1 2 3 4 5 6 7 8 9) 
        doWithExit:[:element :exit |
            Transcript showCR:element.
            element >= 99 ifTrue:[exit value:element]]
    "

    "to demonstrate the difference to returning from the block:
     this works:

     |el|

     el := #(1 2 3 4 999 5 6 7 8 9) 
        doWithExit:[:element :exit |
            element >= 99 ifTrue:[exit value:element]].
     Transcript showCR:el.


     this does NOT work as expected by a newComer ;-) (the showCR is not reached):

     |el|

     el := #(1 2 3 4 999 5 6 7 8 9) 
        do:[:element |
            element >= 99 ifTrue:[^ element]].
     Transcript showCR:el.
    "

    "Modified: 18.4.1996 / 14:16:59 / cg"
!

inject:thisValue into:binaryBlock
    "starting with thisValue for value, pass this value and each element
     to binaryBlock, replacing value with the result returned from the block
     in the next iteration."

    |nextValue|

    nextValue := thisValue.
    self do: [:each | nextValue := binaryBlock value:nextValue value:each].
    ^ nextValue

    "sum up the elements of a collection:

     #(1 2 3 4) inject:0 into:[:accu :element | accu + element]   
     (1 to:10) inject:0 into:[:accu :element | accu + element]     

     find the minimum:

     |coll|
     coll := #(1 99 -15 20 100).
     coll inject:(coll first) into:[:minSoFar :element | minSoFar min:element]
    "

    "Modified: 23.4.1996 / 13:47:06 / cg"
!

keysAndValuesDo:aTwoArgBlock
    "evaluate the argument, aBlock for every element in the collection,
     passing both index and element as arguments."

    ^ self errorNotKeyed
!

keysAndValuesReverseDo:aTwoArgBlock
    "evaluate the argument, aBlock in reverse order for every element in the collection,
     passing both index and element as arguments."

    ^ self errorNotKeyed

    "Created: 9.5.1996 / 00:58:24 / cg"
!

pairsDo:aBlock
    "evaluate the argument, aBlock for every element in the collection,
     which is supposed to consist of 2-element collections.
     The block is called with 2 arguments for each collection in the receiver."

    self do:[:aPair |
	aBlock value:(aPair at:1) value:(aPair at:2).
    ]
    "
     #( (1 one) (2 two) (3 three) (4 four) (5 five) (6 six)) 
     pairsDo:[:num :sym | Transcript show:num; show:' is: '; showCR:sym]


     #( (1 1)  (1 2)  (1 3)  (1 4)  (1 5)) 
     pairsDo:[:x :y | Transcript showCR:x@y]
    "
!

reject:aBlock
    "return a new collection with all elements from the receiver, for which
     the argument aBlock evaluates to false"

    ^ self select:[:element | (aBlock value:element) == false]

    "
     #(1 2 3 4) reject:[:e | e odd]   
     (1 to:10) reject:[:e | e even]     
    "
!

reverseDo:aBlock
    "evaluate the argument, aBlock for each element in reverse order."

    "it could be defined in terms of do: - but very inefficient.
     Better force programmer to define a better version ..."

    ^ self subclassResponsibility
!

select:aBlock
    "return a new collection with all elements from the receiver, for which
     the argument aBlock evaluates to true.
     See also: #removeAllFoundIn: and #removeAllSuchThat:"

    |newCollection|

    newCollection := self species new.
    self do:[:each |
        (aBlock value:each) ifTrue:[newCollection add:each].
    ].
    ^ newCollection

    "
     #(1 2 3 4) select:[:e | e odd]   
     (1 to:10) select:[:e | e even]     
    "
!

select:aBlock ifNone:exceptionBlock
    "try a new collection with all elements from the receiver, for which
     the argument aBlock evaluates to true. If none of the elements passes
     the check of aBlock, return the result of evaluating exceptionBlock.
     See also: #removeAllFoundIn: and #removeAllSuchThat:"

    |newCollection|

    newCollection := self select:aBlock.
    newCollection isEmpty ifTrue:[^ exceptionBlock value].
    ^ newCollection

    "
     #(1 2 3 4) select:[:e | e > 10] ifNone:['sorry']  
    "
!

select:selectBlock thenCollect:collectBlock
    "combination of select followed by collect.
     May be redefined by some subclasses for optimal performance
     (avoidong the creation of intermediate garbage)"

    ^ (self select:selectBlock) collect:collectBlock

    "
     #(1 2 3 4 5 6 7) select:[:i | i even] thenCollect:[:i | i * 2]
    "
!

triplesDo:aBlock
    "evaluate the argument, aBlock for every element in the collection,
     which is supposed to consist of 3-element collections.
     The block is called with 3 arguments for each collection in the receiver."

    self do:[:aTriple |
        aBlock value:(aTriple at:1) value:(aTriple at:2) value:(aTriple at:3).
    ]
    "
     #( (1 one eins) (2 two zwei) (3 three drei) (4 four vier) (5 five #'fuenf') (6 six sechs)) 
     triplesDo:[:num :sym1 :sym2 | Transcript show:num; space; show:sym1; space; showCR:sym2]
    "

    "Modified: 10.5.1997 / 14:15:43 / cg"
!

with:aCollection collect:aTwoArgBlock
    "evaluate the argument, aBlock for successive elements from
     each the receiver and the argument, aSequenceableCollection;
     The second argument, aBlock must be a two-argument block, which is
     evaluated for each element-pair.
     Collect the results and return a collection containing them.
     This method fails if neither the receiver nor aCollection is
     a sequenceable collection (i.e. implements numeric key access)."

    |index  "{ Class: SmallInteger }" 
     newCollection|

    newCollection := self species new.
    index := 1.
    aCollection isSequenceable ifFalse:[
	self isSequenceable ifFalse:[
	    ^ self error:'neither collection is sequenceable'.
	].
	aCollection do:[:element |
	    newCollection add:(aTwoArgBlock value:(self at:index) 
					    value:element).
	    index := index + 1
	]
    ] ifTrue:[
	self do:[:element |
	    newCollection add:(aTwoArgBlock value:element 
					    value:(aCollection at:index)).
	    index := index + 1
	]
    ].
    ^ newCollection

    "
     (1 to:3) with:#(one two three) collect:[:num :sym | (num->sym)]
     #(1 2 3) with:#(10 20 30) collect:[:x :y | (x@y)]
    "
!

with:aCollection do:aTwoArgBlock
    "evaluate the argument, aBlock for successive elements from
     each the receiver and the argument, aSequenceableCollection.
     The second argument, aBlock must be a two-argument block.
     This method fails if neither the receiver nor aCollection is
     a sequenceable collection (i.e. implements numeric key access)."

    |index  "{ Class: SmallInteger }"|

    index := 1.
    aCollection isSequenceable ifFalse:[
	self isSequenceable ifFalse:[
	    ^ self error:'neither collection is sequenceable'.
	].
	aCollection do:[:element |
	    aTwoArgBlock value:(self at:index) value:element.
	    index := index + 1
	]
    ] ifTrue:[
	self do:[:element |
	    aTwoArgBlock value:element value:(aCollection at:index).
	    index := index + 1
	]
    ]

    "
     (1 to:3) with:#(one two three) do:[:num :sym |
	Transcript showCR:(num->sym)
     ]
     (1 to:3) with:#(one two three) asSet do:[:num :sym |
	Transcript showCR:(num->sym)
     ].
     (1 to:3) asSet with:#(one two three) do:[:num :sym |
	Transcript showCR:(num->sym)
     ]
    "
! !

!Collection methodsFor:'error handling'!

emptyCheck 
    "check if the receiver is empty; report an error if so"

    self size == 0 ifTrue:[
	^ self emptyCollectionError.
    ].
!

emptyCollectionError
    "report an error that the operation is not allowed for
     empty collections"

    ^ EmptyCollectionSignal raise
!

errorInvalidKey:aKey
    "report an error that the given key was invalid"

    ^ InvalidKeySignal raiseRequestWith:aKey
!

errorNotKeyed
    "report an error that keyed access methods are not allowed"

    ^ self error:(self class name, 's do not respond to keyed accessing messages')
!

errorValueNotFound:anObject
    "report an error that an object was not found in the collection"

    ^ ValueNotFoundSignal 
        raiseRequestWith:anObject

    "Modified: / 30.10.1997 / 15:52:18 / cg"
!

notEnoughElementsError
    "report an error that the operation is not allowed,  
     since not enough elements are in the collection"

    ^ NotEnoughElementsSignal raise
! !

!Collection methodsFor:'growing'!

grow
    "make the receiver larger"

    self grow:(self size + self growSize)
!

grow:howBig
    "change the receivers size"

    ^ self subclassResponsibility
!

growSize
    "return a suitable size increment for growing.
     The default returned here may be (and is) redefined in subclasses."

    ^ self size max:2
! !

!Collection methodsFor:'printing & storing'!

displayString
    "return a printed representation of the receiver for display in inspectors etc."

    |thisString buffer count string noneYet total limit|

    thisContext isRecursive ifTrue:[
        'Collection [error]: displayString of self referencing collection.' errorPrintCR.
        ^ '#("recursive")'
    ].

    string := self displayStringName , '('.
    noneYet := true.
    buffer := ''.
    count := 0.
    total := 0.
    limit := self maxPrint.

    self printElementsDo: [:element |
        thisString := element displayString.
        noneYet ifTrue:[
            noneYet := false.
            buffer := buffer , thisString
        ] ifFalse:[
            buffer := buffer , (' ' , thisString)
        ].
        count := count + 1.
        (count == 20) ifTrue:[
            string := string , buffer.
            buffer := ''.
            count := 0
        ].
        total := total + 1.
        (total > limit) ifTrue:[
            string := string , buffer , '... )'.
            ^ string
        ]
    ].
    string := string , buffer , ')'.
    ^ string

    "
     #(1 2 3 'hello' $a) asOrderedCollection displayString

     (Dictionary new at:#hello put:'world'; 
                     at:#foo put:'bar'; yourself) displayString
    "

    "Modified: / 20.1.1998 / 14:11:03 / stefan"
    "Modified: / 2.2.1999 / 22:39:44 / cg"
!

displayStringName
    "redefinable helper for displayString"

    ^ (self class name)

    "Created: / 2.2.1999 / 22:39:33 / cg"
!

maxPrint
    "the print-limit; printOn: will try to not produce more output
     than the limit defined here."

    ^ 5000
!

printElementsDo:aBlock
    "perform aBlock (1 arg) for all elements.
     Used in #printOn:.
     Subclasses (e.g. Dictionary) may redefine this."

    ^ self do:aBlock

    "Created: / 20.1.1998 / 14:11:02 / stefan"
!

printOn:aStream
    "append a user readable representation of the receiver to aStream.
     The text appended is not meant to be read back for reconstruction of
     the receiver. Also, this method limits the size of generated string.
    "

    |limit firstOne s|

    thisContext isRecursive ifTrue:[
        'Collection [error]: printOn: of self referencing collection.' errorPrintCR.
        aStream nextPutAll:'#("recursive")'.
        ^ self
    ].

    aStream nextPutAll:self class name.
    aStream nextPut:$(.
    firstOne := true.

    "
     if aStream is not positionable, create an temporary positionable stream
     (needed for limit calculation)
    "
    aStream isPositionable ifTrue:[
        s := aStream.
    ] ifFalse:[
        s := WriteStream on:(String new:50).
    ].
    limit := s position + self maxPrint.

    self printElementsDo:[:element |
        firstOne ifFalse:[
            s space
        ] ifTrue:[
            firstOne := false
        ].
        (s position >= limit) ifTrue:[
            s ~~ aStream ifTrue:[
                aStream nextPutAll:(s contents).
            ].
            aStream nextPutAll:'...etc...)'.
            ^ self
        ] ifFalse:[
            element printOn:s.
        ].
    ].
    s ~~ aStream ifTrue:[
        aStream nextPutAll:(s contents).
    ].
    aStream nextPut:$)

    "
     #(1 2 3 'hello' $a) printOn:Transcript
     (Array new:100000) printOn:Transcript
     (Array new:100000) printOn:Stdout          
     (Array new:100000) printString size 
     (Dictionary new at:#hello put:'world'; 
                     at:#foo put:'bar'; yourself) printOn:Transcript
    "
    "
     |a| 
     a := Array new:3. 
     a at:2 put:a.
     a printOn:Transcript
    "

    "Modified: / 28.1.1997 / 00:39:17 / cg"
    "Modified: / 20.1.1998 / 14:11:03 / stefan"
!

storeOn:aStream
    "output a printed representation onto the argument, aStream.
     The text can be re-read to reconstruct (a copy of) the receiver.
     Recursive (i.e. cyclic) collections cannot be stored correctly
     (use storeBinaryOn: to handle those)."

    |notEmpty|

    thisContext isRecursive ifTrue:[
        Object recursiveStoreStringSignal raiseRequestWith:self.
        'Collection [error]: storeOn: of self referencing collection.' errorPrintCR.
        aStream nextPutAll:'#recursive'.
        ^ self
    ].

    aStream nextPutAll:'('.
    aStream nextPutAll:(self class name).
    aStream nextPutAll:' new'.
    notEmpty := false.
    self do:[:element |
        aStream nextPutAll:' add:'.
        element storeOn:aStream.
        aStream nextPutAll:';'.
        notEmpty := true
    ].
    notEmpty ifTrue:[aStream nextPutAll:' yourself'].
    aStream nextPut:$)

    "
     OrderedCollection new storeOn:Transcript
     (1 to:10) storeOn:Transcript
     (Set new add:1; add:'hello'; yourself) storeOn:Transcript
    "
    "
     |s|

     s := Set new.
     s add:1; add:'hello'; add:s.
     s storeOn:Transcript
    "

    "Modified: / 11.2.2000 / 11:24:56 / cg"
! !

!Collection methodsFor:'queries'!

defaultElement
    ^  nil
!

isCollection
    "return true, if the receiver is some kind of collection;
     true is returned here - the method is redefined from Object."

    ^ true
!

isSorted
    "return true, if the receiver is sorted.
     Collections which hold their elements in sorted order
     should return true. Some algorithms (quicksort) degenerate when 
     operating on sorted collections and can be avoided if this information
     is given. The default returned here (false) should not hurt.
     I.e. you should NEVER depend on that in your application."

    ^ false

    "Created: 13.4.1996 / 12:35:55 / cg"
!

isSortedBy:aBlock
    "return true, if my elements are sorted (already) by the given criterion (sortBlock).
     Collections which hold their elements in sorted order
     should return true. Some algorithms (quicksort) degenerate when 
     operating on sorted collections and can be avoided if this information
     is given. The default returned here (false) should not hurt.
     I.e. you should NEVER depend on that in your application."

    ^ false

!

isSortedCollection
    "return true, if the receiver is a sortedCollection."

    ^ false

!

longestCommonPrefix
    "return the longest common prefix of my elements.
     Typically used with string collections."

    ^ self longestCommonPrefixIgnoreCase:false

    "
     #('Array' 'ArrayedCollection' 'ArrayOfFoo') longestCommonPrefix 
     #('Arra' 'ArrayedCollection' 'ArrayOfFoo') longestCommonPrefix 
     #('Arra' 'b' 'c') longestCommonPrefix 
     #( (1 2 3 4) (1 2 3) (1 2 3 7) (1 2 3 9 10 11)) longestCommonPrefix
    "

    "Modified: 2.3.1997 / 00:21:41 / cg"
!

longestCommonPrefixIgnoreCase:ignoreCase
    "return the longest common prefix of my elements.
     Typically used with string collections."

    |try allMatching matchLen|

    "
     find the longest common prefix
    "
    matchLen := 0.
    self do:[:aName |
        aName size > matchLen ifTrue:[
            matchLen := aName size.
            try := aName
        ]
    ].

    allMatching := true.

    [true] whileTrue:[
        allMatching := true.
        self do:[:aName |
            ((ignoreCase not and:[aName startsWith:try])
            or:[ignoreCase and:[aName asLowercase startsWith:try asLowercase]]) ifFalse:[
                allMatching := false
            ]
        ].
        allMatching ifTrue:[
            ^ try
        ].
        matchLen := matchLen - 1.
        matchLen == 0 ifTrue:[^ ''].
        try := try copyTo:matchLen.
    ].
    ^ try

    "
     #('Array' 'arrayedCollection' 'ARRAYOfFoo') longestCommonPrefixIgnoreCase:true 
     #('Array' 'arrayedCollection' 'ARRAYOfFoo') longestCommonPrefixIgnoreCase:false 
     #('Array' 'ArayedCollection' 'ARRAYOfFoo') longestCommonPrefixIgnoreCase:false   
    "
!

size
    "return the number of elements in the receiver.
     This is usually redefined in subclasses for more performance."

    |count "{ Class: SmallInteger }" |

    count := 0.
    self do:[:element |
	count := count + 1
    ].
    ^ count
! !

!Collection methodsFor:'testing'!

capacity
    "return the number of elements, that the receiver is
     prepared to take. For most collections, this is the actual
     size. However, some have more space preallocated to allow
     for faster adding of elements. 
     Not used by the system; added for ST-80 compatibility."

    ^ self size
!

includes:anElement
    "return true, if an object equal to the argument, anObject is in the list.
     This compares using #= (i.e. it does not look for the object itself,
     instead, one that compares equal).
     See #includesIdentical: when identity is asked for."

    self do:[:element |
	(anElement = element) ifTrue:[^ true].
    ].
    ^ false
!

includesAll:aCollection
    "return true, if the the receiver includes all elements of
     the argument, aCollection; false if any is missing.
     Notice: this method has O-square runtime behavior and may be
	     slow for big receivers/args. Think about using a Set,
	     or Dictionary."

    aCollection do:[:element |
	(self includes:element) ifFalse:[^ false].
    ].
    ^ true

    "
     #(1 2 3 4 5 6 7) includesAll:#(1 2 3)
     #('hello' 'there' 'world') includesAll:#('hello' 'world')
     #(1 2 3 4 5 6 7) includesAll:#(7 8 9)
    "
!

includesAny:aCollection
    "return true, if the the receiver includes any elements of
     the argument, aCollection; false if it includes none.
     Notice: this method has O-square runtime behavior and may be
	     slow for big receivers/args. Think about using a Set,
	     or Dictionary. Speedup is possible, by arrangy highly
	     probable elements towards the beginning of aCollection,
	     to avoid useless searches."

    aCollection do:[:element |
	(self includes:element) ifTrue:[^ true].
    ].
    ^ false

    "
     #(1 2 3 4 5 6 7) includesAny:#(1 2 3)
     #('hello' 'there' 'world') includesAny:#('hello' 'world')
     #(1 2 3 4 5 6 7) includesAny:#(7 8 9)
     #(1 2 3 4 5 6 7) includesAny:#(8 9 10)
    "
!

includesIdentical:anElement
    "return true, if the argument, anObject is in the list.
     This compares using #== (i.e. object identity).
     See #includes: when equality is asked for."

    self do:[:element |
	(anElement == element) ifTrue:[^ true].
    ].
    ^ false
!

isEmpty
    "return true, if the receiver is empty"

    ^ self size == 0
!

max
    "return the maximum value in the receiver collection,
     using #> to compare elements."

    ^ self inject:nil
            into:[:maxSoFar :this | 
                        (maxSoFar isNil 
                        or:[this > maxSoFar]) ifTrue:[this]
                        ifFalse:[maxSoFar]]

    "
     #(15 1 -9 10 5) max  
     (1 to:15) max  
    "

    "Modified: 8.1.1997 / 22:09:37 / cg"
!

min
    "return the minimum value in the receiver collection,
     using < to compare elements."

    ^ self inject:nil
            into:[:minSoFar :this | 
                        (minSoFar isNil 
                        or:[this < minSoFar]) ifTrue:[this]
                        ifFalse:[minSoFar]]

    "
     #(15 1 -9 10 5) min 
     (1 to:15) min        
    "

    "Modified: 8.1.1997 / 22:09:49 / cg"
!

notEmpty
    "return true, if the receiver is not empty"

    ^ self isEmpty not
!

occurrencesOf:anElement
    "return the number of occurrences of the argument, anElement in
     the receiver. Uses #= (i.e. equality) compare."

    |count "{ Class: SmallInteger }" |

    count := 0.
    self do:[:element |
        (anElement = element) ifTrue:[
            count := count + 1
        ].
    ].
    ^ count
! !

!Collection methodsFor:'tracing'!

traceInto:aRequestor level:level from:referrer
    "double dispatch into tracer, passing my type implicitely in the selector"

    ^ aRequestor traceCollection:self level:level from:referrer


! !

!Collection class methodsFor:'documentation'!

version
    ^ '$Header: /cvs/stx/stx/libbasic/Collection.st,v 1.102 2000-08-22 13:56:10 cg Exp $'
! !
Collection initialize!