235 c at:8. |
235 c at:8. |
236 c at:9. |
236 c at:9. |
237 c at:10. |
237 c at:10. |
238 " |
238 " |
239 |
239 |
240 "Modified: 10.5.1996 / 16:59:03 / cg" |
240 "Modified: 11.5.1996 / 13:33:50 / cg" |
241 ! |
241 ! |
242 |
242 |
243 at:index put:anObject |
243 at:index put:anObject |
244 "Put anObject at element index anInteger. |
244 "Put anObject at element index anInteger. |
245 at:put: can not be used to append, front or back, to an ordered |
245 at:put: can not be used to append, front or back, to an ordered |
246 collection; it is used by a knowledgeable client to replace an |
246 collection; it is used by a knowledgeable client to replace an |
247 element. It doesn't make a lot of sense for a compressed collection, |
247 element. |
248 and as you can see, the implementation is awful - still if you will |
248 This is a pretty dumb thing to do to a runArray and it is |
249 insist on using this what can you expect. Basically this just copies |
249 very inefficient, since we have to check if runs are to be merged or |
250 itself up to the start point then adds the required element then |
250 splitted." |
251 copies the rest of itself" |
|
252 |
251 |
253 |runSz runIndex runOffset len l1 l2 prevIdx nextIdx |
252 |runSz runIndex runOffset len l1 l2 prevIdx nextIdx |
254 val newRuns newValues prevLen prevVal nextLen nextVal idx| |
253 val newRuns newValues prevLen prevVal nextLen nextVal idx| |
255 |
254 |
256 runSz := runs size. |
255 runSz := contentsArray size. |
257 |
256 |
258 runIndex := nil. |
257 runIndex := nil. |
259 (index > 0) ifTrue:[ |
258 (index > 0) ifTrue:[ |
260 runOffset := 1. |
259 runOffset := 1. |
261 idx := 1. |
260 idx := 1. |
262 [runIndex isNil and:[idx < runSz]] whileTrue:[ |
261 [runIndex isNil and:[idx < runSz]] whileTrue:[ |
263 len := runs at:idx. |
262 len := contentsArray at:idx. |
264 nextIdx := runOffset + len. |
263 nextIdx := runOffset + len. |
265 index >= runOffset ifTrue:[ |
264 index >= runOffset ifTrue:[ |
266 index < nextIdx ifTrue:[ |
265 index < nextIdx ifTrue:[ |
267 runIndex := idx. |
266 runIndex := idx. |
268 nextIdx := runOffset. "/ dont advance |
267 nextIdx := runOffset. "/ dont advance |
274 ]. |
273 ]. |
275 runIndex isNil ifTrue:[ |
274 runIndex isNil ifTrue:[ |
276 ^ self errorInvalidKey:index |
275 ^ self errorInvalidKey:index |
277 ]. |
276 ]. |
278 |
277 |
279 val := runs at:(runIndex + 1). |
278 val := contentsArray at:(runIndex + 1). |
280 |
279 |
281 "/ easiest: value there is the same ... |
280 "/ easiest: value there is the same ... |
282 |
281 |
283 val = anObject ifTrue:[ |
282 val = anObject ifTrue:[ |
284 ^ anObject |
283 ^ anObject |
285 ]. |
284 ]. |
286 |
285 |
287 "/ if the length is 1, this is an island ... |
286 "/ if the length is 1, this is an island ... |
288 "/ ... which is either easy, or requires a merge. |
287 "/ ... which is either easy, or requires a merge. |
289 |
288 |
290 len := runs at:runIndex. |
289 len := contentsArray at:runIndex. |
291 len = 1 ifTrue:[ |
290 len = 1 ifTrue:[ |
292 "/ check if it can be merged into the next or previous run |
291 "/ check if it can be merged into the next or previous run |
293 |
292 |
294 runIndex > 1 ifTrue:[ |
293 runIndex > 1 ifTrue:[ |
295 prevIdx := runIndex - 2. |
294 prevIdx := runIndex - 2. |
296 prevVal := runs at:(prevIdx + 1). |
295 prevVal := contentsArray at:(prevIdx + 1). |
297 prevVal = anObject ifTrue:[ |
296 prevVal = anObject ifTrue:[ |
298 "/ can merge it into previous |
297 "/ can merge it into previous |
299 |
298 |
300 prevLen := runs at:prevIdx. |
299 prevLen := contentsArray at:prevIdx. |
301 |
300 |
302 "/ check if merge into next is also possible (filling an island) |
301 "/ check if merge into next is also possible (filling an island) |
303 |
302 |
304 runIndex < (runSz - 1) ifTrue:[ |
303 runIndex < (runSz - 1) ifTrue:[ |
305 nextIdx := runIndex + 2. |
304 nextIdx := runIndex + 2. |
306 nextVal := runs at:(nextIdx + 1). |
305 nextVal := contentsArray at:(nextIdx + 1). |
307 nextVal = anObject ifTrue:[ |
306 nextVal = anObject ifTrue:[ |
308 "/ can merge with both. |
307 "/ can merge with both. |
309 |
308 |
310 nextLen := runs at:nextIdx. |
309 nextLen := contentsArray at:nextIdx. |
311 |
310 |
312 runs at:prevIdx put:prevLen+nextLen+1. |
311 contentsArray at:prevIdx put:prevLen+nextLen+1. |
313 runSz := (runSz - 4). |
312 runSz := (runSz - 4). |
314 newRuns := Array new:runSz. |
313 newRuns := Array new:runSz. |
315 newRuns replaceFrom:1 to:(prevIdx + 1) with:runs startingAt:1. |
314 newRuns replaceFrom:1 to:(prevIdx + 1) with:contentsArray startingAt:1. |
316 newRuns replaceFrom:runIndex to:runSz with:runs startingAt:nextIdx+2. |
315 newRuns replaceFrom:runIndex to:runSz with:contentsArray startingAt:nextIdx+2. |
317 runs := newRuns. |
316 contentsArray := newRuns. |
318 ^ anObject |
317 ^ anObject |
319 ] |
318 ] |
320 ]. |
319 ]. |
321 |
320 |
322 runs at:prevIdx put:prevLen+1. |
321 contentsArray at:prevIdx put:prevLen+1. |
323 |
322 |
324 runSz := (runSz - 2). |
323 runSz := (runSz - 2). |
325 newRuns := Array new:runSz. |
324 newRuns := Array new:runSz. |
326 newRuns replaceFrom:1 to:(runIndex - 1) with:runs startingAt:1. |
325 newRuns replaceFrom:1 to:(runIndex - 1) with:contentsArray startingAt:1. |
327 newRuns replaceFrom:runIndex to:runSz with:runs startingAt:runIndex+2. |
326 newRuns replaceFrom:runIndex to:runSz with:contentsArray startingAt:runIndex+2. |
328 runs := newRuns. |
327 contentsArray := newRuns. |
329 |
328 |
330 ^ anObject |
329 ^ anObject |
331 ]. |
330 ]. |
332 ]. |
331 ]. |
333 |
332 |
334 "/ check if merge into next is possible |
333 "/ check if merge into next is possible |
335 |
334 |
336 runIndex < runSz ifTrue:[ |
335 runIndex < runSz ifTrue:[ |
337 nextIdx := runIndex + 2. |
336 nextIdx := runIndex + 2. |
338 nextVal := runs at:nextIdx+1. |
337 nextVal := contentsArray at:nextIdx+1. |
339 nextVal = anObject ifTrue:[ |
338 nextVal = anObject ifTrue:[ |
340 nextLen := runs at:nextIdx. |
339 nextLen := contentsArray at:nextIdx. |
341 runs at:nextIdx put:nextLen + 1. |
340 contentsArray at:nextIdx put:nextLen + 1. |
342 |
341 |
343 runSz := (runSz - 2). |
342 runSz := (runSz - 2). |
344 newRuns := Array new:runSz. |
343 newRuns := Array new:runSz. |
345 newRuns replaceFrom:1 to:(runIndex - 1) with:runs startingAt:1. |
344 newRuns replaceFrom:1 to:(runIndex - 1) with:contentsArray startingAt:1. |
346 newRuns replaceFrom:runIndex to:runSz with:runs startingAt:nextIdx. |
345 newRuns replaceFrom:runIndex to:runSz with:contentsArray startingAt:nextIdx. |
347 runs := newRuns. |
346 contentsArray := newRuns. |
348 ^ anObject |
347 ^ anObject |
349 ]. |
348 ]. |
350 ]. |
349 ]. |
351 |
350 |
352 "/ no merge; island remains |
351 "/ no merge; island remains |
353 |
352 |
354 runs at:(runIndex+1) put:anObject. |
353 contentsArray at:(runIndex+1) put:anObject. |
355 ^ anObject |
354 ^ anObject |
356 ]. |
355 ]. |
357 |
356 |
358 runOffset == index ifTrue:[ |
357 runOffset == index ifTrue:[ |
359 "/ at the beginning of that run ... |
358 "/ at the beginning of that run ... |
360 |
359 |
361 "/ check if its better added to the previous run ... |
360 "/ check if its better added to the previous run ... |
362 |
361 |
363 runIndex > 1 ifTrue:[ |
362 runIndex > 1 ifTrue:[ |
364 prevIdx := runIndex - 2. |
363 prevIdx := runIndex - 2. |
365 prevVal := runs at:prevIdx+1. |
364 prevVal := contentsArray at:prevIdx+1. |
366 prevVal = anObject ifTrue:[ |
365 prevVal = anObject ifTrue:[ |
367 prevLen := runs at:prevIdx. |
366 prevLen := contentsArray at:prevIdx. |
368 runs at:prevIdx put:prevLen + 1. |
367 contentsArray at:prevIdx put:prevLen + 1. |
369 runs at:runIndex put:len - 1. |
368 contentsArray at:runIndex put:len - 1. |
370 ^ anObject. |
369 ^ anObject. |
371 ]. |
370 ]. |
372 ]. |
371 ]. |
373 |
372 |
374 "/ must cut off 1 & insert a new run before .. |
373 "/ must cut off 1 & insert a new run before .. |
375 |
374 |
376 runs at:runIndex put:len - 1. |
375 contentsArray at:runIndex put:len - 1. |
377 |
376 |
378 runSz := (runSz + 2). |
377 runSz := (runSz + 2). |
379 newRuns := Array new:runSz. |
378 newRuns := Array new:runSz. |
380 newRuns replaceFrom:1 to:(runIndex - 1) with:runs startingAt:1. |
379 newRuns replaceFrom:1 to:(runIndex - 1) with:contentsArray startingAt:1. |
381 newRuns replaceFrom:runIndex+2 to:runSz with:runs startingAt:runIndex. |
380 newRuns replaceFrom:runIndex+2 to:runSz with:contentsArray startingAt:runIndex. |
382 runs := newRuns. |
381 contentsArray := newRuns. |
383 |
382 |
384 runs at:runIndex put:1. |
383 contentsArray at:runIndex put:1. |
385 runs at:runIndex+1 put:anObject. |
384 contentsArray at:runIndex+1 put:anObject. |
386 ^ anObject |
385 ^ anObject |
387 ]. |
386 ]. |
388 |
387 |
389 (runOffset + len - 1) == index ifTrue:[ |
388 (runOffset + len - 1) == index ifTrue:[ |
390 "/ at the end ... |
389 "/ at the end ... |
391 |
390 |
392 "/ check if its better added to the next run ... |
391 "/ check if its better added to the next run ... |
393 |
392 |
394 runIndex < runSz ifTrue:[ |
393 runIndex < runSz ifTrue:[ |
395 nextIdx := runIndex + 2. |
394 nextIdx := runIndex + 2. |
396 nextVal := runs at:nextIdx+1. |
395 nextVal := contentsArray at:nextIdx+1. |
397 nextVal = anObject ifTrue:[ |
396 nextVal = anObject ifTrue:[ |
398 nextLen := runs at:nextIdx. |
397 nextLen := contentsArray at:nextIdx. |
399 runs at:nextIdx put:nextLen + 1. |
398 contentsArray at:nextIdx put:nextLen + 1. |
400 runs at:runIndex put:len - 1. |
399 contentsArray at:runIndex put:len - 1. |
401 ^ anObject. |
400 ^ anObject. |
402 ]. |
401 ]. |
403 ]. |
402 ]. |
404 |
403 |
405 "/ must cut off 1 & insert a new run after .. |
404 "/ must cut off 1 & insert a new run after .. |
406 |
405 |
407 runs at:runIndex put:len - 1. |
406 contentsArray at:runIndex put:len - 1. |
408 |
407 |
409 runSz := (runSz + 2). |
408 runSz := (runSz + 2). |
410 newRuns := Array new:runSz. |
409 newRuns := Array new:runSz. |
411 newRuns replaceFrom:1 to:(runIndex + 1) with:runs startingAt:1. |
410 newRuns replaceFrom:1 to:(runIndex + 1) with:contentsArray startingAt:1. |
412 newRuns replaceFrom:runIndex+4 to:runSz with:runs startingAt:runIndex+2. |
411 newRuns replaceFrom:runIndex+4 to:runSz with:contentsArray startingAt:runIndex+2. |
413 runs := newRuns. |
412 contentsArray := newRuns. |
414 |
413 |
415 runs at:runIndex+2 put:1. |
414 contentsArray at:runIndex+2 put:1. |
416 runs at:runIndex+2+1 put:anObject. |
415 contentsArray at:runIndex+2+1 put:anObject. |
417 ^ anObject |
416 ^ anObject |
418 ]. |
417 ]. |
419 |
418 |
420 "/ hardest - split run into two, insert new run in-between |
419 "/ hardest - split run into two, insert new run in-between |
421 |
420 |
422 runSz := (runSz + 4). |
421 runSz := (runSz + 4). |
423 newRuns := Array new:runSz. |
422 newRuns := Array new:runSz. |
424 |
423 |
425 runIndex > 1 ifTrue:[ |
424 runIndex > 1 ifTrue:[ |
426 newRuns replaceFrom:1 to:runIndex-1 with:runs. |
425 newRuns replaceFrom:1 to:runIndex-1 with:contentsArray. |
427 ]. |
426 ]. |
428 newRuns replaceFrom:runIndex+6 to:(runSz+4) with:runs startingAt:runIndex+2. |
427 newRuns replaceFrom:runIndex+6 to:(runSz+4) with:contentsArray startingAt:runIndex+2. |
429 |
428 |
430 l2 := len - (index - runOffset). |
429 l2 := len - (index - runOffset). |
431 l1 := len - l2. |
430 l1 := len - l2. |
432 l2 := l2 - 1. |
431 l2 := l2 - 1. |
433 |
432 |
609 c grow:6; yourself. |
611 c grow:6; yourself. |
610 |
612 |
611 c grow:0; yourself. |
613 c grow:0; yourself. |
612 " |
614 " |
613 |
615 |
614 "Modified: 10.5.1996 / 18:11:54 / cg" |
616 "Modified: 11.5.1996 / 13:34:53 / cg" |
615 ! ! |
617 ! ! |
616 |
618 |
617 !RunArray methodsFor:'converting'! |
619 !RunArray methodsFor:'converting'! |
618 |
620 |
619 asOrderedCollection |
621 asOrderedCollection |
620 "Uncompress this collection." |
622 "return a new orderedCollection, containing the receivers elements." |
621 |
623 |
622 |newCollection| |
624 |newCollection| |
623 |
625 |
624 newCollection := OrderedCollection new. |
626 contentsArray isNil ifTrue:[^ OrderedCollection new]. |
625 newCollection addAll:self. |
627 |
|
628 newCollection := OrderedCollection new:(self size). |
|
629 contentsArray pairWiseDo:[:len :value | |
|
630 newCollection add:value withOccurrences:len |
|
631 ]. |
626 ^ newCollection |
632 ^ newCollection |
627 |
633 |
628 "Modified: 10.5.1996 / 13:31:49 / cg" |
634 " |
|
635 |r| |
|
636 |
|
637 r := RunArray withAll:#(1 2 3 3 3 3 4 4 4 5 6 7 7 7 7 7 7 7). |
|
638 Transcript showCr:r. |
|
639 Transcript showCr:r asOrderedCollection |
|
640 " |
|
641 |
|
642 "Modified: 11.5.1996 / 13:34:59 / cg" |
629 ! ! |
643 ! ! |
630 |
644 |
631 !RunArray methodsFor:'enumerating'! |
645 !RunArray methodsFor:'enumerating'! |
632 |
646 |
633 do:aBlock |
647 do:aBlock |
634 "Evaluate aBlock with each of the receiver's elements as the |
648 "Evaluate aBlock with each of the receiver's elements as the |
635 argument. " |
649 argument. " |
636 |
650 |
637 runs notNil ifTrue:[ |
651 contentsArray notNil ifTrue:[ |
638 runs pairWiseDo:[:len :val | |
652 contentsArray pairWiseDo:[:len :val | |
639 len timesRepeat: [aBlock value:val] |
653 len timesRepeat: [aBlock value:val] |
640 ] |
654 ] |
641 ] |
655 ] |
642 |
656 |
643 "Modified: 10.5.1996 / 16:56:01 / cg" |
657 "Modified: 11.5.1996 / 13:35:03 / cg" |
644 ! ! |
658 ! ! |
645 |
659 |
646 !RunArray methodsFor:'printing'! |
660 !RunArray methodsFor:'printing'! |
647 |
661 |
648 storeOn:aStream |
662 storeOn:aStream |
649 "Append to aStream an expression which, if evaluated, will generate |
663 "Append to aStream an expression which, if evaluated, will generate |
650 an object similar to the receiver." |
664 an object similar to the receiver." |
651 |
665 |
652 aStream nextPutAll: '(RunArray new'. |
666 aStream nextPutAll: '(RunArray new'. |
653 runs notNil ifTrue:[ |
667 contentsArray notNil ifTrue:[ |
654 runs pairWiseDo:[:len :val | |
668 contentsArray pairWiseDo:[:len :val | |
655 aStream nextPutAll: ' add:'; nextPutAll:val storeString. |
669 aStream nextPutAll: ' add:'; nextPutAll:val storeString. |
656 len == 1 ifFalse:[ |
670 len == 1 ifFalse:[ |
657 aStream nextPutAll:' withCount:'; nextPutAll:len printString. |
671 aStream nextPutAll:' withCount:'; nextPutAll:len printString. |
658 ]. |
672 ]. |
659 aStream nextPutAll:';' |
673 aStream nextPutAll:';' |
711 element of that value." |
727 element of that value." |
712 |
728 |
713 |position| |
729 |position| |
714 |
730 |
715 position := 1. |
731 position := 1. |
716 runs notNil ifTrue:[ |
732 contentsArray notNil ifTrue:[ |
717 runs pairWiseDo:[:len :val | |
733 contentsArray pairWiseDo:[:len :val | |
718 val = oldObject ifTrue:[ |
734 val = oldObject ifTrue:[ |
719 ^ position |
735 ^ position |
720 ]. |
736 ]. |
721 position := position + len. |
737 position := position + len. |
722 ]. |
738 ]. |
723 ]. |
739 ]. |
724 ^ exceptionBlock value |
740 ^ exceptionBlock value |
725 |
741 |
726 "Modified: 10.5.1996 / 13:54:25 / cg" |
742 "Modified: 11.5.1996 / 13:35:14 / cg" |
727 ! |
743 ! |
728 |
744 |
729 isEmpty |
745 isEmpty |
730 "Am I empty or not. Returns a boolean" |
746 "Am I empty or not. Returns a boolean" |
731 |
747 |
732 ^ runs notNil |
748 ^ contentsArray notNil |
|
749 |
|
750 "Modified: 11.5.1996 / 13:35:17 / cg" |
733 ! |
751 ! |
734 |
752 |
735 runIndexAndStartIndexForIndex:anIndex |
753 runIndexAndStartIndexForIndex:anIndex |
736 "given a logical index, find the index of that run and the logical index |
754 "given a logical index, find the index of that run and the logical index |
737 of the first item in that run." |
755 of the first item in that run." |
738 |
756 |
739 |position nRuns "{ Class: SmallInteger }"| |
757 |position nRuns "{ Class: SmallInteger }"| |
740 |
758 |
741 position := 1. |
759 position := 1. |
742 nRuns := runs size. |
760 nRuns := contentsArray size. |
743 1 to:nRuns by:2 do:[:runIndex | |
761 1 to:nRuns by:2 do:[:runIndex | |
744 |runLen runLast| |
762 |runLen runLast| |
745 |
763 |
746 runLen := runs at:runIndex. |
764 runLen := contentsArray at:runIndex. |
747 anIndex >= position ifTrue:[ |
765 anIndex >= position ifTrue:[ |
748 runLast := position + runLen - 1. |
766 runLast := position + runLen - 1. |
749 anIndex <= runLast ifTrue:[ |
767 anIndex <= runLast ifTrue:[ |
750 ^ Array with:runIndex with:position |
768 ^ Array with:runIndex with:position |
751 ]. |
769 ]. |