Uses of ::= in core.
[cslatevm.git] / src / core / stream-collections.slate
blobc293ab478f88b65e2ca9268a3d7c2ff17a2737ef
1 Collection traits define: #Stream &parents: {PositionableStream} &slots: {#collection}.
2 "Collection Streams allow accessing of and writing into Collections like any
3 other Stream terminal."
5 s@(Collection Stream traits) terminal [s collection].
7 s@(Collection Stream traits) contents
8 "Answer the Stream's contents, in the default case the collection itself."
10   s collection
13 s@(Collection Stream traits) close
14 "Closes the link between the Stream and the Collection and resets it,
15 returning the Collection."
17   result ::= s collection.
18   s collection := Nil.
19   s reset.
20   result
23 s@(Collection Stream traits) hasAnEnd
24 "All Collections are finite, so Streams over them have an end."
25 [True].
27 s@(Collection Stream traits) collectionType
28 [#{}].
30 streamBlock@(Method traits) writingInto: c@(Collection traits)
31 "Create a new WriteStream for the given collection and apply the block to it,
32 answering the contents once done."
34   stream ::= c writer.
35   streamBlock applyWith: stream.
36   stream contents
39 streamBlock@(Method traits) writingAs: c@(Collection traits) &capacity: capacity
40 "Create a new WriteStream for a new collection like the given one and apply the
41 block to it, answering the contents once done."
43   streamBlock writingInto: (c new &capacity: capacity)
46 streamBlock@(Method traits) writingAs: s@(ReadStream traits) &capacity: capacity
48   (streamBlock writingAs: s contents new &capacity: capacity) reader
51 Collection traits define: #ReadStream
52                   &parents: {Collection Stream. ReadStream}.
53 "The default kind of iterator, a slot on the shared traits of Collection."
55 ExtensibleCollection traits define: #WriteStream &parents: {WriteStream} &slots: {#collection}.
56 "A totally non-Positionable WriteStream variant which just maps the protocol
57 to Collection addition protocol."
59 ws@(ExtensibleCollection WriteStream traits) on: c
60 "Targets the collection."
62   ws collection := c.
63   ws
66 ws@(ExtensibleCollection WriteStream traits) contents
68   ws collection
71 ws@(ExtensibleCollection WriteStream traits) nextPut: obj
72 [ws collection add: obj].
74 ws@(ExtensibleCollection WriteStream traits) nextPutAll: c
75 [ws collection addAll: c].
77 ws@(ExtensibleCollection WriteStream traits) next: n putAll: seq startingAt: start
79   ws collection addAll: (seq sliceFrom: start)
82 ws@(ExtensibleCollection WriteStream traits) close
83 "Closes the link between the Stream and the Collection and resets it."
85   result ::= ws collection.
86   ws collection := Nil.
87   result
90 ws@(ExtensibleCollection WriteStream traits) hasAnEnd [True].
92 ws@(ExtensibleCollection WriteStream traits) isAtEnd
93 "This type of stream cannot write over the contents and is perpetually
94 `at the end' of the contents, adding new elements."
95 [True].
97 c@(Collection traits) iterator
98 "Syntactic sugar for getting a new ReadStream or ReadWriteStream over the
99 given Collection that respects the same type."
100 [c reader].
102 c@(Collection traits) reader
103 "Syntactic sugar for getting a new ReadStream onto the given Collection
104 that respects the same type."
105 [c ReadStream newOn: c].
107 c@(Collection traits) writer
108 "Syntactic sugar for getting a new WriteStream onto the given Collection
109 that respects the same type."
110 [c WriteStream newOn: c].
112 cols@(Collection traits) iterators
113 "Returns a Collection of ReadStreams on the those in the given one. The
114 argument collection cannot contain non-collections."
116   cols collect: #iterator `er into: Array
119 cols@(Sequence traits) allDo: block
120 "Apply a coordinated do: over all of the collections in the given one,
121 using iterators."
123   iterators ::= cols iterators.
124   args ::= Array newSizeOf: iterators.
125   [iterators anySatisfy: #isAtEnd `er]
126     whileFalse:
127       [iterators collect: #next `er into: args.
128        block applyTo: args].
131 x@(Collection traits) with: y@(Collection traits) do: block
132 [{x. y} allDo: block].
134 cols@(Sequence traits) allCollect: block into: result
135 "Uses allDo: to perform a collect: over the Sequence's Collections' elements,
136 using a stream in between."
137 [[| :result | cols allDo: [| *vals | result nextPut: (block applyTo: vals)]]
138   writingAs: result
141 cols@(Sequence traits) allCollect: block
142 "Perform allCollect:into: using the Sequence as the result template."
143 [cols allCollect: block into: cols].
145 cols@(Sequence traits) streamAllCollect: block
147   [(cols iterators collect: #next`er)
148      reader collect: [| *rest | block applyTo: rest]]
149     breakOn: Exhaustion
152 x@(Collection traits) with: y@(Collection traits) collect: block
153 [{x. y} allCollect: block].
155 cols@(Sequence traits) zip
156 "Uses allCollect: to gather all the collection's collections' elements into
157 one collection. In other words, zip means to turn a pair of lists into
158 a list of pairs (for general values of 'pair')."
159 [cols allCollect: [| *vals | vals]].
161 cols@(Sequence traits) unzip
162 "Transposes a sequence of collection into a collection of sequences of those
163 elements across them, using a collection of streams and running with:do:
164 across the collection-result mapping. In other words, unzip means to turn a
165 list of pairs into a pair of lists (for general values of 'pair')."
167   results ::= cols first collect: [| :_ | cols newSameSize writer].
168   cols do:
169     [| :col | col with: results do: [| :val :result | result nextPut: val]].
170   results collect: #contents `er
173 cols@(Sequence traits) allInject: start into: block
174 "Runs inject:into: across all the given collection's collections' elements."
175 [| result |
176   result := start.
177   cols allDo: [| *vals | result := block applyTo: (vals copyWith: result at: 0)].
178   result
181 source@(Root traits) streamInto: target
182 "Totally generic method for streaming the contents of one thing into another."
184   source reader >> target writer
187 source@(Root traits) streamFrom: target
189   target streamInto: source
192 cols@(Sequence traits) combinationsDo: block
193 "This performs a basic increment-with-carry across the iterators until
194 they are exhausted. The block is applied to all intermediate results."
195 [| position it |
196   ((iterators ::= cols iterators) anySatisfy: #isAtEnd `er)
197    ifTrue: [^ Nil].
198   values ::= iterators collect: #next `er .
199   block applyTo: values.
200   [position := iterators indexLast.
201    eachIterator := iterators at: position.
202    [eachIterator isAtEnd /\ [position > 0]]
203      whileTrue:
204        [eachIterator reset.
205         values at: position put: eachIterator next.
206         position -= 1.
207         eachIterator := iterators at: position].
208    eachIterator isAtEnd /\ [position isZero]
209      ifTrue:
210        [^ Nil]
211      ifFalse:
212        [values at: position put: eachIterator next].
213    block applyTo: values] loop
216 cols@(Sequence traits) combinationsCollect: block into: result
217 "Uses combinationsDo: to perform a collect: over all combinations of elements from the
218 Collections in the Sequence, using a stream in between."
219 [[| :result | cols combinationsDo: [| *vals | result nextPut: (block applyTo: vals)]]
220   writingAs: result
223 cols@(Sequence traits) combinationsCollect: block
224 "Perform combinationsCollect:into: using the Sequence as the result template."
225 [cols combinationsCollect: block into: cols].
227 cols@(Sequence traits) combinationsInject: start into: block
228 "Runs inject:into: across all the combinations of the given Sequence's Collections' elements."
229 [| result |
230   result := start.
231   cols combinationsDo: [| *vals | result := block applyTo: (vals copyWith: result at: 0)].
232   result
235 Set traits define: #ReadStream &parents: {Collection ReadStream} &slots: {
236   #collection -> Set new.
237   #position -> 0. "The number of elements passed so far."
238   #index -> 0. "The index into the Set's contents Array."
240 "Set ReadStreams are just Positionable- over the element order in the Set's
241 contents Array. They're not very efficient, having to check for Nil's."
243 i@(Set ReadStream traits) on: c
244 "Retargets to the new Set, and resets position, etc."
245 [i `>> [collection := c. position := 0. index := 0. ]].
247 i@(Set ReadStream traits) next
248 "Increment the index through the array until a non-Nil element is reached.
249 This is poor for sparse Sets."
251   (i collection contents indexOfFirstSatisfying: [| :x | x isNotNil] startingAt: i index)
252     ifNil: [i exhausted]
253     ifNotNilDo:
254       [| :nextIndex |
255        i index := nextIndex + 1.
256        i position := i position + 1.
257        i collection contents at: nextIndex]
260 i@(Set ReadStream traits) next: n putInto: seq startingAt: start
261 [| numRead nextIndex |
262   numRead := 0.
263   contents ::= i collection contents.
264   nextIndex := i index.
265   seqIndex := start.
266   [(nextIndex := contents indexOfFirstSatisfying: #isNotNil `er startingAt: i index) isNil] whileFalse:
267     [i index := nextIndex + 1.
268      i position += 1.
269      seq at: seqIndex put: (contents at: nextIndex).
270      numRead += 1.
271      seqIndex += 1].
272   numRead
275 i@(Set ReadStream traits) isAtEnd
276 "Checks both the Set size and then the underlying Array index, since a sparse
277 Set would reach the first before the second."
279   i position = i collection size \/ [i index = i collection contents indexLast]
282 Sequence traits define: #Stream &parents: {PositionableStream} &slots: {#collection -> ExtensibleArray new}.
283 "A Stream over a Sequence, where the position corresponds to the index within
284 the Sequence."
286 s@(Sequence Stream traits) on: c
287 "Target the stream to the specific collection, and reset the indices."
288 [s `>> [reset. collection := c. readLimit := c size. ]].
290 s@(Sequence Stream traits) contents
291 "Answer the contents of the target by copying, up to the limit."
293   s collection copyFrom: 0 below: s readLimit
296 s@(Sequence Stream traits) collectionType
297 [s collection].
299 s@(Sequence Stream traits) last
301   s collection at: s position
304 Sequence traits define: #ReadStream
305   &parents: {Sequence Stream. ReadStream}.
306 "A Stream used to read from a Sequence object."
308 s@(Stream traits) newFrom: obj
309 "A convenient method to override for creating new ReadStreams of the
310 appropriate type for a given type of object."
311 "NOTE: determine what overrides justify this since #reader is easier for nearly
312 all cases."
313 [obj ReadStream newOn: obj].
315 rs@(Sequence ReadStream traits) next
317   (pos ::= rs position) < rs readLimit
318     ifTrue:
319       [rs position := pos + 1.
320        rs collection at: pos]
321     ifFalse: [rs exhausted]
324 rs@(Sequence ReadStream traits) next: n
325 "Overridden for efficiency."
327   end ::= rs position + n min: rs readLimit.
328   result ::= rs collection copyFrom: rs position below: end.
329   rs position := end.
330   result
333 rs@(Sequence ReadStream traits) next: n putInto: c startingAt: start
335   max ::= rs readLimit - rs position min: n.
336   c replaceFrom: start to: start + max - 1 with: rs collection startingAt: rs position.
337   rs position += max.
338   max
341 rs@(Sequence ReadStream traits) peekAt: offset
343   rs collection at: rs position + offset
346 rs@(Sequence ReadStream traits) peek
347 [rs peekAt: 0].
349 rs@(Sequence ReadStream traits) peekBack
351   rs position isZero ifFalse: [rs position := rs position - 1. rs next]
354 rs@(Sequence ReadStream traits) nextPut: obj
355 "Sequence ReadStreams should not place elements into the stream."
356 [Nil].
358 rs@(Sequence ReadStream traits) size
359 "The limit is effectively the number of elements that can be collected."
361   rs readLimit
364 rs@(Sequence ReadStream traits) upTo: obj
365 "Answer all the elements until the given object is reached."
367   start ::= rs position.
368   end ::= rs collection indexOf: obj startingAt: start ifAbsent:
369     [rs position := rs collection size. ^ (rs collection copyFrom: start)].
370   rs position := end + 1.
371   rs collection copyFrom: start below: end
374 rs@(Sequence ReadStream traits) upToEnd
375 "Answer all the elements up to the limit by a copy."
377   start ::= rs position.
378   rs position := rs collection size.
379   rs collection copyFrom: start below: rs position
382 rs@(Sequence ReadStream traits) on: c from: start to: end
383 "Target the stream on a particular slice of a collection."
384 [rs `>> [collection := c. readLimit := end min: c size. position := start. ]].
386 Sequence traits define: #WriteStream
387                 &parents: {Sequence Stream. WriteStream}
388                 &slots: {#writeLimit}.
390 s@(Stream traits) newTo: obj@(Sequence traits) &position: position
391 [obj WriteStream newOn: obj &position: position].
393 seq@(Sequence traits) writer &position: position
394 [seq WriteStream newOn: seq &position: position].
396 seq@(Sequence traits) appender
397 [seq WriteStream newOn: seq &position: seq size].
399 ws@(Sequence WriteStream traits) newOn: c &position: position
400 [ws clone on: c &position: position].
402 ws@(Sequence WriteStream traits) on: c &position: position
404   resend.
405   ws writeLimit := c size.
406   position ifNotNil: [ws position := position].
407   ws
410 ws@(Sequence WriteStream traits) contents
412   ws readLimit := ws readLimit max: ws position.
413   ws collection copyFrom: 0 below: ws readLimit
416 ws@(Sequence WriteStream traits) next
417 [Nil].
419 ws@(Sequence WriteStream traits) growCollectionAtEnd &byAtLeast: minGrowth
421   c ::= ws collection.
422   newSize ::= c size + (c size min: 1000000 max: (minGrowth ifNil: [20])).
423   ws collection := c newSize: newSize.
424   ws collection replaceFrom: 0 to: c size - 1 with: c.
425   ws writeLimit := newSize.
428 ws@(Sequence WriteStream traits) pastEndPut: obj
430   ws growCollectionAtEnd.
431   ws collection at: ws position put: obj.
432   ws position := ws position + 1.
433   obj
436 ws@(Sequence WriteStream traits) nextPut: obj
438   (pos ::= ws position) >= ws writeLimit
439     ifTrue: [ws pastEndPut: obj]
440     ifFalse: [ws position := pos + 1.
441               ws collection at: pos put: obj]
444 ws@(Sequence WriteStream traits) next: n putAll: c startingAt: start
446   (newEnd ::= ws position + n - 1) >= ws writeLimit ifTrue:
447     [ws growCollectionAtEnd &byAtLeast: newEnd - ws writeLimit + 4].
448   ws collection replaceFrom: ws position to: newEnd with: c startingAt: start.
449   ws position := newEnd + 1.
450   n
453 ws@(Sequence WriteStream traits) size
455   ws readLimit := ws readLimit max: ws position
458 ws@(Sequence WriteStream traits) position: n
460   ws readLimit := ws readLimit max: n.
461   resend.
462   ws
465 ws@(Sequence WriteStream traits) newLine
466 "Output an appropriate newLine character."
467 "TODO: make this portable."
469   ws nextPut: $\n
472 ws@(Sequence WriteStream traits) atBeginningOfLine
473 "Returns whether the stream is writing at a point where a line ending has
474 just occurred."
475 "TODO: make this portable."
477   (ws collection at: ws position - 1) = $\n
480 ws@(Sequence WriteStream traits) freshLine
481 "Output a newLine character character if not currently at the end of a line."
483   ws atBeginningOfLine ifFalse: [ws newLine]
486 ws@(Sequence WriteStream traits) reset
488   ws readLimit := ws readLimit max: ws position.
489   ws position := 0.
490   ws
493 ws@(Sequence WriteStream traits) resetToStart
495   ws readLimit := ws position := 0.
496   ws
499 ws@(Sequence WriteStream traits) setToEnd
501   ws position := ws size.
502   ws
505 ws@(Sequence WriteStream traits) on: c from: start to: end
507   ws collection := c.
508   ws readLimit := ws writeLimit := end min: c size.
509   ws position := start.
510   ws
513 ws@(Sequence WriteStream traits) peekLast
515   ws position ifNotNil: [ws contents at: position]
518 ws@(Sequence WriteStream traits) with: c
520   ws collection := c.
521   ws position := ws readLimit := ws writeLimit := c size.
522   ws
525 Sequence traits define: #ReadWriteStream
526                 &parents: {Sequence WriteStream. Sequence ReadStream}.
528 rws@(Sequence traits) iterator
530   rws ReadWriteStream newOn: rws
533 rws@(Sequence ReadWriteStream traits) contents
535   rws readLimit := rws readLimit max: rws position.
536   rws collection copyFrom: 0 below: rws readLimit
539 rws@(Sequence ReadWriteStream traits) next
541   (pos ::= rws position) >= rws readLimit
542     ifTrue: [rws exhausted]
543     ifFalse: [rws position := pos + 1.
544               rws collection at: pos]
547 rws@(Sequence ReadWriteStream traits) next: n
549   rws readLimit := rws readLimit max: rws position.
550   end ::= rws position + n min: rws readLimit.
551   result ::= rws collection copyFrom: rws position below: end.
552   rws position := end.
553   result
556 rws@(Sequence ReadWriteStream traits) = rws2@(Sequence ReadWriteStream traits)
558   rws position = rws2 position /\ [rws contents = rws2 contents]
561 rws@(Sequence ReadWriteStream traits) hash
563   (rws isSameAs: Sequence ReadWriteStream) ifFalse: [^ resend].
564   (rws position + rws readLimit + 53) hash
567 ExtensibleSequence traits define: #WriteStream
568   &parents: {Sequence WriteStream}.
569 "A Stream used to write to a new or existing ExtensibleSequence."
571 ws@(ExtensibleSequence WriteStream traits) pastEndPut: obj
573   c ::= ws collection.
574   c addLast: obj.
575   ws writeLimit := c size.
576   ws position += 1.
577   obj
580 ws@(ExtensibleSequence WriteStream traits) next: n putAll: c startingAt: start
582   ws collection at: ws position insertAll: (c copyFrom: start below: start + n).
583   ws position += n.
584   n
587 ExtensibleSequence traits define: #ReadWriteStream
588   &parents: {ExtensibleSequence WriteStream. ExtensibleSequence ReadStream}.