"======================================================================
|
|   Collection Method Definitions
|
|   $Revision: 1.7.5$
|   $Date: 2000/05/28 16:56:52$
|   $Author: pb$
|
 ======================================================================"


"======================================================================
|
| Copyright 1988-92, 1994-95, 1999, 2000 Free Software Foundation, Inc.
| Written by Steve Byrne.
|
| This file is part of the GNU Smalltalk class library.
|
| The GNU Smalltalk class library is free software; you can redistribute it
| and/or modify it under the terms of the GNU Lesser General Public License
| as published by the Free Software Foundation; either version 2.1, or (at
| your option) any later version.
| 
| The GNU Smalltalk class library is distributed in the hope that it will be
| useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
| General Public License for more details.
| 
| You should have received a copy of the GNU Lesser General Public License
| along with the GNU Smalltalk class library; see the file COPYING.LESSER.
| If not, write to the Free Software Foundation, 59 Temple Place - Suite
| 330, Boston, MA 02111-1307, USA.  
|
 ======================================================================"



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

Collection comment: 
'I am an abstract class.  My instances are collections of objects.  My
subclasses may place some restrictions or add some definitions to how
the objects are stored or organized; I say nothing about this.  I merely
provide some object creation and access routines for general collections
of objects.' !



!Collection class methodsFor: 'instance creation'!

withAll: aCollection
    "Answer a collection whose elements are all those in aCollection"
    ^self new addAll: aCollection; yourself
!

with: anObject
    "Answer a collection whose only element is anObject"
    ^self new add: anObject; yourself
!

with: firstObject with: secondObject
    "Answer a collection whose only elements are the parameters in the order
     they were passed"
    ^self new add: firstObject; add: secondObject; yourself
!

with: firstObject with: secondObject with: thirdObject
    "Answer a collection whose only elements are the parameters in the order
     they were passed"
    ^self new add: firstObject; add: secondObject; add: thirdObject; yourself
!

with: firstObject with: secondObject with: thirdObject with: fourthObject
    "Answer a collection whose only elements are the parameters in the order
     they were passed"
    ^self new add: firstObject; add: secondObject; add: thirdObject;
    	add: fourthObject; yourself
! !



!Collection methodsFor: 'Adding to a collection'!

add: newObject
    "Add newObject to the receiver, answer it"
    self subclassResponsibility
!

addAll: aCollection
    "Adds all the elements of 'aCollection' to the receiver, answer
     aCollection"
    aCollection do: [ :element | self add: element ].
    ^aCollection
! !



!Collection methodsFor: 'Removing from a collection'!

remove: oldObject ifAbsent: anExceptionBlock
    "Remove oldObject from the receiver. If absent, evaluate anExceptionBlock
     and answer the result, else answer oldObject."

    self subclassResponsibility
!

remove: oldObject
    "Remove oldObject from the receiver. If absent, fail, else
     answer oldObject."

    ^self remove: oldObject
	 ifAbsent: [ self error: 'Object not found' ].
!

removeAll: aCollection
    "Remove each object in aCollection, answer aCollection, fail if some
     of them is absent. Warning: this could leave the collection in a
     semi-updated state."

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

removeAll: aCollection ifAbsent: aBlock
    "Remove each object in aCollection, answer aCollection; if some
     element is absent, pass it to aBlock."

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



!Collection methodsFor: 'testing collections'!

capacity
    "Answer how many elements the receiver can hold before having to grow."
    ^self basicSize
!

includes: anObject
    "Answer whether we include anObject"
    self do: [ :element | anObject = element ifTrue: [ ^true ] ].
    ^false
!

isEmpty
    "Answer whether we are (still) empty"
    ^self size == 0
!

notEmpty
    "Answer whether we include at least one object"
    ^self size > 0
!

occurrencesOf: anObject
    "Answer how many occurrences of anObject we include"
    | count |
    count := 0.
    self do: [ :element | anObject == element ifTrue: [ count := count + 1 ] ].
    ^count
