a bit of cleanup
[bills-tools.git] / seq / seq.go
blobe578449456726d3d220e6a7374d40201d1a61bdd
1 // Copyright 2010 Bill Burdick. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4 //
5 package seq
7 import "fmt"
8 import "io"
9 import "os"
10 import "container/vector"
12 type El interface{}
13 type Seq interface {
14 // core methods
15 While(f func(i El)bool)
16 Rest() Seq
17 Len() int
18 // wrappers that keep the current type
19 Append(s2 Seq) Seq
20 Prepend(s2 Seq) Seq
21 Filter(filter func(e El) bool) Seq
22 Map(f func(i El) El) Seq
23 FlatMap(f func(i El) Seq) Seq
26 //convert a sequence to a concurrent sequence
27 func Concurrent(s Seq) ConcurrentSeq {
28 switch seq := s.(type) {case ConcurrentSeq: return seq}
29 return Gen(func(c SeqChan){Output(s, c)})
32 //convert a sequence to a sequential sequence
33 func Sequential(s Seq) *SequentialSeq {
34 switch seq := s.(type) {case *SequentialSeq: return seq}
35 vec := make(vector.Vector, 0, 8)
36 Do(s, func(v El){vec.Push(v)})
37 return (*SequentialSeq)(&vec)
40 func FirstN(s Seq, n int) []interface{} {
41 r := make([]interface{}, n)
42 x := 0
43 While(s, func(el El)bool{
44 r[x] = el
45 x++
46 return x < n
48 return r
51 func First2(s Seq) (a, b interface{}) {
52 r := FirstN(s, 2)
53 return r[0], r[1]
56 func First3(s Seq) (a, b, c interface{}) {
57 r := FirstN(s, 3)
58 return r[0], r[1], r[2]
61 func First4(s Seq) (a, b, c, d interface{}) {
62 r := FirstN(s, 4)
63 return r[0], r[1], r[2], r[3]
66 func First5(s Seq) (a, b, c, d, e interface{}) {
67 r := FirstN(s, 5)
68 return r[0], r[1], r[2], r[3], r[4]
71 func First6(s Seq) (a, b, c, d, e, f interface{}) {
72 r := FirstN(s, 6)
73 return r[0], r[1], r[2], r[3], r[4], r[5]
76 func IsSeq(s interface{}) bool {
77 _, test := s.(Seq)
78 return test
81 func First(s Seq) interface{} {
82 var result interface{}
83 s.While(func(el El)bool{
84 result = el
85 return false
87 return result
90 func IsEmpty(s Seq) bool {
91 empty := true
92 s.While(func(el El)bool{
93 empty = false
94 return false
96 return empty
99 func While(s Seq, f func(el El) bool) {s.While(f)}
101 func Do(s Seq, f func(el El)) {
102 s.While(func(el El)bool{
103 f(el)
104 return true
108 func Len(s Seq) int {return s.Len()}
110 func Output(s Seq, c SeqChan) {
111 Do(s, func(el El){
112 c <- el
116 func Rest(s Seq) Seq {return s.Rest()}
118 func Append(s1 Seq, s2 Seq) Seq {return s1.Append(s2)}
120 func AppendToVector(s Seq, vec *vector.Vector) {
121 switch arg := s.(type) {
122 case *SequentialSeq: vec.AppendVector((*vector.Vector)(arg))
123 default: Do(s, func(el El){vec.Push(el)})
127 func SAppend(s Seq, s2 Seq) Seq {
128 vec := make(vector.Vector, 0, quickLen(s, 8) + quickLen(s2, 8))
129 AppendToVector(s, &vec)
130 AppendToVector(s2, &vec)
131 //print("SAppend ");Prettyln(s);print(" + ");Prettyln(s2);println(" = ");Prettyln((*SequentialSeq)(&vec))
132 return (*SequentialSeq)(&vec)
135 func CAppend(s Seq, s2 Seq) Seq {
136 return Gen(func(c SeqChan){
137 Output(s, c)
138 Output(s2, c)
142 func Prepend(s1 Seq, s2 Seq) Seq {return s1.Prepend(s2)}
144 func quickLen(s Seq, d int) int {
145 switch seq := s.(type) {case *SequentialSeq: return s.Len()}
146 return d
149 func Filter(s Seq, filter func(e El)bool) Seq {return s.Filter(filter)}
151 func SFilter(s Seq, filter func(e El)bool) Seq {
152 //continue shrinking
153 vec := make(vector.Vector, 0, quickLen(s, 8))
154 Do(s, func(el El){
155 if filter(el) {vec.Push(el)}
157 return (*SequentialSeq)(&vec)
160 func CFilter(s Seq, filter func(e El)bool) Seq {
161 return Gen(func(c SeqChan){
162 Do(s, func(el El){
163 if filter(el) {c <- el}
168 func Map(s Seq, f func(el El) El) Seq {return s.Map(f)}
170 func SMap(s Seq, f func(i El)El) Seq {
171 vec := make(vector.Vector, 0, quickLen(s, 8))
172 Do(s, func(el El){vec.Push(f(el))})
173 return (*SequentialSeq)(&vec)
176 type reply struct {
177 index int;
178 result El
181 type swEntry struct {
182 present boolean
183 value El
186 // SlidingWindow is a vector with limited capacity and a base
187 type SlidingWindow {
188 start, base, count int
189 values []swEntry
191 // NewSlidingWindow creates a new SlidingWindow with capacity size
192 func NewSlidingWindow(size int) *SlidingWindow {return &SlidingWindow{0, 0, 0, make([]swEntry, size)}}
193 func (r *SlidingWindow) Max() int {return r.base + r.Capacity()}
194 func (r *SlidingWindow) Capacity() int {return len(r.values)}
195 func (r *SlidingWindow) normalize(index int) int {return (index + r.Capacity()) % r.Capacity()}
196 func (r *SlidingWindow) IsEmpty() bool {return r.count == 0}
197 func (r *SlidingWindow) IsFull() bool {return r.count == r.Capacity()}
198 func (r *SlidingWindow) GetFirst() (interface{}, bool) {return r.values[r.start].value, r.values[r.start].present}
199 func (r *SlidingWindow) RemoveFirst() (interface{}, boolean) {
200 if count == 0 {return nil, false}
201 result := r.values[r.start]
202 r.values[r.start] = swEntry{false, nil}
203 if result.present {r.count--}
204 r.start = normalize(r.start++)
205 r.base++
206 return result.value, result.present
208 func (r *SlidingWindow) RemoveLast() (interface{}, boolean) {
209 if count == 0 {return nil, false}
210 end := r.normalize(r.start + r.Capacity() - 1)
211 result := r.values[end]
212 r.values[end] = swEntry{false, nil}
213 if result.present {r.count--}
214 if r.start > 0 {
215 r.start = normalize(r.start--)
216 r.base--
218 return result.value, result.present
220 func (r *SlidingWindow) Get(index int) (value interface{}, boolean) {
221 index = r.normalize(r.index - r.base + r.start)
222 if index < 0 || index >= r.Capacity() {return nil, false}
223 value = r.values[index]
224 return value.value, value.present
226 func (r *SlidingWindow) Set(index int, value interface{}) boolean {
227 index = r.normalize(r.index - r.base + r.start)
228 if index < 0 || index >= r.Capacity() {return false}
229 r.values[index].value = value
230 if !r.values[index].present {
231 r.values[index].present = true
232 r.count++
234 return true
237 // spawn a goroutine that does the following for each value, with up to size pending at a time:
238 // spawn a goroutine to apply f to the value and send the result back in a channel
239 // send the results in order to the ouput channel as they are completed
240 func CMap(s Seq, f func(el El) El, sizeOpt... int) Seq {
241 size := 64
242 if len(sizeOpt) > 0 {size = sizeOpt[0]}
243 return Gen(func(output SeqChan){
244 //punt and convert sequence to concurrent
245 //maybe someday we'll handle SequentialSequences separately
246 input := Concurrent(s)()
247 go func(){
248 window := NewSlidingWindow(size)
249 replyChannel := make(chan reply)
250 inputCount, pendingInput, pendingOutput := 0, 0, 0
251 inputClosed := false
252 for {
253 first, hasFirst := window.GetFirst()
254 ic, oc, rc := input, output, replyChannel
255 if !hasFirst {oc = nil}
256 if inputClosed || pendingInput >= size {ic = nil}
257 if pendingOutput >= size {rc = nil}
258 select {
259 case oc <- first:
260 window.RemoveFirst()
261 pendingOutput--
262 case inputMsg := <- ic:
263 if closed(ic) {
264 inputClosed = true
265 } else {
266 go func(index int, value interface{}) {
267 replyChannel <- reply{index, f(value)}
268 }(inputCount, v)
269 inputCount++
270 pendingInput++
272 case replyMsg := <- rc:
273 window.addLast(replyMsg)
274 pendingInput--
275 pendingOutput++
282 func FlatMap(s Seq, f func(el El) Seq) Seq {return s.FlatMap(f)}
284 func SFlatMap(s Seq, f func(i El) Seq) Seq {
285 vec := make(vector.Vector, 0, quickLen(s, 8))
286 Do(SMap(s, f), func(sub El){vec.Push(sub)})
287 return (*SequentialSeq)(&vec)
290 func CFlatMap(s Seq, f func(i El) Seq, sizeOpt... int) Seq {
291 return Gen(func(c SeqChan){
292 Do(CMap(s, f, sizeOpt), func(sub El){c <- sub})
296 func Fold(s Seq, init interface{}, f func(acc, el El)El) interface{} {
297 Do(s, func(el El){init = f(init, el)})
298 return init
301 //maybe convert this to use an accumulator instead of append?
302 func Combinations(s Seq, number int) Seq {
303 if number == 0 || IsEmpty(s) {return From(From())}
304 return Combinations(s.Rest(), number).Prepend(Combinations(s.Rest(), number - 1).Map(func(el El)El{
305 return el.(Seq).Prepend(From(First(s)))
309 //returns the product of the Seqs contained in sequences
310 func Product(sequences Seq) Seq {
311 return Fold(sequences, From(From()), func(result, each El)El{
312 //fmt.Print("folding: ");Pretty(each);fmt.Print(" into ");Prettyln(result)
313 return result.(Seq).FlatMap(func(seq El)Seq{
314 //fmt.Print("flat map with: ");Prettyln(seq)
315 return each.(Seq).Map(func(i El) El {
316 //fmt.Print("map with: ");Prettyln(i)
317 return seq.(Seq).Append(From(i))
320 }).(Seq)
323 func Prettyln(s interface{}, rest... interface{}) {
324 writer := Pretty(s, rest...)
325 fmt.Fprintln(writer)
327 func Pretty(s interface{}, args... interface{}) io.Writer {
328 var writer io.Writer = os.Stdout
329 var names map[interface{}]string
330 for i := 0; i < len(args); i++ {
331 switch arg := args[i].(type) {
332 case map[interface{}]string: names = arg
333 case io.Writer: writer = arg
336 if names == nil {names = map[interface{}]string{}}
337 prettyLevel(s, 0, names, writer)
338 return writer
341 //This is pretty ugly :)
342 func prettyLevel(s interface{}, level int, names map[interface{}]string, w io.Writer) {
343 name, hasName := names[s]
344 if hasName {
345 fmt.Fprint(w, name)
346 } else switch arg := s.(type) {
347 case Seq:
348 fmt.Fprintf(w, "%*s%s", level, "", "[")
349 first := true
350 innerSeq := false
351 named := false
352 Do(arg, func(v El) {
353 _, named = names[v]
354 _,innerSeq = v.(Seq)
355 if first {
356 first = false
357 if !named && innerSeq {
358 fmt.Fprintln(w)
360 } else if !named && innerSeq {
361 fmt.Fprintln(w, ",")
362 } else {
363 fmt.Fprint(w, ", ")
365 if innerSeq {
366 prettyLevel(v.(Seq), level + 4, names, w)
367 } else {
368 fmt.Fprintf(w, "%v", v)
371 if innerSeq {
372 if !named {
373 fmt.Fprintf(w, "\n%*s", level, "")
376 fmt.Fprintf(w, "]")
377 default:
378 fmt.Print(arg)
382 //ConcurrentSeq
384 type SeqChan chan interface{}
386 type ConcurrentSeq func()SeqChan
388 // f must behave properly when the channel is closed, so that IsEmpty and First work properly
389 func Gen(f func(c SeqChan)) ConcurrentSeq {
390 return func() SeqChan {
391 c := make(SeqChan)
392 go func() {
393 defer close(c)
394 f(c)
396 return c
400 func CUpto(limit int) ConcurrentSeq {
401 return Gen(func(c SeqChan) {
402 for i := 0; i < limit; i++ {
403 c <- i
408 func (s ConcurrentSeq) While(f func(el El)bool) {
409 c := s()
410 defer close(c)
411 for el := <- c; !closed(c) && f(el); el = <- c {}
414 func (s ConcurrentSeq) Rest() Seq {
415 return ConcurrentSeq(func()SeqChan{
416 c := s()
417 <- c
418 return c
422 func (s ConcurrentSeq) Len() int {
423 len := 0
424 Do(s, func(el El){
425 len++
427 return len
430 func (s ConcurrentSeq) Append(s2 Seq) Seq {return CAppend(s, s2)}
432 func (s ConcurrentSeq) Prepend(s2 Seq) Seq {return CAppend(s2, s)}
434 func (s ConcurrentSeq) Filter(f func(e El)bool) Seq {return CFilter(s, f)}
436 func (s ConcurrentSeq) Map(f func(i El)El) Seq {return CMap(s, f)}
438 func (s ConcurrentSeq) FlatMap(f func(i El) Seq) Seq {return CFlatMap(s, f)}
440 func toSequentialSeq(el interface{}) interface{} {
441 switch seq := el.(type) {
442 case ConcurrentSeq: return seq.ToSequentialSeq()
443 case []interface{}:
444 cpy := make([]interface{}, len(seq))
445 copy(cpy, seq)
446 return cpy
448 return el
451 func (s ConcurrentSeq) ToSequentialSeq() *SequentialSeq {
452 vec := make(vector.Vector, 0, 8)
453 Do(s, func(v El){vec.Push(toSequentialSeq(v))})
454 return (*SequentialSeq)(&vec)
458 // SequentialSeq
460 type SequentialSeq []interface{}
462 func From(els... interface{}) *SequentialSeq {return (*SequentialSeq)(&els)}
464 func AUpto(limit int) *SequentialSeq {
465 a := make([]interface{}, limit)
466 for i := 0; i < limit; i++ {
467 a[i] = i
469 return (*SequentialSeq)(&a)
472 func (s *SequentialSeq) While(f func(el El)bool) {
473 for i := 0; i < len(*s) && f((*s)[i]); i++ {}
476 func (s *SequentialSeq) Rest() Seq {
477 s2 := (*s)[1:]
478 return (*SequentialSeq)(&s2)
481 func (s *SequentialSeq) Len() int {return len(*s)}
483 func (s *SequentialSeq) Append(s2 Seq) Seq {return SAppend(s, s2)}
485 func (s *SequentialSeq) Prepend(s2 Seq) Seq {return SAppend(s2, s)}
487 func (s *SequentialSeq) Filter(f func(e El)bool) Seq {return SFilter(s, f)}
489 func (s *SequentialSeq) Map(f func(i El)El) Seq {return SMap(s, f)}
491 func (s *SequentialSeq) FlatMap(f func(i El) Seq) Seq {return SFlatMap(s, f)}