Collection.st
author claus
Fri, 16 Jul 1993 11:39:45 +0200
changeset 1 a27a279701f8
child 2 6526dde5f3ac
permissions -rw-r--r--
Initial revision

"
 COPYRIGHT (c) 1989-93 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.
"

Object subclass:#Collection
       instanceVariableNames:''
       classVariableNames:''
       poolDictionaries:''
       category:'Collections-Abstract'
!

Collection comment:'

COPYRIGHT (c) 1989-93 by Claus Gittinger
              All Rights Reserved

Abstract superclass for all collections

%W% %E%
'!

!Collection class methodsFor:'instance creation'!

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.
    newCollection add:secondObject.
    ^ newCollection
!

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

    |newCollection|

    newCollection := self new.
    newCollection add:firstObject.
    newCollection add:secondObject.
    newCollection 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.
    newCollection add:secondObject.
    newCollection add:thirdObject.
    newCollection add:fourthObject.
    ^ newCollection
!

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]
!

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

    |newCollection|

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

!Collection methodsFor:'error handling'!

errorNotFound
    "report an error that Object was not in the collection"

    self error:'Object is not in the Collection'
!

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

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

!Collection methodsFor:'accessing'!

anElement
    "return any element from the collection"

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

!Collection methodsFor:'adding & removing'!

add:anObject
    "add the argument, anObject to the receiver"

    ^ self subclassResponsibility
!

addLast:anObject
    "add the argument, anObject to the receiver"

    ^ self add:anObject
!

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

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

remove:anObject ifAbsent:exceptionBlock
    "remove the argument, anObject from the receiver - if it was not
     in the collection returns the the value of the exceptionBlock"

    ^ self subclassResponsibility
!

remove:anObject
    "remove the argument, anObject from the receiver"

    self remove:anObject ifAbsent:[self errorNotFound]
!

removeAll:aCollection
    "remove all elements of the argument, aCollection from the receiver"

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

!Collection methodsFor:'growing'!

growSize
    "return a suitable size increment for growing"

    ^ self size max:2
!

grow
    "make the receiver larger"

    self grow:(self size + self growSize)
!

grow:howBig
    "change the receivers size"

    ^ self subclassResponsibility
! !

!Collection methodsFor:'testing'!

isEmpty
    "return true, if the receiver is empty"

    ^ self size == 0
!

includes:anElement
    "return true, if the argument, anObject is in the list"

    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"

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

occurrencesOf:anElement
    "return the number of occurrences of the argument, anElement in
     the receiver"

    |count "<SmallInteger>" |

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

size
    "return the number of elements in the receiver"

    |count "<SmallInteger>" |

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

!Collection methodsFor:'enumerating'!

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

    ^ self subclassResponsibility
!

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:[:each | newCollection add:(aBlock value:each)].
    ^ newCollection
!

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 return true, report an error"

    ^ self detect:aBlock ifNone:[self errorNotFound]
!

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
!

inject:thisValue into:binaryBlock
    |nextValue|

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

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]
!

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

    |newCollection|

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

!Collection methodsFor:'converting'!

asArray
    "return a new Array with the collections elements"

    |anArray 
     index "<SmallInteger>" |

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

asByteArray
    "return a new ByteArray with the collections elements"

    |aByteArray 
     index "<SmallInteger>" |

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

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

    |aString 
     index "<SmallInteger>" |

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

asText
    "return a new Text-object with the elements printstings"

    |aText
     index "<SmallInteger>" |

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

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

    |aBag|

    aBag := Bag new.
    self do:[:each | aBag add:each].
    ^ aBag
!

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

    |anOrderedCollection|

    anOrderedCollection := OrderedCollection new:self size.
    self do:[:each | anOrderedCollection addLast:each].
    ^ anOrderedCollection
!

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

    |aSet|

    aSet := Set new: self size.
    self do:[:each | aSet add:each].
    ^ aSet
!

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
! !

!Collection methodsFor:'printing & storing'!

maxPrint
    ^ 5000
!

printString
    "return the printString of a big collection can take a long time
     due to long temporary strings - I use a buffer here collecting some
     elements to reduce the GC overhead ...
    "

    |thisString buffer count string noneYet total|

    string := (self class name) , '('.
    noneYet := true.
    buffer := ''.
    count := 0.
    total := 0.
    self do: [:element |
        thisString := element printString.
        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 > 5000) ifTrue:[
            string := string , buffer , '... )'.
            ^string
        ]
    ].
    string := string , buffer , ')'.
    ^string
!

displayString
    "return the printString of a big collection can take a long time
     due to long temporary strings - I use a buffer here collecting some
     elements to reduce the GC overhead ...
    "

    |thisString buffer count string noneYet total|

    string := (self class name) , '('.
    noneYet := true.
    buffer := ''.
    count := 0.
    total := 0.
    self do: [: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 > 5000) ifTrue:[
            string := string , buffer , '... )'.
            ^string
        ]
    ].
    string := string , buffer , ')'.
    ^string
!

printOn:aStream
    |tooMany firstOne noMore|

    tooMany := aStream position + self maxPrint.
    aStream nextPutAll:self class name.
    aStream nextPut:$(.
    firstOne := true.
    noMore := false.
    self do:[:element |
        noMore ifFalse:[
            firstOne ifFalse:[
                aStream nextPut:(Character space)
            ] ifTrue:[
                firstOne := false
            ].
            (aStream position > tooMany) ifTrue:[
                aStream nextPutAll:'...etc...)'.
                noMore := true
            ] ifFalse:[
                element printOn:aStream
            ]
        ].
    ].
    aStream nextPut:$)
!

storeOn:aStream
    "output a printed representation (which can be re-read)
     onto the argument aStream"

    |isEmpty|

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