SortedCollection.st
changeset 607 a9a526c51233
parent 530 07d0bce293c9
child 629 2ceefe9b5a19
equal deleted inserted replaced
606:7a9ab63a6757 607:a9a526c51233
    31  other person.  No title to or ownership of the software is
    31  other person.  No title to or ownership of the software is
    32  hereby transferred.
    32  hereby transferred.
    33 "
    33 "
    34 !
    34 !
    35 
    35 
    36 version
       
    37     ^ '$Header: /cvs/stx/stx/libbasic/SortedCollection.st,v 1.21 1995-11-11 15:27:30 cg Exp $'
       
    38 !
       
    39 
       
    40 documentation
    36 documentation
    41 "
    37 "
    42     I keep my elements sorted. The sort order is defined by a sortblock,
    38     I keep my elements sorted. The sort order is defined by a sortblock,
    43     a two-argument block which, when given two elements of the collection, 
    39     a two-argument block which, when given two elements of the collection, 
    44     should return true if the element given as first arg has to come before the 
    40     should return true if the element given as first arg has to come before the 
    46 
    42 
    47     Thus a sortBlock of [:a :b | a < b] defines ascending sort-order,
    43     Thus a sortBlock of [:a :b | a < b] defines ascending sort-order,
    48     while [:a :b | a > b] defines descening order.
    44     while [:a :b | a > b] defines descening order.
    49     The default sortBlock for SortedCollections is the first one.
    45     The default sortBlock for SortedCollections is the first one.
    50 "
    46 "
       
    47 !
       
    48 
       
    49 version
       
    50     ^ '$Header: /cvs/stx/stx/libbasic/SortedCollection.st,v 1.22 1995-11-23 01:20:20 cg Exp $'
    51 ! !
    51 ! !
    52 
    52 
    53 !SortedCollection class methodsFor:'initialization'!
    53 !SortedCollection class methodsFor:'initialization'!
    54 
    54 
    55 initialize
    55 initialize
    89      SortedCollection withAll:#(1 2 3 4 5 6 7 8 9 0)
    89      SortedCollection withAll:#(1 2 3 4 5 6 7 8 9 0)
    90 		      sortBlock:[:a :b | a > b] 
    90 		      sortBlock:[:a :b | a > b] 
    91     "
    91     "
    92 ! !
    92 ! !
    93 
    93 
    94 !SortedCollection methodsFor:'copying'!
       
    95 
       
    96 copyEmpty:size
       
    97     "return a copy of the receiver with no elements, but
       
    98      the same size. This method has been be redefined to
       
    99      preserve the sortBlock."
       
   100 
       
   101     ^ (self species new:size) sortBlock:sortBlock
       
   102 ! !
       
   103 
       
   104 !SortedCollection methodsFor:'adding & removing'!
    94 !SortedCollection methodsFor:'adding & removing'!
   105 
    95 
   106 addFirst:anObject
    96 add:anObject
   107     "catch this - its not allowed for sortedCollections"
    97     "add the argument, anObject at the proper place in the
   108 
    98      receiver. Returns the argument, anObject."
   109     self shouldNotImplement
    99 
   110 !
   100     |index|
   111 
   101 
   112 addLast:anObject
   102     lastIndex < firstIndex "i.e. self size == 0" ifTrue:[
   113     "catch this - its not allowed for sortedCollections"
   103 	super add:anObject
   114 
   104     ] ifFalse:[
   115     self shouldNotImplement
   105 	index := self indexForInserting:anObject. 
   116 !
   106 	self makeRoomAtIndex:index.
   117 
   107 	contentsArray at:index put:anObject
   118 at:index put:anObject
   108     ].
   119     "catch this - its not allowed for sortedCollections"
   109     ^ anObject
   120 
   110 
   121     self shouldNotImplement
   111     "
       
   112      |c| #(7 3 9 10 99) asSortedCollection add:5; yourself    
       
   113      #(7 3 9 10 99) asSortedCollection add:1; yourself        
       
   114      #(7 3 9 10 99) asSortedCollection add:1000; yourself     
       
   115     "
   122 !
   116 !
   123 
   117 
   124 add:newObject after:oldObject
   118 add:newObject after:oldObject
   125     "catch this - its not allowed for sortedCollections"
   119     "catch this - its not allowed for sortedCollections"
   126 
   120 
   173     "
   167     "
   174      #(7 3 9 10 99) asSortedCollection addAll:#(77 0 1 16 5) 
   168      #(7 3 9 10 99) asSortedCollection addAll:#(77 0 1 16 5) 
   175     "
   169     "
   176 !
   170 !
   177 
   171 
   178 add:anObject
   172 addFirst:anObject
   179     "add the argument, anObject at the proper place in the
   173     "catch this - its not allowed for sortedCollections"
   180      receiver. Returns the argument, anObject."
   174 
   181 
   175     self shouldNotImplement
   182     |index|
   176 !
   183 
   177 
   184     lastIndex < firstIndex "i.e. self size == 0" ifTrue:[
   178 addLast:anObject
   185 	super add:anObject
   179     "catch this - its not allowed for sortedCollections"
   186     ] ifFalse:[
   180 
   187 	index := self indexForInserting:anObject. 
   181     self shouldNotImplement
   188 	self makeRoomAtIndex:index.
   182 !
   189 	contentsArray at:index put:anObject
   183 
   190     ].
   184 at:index put:anObject
   191     ^ anObject
   185     "catch this - its not allowed for sortedCollections"
   192 
   186 
   193     "
   187     self shouldNotImplement
   194      |c| #(7 3 9 10 99) asSortedCollection add:5; yourself    
   188 ! !
   195      #(7 3 9 10 99) asSortedCollection add:1; yourself        
   189 
   196      #(7 3 9 10 99) asSortedCollection add:1000; yourself     
   190 !SortedCollection methodsFor:'converting'!
   197     "
   191 
       
   192 asSortedCollection
       
   193     "return the receiver as a sorted collection"
       
   194 
       
   195     "could be an instance of a subclass..."
       
   196     self class == SortedCollection ifTrue:[
       
   197 	^ self
       
   198     ].
       
   199     ^ super asSortedCollection
   198 ! !
   200 ! !
   199 
   201 
   200 !SortedCollection methodsFor:'copying'!
   202 !SortedCollection methodsFor:'copying'!
       
   203 
       
   204 copyEmpty:size
       
   205     "return a copy of the receiver with no elements, but
       
   206      the same size. This method has been be redefined to
       
   207      preserve the sortBlock."
       
   208 
       
   209     ^ (self species new:size) sortBlock:sortBlock
       
   210 !
   201 
   211 
   202 postCopyFrom:anOriginal
   212 postCopyFrom:anOriginal
   203     "sent after a copy or when a new collection species has been created.
   213     "sent after a copy or when a new collection species has been created.
   204      The new collection should have the same sortBlock as the original."
   214      The new collection should have the same sortBlock as the original."
   205 
   215 
   212      (#(4 7 1 99 -1 17) asSortedCollection sortBlock:[:a :b | a > b]) copy inspect
   222      (#(4 7 1 99 -1 17) asSortedCollection sortBlock:[:a :b | a > b]) copy inspect
   213      (#(4 7 1 99 -1 17) asSortedCollection select:[:e| e even]) inspect
   223      (#(4 7 1 99 -1 17) asSortedCollection select:[:e| e even]) inspect
   214     "
   224     "
   215 ! !
   225 ! !
   216 
   226 
   217 !SortedCollection methodsFor:'converting'!
       
   218 
       
   219 asSortedCollection
       
   220     "return the receiver as a sorted collection"
       
   221 
       
   222     "could be an instance of a subclass..."
       
   223     self class == SortedCollection ifTrue:[
       
   224 	^ self
       
   225     ].
       
   226     ^ super asSortedCollection
       
   227 ! !
       
   228 
       
   229 !SortedCollection methodsFor:'enumerating'!
   227 !SortedCollection methodsFor:'enumerating'!
   230 
   228 
   231 collect:aBlock
   229 collect:aBlock
   232     "evaluate the argument, aBlock for every element in the collection
   230     "evaluate the argument, aBlock for every element in the collection
   233      and return a collection of the results. Redefined to return an OrderedCollection;
   231      and return a collection of the results. Redefined to return an OrderedCollection;
   244 	newCollection add:(aBlock value:(contentsArray at:index)).
   242 	newCollection add:(aBlock value:(contentsArray at:index)).
   245     ].
   243     ].
   246     ^ newCollection
   244     ^ newCollection
   247 ! !
   245 ! !
   248 
   246 
   249 !SortedCollection methodsFor:'testing'!
       
   250 
       
   251 includes:anObject
       
   252     "return true, if the argument, anObject is in the collection.
       
   253      Redefined, since due to being sorted, the inclusion check can
       
   254      be done with log-n compares i.e. much faster."
       
   255 
       
   256     |index "{ Class: SmallInteger }"|
       
   257 
       
   258     index := self indexForInserting:anObject.
       
   259     ((index < firstIndex) or:[index > lastIndex]) ifTrue:[^ false].
       
   260     ^ (contentsArray at:index) = anObject
       
   261 
       
   262     "
       
   263      #(7 3 9 10 99) asSortedCollection includes:50
       
   264      #(7 3 9 10 99) asSortedCollection includes:10
       
   265     "
       
   266 !
       
   267 
       
   268 occurrencesOf:anObject
       
   269     "return how many times the argument, anObject is in the collection.
       
   270      Redefined, since due to being sorted, the range of checked objects
       
   271      can be limited i.e. it can be done much faster."
       
   272 
       
   273     |index      "{ Class: SmallInteger }"
       
   274      tally      "{ Class: SmallInteger }" |
       
   275 
       
   276     index := self indexForInserting:anObject.
       
   277     ((index < firstIndex) or:[index > lastIndex]) ifTrue:[^ 0].
       
   278 
       
   279     tally := 0.
       
   280     [(index <= lastIndex) and:[(contentsArray at:index) = anObject]] whileTrue:[
       
   281 	tally := tally + 1.
       
   282 	index := index + 1
       
   283     ].
       
   284     ^ tally
       
   285 
       
   286     "
       
   287      #(7 3 9 10 99) asSortedCollection occurrencesOf:50
       
   288      #(7 3 9 10 99) asSortedCollection occurrencesOf:10
       
   289      #(7 10 3 10 9 10 10 99) asSortedCollection occurrencesOf:10
       
   290     "
       
   291 ! !
       
   292 
       
   293 !SortedCollection methodsFor:'searching'!
       
   294 
       
   295 before:anObject
       
   296     "return the element before the argument, anObject; or nil if there is none.
       
   297      If the receiver does not contain anObject, report an error"
       
   298 
       
   299     ^ self before:anObject ifAbsent:[self errorValueNotFound:anObject]
       
   300 
       
   301     "
       
   302      #(7 3 9 10 99) asSortedCollection before:50
       
   303      #(7 3 9 10 99) asSortedCollection before:1 
       
   304      #(7 3 9 10 99) asSortedCollection before:1000 
       
   305      #(7 3 9 10 99) asSortedCollection before:10
       
   306      #(7 3 9 10 99) asSortedCollection before:7 
       
   307      #(7 3 9 10 99) asSortedCollection before:99 
       
   308      #(7 10 3 10 9 10 10 99) asSortedCollection before:9
       
   309      #(7 10 3 10 9 10 10 99) asSortedCollection before:10
       
   310     "
       
   311 !
       
   312 
       
   313 before:anObject ifAbsent:exceptionBlock
       
   314     "return the element before the argument, anObject; or nil if there is none.
       
   315      If the receiver does not contain anObject, return the result from evaluating
       
   316      exceptionBlock."
       
   317 
       
   318     |index      "{ Class: SmallInteger }"|
       
   319 
       
   320     index := self indexForInserting:anObject.
       
   321     ((index <= firstIndex) 
       
   322      or:[(contentsArray at:index) ~= anObject]) ifTrue:[^ exceptionBlock value].
       
   323 
       
   324     ^ contentsArray at:index - 1
       
   325 
       
   326     "
       
   327      #(7 3 9 10 99) asSortedCollection before:50
       
   328      #(7 3 9 10 99) asSortedCollection before:1 
       
   329      #(7 3 9 10 99) asSortedCollection before:10  
       
   330      #(7 3 9 10 99) asSortedCollection before:7   
       
   331      #(7 3 9 10 99) asSortedCollection before:99   
       
   332      #(7 10 3 10 9 10 10 99) asSortedCollection before:9  
       
   333      #(7 10 3 10 9 10 10 99) asSortedCollection before:10   
       
   334     "
       
   335 !
       
   336 
       
   337 after:anObject
       
   338     "return the element after the argument, anObject; or nil if there is none.
       
   339      If anObject is contained multiple times in the collection, return the
       
   340      the first element which is non-equal to anObject.
       
   341      If the receiver does not contain anObject, report an error"
       
   342 
       
   343     ^ self after:anObject ifAbsent:[self errorValueNotFound:anObject]
       
   344 
       
   345     "
       
   346      #(7 3 9 10 99) asSortedCollection after:50
       
   347      #(7 3 9 10 99) asSortedCollection after:1 
       
   348      #(7 3 9 10 99) asSortedCollection after:10
       
   349      #(7 3 9 10 99) asSortedCollection after:7 
       
   350      #(7 3 9 10 99) asSortedCollection after:99 
       
   351      #(7 10 3 10 9 10 10 99) asSortedCollection after:9  
       
   352      #(7 10 3 10 9 10 10 99) asSortedCollection after:10 
       
   353     "
       
   354 !
       
   355 
       
   356 after:anObject ifAbsent:exceptionBlock
       
   357     "return the element after the argument, anObject; or nil if there is none.
       
   358      If anObject is contained multiple times in the collection, return the
       
   359      the first element which is non-equal to anObject.
       
   360      If the receiver does not contain anObject, return the result from evaluating
       
   361      exceptionBlock."
       
   362 
       
   363     |index      "{ Class: SmallInteger }"|
       
   364 
       
   365     index := self indexForInserting:anObject.
       
   366     ((index < firstIndex) 
       
   367      or:[(contentsArray at:index) ~= anObject]) ifTrue:[^ exceptionBlock value].
       
   368 
       
   369     "skip multiple occurences of the same ..."
       
   370 
       
   371     [(index <= lastIndex) and:[(contentsArray at:index) = anObject]] whileTrue:[
       
   372 	index := index + 1
       
   373     ].
       
   374     (index > lastIndex) ifTrue:[^ nil].
       
   375     ^ contentsArray at:index
       
   376 ! !
       
   377 
       
   378 !SortedCollection methodsFor:'instance protocol'!
   247 !SortedCollection methodsFor:'instance protocol'!
   379 
   248 
   380 sortBlock
   249 sortBlock
   381     "return the block used for sorting"
   250     "return the block used for sorting"
   382 
   251 
   402      #($f $G $z $Y $o $H) asSortedCollection sortBlock:[:a : b | a asUppercase < b asUppercase]
   271      #($f $G $z $Y $o $H) asSortedCollection sortBlock:[:a : b | a asUppercase < b asUppercase]
   403     "
   272     "
   404 ! !
   273 ! !
   405 
   274 
   406 !SortedCollection methodsFor:'private'!
   275 !SortedCollection methodsFor:'private'!
   407 
       
   408 setSortBlock: aSortBlock
       
   409     "set the sortblock without resorting - private only"
       
   410 
       
   411     sortBlock := aSortBlock
       
   412 !
       
   413 
   276 
   414 indexForInserting:anObject
   277 indexForInserting:anObject
   415     "search the index at which to insert anObject. Can also be used
   278     "search the index at which to insert anObject. Can also be used
   416      to search for an existing element by checking if the element at
   279      to search for an existing element by checking if the element at
   417      the returned index is the one we look for.
   280      the returned index is the one we look for.
   443     "
   306     "
   444      #(1 2 3 4 7 99 1313 981989 898989898) asSortedCollection indexForInserting:50      
   307      #(1 2 3 4 7 99 1313 981989 898989898) asSortedCollection indexForInserting:50      
   445      #(1.0 2.0 3 4 7 49.0 51.0 99 1313 981989 898989898) asSortedCollection indexForInserting:50 
   308      #(1.0 2.0 3 4 7 49.0 51.0 99 1313 981989 898989898) asSortedCollection indexForInserting:50 
   446     "
   309     "
   447 
   310 
   448 ! !
   311 !
       
   312 
       
   313 setSortBlock: aSortBlock
       
   314     "set the sortblock without resorting - private only"
       
   315 
       
   316     sortBlock := aSortBlock
       
   317 ! !
       
   318 
       
   319 !SortedCollection methodsFor:'searching'!
       
   320 
       
   321 after:anObject
       
   322     "return the element after the argument, anObject; or nil if there is none.
       
   323      If anObject is contained multiple times in the collection, return the
       
   324      the first element which is non-equal to anObject.
       
   325      If the receiver does not contain anObject, report an error"
       
   326 
       
   327     ^ self after:anObject ifAbsent:[self errorValueNotFound:anObject]
       
   328 
       
   329     "
       
   330      #(7 3 9 10 99) asSortedCollection after:50
       
   331      #(7 3 9 10 99) asSortedCollection after:1 
       
   332      #(7 3 9 10 99) asSortedCollection after:10
       
   333      #(7 3 9 10 99) asSortedCollection after:7 
       
   334      #(7 3 9 10 99) asSortedCollection after:99 
       
   335      #(7 10 3 10 9 10 10 99) asSortedCollection after:9  
       
   336      #(7 10 3 10 9 10 10 99) asSortedCollection after:10 
       
   337     "
       
   338 !
       
   339 
       
   340 after:anObject ifAbsent:exceptionBlock
       
   341     "return the element after the argument, anObject; or nil if there is none.
       
   342      If anObject is contained multiple times in the collection, return the
       
   343      the first element which is non-equal to anObject.
       
   344      If the receiver does not contain anObject, return the result from evaluating
       
   345      exceptionBlock."
       
   346 
       
   347     |index      "{ Class: SmallInteger }"|
       
   348 
       
   349     index := self indexForInserting:anObject.
       
   350     ((index < firstIndex) 
       
   351      or:[(contentsArray at:index) ~= anObject]) ifTrue:[^ exceptionBlock value].
       
   352 
       
   353     "skip multiple occurences of the same ..."
       
   354 
       
   355     [(index <= lastIndex) and:[(contentsArray at:index) = anObject]] whileTrue:[
       
   356 	index := index + 1
       
   357     ].
       
   358     (index > lastIndex) ifTrue:[^ nil].
       
   359     ^ contentsArray at:index
       
   360 !
       
   361 
       
   362 before:anObject
       
   363     "return the element before the argument, anObject; or nil if there is none.
       
   364      If the receiver does not contain anObject, report an error"
       
   365 
       
   366     ^ self before:anObject ifAbsent:[self errorValueNotFound:anObject]
       
   367 
       
   368     "
       
   369      #(7 3 9 10 99) asSortedCollection before:50
       
   370      #(7 3 9 10 99) asSortedCollection before:1 
       
   371      #(7 3 9 10 99) asSortedCollection before:1000 
       
   372      #(7 3 9 10 99) asSortedCollection before:10
       
   373      #(7 3 9 10 99) asSortedCollection before:7 
       
   374      #(7 3 9 10 99) asSortedCollection before:99 
       
   375      #(7 10 3 10 9 10 10 99) asSortedCollection before:9
       
   376      #(7 10 3 10 9 10 10 99) asSortedCollection before:10
       
   377     "
       
   378 !
       
   379 
       
   380 before:anObject ifAbsent:exceptionBlock
       
   381     "return the element before the argument, anObject; or nil if there is none.
       
   382      If the receiver does not contain anObject, return the result from evaluating
       
   383      exceptionBlock."
       
   384 
       
   385     |index      "{ Class: SmallInteger }"|
       
   386 
       
   387     index := self indexForInserting:anObject.
       
   388     ((index <= firstIndex) 
       
   389      or:[(contentsArray at:index) ~= anObject]) ifTrue:[^ exceptionBlock value].
       
   390 
       
   391     ^ contentsArray at:index - 1
       
   392 
       
   393     "
       
   394      #(7 3 9 10 99) asSortedCollection before:50
       
   395      #(7 3 9 10 99) asSortedCollection before:1 
       
   396      #(7 3 9 10 99) asSortedCollection before:10  
       
   397      #(7 3 9 10 99) asSortedCollection before:7   
       
   398      #(7 3 9 10 99) asSortedCollection before:99   
       
   399      #(7 10 3 10 9 10 10 99) asSortedCollection before:9  
       
   400      #(7 10 3 10 9 10 10 99) asSortedCollection before:10   
       
   401     "
       
   402 ! !
       
   403 
       
   404 !SortedCollection methodsFor:'testing'!
       
   405 
       
   406 includes:anObject
       
   407     "return true, if the argument, anObject is in the collection.
       
   408      Redefined, since due to being sorted, the inclusion check can
       
   409      be done with log-n compares i.e. much faster."
       
   410 
       
   411     |index "{ Class: SmallInteger }"|
       
   412 
       
   413     index := self indexForInserting:anObject.
       
   414     ((index < firstIndex) or:[index > lastIndex]) ifTrue:[^ false].
       
   415     ^ (contentsArray at:index) = anObject
       
   416 
       
   417     "
       
   418      #(7 3 9 10 99) asSortedCollection includes:50
       
   419      #(7 3 9 10 99) asSortedCollection includes:10
       
   420     "
       
   421 !
       
   422 
       
   423 occurrencesOf:anObject
       
   424     "return how many times the argument, anObject is in the collection.
       
   425      Redefined, since due to being sorted, the range of checked objects
       
   426      can be limited i.e. it can be done much faster."
       
   427 
       
   428     |index      "{ Class: SmallInteger }"
       
   429      tally      "{ Class: SmallInteger }" |
       
   430 
       
   431     index := self indexForInserting:anObject.
       
   432     ((index < firstIndex) or:[index > lastIndex]) ifTrue:[^ 0].
       
   433 
       
   434     tally := 0.
       
   435     [(index <= lastIndex) and:[(contentsArray at:index) = anObject]] whileTrue:[
       
   436 	tally := tally + 1.
       
   437 	index := index + 1
       
   438     ].
       
   439     ^ tally
       
   440 
       
   441     "
       
   442      #(7 3 9 10 99) asSortedCollection occurrencesOf:50
       
   443      #(7 3 9 10 99) asSortedCollection occurrencesOf:10
       
   444      #(7 10 3 10 9 10 10 99) asSortedCollection occurrencesOf:10
       
   445     "
       
   446 ! !
       
   447 
       
   448 SortedCollection initialize!