2018-05-04 21:45:21 -07:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2018-05-04 21:57:32 -07:00
|
|
|
"container/heap"
|
2018-05-05 09:43:01 -07:00
|
|
|
"flag"
|
2018-05-04 21:45:21 -07:00
|
|
|
"fmt"
|
2018-05-05 09:43:01 -07:00
|
|
|
"math"
|
2018-05-04 21:45:21 -07:00
|
|
|
"math/rand"
|
2018-05-05 09:23:42 -07:00
|
|
|
"os"
|
2018-05-04 21:45:21 -07:00
|
|
|
"sort"
|
2018-05-05 09:23:42 -07:00
|
|
|
"strconv"
|
2018-05-04 21:45:21 -07:00
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
2018-05-05 09:23:42 -07:00
|
|
|
const usage = "smerge [count, count, ... count]"
|
|
|
|
|
2018-05-05 09:43:01 -07:00
|
|
|
var max = flag.Int("max", 1000, "maximum random number for each source")
|
|
|
|
|
2018-05-04 21:45:21 -07:00
|
|
|
func main() {
|
2018-05-05 09:43:01 -07:00
|
|
|
flag.Parse()
|
|
|
|
|
|
|
|
args := flag.Args()
|
2018-05-05 09:23:42 -07:00
|
|
|
if len(args) < 1 {
|
|
|
|
fmt.Fprintf(os.Stderr, "usage: %v\n", usage)
|
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
srcs := []<-chan int{}
|
|
|
|
for _, arg := range args {
|
|
|
|
i, err := strconv.Atoi(arg)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Fprintf(os.Stderr, "%v\n", err)
|
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
|
2018-05-05 09:43:01 -07:00
|
|
|
srcs = append(srcs, source(i, *max))
|
2018-05-05 09:23:42 -07:00
|
|
|
}
|
2018-05-05 09:43:01 -07:00
|
|
|
f := fmt.Sprintf("%%%dd\n", int(math.Log10(float64(*max))))
|
2018-05-05 09:23:42 -07:00
|
|
|
for i := range merge(srcs...) {
|
2018-05-05 09:43:01 -07:00
|
|
|
fmt.Printf(f, i)
|
2018-05-04 21:45:21 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-05 09:43:01 -07:00
|
|
|
func source(c, max int) <-chan int {
|
2018-05-04 21:45:21 -07:00
|
|
|
out := make(chan int)
|
|
|
|
go func() {
|
|
|
|
vals := make([]int, c)
|
|
|
|
src := rand.New(rand.NewSource(time.Now().UnixNano()))
|
|
|
|
for i := 0; i < c; i++ {
|
2018-05-05 09:43:01 -07:00
|
|
|
vals[i] = src.Intn(max)
|
2018-05-04 21:45:21 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
sort.Ints(vals)
|
|
|
|
|
|
|
|
for _, i := range vals {
|
|
|
|
out <- i
|
|
|
|
}
|
|
|
|
close(out)
|
|
|
|
}()
|
|
|
|
return out
|
|
|
|
}
|
|
|
|
|
|
|
|
func merge(cs ...<-chan int) <-chan int {
|
|
|
|
out := make(chan int)
|
|
|
|
|
2018-05-04 21:57:32 -07:00
|
|
|
go func() {
|
2018-05-05 09:32:00 -07:00
|
|
|
h := &items{}
|
2018-05-04 21:57:32 -07:00
|
|
|
heap.Init(h)
|
|
|
|
|
|
|
|
// prime the pumps
|
|
|
|
for i, src := range cs {
|
|
|
|
head, ok := <-src
|
|
|
|
if !ok {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
it := item{
|
|
|
|
val: head,
|
|
|
|
src: i,
|
|
|
|
}
|
|
|
|
heap.Push(h, it)
|
|
|
|
}
|
|
|
|
|
|
|
|
for h.Len() > 0 {
|
|
|
|
top := heap.Pop(h).(item)
|
|
|
|
out <- top.val
|
|
|
|
if head, ok := <-cs[top.src]; ok {
|
|
|
|
it := item{
|
|
|
|
val: head,
|
|
|
|
src: top.src,
|
|
|
|
}
|
|
|
|
heap.Push(h, it)
|
|
|
|
}
|
2018-05-04 21:45:21 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
close(out)
|
|
|
|
}()
|
|
|
|
return out
|
|
|
|
}
|
2018-05-04 21:57:32 -07:00
|
|
|
|
2018-05-05 09:32:00 -07:00
|
|
|
// item keeps track of an integer value and the index of its source.
|
|
|
|
//
|
|
|
|
// the index is used to chose the next source to use when a value has been
|
|
|
|
// pulled.
|
|
|
|
type item struct {
|
|
|
|
val int
|
|
|
|
src int
|
|
|
|
}
|
|
|
|
|
|
|
|
// items is a min-heap of item.
|
|
|
|
type items []item
|
2018-05-04 21:57:32 -07:00
|
|
|
|
2018-05-05 09:32:00 -07:00
|
|
|
func (h items) Len() int { return len(h) }
|
|
|
|
func (h items) Less(i, j int) bool { return h[i].val < h[j].val }
|
|
|
|
func (h items) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
|
2018-05-04 21:57:32 -07:00
|
|
|
|
2018-05-05 09:32:00 -07:00
|
|
|
func (h *items) Push(x interface{}) {
|
2018-05-04 21:57:32 -07:00
|
|
|
*h = append(*h, x.(item))
|
|
|
|
}
|
|
|
|
|
2018-05-05 09:32:00 -07:00
|
|
|
func (h *items) Pop() interface{} {
|
2018-05-04 21:57:32 -07:00
|
|
|
old := *h
|
|
|
|
n := len(old)
|
|
|
|
x := old[n-1]
|
|
|
|
*h = old[0 : n-1]
|
|
|
|
return x
|
|
|
|
}
|