|
|
|
@ -49,19 +49,9 @@ type (
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// empty a empty Stream.
|
|
|
|
|
var empty Stream
|
|
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
|
// initial empty Stream.
|
|
|
|
|
source := make(chan interface{})
|
|
|
|
|
close(source)
|
|
|
|
|
empty.source = source
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Empty Returns a empty stream.
|
|
|
|
|
func Empty() Stream {
|
|
|
|
|
return empty
|
|
|
|
|
// Concat returns a concatenated Stream.
|
|
|
|
|
func Concat(s Stream, others ...Stream) Stream {
|
|
|
|
|
return s.Concat(others...)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// From constructs a Stream from the given GenerateFunc.
|
|
|
|
@ -94,21 +84,42 @@ func Range(source <-chan interface{}) Stream {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Concat Returns a concat Stream.
|
|
|
|
|
func Concat(a Stream, others ...Stream) Stream {
|
|
|
|
|
return a.Concat(others...)
|
|
|
|
|
// AllMach returns whether all elements of this stream match the provided predicate.
|
|
|
|
|
// May not evaluate the predicate on all elements if not necessary for determining the result.
|
|
|
|
|
// If the stream is empty then true is returned and the predicate is not evaluated.
|
|
|
|
|
func (s Stream) AllMach(predicate func(item interface{}) bool) bool {
|
|
|
|
|
for item := range s.source {
|
|
|
|
|
if !predicate(item) {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// AnyMach returns whether any elements of this stream match the provided predicate.
|
|
|
|
|
// May not evaluate the predicate on all elements if not necessary for determining the result.
|
|
|
|
|
// If the stream is empty then false is returned and the predicate is not evaluated.
|
|
|
|
|
func (s Stream) AnyMach(predicate func(item interface{}) bool) bool {
|
|
|
|
|
for item := range s.source {
|
|
|
|
|
if predicate(item) {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Buffer buffers the items into a queue with size n.
|
|
|
|
|
// It can balance the producer and the consumer if their processing throughput don't match.
|
|
|
|
|
func (p Stream) Buffer(n int) Stream {
|
|
|
|
|
func (s Stream) Buffer(n int) Stream {
|
|
|
|
|
if n < 0 {
|
|
|
|
|
n = 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
source := make(chan interface{}, n)
|
|
|
|
|
go func() {
|
|
|
|
|
for item := range p.source {
|
|
|
|
|
for item := range s.source {
|
|
|
|
|
source <- item
|
|
|
|
|
}
|
|
|
|
|
close(source)
|
|
|
|
@ -117,23 +128,51 @@ func (p Stream) Buffer(n int) Stream {
|
|
|
|
|
return Range(source)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Concat returns a Stream that concatenated other streams
|
|
|
|
|
func (s Stream) Concat(others ...Stream) Stream {
|
|
|
|
|
source := make(chan interface{})
|
|
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
|
group := threading.NewRoutineGroup()
|
|
|
|
|
group.Run(func() {
|
|
|
|
|
for item := range s.source {
|
|
|
|
|
source <- item
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
for _, each := range others {
|
|
|
|
|
each := each
|
|
|
|
|
group.Run(func() {
|
|
|
|
|
for item := range each.source {
|
|
|
|
|
source <- item
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
group.Wait()
|
|
|
|
|
close(source)
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
return Range(source)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Count counts the number of elements in the result.
|
|
|
|
|
func (p Stream) Count() (count int) {
|
|
|
|
|
for range p.source {
|
|
|
|
|
func (s Stream) Count() (count int) {
|
|
|
|
|
for range s.source {
|
|
|
|
|
count++
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Distinct removes the duplicated items base on the given KeyFunc.
|
|
|
|
|
func (p Stream) Distinct(fn KeyFunc) Stream {
|
|
|
|
|
func (s Stream) Distinct(fn KeyFunc) Stream {
|
|
|
|
|
source := make(chan interface{})
|
|
|
|
|
|
|
|
|
|
threading.GoSafe(func() {
|
|
|
|
|
defer close(source)
|
|
|
|
|
|
|
|
|
|
keys := make(map[interface{}]lang.PlaceholderType)
|
|
|
|
|
for item := range p.source {
|
|
|
|
|
for item := range s.source {
|
|
|
|
|
key := fn(item)
|
|
|
|
|
if _, ok := keys[key]; !ok {
|
|
|
|
|
source <- item
|
|
|
|
@ -146,14 +185,14 @@ func (p Stream) Distinct(fn KeyFunc) Stream {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Done waits all upstreaming operations to be done.
|
|
|
|
|
func (p Stream) Done() {
|
|
|
|
|
for range p.source {
|
|
|
|
|
func (s Stream) Done() {
|
|
|
|
|
for range s.source {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Filter filters the items by the given FilterFunc.
|
|
|
|
|
func (p Stream) Filter(fn FilterFunc, opts ...Option) Stream {
|
|
|
|
|
return p.Walk(func(item interface{}, pipe chan<- interface{}) {
|
|
|
|
|
func (s Stream) Filter(fn FilterFunc, opts ...Option) Stream {
|
|
|
|
|
return s.Walk(func(item interface{}, pipe chan<- interface{}) {
|
|
|
|
|
if fn(item) {
|
|
|
|
|
pipe <- item
|
|
|
|
|
}
|
|
|
|
@ -161,21 +200,21 @@ func (p Stream) Filter(fn FilterFunc, opts ...Option) Stream {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ForAll handles the streaming elements from the source and no later streams.
|
|
|
|
|
func (p Stream) ForAll(fn ForAllFunc) {
|
|
|
|
|
fn(p.source)
|
|
|
|
|
func (s Stream) ForAll(fn ForAllFunc) {
|
|
|
|
|
fn(s.source)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ForEach seals the Stream with the ForEachFunc on each item, no successive operations.
|
|
|
|
|
func (p Stream) ForEach(fn ForEachFunc) {
|
|
|
|
|
for item := range p.source {
|
|
|
|
|
func (s Stream) ForEach(fn ForEachFunc) {
|
|
|
|
|
for item := range s.source {
|
|
|
|
|
fn(item)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Group groups the elements into different groups based on their keys.
|
|
|
|
|
func (p Stream) Group(fn KeyFunc) Stream {
|
|
|
|
|
func (s Stream) Group(fn KeyFunc) Stream {
|
|
|
|
|
groups := make(map[interface{}][]interface{})
|
|
|
|
|
for item := range p.source {
|
|
|
|
|
for item := range s.source {
|
|
|
|
|
key := fn(item)
|
|
|
|
|
groups[key] = append(groups[key], item)
|
|
|
|
|
}
|
|
|
|
@ -192,7 +231,7 @@ func (p Stream) Group(fn KeyFunc) Stream {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Head returns the first n elements in p.
|
|
|
|
|
func (p Stream) Head(n int64) Stream {
|
|
|
|
|
func (s Stream) Head(n int64) Stream {
|
|
|
|
|
if n < 1 {
|
|
|
|
|
panic("n must be greater than 0")
|
|
|
|
|
}
|
|
|
|
@ -200,7 +239,7 @@ func (p Stream) Head(n int64) Stream {
|
|
|
|
|
source := make(chan interface{})
|
|
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
|
for item := range p.source {
|
|
|
|
|
for item := range s.source {
|
|
|
|
|
n--
|
|
|
|
|
if n >= 0 {
|
|
|
|
|
source <- item
|
|
|
|
@ -221,16 +260,16 @@ func (p Stream) Head(n int64) Stream {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Map converts each item to another corresponding item, which means it's a 1:1 model.
|
|
|
|
|
func (p Stream) Map(fn MapFunc, opts ...Option) Stream {
|
|
|
|
|
return p.Walk(func(item interface{}, pipe chan<- interface{}) {
|
|
|
|
|
func (s Stream) Map(fn MapFunc, opts ...Option) Stream {
|
|
|
|
|
return s.Walk(func(item interface{}, pipe chan<- interface{}) {
|
|
|
|
|
pipe <- fn(item)
|
|
|
|
|
}, opts...)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Merge merges all the items into a slice and generates a new stream.
|
|
|
|
|
func (p Stream) Merge() Stream {
|
|
|
|
|
func (s Stream) Merge() Stream {
|
|
|
|
|
var items []interface{}
|
|
|
|
|
for item := range p.source {
|
|
|
|
|
for item := range s.source {
|
|
|
|
|
items = append(items, item)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -242,21 +281,21 @@ func (p Stream) Merge() Stream {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Parallel applies the given ParallelFunc to each item concurrently with given number of workers.
|
|
|
|
|
func (p Stream) Parallel(fn ParallelFunc, opts ...Option) {
|
|
|
|
|
p.Walk(func(item interface{}, pipe chan<- interface{}) {
|
|
|
|
|
func (s Stream) Parallel(fn ParallelFunc, opts ...Option) {
|
|
|
|
|
s.Walk(func(item interface{}, pipe chan<- interface{}) {
|
|
|
|
|
fn(item)
|
|
|
|
|
}, opts...).Done()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Reduce is a utility method to let the caller deal with the underlying channel.
|
|
|
|
|
func (p Stream) Reduce(fn ReduceFunc) (interface{}, error) {
|
|
|
|
|
return fn(p.source)
|
|
|
|
|
func (s Stream) Reduce(fn ReduceFunc) (interface{}, error) {
|
|
|
|
|
return fn(s.source)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Reverse reverses the elements in the stream.
|
|
|
|
|
func (p Stream) Reverse() Stream {
|
|
|
|
|
func (s Stream) Reverse() Stream {
|
|
|
|
|
var items []interface{}
|
|
|
|
|
for item := range p.source {
|
|
|
|
|
for item := range s.source {
|
|
|
|
|
items = append(items, item)
|
|
|
|
|
}
|
|
|
|
|
// reverse, official method
|
|
|
|
@ -268,10 +307,36 @@ func (p Stream) Reverse() Stream {
|
|
|
|
|
return Just(items...)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Skip returns a Stream that skips size elements.
|
|
|
|
|
func (s Stream) Skip(n int64) Stream {
|
|
|
|
|
if n < 0 {
|
|
|
|
|
panic("n must not be negative")
|
|
|
|
|
}
|
|
|
|
|
if n == 0 {
|
|
|
|
|
return s
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
source := make(chan interface{})
|
|
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
|
for item := range s.source {
|
|
|
|
|
n--
|
|
|
|
|
if n >= 0 {
|
|
|
|
|
continue
|
|
|
|
|
} else {
|
|
|
|
|
source <- item
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
close(source)
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
return Range(source)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Sort sorts the items from the underlying source.
|
|
|
|
|
func (p Stream) Sort(less LessFunc) Stream {
|
|
|
|
|
func (s Stream) Sort(less LessFunc) Stream {
|
|
|
|
|
var items []interface{}
|
|
|
|
|
for item := range p.source {
|
|
|
|
|
for item := range s.source {
|
|
|
|
|
items = append(items, item)
|
|
|
|
|
}
|
|
|
|
|
sort.Slice(items, func(i, j int) bool {
|
|
|
|
@ -283,7 +348,7 @@ func (p Stream) Sort(less LessFunc) Stream {
|
|
|
|
|
|
|
|
|
|
// Split splits the elements into chunk with size up to n,
|
|
|
|
|
// might be less than n on tailing elements.
|
|
|
|
|
func (p Stream) Split(n int) Stream {
|
|
|
|
|
func (s Stream) Split(n int) Stream {
|
|
|
|
|
if n < 1 {
|
|
|
|
|
panic("n should be greater than 0")
|
|
|
|
|
}
|
|
|
|
@ -291,7 +356,7 @@ func (p Stream) Split(n int) Stream {
|
|
|
|
|
source := make(chan interface{})
|
|
|
|
|
go func() {
|
|
|
|
|
var chunk []interface{}
|
|
|
|
|
for item := range p.source {
|
|
|
|
|
for item := range s.source {
|
|
|
|
|
chunk = append(chunk, item)
|
|
|
|
|
if len(chunk) == n {
|
|
|
|
|
source <- chunk
|
|
|
|
@ -308,7 +373,7 @@ func (p Stream) Split(n int) Stream {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Tail returns the last n elements in p.
|
|
|
|
|
func (p Stream) Tail(n int64) Stream {
|
|
|
|
|
func (s Stream) Tail(n int64) Stream {
|
|
|
|
|
if n < 1 {
|
|
|
|
|
panic("n should be greater than 0")
|
|
|
|
|
}
|
|
|
|
@ -317,7 +382,7 @@ func (p Stream) Tail(n int64) Stream {
|
|
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
|
ring := collection.NewRing(int(n))
|
|
|
|
|
for item := range p.source {
|
|
|
|
|
for item := range s.source {
|
|
|
|
|
ring.Add(item)
|
|
|
|
|
}
|
|
|
|
|
for _, item := range ring.Take() {
|
|
|
|
@ -330,16 +395,16 @@ func (p Stream) Tail(n int64) Stream {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Walk lets the callers handle each item, the caller may write zero, one or more items base on the given item.
|
|
|
|
|
func (p Stream) Walk(fn WalkFunc, opts ...Option) Stream {
|
|
|
|
|
func (s Stream) Walk(fn WalkFunc, opts ...Option) Stream {
|
|
|
|
|
option := buildOptions(opts...)
|
|
|
|
|
if option.unlimitedWorkers {
|
|
|
|
|
return p.walkUnlimited(fn, option)
|
|
|
|
|
return s.walkUnlimited(fn, option)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return p.walkLimited(fn, option)
|
|
|
|
|
return s.walkLimited(fn, option)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p Stream) walkLimited(fn WalkFunc, option *rxOptions) Stream {
|
|
|
|
|
func (s Stream) walkLimited(fn WalkFunc, option *rxOptions) Stream {
|
|
|
|
|
pipe := make(chan interface{}, option.workers)
|
|
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
@ -348,7 +413,7 @@ func (p Stream) walkLimited(fn WalkFunc, option *rxOptions) Stream {
|
|
|
|
|
|
|
|
|
|
for {
|
|
|
|
|
pool <- lang.Placeholder
|
|
|
|
|
item, ok := <-p.source
|
|
|
|
|
item, ok := <-s.source
|
|
|
|
|
if !ok {
|
|
|
|
|
<-pool
|
|
|
|
|
break
|
|
|
|
@ -373,14 +438,14 @@ func (p Stream) walkLimited(fn WalkFunc, option *rxOptions) Stream {
|
|
|
|
|
return Range(pipe)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p Stream) walkUnlimited(fn WalkFunc, option *rxOptions) Stream {
|
|
|
|
|
func (s Stream) walkUnlimited(fn WalkFunc, option *rxOptions) Stream {
|
|
|
|
|
pipe := make(chan interface{}, defaultWorkers)
|
|
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
|
|
|
|
|
|
for {
|
|
|
|
|
item, ok := <-p.source
|
|
|
|
|
item, ok := <-s.source
|
|
|
|
|
if !ok {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
@ -400,93 +465,6 @@ func (p Stream) walkUnlimited(fn WalkFunc, option *rxOptions) Stream {
|
|
|
|
|
return Range(pipe)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// AnyMach Returns whether any elements of this stream match the provided predicate.
|
|
|
|
|
// May not evaluate the predicate on all elements if not necessary for determining the result.
|
|
|
|
|
// If the stream is empty then false is returned and the predicate is not evaluated.
|
|
|
|
|
func (p Stream) AnyMach(f func(item interface{}) bool) (isFind bool) {
|
|
|
|
|
for item := range p.source {
|
|
|
|
|
if f(item) {
|
|
|
|
|
isFind = true
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// AllMach Returns whether all elements of this stream match the provided predicate.
|
|
|
|
|
// May not evaluate the predicate on all elements if not necessary for determining the result.
|
|
|
|
|
// If the stream is empty then true is returned and the predicate is not evaluated.
|
|
|
|
|
func (p Stream) AllMach(f func(item interface{}) bool) (isFind bool) {
|
|
|
|
|
isFind = true
|
|
|
|
|
for item := range p.source {
|
|
|
|
|
if !f(item) {
|
|
|
|
|
isFind = false
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Concat Returns a Stream that concat others streams
|
|
|
|
|
func (p Stream) Concat(others ...Stream) Stream {
|
|
|
|
|
source := make(chan interface{})
|
|
|
|
|
wg := sync.WaitGroup{}
|
|
|
|
|
for _, other := range others {
|
|
|
|
|
if p == other {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
wg.Add(1)
|
|
|
|
|
go func(iother Stream) {
|
|
|
|
|
for item := range iother.source {
|
|
|
|
|
source <- item
|
|
|
|
|
}
|
|
|
|
|
wg.Done()
|
|
|
|
|
}(other)
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
wg.Add(1)
|
|
|
|
|
go func() {
|
|
|
|
|
for item := range p.source {
|
|
|
|
|
source <- item
|
|
|
|
|
}
|
|
|
|
|
wg.Done()
|
|
|
|
|
}()
|
|
|
|
|
go func() {
|
|
|
|
|
wg.Wait()
|
|
|
|
|
close(source)
|
|
|
|
|
}()
|
|
|
|
|
return Range(source)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Skip Returns a Stream that skips size elements.
|
|
|
|
|
func (p Stream) Skip(size int64) Stream {
|
|
|
|
|
if size == 0 {
|
|
|
|
|
return p
|
|
|
|
|
}
|
|
|
|
|
if size < 0 {
|
|
|
|
|
panic("size must be greater than -1")
|
|
|
|
|
}
|
|
|
|
|
source := make(chan interface{})
|
|
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
|
i := 0
|
|
|
|
|
for item := range p.source {
|
|
|
|
|
if i >= int(size) {
|
|
|
|
|
source <- item
|
|
|
|
|
}
|
|
|
|
|
i++
|
|
|
|
|
}
|
|
|
|
|
close(source)
|
|
|
|
|
}()
|
|
|
|
|
return Range(source)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Chan Returns a channel of Stream.
|
|
|
|
|
func (p Stream) Chan() <-chan interface{} {
|
|
|
|
|
return p.source
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// UnlimitedWorkers lets the caller to use as many workers as the tasks.
|
|
|
|
|
func UnlimitedWorkers() Option {
|
|
|
|
|
return func(opts *rxOptions) {
|
|
|
|
|