!

size
    "Answer how many objects we include"
    | count |
    count := 0.
    self do: [ :element | count := count + 1].
    ^count
! !



!Collection methodsFor: 'enumerating the elements of a collection'!

anyOne
    "Answer an unspecified element of the collection. Example usage:
	^coll inject: coll anyOne into: [ :max :each |
	    max max: each ]

     to be used when you don't have a valid lowest-possible-value
     (which happens in common cases too, such as with arbitrary numbers"

    self do: [ :each | ^each ]
!

do: aBlock
    "Enumerate each object of the receiver, passing them to aBlock"
    self subclassResponsibility
!

do: aBlock separatedBy: separatorBlock
    "Enumerate each object of the receiver, passing them to aBlock.
     Between every two invocations of aBlock, invoke separatorBlock"
    | first |
    first := true.
    self do: [ :each |
	aBlock value: each.
	first
	    ifTrue: [ first := false ]
	    ifFalse: [ separatorBlock value ]
    ]
!

select: aBlock
    "Answer a new instance of a Collection containing all the elements
     in the receiver which, when passed to aBlock, answer true"

    | newCollection |
    newCollection := self copyEmpty.
    self do: [ :element | (aBlock value: element)
    	    	    	    ifTrue: [ newCollection add: element ]
	     ].
    ^newCollection
!

reject: aBlock
    "Answer a new instance of a Collection containing all the elements
     in the receiver which, when passed to aBlock, don't answer true"

    | newCollection |
    newCollection := self copyEmpty.
    self do: [ :element | (aBlock value: element)
    	    	    	    ifFalse: [ newCollection add: element ]
	     ].
    ^newCollection
!

collect: aBlock
    "Answer a new instance of a Collection containing all the results
     of evaluating aBlock passing each of the receiver's elements"

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

detect: aBlock ifNone: exceptionBlock
    "Search the receiver for an element for which aBlock returns true.
     If some does, answer it. If none does, answer the result of evaluating
     aBlock"

    self do: [ :element | (aBlock value: element) ifTrue: [ ^element ] ].
    ^exceptionBlock value    
!
    
allSatisfy: aBlock
    "Search the receiver for an element for which aBlock returns false.
     Answer true if none does, false otherwise."
    self do: [ :element | (aBlock value: element) ifFalse: [ ^false ] ].
    ^true
!

anySatisfy: aBlock
    "Search the receiver for an element for which aBlock returns true.
     Answer true if some does, false otherwise."
    self do: [ :element | (aBlock value: element) ifTrue: [ ^true ] ].
    ^false
!

conform: aBlock
    "Search the receiver for an element for which aBlock returns false.
     Answer true if none does, false otherwise."
    self do: [ :element | (aBlock value: element) ifFalse: [ ^false ] ].
    ^true
!

contains: aBlock
    "Search the receiver for an element for which aBlock returns true.
     Answer true if some does, false otherwise."
    self do: [ :element | (aBlock value: element) ifTrue: [ ^true ] ].
    ^false
!

detect: aBlock
    "Search the receiver for an element for which aBlock returns true.
     If some does, answer it. If none does, fail"
    ^self detect: aBlock
	  ifNone: [ ^self error: 'No item satisfies detect: condition']
!

inject: thisValue into: binaryBlock
    "Pass to binaryBlock receiver thisValue and the first element of the
     receiver; for each subsequent element, pass the result of the previous
     evaluation and an element. Answer the result of the last invocation."

    | result |
    result := thisValue.
    self do: [ :element |
	result := binaryBlock value: result value: element
    ].
    ^result
! !



!Collection methodsFor: 'converting'!

asArray
    "Answer an Array containing all the elements in the receiver"

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

asByteArray
    "Answer a ByteArray containing all the elements in the receiver"

    | anArray index |
    anArray := ByteArray new: self size.
    index := 1.
    self do: [ :element | anArray at: index put: element. index := index + 1 ].
    ^anArray
!

asBag
    "Answer a Bag containing all the elements in the receiver"

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

asSet
    "Answer a Set containing all the elements in the receiver with no
     duplicates"

    | aSet |
    aSet := Set new: self size * 2.
    self do: [ :element | aSet add: element ].
    ^aSet
!

asOrderedCollection
    "Answer an OrderedCollection containing all the elements in the receiver"
    | anOrderedCollection |
    anOrderedCollection := OrderedCollection new: self size * 2.
    self do: [ :element | anOrderedCollection add: element ].
    ^anOrderedCollection
!

asSortedCollection
    "Answer a SortedCollection containing all the elements in the receiver
     with the default sort block - [ :a :b | a <= b ]"

    ^self asSortedCollection: SortedCollection defaultSortBlock
!

asSortedCollection: aBlock
    "Answer a SortedCollection whose elements are the elements of the receiver,
     sorted according to the sort block aBlock"

    | sorted |
    (sorted := SortedCollection basicNew: self size + 10)
	setSortBlock: aBlock;
	firstIndex: 5 lastIndex: 4.

    self do: [ :elem | sorted basicAddLast: elem ].
    self size < 2 ifFalse: [ sorted sortFrom: 5 to: 4 + self size ].
    ^sorted
! !



!Collection methodsFor: 'copying Collections'!

copyReplacing: targetObject withObject: newObject
    "Copy replacing each object which is = to targetObject
     with newObject"

    ^self collect: [:each |
	each = targetObject ifFalse: [each] ifTrue: [newObject]
    ]
!

copyWith: newElement
    "Answer a copy of the receiver to which newElement is added"

    ^(self copyEmpty: self basicSize + 1)
       addAll: self;
       add: newElement;
       yourself
!

copyWithout: oldElement
    "Answer a copy of the receiver to which all occurrences of oldElement are
     removed"

    ^self reject: [ :element | element = oldElement ].
! !



!Collection methodsFor: 'private'!

copyEmpty
    "Private - Answer an empty copy of the receiver"
    ^self copyEmpty: self basicSize
!

copyEmpty: newSize
    "Private - Answer an empty copy of the receiver"
    ^self species new: newSize
!

copyEmptyForCollect
    "Answer an empty copy of the receiver, with the class answered by the
     collect: method."
    ^self copyEmpty
!

rehash
    "Private - Do nothing, present for consistency in protocol"
! !
    


!Collection methodsFor: 'printing'!

inspect
    "Print all the instance variables and objects in the receiver on the
     Transcript"

    | class instVars i |
    class := self class.
    instVars := class allInstVarNames.
    Transcript nextPutAll: 'An instance of '.
    class printNl.
    1 to: instVars size do:
    	[ :i | Transcript nextPutAll: '  ';
		   nextPutAll: (instVars at: i);
		   nextPutAll: ': '.
	       (self instVarAt: i)  printNl ].

    Transcript nextPutAll: '  contents: ['; nl.
    self do: [ :obj |
	Transcript 
	   nextPutAll: '    ';
	   print: obj;
	   nl
    ].
    Transcript nextPutAll: '  ]'; nl
!

printOn: aStream
    "Print a representation of the receiver on aStream"
    aStream nextPutAll: self classNameString.
    aStream nextPutAll: ' ('.
    self do:
    	[ :element | element printOn: aStream.
		     aStream space ].
    aStream nextPut: $)
! !



!Collection methodsFor: 'storing'!

storeOn: aStream
    "Store Smalltalk code compiling to the receiver on aStream"
    | noElements |
    aStream nextPut: $(.
    aStream nextPutAll: self classNameString.
    aStream nextPutAll: ' new'.
    noElements := true.
    self do:
    	[ :element | aStream nextPutAll: ' add: '.
    	    	     element storeOn: aStream.
		     aStream nextPut: $;.
		     noElements := false ].
    noElements ifFalse: [ aStream nextPutAll: ' yourself' ].
    aStream nextPut: $)
! !

