// Generated by tmpl // https://github.com/benbjohnson/tmpl // // DO NOT EDIT! // Source: array_cursor.gen.go.tmpl package reads import ( "errors" "fmt" "math" "github.com/influxdata/flux/interval" "github.com/influxdata/flux/values" errors2 "github.com/influxdata/influxdb/v2/kit/platform/errors" "github.com/influxdata/influxdb/v2/tsdb/cursors" ) const ( // MaxPointsPerBlock is the maximum number of points in an encoded // block in a TSM file. It should match the value in the tsm1 // package, but we don't want to import it. MaxPointsPerBlock = 1000 ) func newLimitArrayCursor(cur cursors.Cursor) cursors.Cursor { switch cur := cur.(type) { case cursors.FloatArrayCursor: return newFloatLimitArrayCursor(cur) case cursors.IntegerArrayCursor: return newIntegerLimitArrayCursor(cur) case cursors.UnsignedArrayCursor: return newUnsignedLimitArrayCursor(cur) case cursors.StringArrayCursor: return newStringLimitArrayCursor(cur) case cursors.BooleanArrayCursor: return newBooleanLimitArrayCursor(cur) default: panic(fmt.Sprintf("unreachable: %T", cur)) } } func newWindowFirstArrayCursor(cur cursors.Cursor, window interval.Window) cursors.Cursor { if window.IsZero() { return newLimitArrayCursor(cur) } switch cur := cur.(type) { case cursors.FloatArrayCursor: return newFloatWindowFirstArrayCursor(cur, window) case cursors.IntegerArrayCursor: return newIntegerWindowFirstArrayCursor(cur, window) case cursors.UnsignedArrayCursor: return newUnsignedWindowFirstArrayCursor(cur, window) case cursors.StringArrayCursor: return newStringWindowFirstArrayCursor(cur, window) case cursors.BooleanArrayCursor: return newBooleanWindowFirstArrayCursor(cur, window) default: panic(fmt.Sprintf("unreachable: %T", cur)) } } func newWindowLastArrayCursor(cur cursors.Cursor, window interval.Window) cursors.Cursor { if window.IsZero() { return newLimitArrayCursor(cur) } switch cur := cur.(type) { case cursors.FloatArrayCursor: return newFloatWindowLastArrayCursor(cur, window) case cursors.IntegerArrayCursor: return newIntegerWindowLastArrayCursor(cur, window) case cursors.UnsignedArrayCursor: return newUnsignedWindowLastArrayCursor(cur, window) case cursors.StringArrayCursor: return newStringWindowLastArrayCursor(cur, window) case cursors.BooleanArrayCursor: return newBooleanWindowLastArrayCursor(cur, window) default: panic(fmt.Sprintf("unreachable: %T", cur)) } } func newWindowCountArrayCursor(cur cursors.Cursor, window interval.Window) cursors.Cursor { switch cur := cur.(type) { case cursors.FloatArrayCursor: return newFloatWindowCountArrayCursor(cur, window) case cursors.IntegerArrayCursor: return newIntegerWindowCountArrayCursor(cur, window) case cursors.UnsignedArrayCursor: return newUnsignedWindowCountArrayCursor(cur, window) case cursors.StringArrayCursor: return newStringWindowCountArrayCursor(cur, window) case cursors.BooleanArrayCursor: return newBooleanWindowCountArrayCursor(cur, window) default: panic(fmt.Sprintf("unreachable: %T", cur)) } } func newWindowSumArrayCursor(cur cursors.Cursor, window interval.Window) (cursors.Cursor, error) { switch cur := cur.(type) { case cursors.FloatArrayCursor: return newFloatWindowSumArrayCursor(cur, window), nil case cursors.IntegerArrayCursor: return newIntegerWindowSumArrayCursor(cur, window), nil case cursors.UnsignedArrayCursor: return newUnsignedWindowSumArrayCursor(cur, window), nil default: return nil, &errors2.Error{ Code: errors2.EInvalid, Msg: fmt.Sprintf("unsupported input type for sum aggregate: %s", arrayCursorType(cur)), } } } func newWindowMinArrayCursor(cur cursors.Cursor, window interval.Window) cursors.Cursor { switch cur := cur.(type) { case cursors.FloatArrayCursor: return newFloatWindowMinArrayCursor(cur, window) case cursors.IntegerArrayCursor: return newIntegerWindowMinArrayCursor(cur, window) case cursors.UnsignedArrayCursor: return newUnsignedWindowMinArrayCursor(cur, window) default: panic(fmt.Sprintf("unsupported for aggregate min: %T", cur)) } } func newWindowMaxArrayCursor(cur cursors.Cursor, window interval.Window) cursors.Cursor { switch cur := cur.(type) { case cursors.FloatArrayCursor: return newFloatWindowMaxArrayCursor(cur, window) case cursors.IntegerArrayCursor: return newIntegerWindowMaxArrayCursor(cur, window) case cursors.UnsignedArrayCursor: return newUnsignedWindowMaxArrayCursor(cur, window) default: panic(fmt.Sprintf("unsupported for aggregate max: %T", cur)) } } func newWindowMeanArrayCursor(cur cursors.Cursor, window interval.Window) (cursors.Cursor, error) { switch cur := cur.(type) { case cursors.FloatArrayCursor: return newFloatWindowMeanArrayCursor(cur, window), nil case cursors.IntegerArrayCursor: return newIntegerWindowMeanArrayCursor(cur, window), nil case cursors.UnsignedArrayCursor: return newUnsignedWindowMeanArrayCursor(cur, window), nil default: return nil, &errors2.Error{ Code: errors2.EInvalid, Msg: fmt.Sprintf("unsupported input type for mean aggregate: %s", arrayCursorType(cur)), } } } // ******************** // Float Array Cursor type floatArrayFilterCursor struct { cursors.FloatArrayCursor cond expression m *singleValue res *cursors.FloatArray tmp *cursors.FloatArray } func newFloatFilterArrayCursor(cond expression) *floatArrayFilterCursor { return &floatArrayFilterCursor{ cond: cond, m: &singleValue{}, res: cursors.NewFloatArrayLen(MaxPointsPerBlock), tmp: &cursors.FloatArray{}, } } func (c *floatArrayFilterCursor) reset(cur cursors.FloatArrayCursor) { c.FloatArrayCursor = cur c.tmp.Timestamps, c.tmp.Values = nil, nil } func (c *floatArrayFilterCursor) Stats() cursors.CursorStats { return c.FloatArrayCursor.Stats() } func (c *floatArrayFilterCursor) Next() *cursors.FloatArray { pos := 0 c.res.Timestamps = c.res.Timestamps[:cap(c.res.Timestamps)] c.res.Values = c.res.Values[:cap(c.res.Values)] var a *cursors.FloatArray if c.tmp.Len() > 0 { a = c.tmp } else { a = c.FloatArrayCursor.Next() } LOOP: for len(a.Timestamps) > 0 { for i, v := range a.Values { c.m.v = v if c.cond.EvalBool(c.m) { c.res.Timestamps[pos] = a.Timestamps[i] c.res.Values[pos] = v pos++ if pos >= MaxPointsPerBlock { c.tmp.Timestamps = a.Timestamps[i+1:] c.tmp.Values = a.Values[i+1:] break LOOP } } } // Clear buffered timestamps & values if we make it through a cursor. // The break above will skip this if a cursor is partially read. c.tmp.Timestamps = nil c.tmp.Values = nil a = c.FloatArrayCursor.Next() } c.res.Timestamps = c.res.Timestamps[:pos] c.res.Values = c.res.Values[:pos] return c.res } type floatMultiShardArrayCursor struct { cursors.FloatArrayCursor cursorContext filter *floatArrayFilterCursor } func (c *floatMultiShardArrayCursor) reset(cur cursors.FloatArrayCursor, itrs cursors.CursorIterators, cond expression) { if cond != nil { if c.filter == nil { c.filter = newFloatFilterArrayCursor(cond) } c.filter.reset(cur) cur = c.filter } c.FloatArrayCursor = cur c.itrs = itrs c.err = nil } func (c *floatMultiShardArrayCursor) Err() error { return c.err } func (c *floatMultiShardArrayCursor) Stats() cursors.CursorStats { return c.FloatArrayCursor.Stats() } func (c *floatMultiShardArrayCursor) Next() *cursors.FloatArray { for { a := c.FloatArrayCursor.Next() if a.Len() == 0 { if c.nextArrayCursor() { continue } } return a } } func (c *floatMultiShardArrayCursor) nextArrayCursor() bool { if len(c.itrs) == 0 { return false } c.FloatArrayCursor.Close() var itr cursors.CursorIterator var cur cursors.Cursor for cur == nil && len(c.itrs) > 0 { itr, c.itrs = c.itrs[0], c.itrs[1:] cur, _ = itr.Next(c.ctx, c.req) } var ok bool if cur != nil { var next cursors.FloatArrayCursor next, ok = cur.(cursors.FloatArrayCursor) if !ok { cur.Close() next = FloatEmptyArrayCursor c.err = errors.New("expected float cursor") } else { if c.filter != nil { c.filter.reset(next) next = c.filter } } c.FloatArrayCursor = next } else { c.FloatArrayCursor = FloatEmptyArrayCursor } return ok } type floatLimitArrayCursor struct { cursors.FloatArrayCursor res *cursors.FloatArray done bool } func newFloatLimitArrayCursor(cur cursors.FloatArrayCursor) *floatLimitArrayCursor { return &floatLimitArrayCursor{ FloatArrayCursor: cur, res: cursors.NewFloatArrayLen(1), } } func (c *floatLimitArrayCursor) Stats() cursors.CursorStats { return c.FloatArrayCursor.Stats() } func (c *floatLimitArrayCursor) Next() *cursors.FloatArray { if c.done { return &cursors.FloatArray{} } a := c.FloatArrayCursor.Next() if len(a.Timestamps) == 0 { return a } c.done = true c.res.Timestamps[0] = a.Timestamps[0] c.res.Values[0] = a.Values[0] return c.res } type floatWindowLastArrayCursor struct { cursors.FloatArrayCursor windowEnd int64 res *cursors.FloatArray tmp *cursors.FloatArray window interval.Window } // Window array cursors assume that every != 0 && every != MaxInt64. // Such a cursor will panic in the first case and possibly overflow in the second. func newFloatWindowLastArrayCursor(cur cursors.FloatArrayCursor, window interval.Window) *floatWindowLastArrayCursor { return &floatWindowLastArrayCursor{ FloatArrayCursor: cur, windowEnd: math.MinInt64, res: cursors.NewFloatArrayLen(MaxPointsPerBlock), tmp: &cursors.FloatArray{}, window: window, } } func (c *floatWindowLastArrayCursor) Stats() cursors.CursorStats { return c.FloatArrayCursor.Stats() } func (c *floatWindowLastArrayCursor) Next() *cursors.FloatArray { cur := -1 NEXT: var a *cursors.FloatArray if c.tmp.Len() > 0 { a = c.tmp } else { a = c.FloatArrayCursor.Next() } if a.Len() == 0 { c.res.Timestamps = c.res.Timestamps[:cur+1] c.res.Values = c.res.Values[:cur+1] return c.res } for i, t := range a.Timestamps { if t >= c.windowEnd { cur++ } if cur == MaxPointsPerBlock { c.tmp.Timestamps = a.Timestamps[i:] c.tmp.Values = a.Values[i:] return c.res } c.res.Timestamps[cur] = t c.res.Values[cur] = a.Values[i] c.windowEnd = int64(c.window.GetLatestBounds(values.Time(t)).Stop()) } c.tmp.Timestamps = nil c.tmp.Values = nil goto NEXT } type floatWindowFirstArrayCursor struct { cursors.FloatArrayCursor windowEnd int64 res *cursors.FloatArray tmp *cursors.FloatArray window interval.Window } // Window array cursors assume that every != 0 && every != MaxInt64. // Such a cursor will panic in the first case and possibly overflow in the second. func newFloatWindowFirstArrayCursor(cur cursors.FloatArrayCursor, window interval.Window) *floatWindowFirstArrayCursor { return &floatWindowFirstArrayCursor{ FloatArrayCursor: cur, windowEnd: math.MinInt64, res: cursors.NewFloatArrayLen(MaxPointsPerBlock), tmp: &cursors.FloatArray{}, window: window, } } func (c *floatWindowFirstArrayCursor) Stats() cursors.CursorStats { return c.FloatArrayCursor.Stats() } func (c *floatWindowFirstArrayCursor) Next() *cursors.FloatArray { c.res.Timestamps = c.res.Timestamps[:0] c.res.Values = c.res.Values[:0] NEXT: var a *cursors.FloatArray if c.tmp.Len() > 0 { a = c.tmp } else { a = c.FloatArrayCursor.Next() } if a.Len() == 0 { return c.res } for i, t := range a.Timestamps { if t < c.windowEnd { continue } c.windowEnd = int64(c.window.GetLatestBounds(values.Time(t)).Stop()) c.res.Timestamps = append(c.res.Timestamps, t) c.res.Values = append(c.res.Values, a.Values[i]) if c.res.Len() == MaxPointsPerBlock { c.tmp.Timestamps = a.Timestamps[i+1:] c.tmp.Values = a.Values[i+1:] return c.res } } c.tmp.Timestamps = nil c.tmp.Values = nil goto NEXT } type floatWindowCountArrayCursor struct { cursors.FloatArrayCursor res *cursors.IntegerArray tmp *cursors.FloatArray window interval.Window } func newFloatWindowCountArrayCursor(cur cursors.FloatArrayCursor, window interval.Window) *floatWindowCountArrayCursor { resLen := MaxPointsPerBlock if window.IsZero() { resLen = 1 } return &floatWindowCountArrayCursor{ FloatArrayCursor: cur, res: cursors.NewIntegerArrayLen(resLen), tmp: &cursors.FloatArray{}, window: window, } } func (c *floatWindowCountArrayCursor) Stats() cursors.CursorStats { return c.FloatArrayCursor.Stats() } func (c *floatWindowCountArrayCursor) Next() *cursors.IntegerArray { pos := 0 c.res.Timestamps = c.res.Timestamps[:cap(c.res.Timestamps)] c.res.Values = c.res.Values[:cap(c.res.Values)] var a *cursors.FloatArray if c.tmp.Len() > 0 { a = c.tmp } else { a = c.FloatArrayCursor.Next() } if a.Len() == 0 { return &cursors.IntegerArray{} } rowIdx := 0 var acc int64 = 0 var windowEnd int64 if !c.window.IsZero() { windowEnd = int64(c.window.GetLatestBounds(values.Time(a.Timestamps[rowIdx])).Stop()) } else { windowEnd = math.MaxInt64 } windowHasPoints := false // enumerate windows WINDOWS: for { for ; rowIdx < a.Len(); rowIdx++ { ts := a.Timestamps[rowIdx] if !c.window.IsZero() && ts >= windowEnd { // new window detected, close the current window // do not generate a point for empty windows if windowHasPoints { c.res.Timestamps[pos] = windowEnd c.res.Values[pos] = acc pos++ if pos >= MaxPointsPerBlock { // the output array is full, // save the remaining points in the input array in tmp. // they will be processed in the next call to Next() c.tmp.Timestamps = a.Timestamps[rowIdx:] c.tmp.Values = a.Values[rowIdx:] break WINDOWS } } // start the new window acc = 0 windowEnd = int64(c.window.GetLatestBounds(values.Time(ts)).Stop()) windowHasPoints = false continue WINDOWS } else { acc++ windowHasPoints = true } } // Clear buffered timestamps & values if we make it through a cursor. // The break above will skip this if a cursor is partially read. c.tmp.Timestamps = nil c.tmp.Values = nil // get the next chunk a = c.FloatArrayCursor.Next() if a.Len() == 0 { // write the final point // do not generate a point for empty windows if windowHasPoints { c.res.Timestamps[pos] = windowEnd c.res.Values[pos] = acc pos++ } break WINDOWS } rowIdx = 0 } c.res.Timestamps = c.res.Timestamps[:pos] c.res.Values = c.res.Values[:pos] return c.res } type floatWindowSumArrayCursor struct { cursors.FloatArrayCursor res *cursors.FloatArray tmp *cursors.FloatArray window interval.Window } func newFloatWindowSumArrayCursor(cur cursors.FloatArrayCursor, window interval.Window) *floatWindowSumArrayCursor { resLen := MaxPointsPerBlock if window.IsZero() { resLen = 1 } return &floatWindowSumArrayCursor{ FloatArrayCursor: cur, res: cursors.NewFloatArrayLen(resLen), tmp: &cursors.FloatArray{}, window: window, } } func (c *floatWindowSumArrayCursor) Stats() cursors.CursorStats { return c.FloatArrayCursor.Stats() } func (c *floatWindowSumArrayCursor) Next() *cursors.FloatArray { pos := 0 c.res.Timestamps = c.res.Timestamps[:cap(c.res.Timestamps)] c.res.Values = c.res.Values[:cap(c.res.Values)] var a *cursors.FloatArray if c.tmp.Len() > 0 { a = c.tmp } else { a = c.FloatArrayCursor.Next() } if a.Len() == 0 { return &cursors.FloatArray{} } rowIdx := 0 var acc float64 = 0 var windowEnd int64 if !c.window.IsZero() { windowEnd = int64(c.window.GetLatestBounds(values.Time(a.Timestamps[rowIdx])).Stop()) } else { windowEnd = math.MaxInt64 } windowHasPoints := false // enumerate windows WINDOWS: for { for ; rowIdx < a.Len(); rowIdx++ { ts := a.Timestamps[rowIdx] if !c.window.IsZero() && ts >= windowEnd { // new window detected, close the current window // do not generate a point for empty windows if windowHasPoints { c.res.Timestamps[pos] = windowEnd c.res.Values[pos] = acc pos++ if pos >= MaxPointsPerBlock { // the output array is full, // save the remaining points in the input array in tmp. // they will be processed in the next call to Next() c.tmp.Timestamps = a.Timestamps[rowIdx:] c.tmp.Values = a.Values[rowIdx:] break WINDOWS } } // start the new window acc = 0 windowEnd = int64(c.window.GetLatestBounds(values.Time(ts)).Stop()) windowHasPoints = false continue WINDOWS } else { acc += a.Values[rowIdx] windowHasPoints = true } } // Clear buffered timestamps & values if we make it through a cursor. // The break above will skip this if a cursor is partially read. c.tmp.Timestamps = nil c.tmp.Values = nil // get the next chunk a = c.FloatArrayCursor.Next() if a.Len() == 0 { // write the final point // do not generate a point for empty windows if windowHasPoints { c.res.Timestamps[pos] = windowEnd c.res.Values[pos] = acc pos++ } break WINDOWS } rowIdx = 0 } c.res.Timestamps = c.res.Timestamps[:pos] c.res.Values = c.res.Values[:pos] return c.res } type floatWindowMinArrayCursor struct { cursors.FloatArrayCursor res *cursors.FloatArray tmp *cursors.FloatArray window interval.Window } func newFloatWindowMinArrayCursor(cur cursors.FloatArrayCursor, window interval.Window) *floatWindowMinArrayCursor { resLen := MaxPointsPerBlock if window.IsZero() { resLen = 1 } return &floatWindowMinArrayCursor{ FloatArrayCursor: cur, res: cursors.NewFloatArrayLen(resLen), tmp: &cursors.FloatArray{}, window: window, } } func (c *floatWindowMinArrayCursor) Stats() cursors.CursorStats { return c.FloatArrayCursor.Stats() } func (c *floatWindowMinArrayCursor) Next() *cursors.FloatArray { pos := 0 c.res.Timestamps = c.res.Timestamps[:cap(c.res.Timestamps)] c.res.Values = c.res.Values[:cap(c.res.Values)] var a *cursors.FloatArray if c.tmp.Len() > 0 { a = c.tmp } else { a = c.FloatArrayCursor.Next() } if a.Len() == 0 { return &cursors.FloatArray{} } rowIdx := 0 var acc float64 = math.MaxFloat64 var tsAcc int64 var windowEnd int64 if !c.window.IsZero() { windowEnd = int64(c.window.GetLatestBounds(values.Time(a.Timestamps[rowIdx])).Stop()) } else { windowEnd = math.MaxInt64 } windowHasPoints := false // enumerate windows WINDOWS: for { for ; rowIdx < a.Len(); rowIdx++ { ts := a.Timestamps[rowIdx] if !c.window.IsZero() && ts >= windowEnd { // new window detected, close the current window // do not generate a point for empty windows if windowHasPoints { c.res.Timestamps[pos] = tsAcc c.res.Values[pos] = acc pos++ if pos >= MaxPointsPerBlock { // the output array is full, // save the remaining points in the input array in tmp. // they will be processed in the next call to Next() c.tmp.Timestamps = a.Timestamps[rowIdx:] c.tmp.Values = a.Values[rowIdx:] break WINDOWS } } // start the new window acc = math.MaxFloat64 windowEnd = int64(c.window.GetLatestBounds(values.Time(ts)).Stop()) windowHasPoints = false continue WINDOWS } else { if !windowHasPoints || a.Values[rowIdx] < acc { acc = a.Values[rowIdx] tsAcc = a.Timestamps[rowIdx] } windowHasPoints = true } } // Clear buffered timestamps & values if we make it through a cursor. // The break above will skip this if a cursor is partially read. c.tmp.Timestamps = nil c.tmp.Values = nil // get the next chunk a = c.FloatArrayCursor.Next() if a.Len() == 0 { // write the final point // do not generate a point for empty windows if windowHasPoints { c.res.Timestamps[pos] = tsAcc c.res.Values[pos] = acc pos++ } break WINDOWS } rowIdx = 0 } c.res.Timestamps = c.res.Timestamps[:pos] c.res.Values = c.res.Values[:pos] return c.res } type floatWindowMaxArrayCursor struct { cursors.FloatArrayCursor res *cursors.FloatArray tmp *cursors.FloatArray window interval.Window } func newFloatWindowMaxArrayCursor(cur cursors.FloatArrayCursor, window interval.Window) *floatWindowMaxArrayCursor { resLen := MaxPointsPerBlock if window.IsZero() { resLen = 1 } return &floatWindowMaxArrayCursor{ FloatArrayCursor: cur, res: cursors.NewFloatArrayLen(resLen), tmp: &cursors.FloatArray{}, window: window, } } func (c *floatWindowMaxArrayCursor) Stats() cursors.CursorStats { return c.FloatArrayCursor.Stats() } func (c *floatWindowMaxArrayCursor) Next() *cursors.FloatArray { pos := 0 c.res.Timestamps = c.res.Timestamps[:cap(c.res.Timestamps)] c.res.Values = c.res.Values[:cap(c.res.Values)] var a *cursors.FloatArray if c.tmp.Len() > 0 { a = c.tmp } else { a = c.FloatArrayCursor.Next() } if a.Len() == 0 { return &cursors.FloatArray{} } rowIdx := 0 var acc float64 = -math.MaxFloat64 var tsAcc int64 var windowEnd int64 if !c.window.IsZero() { windowEnd = int64(c.window.GetLatestBounds(values.Time(a.Timestamps[rowIdx])).Stop()) } else { windowEnd = math.MaxInt64 } windowHasPoints := false // enumerate windows WINDOWS: for { for ; rowIdx < a.Len(); rowIdx++ { ts := a.Timestamps[rowIdx] if !c.window.IsZero() && ts >= windowEnd { // new window detected, close the current window // do not generate a point for empty windows if windowHasPoints { c.res.Timestamps[pos] = tsAcc c.res.Values[pos] = acc pos++ if pos >= MaxPointsPerBlock { // the output array is full, // save the remaining points in the input array in tmp. // they will be processed in the next call to Next() c.tmp.Timestamps = a.Timestamps[rowIdx:] c.tmp.Values = a.Values[rowIdx:] break WINDOWS } } // start the new window acc = -math.MaxFloat64 windowEnd = int64(c.window.GetLatestBounds(values.Time(ts)).Stop()) windowHasPoints = false continue WINDOWS } else { if !windowHasPoints || a.Values[rowIdx] > acc { acc = a.Values[rowIdx] tsAcc = a.Timestamps[rowIdx] } windowHasPoints = true } } // Clear buffered timestamps & values if we make it through a cursor. // The break above will skip this if a cursor is partially read. c.tmp.Timestamps = nil c.tmp.Values = nil // get the next chunk a = c.FloatArrayCursor.Next() if a.Len() == 0 { // write the final point // do not generate a point for empty windows if windowHasPoints { c.res.Timestamps[pos] = tsAcc c.res.Values[pos] = acc pos++ } break WINDOWS } rowIdx = 0 } c.res.Timestamps = c.res.Timestamps[:pos] c.res.Values = c.res.Values[:pos] return c.res } type floatWindowMeanArrayCursor struct { cursors.FloatArrayCursor res *cursors.FloatArray tmp *cursors.FloatArray window interval.Window } func newFloatWindowMeanArrayCursor(cur cursors.FloatArrayCursor, window interval.Window) *floatWindowMeanArrayCursor { resLen := MaxPointsPerBlock if window.IsZero() { resLen = 1 } return &floatWindowMeanArrayCursor{ FloatArrayCursor: cur, res: cursors.NewFloatArrayLen(resLen), tmp: &cursors.FloatArray{}, window: window, } } func (c *floatWindowMeanArrayCursor) Stats() cursors.CursorStats { return c.FloatArrayCursor.Stats() } func (c *floatWindowMeanArrayCursor) Next() *cursors.FloatArray { pos := 0 c.res.Timestamps = c.res.Timestamps[:cap(c.res.Timestamps)] c.res.Values = c.res.Values[:cap(c.res.Values)] var a *cursors.FloatArray if c.tmp.Len() > 0 { a = c.tmp } else { a = c.FloatArrayCursor.Next() } if a.Len() == 0 { return &cursors.FloatArray{} } rowIdx := 0 var sum float64 var count int64 var windowEnd int64 if !c.window.IsZero() { windowEnd = int64(c.window.GetLatestBounds(values.Time(a.Timestamps[rowIdx])).Stop()) } else { windowEnd = math.MaxInt64 } windowHasPoints := false // enumerate windows WINDOWS: for { for ; rowIdx < a.Len(); rowIdx++ { ts := a.Timestamps[rowIdx] if !c.window.IsZero() && ts >= windowEnd { // new window detected, close the current window // do not generate a point for empty windows if windowHasPoints { c.res.Timestamps[pos] = windowEnd c.res.Values[pos] = sum / float64(count) pos++ if pos >= MaxPointsPerBlock { // the output array is full, // save the remaining points in the input array in tmp. // they will be processed in the next call to Next() c.tmp.Timestamps = a.Timestamps[rowIdx:] c.tmp.Values = a.Values[rowIdx:] break WINDOWS } } // start the new window sum = 0 count = 0 windowEnd = int64(c.window.GetLatestBounds(values.Time(ts)).Stop()) windowHasPoints = false continue WINDOWS } else { sum += a.Values[rowIdx] count++ windowHasPoints = true } } // Clear buffered timestamps & values if we make it through a cursor. // The break above will skip this if a cursor is partially read. c.tmp.Timestamps = nil c.tmp.Values = nil // get the next chunk a = c.FloatArrayCursor.Next() if a.Len() == 0 { // write the final point // do not generate a point for empty windows if windowHasPoints { c.res.Timestamps[pos] = windowEnd c.res.Values[pos] = sum / float64(count) pos++ } break WINDOWS } rowIdx = 0 } c.res.Timestamps = c.res.Timestamps[:pos] c.res.Values = c.res.Values[:pos] return c.res } type floatEmptyArrayCursor struct { res cursors.FloatArray } var FloatEmptyArrayCursor cursors.FloatArrayCursor = &floatEmptyArrayCursor{} func (c *floatEmptyArrayCursor) Err() error { return nil } func (c *floatEmptyArrayCursor) Close() {} func (c *floatEmptyArrayCursor) Stats() cursors.CursorStats { return cursors.CursorStats{} } func (c *floatEmptyArrayCursor) Next() *cursors.FloatArray { return &c.res } // ******************** // Integer Array Cursor type integerArrayFilterCursor struct { cursors.IntegerArrayCursor cond expression m *singleValue res *cursors.IntegerArray tmp *cursors.IntegerArray } func newIntegerFilterArrayCursor(cond expression) *integerArrayFilterCursor { return &integerArrayFilterCursor{ cond: cond, m: &singleValue{}, res: cursors.NewIntegerArrayLen(MaxPointsPerBlock), tmp: &cursors.IntegerArray{}, } } func (c *integerArrayFilterCursor) reset(cur cursors.IntegerArrayCursor) { c.IntegerArrayCursor = cur c.tmp.Timestamps, c.tmp.Values = nil, nil } func (c *integerArrayFilterCursor) Stats() cursors.CursorStats { return c.IntegerArrayCursor.Stats() } func (c *integerArrayFilterCursor) Next() *cursors.IntegerArray { pos := 0 c.res.Timestamps = c.res.Timestamps[:cap(c.res.Timestamps)] c.res.Values = c.res.Values[:cap(c.res.Values)] var a *cursors.IntegerArray if c.tmp.Len() > 0 { a = c.tmp } else { a = c.IntegerArrayCursor.Next() } LOOP: for len(a.Timestamps) > 0 { for i, v := range a.Values { c.m.v = v if c.cond.EvalBool(c.m) { c.res.Timestamps[pos] = a.Timestamps[i] c.res.Values[pos] = v pos++ if pos >= MaxPointsPerBlock { c.tmp.Timestamps = a.Timestamps[i+1:] c.tmp.Values = a.Values[i+1:] break LOOP } } } // Clear buffered timestamps & values if we make it through a cursor. // The break above will skip this if a cursor is partially read. c.tmp.Timestamps = nil c.tmp.Values = nil a = c.IntegerArrayCursor.Next() } c.res.Timestamps = c.res.Timestamps[:pos] c.res.Values = c.res.Values[:pos] return c.res } type integerMultiShardArrayCursor struct { cursors.IntegerArrayCursor cursorContext filter *integerArrayFilterCursor } func (c *integerMultiShardArrayCursor) reset(cur cursors.IntegerArrayCursor, itrs cursors.CursorIterators, cond expression) { if cond != nil { if c.filter == nil { c.filter = newIntegerFilterArrayCursor(cond) } c.filter.reset(cur) cur = c.filter } c.IntegerArrayCursor = cur c.itrs = itrs c.err = nil } func (c *integerMultiShardArrayCursor) Err() error { return c.err } func (c *integerMultiShardArrayCursor) Stats() cursors.CursorStats { return c.IntegerArrayCursor.Stats() } func (c *integerMultiShardArrayCursor) Next() *cursors.IntegerArray { for { a := c.IntegerArrayCursor.Next() if a.Len() == 0 { if c.nextArrayCursor() { continue } } return a } } func (c *integerMultiShardArrayCursor) nextArrayCursor() bool { if len(c.itrs) == 0 { return false } c.IntegerArrayCursor.Close() var itr cursors.CursorIterator var cur cursors.Cursor for cur == nil && len(c.itrs) > 0 { itr, c.itrs = c.itrs[0], c.itrs[1:] cur, _ = itr.Next(c.ctx, c.req) } var ok bool if cur != nil { var next cursors.IntegerArrayCursor next, ok = cur.(cursors.IntegerArrayCursor) if !ok { cur.Close() next = IntegerEmptyArrayCursor c.err = errors.New("expected integer cursor") } else { if c.filter != nil { c.filter.reset(next) next = c.filter } } c.IntegerArrayCursor = next } else { c.IntegerArrayCursor = IntegerEmptyArrayCursor } return ok } type integerLimitArrayCursor struct { cursors.IntegerArrayCursor res *cursors.IntegerArray done bool } func newIntegerLimitArrayCursor(cur cursors.IntegerArrayCursor) *integerLimitArrayCursor { return &integerLimitArrayCursor{ IntegerArrayCursor: cur, res: cursors.NewIntegerArrayLen(1), } } func (c *integerLimitArrayCursor) Stats() cursors.CursorStats { return c.IntegerArrayCursor.Stats() } func (c *integerLimitArrayCursor) Next() *cursors.IntegerArray { if c.done { return &cursors.IntegerArray{} } a := c.IntegerArrayCursor.Next() if len(a.Timestamps) == 0 { return a } c.done = true c.res.Timestamps[0] = a.Timestamps[0] c.res.Values[0] = a.Values[0] return c.res } type integerWindowLastArrayCursor struct { cursors.IntegerArrayCursor windowEnd int64 res *cursors.IntegerArray tmp *cursors.IntegerArray window interval.Window } // Window array cursors assume that every != 0 && every != MaxInt64. // Such a cursor will panic in the first case and possibly overflow in the second. func newIntegerWindowLastArrayCursor(cur cursors.IntegerArrayCursor, window interval.Window) *integerWindowLastArrayCursor { return &integerWindowLastArrayCursor{ IntegerArrayCursor: cur, windowEnd: math.MinInt64, res: cursors.NewIntegerArrayLen(MaxPointsPerBlock), tmp: &cursors.IntegerArray{}, window: window, } } func (c *integerWindowLastArrayCursor) Stats() cursors.CursorStats { return c.IntegerArrayCursor.Stats() } func (c *integerWindowLastArrayCursor) Next() *cursors.IntegerArray { cur := -1 NEXT: var a *cursors.IntegerArray if c.tmp.Len() > 0 { a = c.tmp } else { a = c.IntegerArrayCursor.Next() } if a.Len() == 0 { c.res.Timestamps = c.res.Timestamps[:cur+1] c.res.Values = c.res.Values[:cur+1] return c.res } for i, t := range a.Timestamps { if t >= c.windowEnd { cur++ } if cur == MaxPointsPerBlock { c.tmp.Timestamps = a.Timestamps[i:] c.tmp.Values = a.Values[i:] return c.res } c.res.Timestamps[cur] = t c.res.Values[cur] = a.Values[i] c.windowEnd = int64(c.window.GetLatestBounds(values.Time(t)).Stop()) } c.tmp.Timestamps = nil c.tmp.Values = nil goto NEXT } type integerWindowFirstArrayCursor struct { cursors.IntegerArrayCursor windowEnd int64 res *cursors.IntegerArray tmp *cursors.IntegerArray window interval.Window } // Window array cursors assume that every != 0 && every != MaxInt64. // Such a cursor will panic in the first case and possibly overflow in the second. func newIntegerWindowFirstArrayCursor(cur cursors.IntegerArrayCursor, window interval.Window) *integerWindowFirstArrayCursor { return &integerWindowFirstArrayCursor{ IntegerArrayCursor: cur, windowEnd: math.MinInt64, res: cursors.NewIntegerArrayLen(MaxPointsPerBlock), tmp: &cursors.IntegerArray{}, window: window, } } func (c *integerWindowFirstArrayCursor) Stats() cursors.CursorStats { return c.IntegerArrayCursor.Stats() } func (c *integerWindowFirstArrayCursor) Next() *cursors.IntegerArray { c.res.Timestamps = c.res.Timestamps[:0] c.res.Values = c.res.Values[:0] NEXT: var a *cursors.IntegerArray if c.tmp.Len() > 0 { a = c.tmp } else { a = c.IntegerArrayCursor.Next() } if a.Len() == 0 { return c.res } for i, t := range a.Timestamps { if t < c.windowEnd { continue } c.windowEnd = int64(c.window.GetLatestBounds(values.Time(t)).Stop()) c.res.Timestamps = append(c.res.Timestamps, t) c.res.Values = append(c.res.Values, a.Values[i]) if c.res.Len() == MaxPointsPerBlock { c.tmp.Timestamps = a.Timestamps[i+1:] c.tmp.Values = a.Values[i+1:] return c.res } } c.tmp.Timestamps = nil c.tmp.Values = nil goto NEXT } type integerWindowCountArrayCursor struct { cursors.IntegerArrayCursor res *cursors.IntegerArray tmp *cursors.IntegerArray window interval.Window } func newIntegerWindowCountArrayCursor(cur cursors.IntegerArrayCursor, window interval.Window) *integerWindowCountArrayCursor { resLen := MaxPointsPerBlock if window.IsZero() { resLen = 1 } return &integerWindowCountArrayCursor{ IntegerArrayCursor: cur, res: cursors.NewIntegerArrayLen(resLen), tmp: &cursors.IntegerArray{}, window: window, } } func (c *integerWindowCountArrayCursor) Stats() cursors.CursorStats { return c.IntegerArrayCursor.Stats() } func (c *integerWindowCountArrayCursor) Next() *cursors.IntegerArray { pos := 0 c.res.Timestamps = c.res.Timestamps[:cap(c.res.Timestamps)] c.res.Values = c.res.Values[:cap(c.res.Values)] var a *cursors.IntegerArray if c.tmp.Len() > 0 { a = c.tmp } else { a = c.IntegerArrayCursor.Next() } if a.Len() == 0 { return &cursors.IntegerArray{} } rowIdx := 0 var acc int64 = 0 var windowEnd int64 if !c.window.IsZero() { windowEnd = int64(c.window.GetLatestBounds(values.Time(a.Timestamps[rowIdx])).Stop()) } else { windowEnd = math.MaxInt64 } windowHasPoints := false // enumerate windows WINDOWS: for { for ; rowIdx < a.Len(); rowIdx++ { ts := a.Timestamps[rowIdx] if !c.window.IsZero() && ts >= windowEnd { // new window detected, close the current window // do not generate a point for empty windows if windowHasPoints { c.res.Timestamps[pos] = windowEnd c.res.Values[pos] = acc pos++ if pos >= MaxPointsPerBlock { // the output array is full, // save the remaining points in the input array in tmp. // they will be processed in the next call to Next() c.tmp.Timestamps = a.Timestamps[rowIdx:] c.tmp.Values = a.Values[rowIdx:] break WINDOWS } } // start the new window acc = 0 windowEnd = int64(c.window.GetLatestBounds(values.Time(ts)).Stop()) windowHasPoints = false continue WINDOWS } else { acc++ windowHasPoints = true } } // Clear buffered timestamps & values if we make it through a cursor. // The break above will skip this if a cursor is partially read. c.tmp.Timestamps = nil c.tmp.Values = nil // get the next chunk a = c.IntegerArrayCursor.Next() if a.Len() == 0 { // write the final point // do not generate a point for empty windows if windowHasPoints { c.res.Timestamps[pos] = windowEnd c.res.Values[pos] = acc pos++ } break WINDOWS } rowIdx = 0 } c.res.Timestamps = c.res.Timestamps[:pos] c.res.Values = c.res.Values[:pos] return c.res } type integerWindowSumArrayCursor struct { cursors.IntegerArrayCursor res *cursors.IntegerArray tmp *cursors.IntegerArray window interval.Window } func newIntegerWindowSumArrayCursor(cur cursors.IntegerArrayCursor, window interval.Window) *integerWindowSumArrayCursor { resLen := MaxPointsPerBlock if window.IsZero() { resLen = 1 } return &integerWindowSumArrayCursor{ IntegerArrayCursor: cur, res: cursors.NewIntegerArrayLen(resLen), tmp: &cursors.IntegerArray{}, window: window, } } func (c *integerWindowSumArrayCursor) Stats() cursors.CursorStats { return c.IntegerArrayCursor.Stats() } func (c *integerWindowSumArrayCursor) Next() *cursors.IntegerArray { pos := 0 c.res.Timestamps = c.res.Timestamps[:cap(c.res.Timestamps)] c.res.Values = c.res.Values[:cap(c.res.Values)] var a *cursors.IntegerArray if c.tmp.Len() > 0 { a = c.tmp } else { a = c.IntegerArrayCursor.Next() } if a.Len() == 0 { return &cursors.IntegerArray{} } rowIdx := 0 var acc int64 = 0 var windowEnd int64 if !c.window.IsZero() { windowEnd = int64(c.window.GetLatestBounds(values.Time(a.Timestamps[rowIdx])).Stop()) } else { windowEnd = math.MaxInt64 } windowHasPoints := false // enumerate windows WINDOWS: for { for ; rowIdx < a.Len(); rowIdx++ { ts := a.Timestamps[rowIdx] if !c.window.IsZero() && ts >= windowEnd { // new window detected, close the current window // do not generate a point for empty windows if windowHasPoints { c.res.Timestamps[pos] = windowEnd c.res.Values[pos] = acc pos++ if pos >= MaxPointsPerBlock { // the output array is full, // save the remaining points in the input array in tmp. // they will be processed in the next call to Next() c.tmp.Timestamps = a.Timestamps[rowIdx:] c.tmp.Values = a.Values[rowIdx:] break WINDOWS } } // start the new window acc = 0 windowEnd = int64(c.window.GetLatestBounds(values.Time(ts)).Stop()) windowHasPoints = false continue WINDOWS } else { acc += a.Values[rowIdx] windowHasPoints = true } } // Clear buffered timestamps & values if we make it through a cursor. // The break above will skip this if a cursor is partially read. c.tmp.Timestamps = nil c.tmp.Values = nil // get the next chunk a = c.IntegerArrayCursor.Next() if a.Len() == 0 { // write the final point // do not generate a point for empty windows if windowHasPoints { c.res.Timestamps[pos] = windowEnd c.res.Values[pos] = acc pos++ } break WINDOWS } rowIdx = 0 } c.res.Timestamps = c.res.Timestamps[:pos] c.res.Values = c.res.Values[:pos] return c.res } type integerWindowMinArrayCursor struct { cursors.IntegerArrayCursor res *cursors.IntegerArray tmp *cursors.IntegerArray window interval.Window } func newIntegerWindowMinArrayCursor(cur cursors.IntegerArrayCursor, window interval.Window) *integerWindowMinArrayCursor { resLen := MaxPointsPerBlock if window.IsZero() { resLen = 1 } return &integerWindowMinArrayCursor{ IntegerArrayCursor: cur, res: cursors.NewIntegerArrayLen(resLen), tmp: &cursors.IntegerArray{}, window: window, } } func (c *integerWindowMinArrayCursor) Stats() cursors.CursorStats { return c.IntegerArrayCursor.Stats() } func (c *integerWindowMinArrayCursor) Next() *cursors.IntegerArray { pos := 0 c.res.Timestamps = c.res.Timestamps[:cap(c.res.Timestamps)] c.res.Values = c.res.Values[:cap(c.res.Values)] var a *cursors.IntegerArray if c.tmp.Len() > 0 { a = c.tmp } else { a = c.IntegerArrayCursor.Next() } if a.Len() == 0 { return &cursors.IntegerArray{} } rowIdx := 0 var acc int64 = math.MaxInt64 var tsAcc int64 var windowEnd int64 if !c.window.IsZero() { windowEnd = int64(c.window.GetLatestBounds(values.Time(a.Timestamps[rowIdx])).Stop()) } else { windowEnd = math.MaxInt64 } windowHasPoints := false // enumerate windows WINDOWS: for { for ; rowIdx < a.Len(); rowIdx++ { ts := a.Timestamps[rowIdx] if !c.window.IsZero() && ts >= windowEnd { // new window detected, close the current window // do not generate a point for empty windows if windowHasPoints { c.res.Timestamps[pos] = tsAcc c.res.Values[pos] = acc pos++ if pos >= MaxPointsPerBlock { // the output array is full, // save the remaining points in the input array in tmp. // they will be processed in the next call to Next() c.tmp.Timestamps = a.Timestamps[rowIdx:] c.tmp.Values = a.Values[rowIdx:] break WINDOWS } } // start the new window acc = math.MaxInt64 windowEnd = int64(c.window.GetLatestBounds(values.Time(ts)).Stop()) windowHasPoints = false continue WINDOWS } else { if !windowHasPoints || a.Values[rowIdx] < acc { acc = a.Values[rowIdx] tsAcc = a.Timestamps[rowIdx] } windowHasPoints = true } } // Clear buffered timestamps & values if we make it through a cursor. // The break above will skip this if a cursor is partially read. c.tmp.Timestamps = nil c.tmp.Values = nil // get the next chunk a = c.IntegerArrayCursor.Next() if a.Len() == 0 { // write the final point // do not generate a point for empty windows if windowHasPoints { c.res.Timestamps[pos] = tsAcc c.res.Values[pos] = acc pos++ } break WINDOWS } rowIdx = 0 } c.res.Timestamps = c.res.Timestamps[:pos] c.res.Values = c.res.Values[:pos] return c.res } type integerWindowMaxArrayCursor struct { cursors.IntegerArrayCursor res *cursors.IntegerArray tmp *cursors.IntegerArray window interval.Window } func newIntegerWindowMaxArrayCursor(cur cursors.IntegerArrayCursor, window interval.Window) *integerWindowMaxArrayCursor { resLen := MaxPointsPerBlock if window.IsZero() { resLen = 1 } return &integerWindowMaxArrayCursor{ IntegerArrayCursor: cur, res: cursors.NewIntegerArrayLen(resLen), tmp: &cursors.IntegerArray{}, window: window, } } func (c *integerWindowMaxArrayCursor) Stats() cursors.CursorStats { return c.IntegerArrayCursor.Stats() } func (c *integerWindowMaxArrayCursor) Next() *cursors.IntegerArray { pos := 0 c.res.Timestamps = c.res.Timestamps[:cap(c.res.Timestamps)] c.res.Values = c.res.Values[:cap(c.res.Values)] var a *cursors.IntegerArray if c.tmp.Len() > 0 { a = c.tmp } else { a = c.IntegerArrayCursor.Next() } if a.Len() == 0 { return &cursors.IntegerArray{} } rowIdx := 0 var acc int64 = math.MinInt64 var tsAcc int64 var windowEnd int64 if !c.window.IsZero() { windowEnd = int64(c.window.GetLatestBounds(values.Time(a.Timestamps[rowIdx])).Stop()) } else { windowEnd = math.MaxInt64 } windowHasPoints := false // enumerate windows WINDOWS: for { for ; rowIdx < a.Len(); rowIdx++ { ts := a.Timestamps[rowIdx] if !c.window.IsZero() && ts >= windowEnd { // new window detected, close the current window // do not generate a point for empty windows if windowHasPoints { c.res.Timestamps[pos] = tsAcc c.res.Values[pos] = acc pos++ if pos >= MaxPointsPerBlock { // the output array is full, // save the remaining points in the input array in tmp. // they will be processed in the next call to Next() c.tmp.Timestamps = a.Timestamps[rowIdx:] c.tmp.Values = a.Values[rowIdx:] break WINDOWS } } // start the new window acc = math.MinInt64 windowEnd = int64(c.window.GetLatestBounds(values.Time(ts)).Stop()) windowHasPoints = false continue WINDOWS } else { if !windowHasPoints || a.Values[rowIdx] > acc { acc = a.Values[rowIdx] tsAcc = a.Timestamps[rowIdx] } windowHasPoints = true } } // Clear buffered timestamps & values if we make it through a cursor. // The break above will skip this if a cursor is partially read. c.tmp.Timestamps = nil c.tmp.Values = nil // get the next chunk a = c.IntegerArrayCursor.Next() if a.Len() == 0 { // write the final point // do not generate a point for empty windows if windowHasPoints { c.res.Timestamps[pos] = tsAcc c.res.Values[pos] = acc pos++ } break WINDOWS } rowIdx = 0 } c.res.Timestamps = c.res.Timestamps[:pos] c.res.Values = c.res.Values[:pos] return c.res } type integerWindowMeanArrayCursor struct { cursors.IntegerArrayCursor res *cursors.FloatArray tmp *cursors.IntegerArray window interval.Window } func newIntegerWindowMeanArrayCursor(cur cursors.IntegerArrayCursor, window interval.Window) *integerWindowMeanArrayCursor { resLen := MaxPointsPerBlock if window.IsZero() { resLen = 1 } return &integerWindowMeanArrayCursor{ IntegerArrayCursor: cur, res: cursors.NewFloatArrayLen(resLen), tmp: &cursors.IntegerArray{}, window: window, } } func (c *integerWindowMeanArrayCursor) Stats() cursors.CursorStats { return c.IntegerArrayCursor.Stats() } func (c *integerWindowMeanArrayCursor) Next() *cursors.FloatArray { pos := 0 c.res.Timestamps = c.res.Timestamps[:cap(c.res.Timestamps)] c.res.Values = c.res.Values[:cap(c.res.Values)] var a *cursors.IntegerArray if c.tmp.Len() > 0 { a = c.tmp } else { a = c.IntegerArrayCursor.Next() } if a.Len() == 0 { return &cursors.FloatArray{} } rowIdx := 0 var sum int64 var count int64 var windowEnd int64 if !c.window.IsZero() { windowEnd = int64(c.window.GetLatestBounds(values.Time(a.Timestamps[rowIdx])).Stop()) } else { windowEnd = math.MaxInt64 } windowHasPoints := false // enumerate windows WINDOWS: for { for ; rowIdx < a.Len(); rowIdx++ { ts := a.Timestamps[rowIdx] if !c.window.IsZero() && ts >= windowEnd { // new window detected, close the current window // do not generate a point for empty windows if windowHasPoints { c.res.Timestamps[pos] = windowEnd c.res.Values[pos] = float64(sum) / float64(count) pos++ if pos >= MaxPointsPerBlock { // the output array is full, // save the remaining points in the input array in tmp. // they will be processed in the next call to Next() c.tmp.Timestamps = a.Timestamps[rowIdx:] c.tmp.Values = a.Values[rowIdx:] break WINDOWS } } // start the new window sum = 0 count = 0 windowEnd = int64(c.window.GetLatestBounds(values.Time(ts)).Stop()) windowHasPoints = false continue WINDOWS } else { sum += a.Values[rowIdx] count++ windowHasPoints = true } } // Clear buffered timestamps & values if we make it through a cursor. // The break above will skip this if a cursor is partially read. c.tmp.Timestamps = nil c.tmp.Values = nil // get the next chunk a = c.IntegerArrayCursor.Next() if a.Len() == 0 { // write the final point // do not generate a point for empty windows if windowHasPoints { c.res.Timestamps[pos] = windowEnd c.res.Values[pos] = float64(sum) / float64(count) pos++ } break WINDOWS } rowIdx = 0 } c.res.Timestamps = c.res.Timestamps[:pos] c.res.Values = c.res.Values[:pos] return c.res } type integerEmptyArrayCursor struct { res cursors.IntegerArray } var IntegerEmptyArrayCursor cursors.IntegerArrayCursor = &integerEmptyArrayCursor{} func (c *integerEmptyArrayCursor) Err() error { return nil } func (c *integerEmptyArrayCursor) Close() {} func (c *integerEmptyArrayCursor) Stats() cursors.CursorStats { return cursors.CursorStats{} } func (c *integerEmptyArrayCursor) Next() *cursors.IntegerArray { return &c.res } // ******************** // Unsigned Array Cursor type unsignedArrayFilterCursor struct { cursors.UnsignedArrayCursor cond expression m *singleValue res *cursors.UnsignedArray tmp *cursors.UnsignedArray } func newUnsignedFilterArrayCursor(cond expression) *unsignedArrayFilterCursor { return &unsignedArrayFilterCursor{ cond: cond, m: &singleValue{}, res: cursors.NewUnsignedArrayLen(MaxPointsPerBlock), tmp: &cursors.UnsignedArray{}, } } func (c *unsignedArrayFilterCursor) reset(cur cursors.UnsignedArrayCursor) { c.UnsignedArrayCursor = cur c.tmp.Timestamps, c.tmp.Values = nil, nil } func (c *unsignedArrayFilterCursor) Stats() cursors.CursorStats { return c.UnsignedArrayCursor.Stats() } func (c *unsignedArrayFilterCursor) Next() *cursors.UnsignedArray { pos := 0 c.res.Timestamps = c.res.Timestamps[:cap(c.res.Timestamps)] c.res.Values = c.res.Values[:cap(c.res.Values)] var a *cursors.UnsignedArray if c.tmp.Len() > 0 { a = c.tmp } else { a = c.UnsignedArrayCursor.Next() } LOOP: for len(a.Timestamps) > 0 { for i, v := range a.Values { c.m.v = v if c.cond.EvalBool(c.m) { c.res.Timestamps[pos] = a.Timestamps[i] c.res.Values[pos] = v pos++ if pos >= MaxPointsPerBlock { c.tmp.Timestamps = a.Timestamps[i+1:] c.tmp.Values = a.Values[i+1:] break LOOP } } } // Clear buffered timestamps & values if we make it through a cursor. // The break above will skip this if a cursor is partially read. c.tmp.Timestamps = nil c.tmp.Values = nil a = c.UnsignedArrayCursor.Next() } c.res.Timestamps = c.res.Timestamps[:pos] c.res.Values = c.res.Values[:pos] return c.res } type unsignedMultiShardArrayCursor struct { cursors.UnsignedArrayCursor cursorContext filter *unsignedArrayFilterCursor } func (c *unsignedMultiShardArrayCursor) reset(cur cursors.UnsignedArrayCursor, itrs cursors.CursorIterators, cond expression) { if cond != nil { if c.filter == nil { c.filter = newUnsignedFilterArrayCursor(cond) } c.filter.reset(cur) cur = c.filter } c.UnsignedArrayCursor = cur c.itrs = itrs c.err = nil } func (c *unsignedMultiShardArrayCursor) Err() error { return c.err } func (c *unsignedMultiShardArrayCursor) Stats() cursors.CursorStats { return c.UnsignedArrayCursor.Stats() } func (c *unsignedMultiShardArrayCursor) Next() *cursors.UnsignedArray { for { a := c.UnsignedArrayCursor.Next() if a.Len() == 0 { if c.nextArrayCursor() { continue } } return a } } func (c *unsignedMultiShardArrayCursor) nextArrayCursor() bool { if len(c.itrs) == 0 { return false } c.UnsignedArrayCursor.Close() var itr cursors.CursorIterator var cur cursors.Cursor for cur == nil && len(c.itrs) > 0 { itr, c.itrs = c.itrs[0], c.itrs[1:] cur, _ = itr.Next(c.ctx, c.req) } var ok bool if cur != nil { var next cursors.UnsignedArrayCursor next, ok = cur.(cursors.UnsignedArrayCursor) if !ok { cur.Close() next = UnsignedEmptyArrayCursor c.err = errors.New("expected unsigned cursor") } else { if c.filter != nil { c.filter.reset(next) next = c.filter } } c.UnsignedArrayCursor = next } else { c.UnsignedArrayCursor = UnsignedEmptyArrayCursor } return ok } type unsignedLimitArrayCursor struct { cursors.UnsignedArrayCursor res *cursors.UnsignedArray done bool } func newUnsignedLimitArrayCursor(cur cursors.UnsignedArrayCursor) *unsignedLimitArrayCursor { return &unsignedLimitArrayCursor{ UnsignedArrayCursor: cur, res: cursors.NewUnsignedArrayLen(1), } } func (c *unsignedLimitArrayCursor) Stats() cursors.CursorStats { return c.UnsignedArrayCursor.Stats() } func (c *unsignedLimitArrayCursor) Next() *cursors.UnsignedArray { if c.done { return &cursors.UnsignedArray{} } a := c.UnsignedArrayCursor.Next() if len(a.Timestamps) == 0 { return a } c.done = true c.res.Timestamps[0] = a.Timestamps[0] c.res.Values[0] = a.Values[0] return c.res } type unsignedWindowLastArrayCursor struct { cursors.UnsignedArrayCursor windowEnd int64 res *cursors.UnsignedArray tmp *cursors.UnsignedArray window interval.Window } // Window array cursors assume that every != 0 && every != MaxInt64. // Such a cursor will panic in the first case and possibly overflow in the second. func newUnsignedWindowLastArrayCursor(cur cursors.UnsignedArrayCursor, window interval.Window) *unsignedWindowLastArrayCursor { return &unsignedWindowLastArrayCursor{ UnsignedArrayCursor: cur, windowEnd: math.MinInt64, res: cursors.NewUnsignedArrayLen(MaxPointsPerBlock), tmp: &cursors.UnsignedArray{}, window: window, } } func (c *unsignedWindowLastArrayCursor) Stats() cursors.CursorStats { return c.UnsignedArrayCursor.Stats() } func (c *unsignedWindowLastArrayCursor) Next() *cursors.UnsignedArray { cur := -1 NEXT: var a *cursors.UnsignedArray if c.tmp.Len() > 0 { a = c.tmp } else { a = c.UnsignedArrayCursor.Next() } if a.Len() == 0 { c.res.Timestamps = c.res.Timestamps[:cur+1] c.res.Values = c.res.Values[:cur+1] return c.res } for i, t := range a.Timestamps { if t >= c.windowEnd { cur++ } if cur == MaxPointsPerBlock { c.tmp.Timestamps = a.Timestamps[i:] c.tmp.Values = a.Values[i:] return c.res } c.res.Timestamps[cur] = t c.res.Values[cur] = a.Values[i] c.windowEnd = int64(c.window.GetLatestBounds(values.Time(t)).Stop()) } c.tmp.Timestamps = nil c.tmp.Values = nil goto NEXT } type unsignedWindowFirstArrayCursor struct { cursors.UnsignedArrayCursor windowEnd int64 res *cursors.UnsignedArray tmp *cursors.UnsignedArray window interval.Window } // Window array cursors assume that every != 0 && every != MaxInt64. // Such a cursor will panic in the first case and possibly overflow in the second. func newUnsignedWindowFirstArrayCursor(cur cursors.UnsignedArrayCursor, window interval.Window) *unsignedWindowFirstArrayCursor { return &unsignedWindowFirstArrayCursor{ UnsignedArrayCursor: cur, windowEnd: math.MinInt64, res: cursors.NewUnsignedArrayLen(MaxPointsPerBlock), tmp: &cursors.UnsignedArray{}, window: window, } } func (c *unsignedWindowFirstArrayCursor) Stats() cursors.CursorStats { return c.UnsignedArrayCursor.Stats() } func (c *unsignedWindowFirstArrayCursor) Next() *cursors.UnsignedArray { c.res.Timestamps = c.res.Timestamps[:0] c.res.Values = c.res.Values[:0] NEXT: var a *cursors.UnsignedArray if c.tmp.Len() > 0 { a = c.tmp } else { a = c.UnsignedArrayCursor.Next() } if a.Len() == 0 { return c.res } for i, t := range a.Timestamps { if t < c.windowEnd { continue } c.windowEnd = int64(c.window.GetLatestBounds(values.Time(t)).Stop()) c.res.Timestamps = append(c.res.Timestamps, t) c.res.Values = append(c.res.Values, a.Values[i]) if c.res.Len() == MaxPointsPerBlock { c.tmp.Timestamps = a.Timestamps[i+1:] c.tmp.Values = a.Values[i+1:] return c.res } } c.tmp.Timestamps = nil c.tmp.Values = nil goto NEXT } type unsignedWindowCountArrayCursor struct { cursors.UnsignedArrayCursor res *cursors.IntegerArray tmp *cursors.UnsignedArray window interval.Window } func newUnsignedWindowCountArrayCursor(cur cursors.UnsignedArrayCursor, window interval.Window) *unsignedWindowCountArrayCursor { resLen := MaxPointsPerBlock if window.IsZero() { resLen = 1 } return &unsignedWindowCountArrayCursor{ UnsignedArrayCursor: cur, res: cursors.NewIntegerArrayLen(resLen), tmp: &cursors.UnsignedArray{}, window: window, } } func (c *unsignedWindowCountArrayCursor) Stats() cursors.CursorStats { return c.UnsignedArrayCursor.Stats() } func (c *unsignedWindowCountArrayCursor) Next() *cursors.IntegerArray { pos := 0 c.res.Timestamps = c.res.Timestamps[:cap(c.res.Timestamps)] c.res.Values = c.res.Values[:cap(c.res.Values)] var a *cursors.UnsignedArray if c.tmp.Len() > 0 { a = c.tmp } else { a = c.UnsignedArrayCursor.Next() } if a.Len() == 0 { return &cursors.IntegerArray{} } rowIdx := 0 var acc int64 = 0 var windowEnd int64 if !c.window.IsZero() { windowEnd = int64(c.window.GetLatestBounds(values.Time(a.Timestamps[rowIdx])).Stop()) } else { windowEnd = math.MaxInt64 } windowHasPoints := false // enumerate windows WINDOWS: for { for ; rowIdx < a.Len(); rowIdx++ { ts := a.Timestamps[rowIdx] if !c.window.IsZero() && ts >= windowEnd { // new window detected, close the current window // do not generate a point for empty windows if windowHasPoints { c.res.Timestamps[pos] = windowEnd c.res.Values[pos] = acc pos++ if pos >= MaxPointsPerBlock { // the output array is full, // save the remaining points in the input array in tmp. // they will be processed in the next call to Next() c.tmp.Timestamps = a.Timestamps[rowIdx:] c.tmp.Values = a.Values[rowIdx:] break WINDOWS } } // start the new window acc = 0 windowEnd = int64(c.window.GetLatestBounds(values.Time(ts)).Stop()) windowHasPoints = false continue WINDOWS } else { acc++ windowHasPoints = true } } // Clear buffered timestamps & values if we make it through a cursor. // The break above will skip this if a cursor is partially read. c.tmp.Timestamps = nil c.tmp.Values = nil // get the next chunk a = c.UnsignedArrayCursor.Next() if a.Len() == 0 { // write the final point // do not generate a point for empty windows if windowHasPoints { c.res.Timestamps[pos] = windowEnd c.res.Values[pos] = acc pos++ } break WINDOWS } rowIdx = 0 } c.res.Timestamps = c.res.Timestamps[:pos] c.res.Values = c.res.Values[:pos] return c.res } type unsignedWindowSumArrayCursor struct { cursors.UnsignedArrayCursor res *cursors.UnsignedArray tmp *cursors.UnsignedArray window interval.Window } func newUnsignedWindowSumArrayCursor(cur cursors.UnsignedArrayCursor, window interval.Window) *unsignedWindowSumArrayCursor { resLen := MaxPointsPerBlock if window.IsZero() { resLen = 1 } return &unsignedWindowSumArrayCursor{ UnsignedArrayCursor: cur, res: cursors.NewUnsignedArrayLen(resLen), tmp: &cursors.UnsignedArray{}, window: window, } } func (c *unsignedWindowSumArrayCursor) Stats() cursors.CursorStats { return c.UnsignedArrayCursor.Stats() } func (c *unsignedWindowSumArrayCursor) Next() *cursors.UnsignedArray { pos := 0 c.res.Timestamps = c.res.Timestamps[:cap(c.res.Timestamps)] c.res.Values = c.res.Values[:cap(c.res.Values)] var a *cursors.UnsignedArray if c.tmp.Len() > 0 { a = c.tmp } else { a = c.UnsignedArrayCursor.Next() } if a.Len() == 0 { return &cursors.UnsignedArray{} } rowIdx := 0 var acc uint64 = 0 var windowEnd int64 if !c.window.IsZero() { windowEnd = int64(c.window.GetLatestBounds(values.Time(a.Timestamps[rowIdx])).Stop()) } else { windowEnd = math.MaxInt64 } windowHasPoints := false // enumerate windows WINDOWS: for { for ; rowIdx < a.Len(); rowIdx++ { ts := a.Timestamps[rowIdx] if !c.window.IsZero() && ts >= windowEnd { // new window detected, close the current window // do not generate a point for empty windows if windowHasPoints { c.res.Timestamps[pos] = windowEnd c.res.Values[pos] = acc pos++ if pos >= MaxPointsPerBlock { // the output array is full, // save the remaining points in the input array in tmp. // they will be processed in the next call to Next() c.tmp.Timestamps = a.Timestamps[rowIdx:] c.tmp.Values = a.Values[rowIdx:] break WINDOWS } } // start the new window acc = 0 windowEnd = int64(c.window.GetLatestBounds(values.Time(ts)).Stop()) windowHasPoints = false continue WINDOWS } else { acc += a.Values[rowIdx] windowHasPoints = true } } // Clear buffered timestamps & values if we make it through a cursor. // The break above will skip this if a cursor is partially read. c.tmp.Timestamps = nil c.tmp.Values = nil // get the next chunk a = c.UnsignedArrayCursor.Next() if a.Len() == 0 { // write the final point // do not generate a point for empty windows if windowHasPoints { c.res.Timestamps[pos] = windowEnd c.res.Values[pos] = acc pos++ } break WINDOWS } rowIdx = 0 } c.res.Timestamps = c.res.Timestamps[:pos] c.res.Values = c.res.Values[:pos] return c.res } type unsignedWindowMinArrayCursor struct { cursors.UnsignedArrayCursor res *cursors.UnsignedArray tmp *cursors.UnsignedArray window interval.Window } func newUnsignedWindowMinArrayCursor(cur cursors.UnsignedArrayCursor, window interval.Window) *unsignedWindowMinArrayCursor { resLen := MaxPointsPerBlock if window.IsZero() { resLen = 1 } return &unsignedWindowMinArrayCursor{ UnsignedArrayCursor: cur, res: cursors.NewUnsignedArrayLen(resLen), tmp: &cursors.UnsignedArray{}, window: window, } } func (c *unsignedWindowMinArrayCursor) Stats() cursors.CursorStats { return c.UnsignedArrayCursor.Stats() } func (c *unsignedWindowMinArrayCursor) Next() *cursors.UnsignedArray { pos := 0 c.res.Timestamps = c.res.Timestamps[:cap(c.res.Timestamps)] c.res.Values = c.res.Values[:cap(c.res.Values)] var a *cursors.UnsignedArray if c.tmp.Len() > 0 { a = c.tmp } else { a = c.UnsignedArrayCursor.Next() } if a.Len() == 0 { return &cursors.UnsignedArray{} } rowIdx := 0 var acc uint64 = math.MaxUint64 var tsAcc int64 var windowEnd int64 if !c.window.IsZero() { windowEnd = int64(c.window.GetLatestBounds(values.Time(a.Timestamps[rowIdx])).Stop()) } else { windowEnd = math.MaxInt64 } windowHasPoints := false // enumerate windows WINDOWS: for { for ; rowIdx < a.Len(); rowIdx++ { ts := a.Timestamps[rowIdx] if !c.window.IsZero() && ts >= windowEnd { // new window detected, close the current window // do not generate a point for empty windows if windowHasPoints { c.res.Timestamps[pos] = tsAcc c.res.Values[pos] = acc pos++ if pos >= MaxPointsPerBlock { // the output array is full, // save the remaining points in the input array in tmp. // they will be processed in the next call to Next() c.tmp.Timestamps = a.Timestamps[rowIdx:] c.tmp.Values = a.Values[rowIdx:] break WINDOWS } } // start the new window acc = math.MaxUint64 windowEnd = int64(c.window.GetLatestBounds(values.Time(ts)).Stop()) windowHasPoints = false continue WINDOWS } else { if !windowHasPoints || a.Values[rowIdx] < acc { acc = a.Values[rowIdx] tsAcc = a.Timestamps[rowIdx] } windowHasPoints = true } } // Clear buffered timestamps & values if we make it through a cursor. // The break above will skip this if a cursor is partially read. c.tmp.Timestamps = nil c.tmp.Values = nil // get the next chunk a = c.UnsignedArrayCursor.Next() if a.Len() == 0 { // write the final point // do not generate a point for empty windows if windowHasPoints { c.res.Timestamps[pos] = tsAcc c.res.Values[pos] = acc pos++ } break WINDOWS } rowIdx = 0 } c.res.Timestamps = c.res.Timestamps[:pos] c.res.Values = c.res.Values[:pos] return c.res } type unsignedWindowMaxArrayCursor struct { cursors.UnsignedArrayCursor res *cursors.UnsignedArray tmp *cursors.UnsignedArray window interval.Window } func newUnsignedWindowMaxArrayCursor(cur cursors.UnsignedArrayCursor, window interval.Window) *unsignedWindowMaxArrayCursor { resLen := MaxPointsPerBlock if window.IsZero() { resLen = 1 } return &unsignedWindowMaxArrayCursor{ UnsignedArrayCursor: cur, res: cursors.NewUnsignedArrayLen(resLen), tmp: &cursors.UnsignedArray{}, window: window, } } func (c *unsignedWindowMaxArrayCursor) Stats() cursors.CursorStats { return c.UnsignedArrayCursor.Stats() } func (c *unsignedWindowMaxArrayCursor) Next() *cursors.UnsignedArray { pos := 0 c.res.Timestamps = c.res.Timestamps[:cap(c.res.Timestamps)] c.res.Values = c.res.Values[:cap(c.res.Values)] var a *cursors.UnsignedArray if c.tmp.Len() > 0 { a = c.tmp } else { a = c.UnsignedArrayCursor.Next() } if a.Len() == 0 { return &cursors.UnsignedArray{} } rowIdx := 0 var acc uint64 = 0 var tsAcc int64 var windowEnd int64 if !c.window.IsZero() { windowEnd = int64(c.window.GetLatestBounds(values.Time(a.Timestamps[rowIdx])).Stop()) } else { windowEnd = math.MaxInt64 } windowHasPoints := false // enumerate windows WINDOWS: for { for ; rowIdx < a.Len(); rowIdx++ { ts := a.Timestamps[rowIdx] if !c.window.IsZero() && ts >= windowEnd { // new window detected, close the current window // do not generate a point for empty windows if windowHasPoints { c.res.Timestamps[pos] = tsAcc c.res.Values[pos] = acc pos++ if pos >= MaxPointsPerBlock { // the output array is full, // save the remaining points in the input array in tmp. // they will be processed in the next call to Next() c.tmp.Timestamps = a.Timestamps[rowIdx:] c.tmp.Values = a.Values[rowIdx:] break WINDOWS } } // start the new window acc = 0 windowEnd = int64(c.window.GetLatestBounds(values.Time(ts)).Stop()) windowHasPoints = false continue WINDOWS } else { if !windowHasPoints || a.Values[rowIdx] > acc { acc = a.Values[rowIdx] tsAcc = a.Timestamps[rowIdx] } windowHasPoints = true } } // Clear buffered timestamps & values if we make it through a cursor. // The break above will skip this if a cursor is partially read. c.tmp.Timestamps = nil c.tmp.Values = nil // get the next chunk a = c.UnsignedArrayCursor.Next() if a.Len() == 0 { // write the final point // do not generate a point for empty windows if windowHasPoints { c.res.Timestamps[pos] = tsAcc c.res.Values[pos] = acc pos++ } break WINDOWS } rowIdx = 0 } c.res.Timestamps = c.res.Timestamps[:pos] c.res.Values = c.res.Values[:pos] return c.res } type unsignedWindowMeanArrayCursor struct { cursors.UnsignedArrayCursor res *cursors.FloatArray tmp *cursors.UnsignedArray window interval.Window } func newUnsignedWindowMeanArrayCursor(cur cursors.UnsignedArrayCursor, window interval.Window) *unsignedWindowMeanArrayCursor { resLen := MaxPointsPerBlock if window.IsZero() { resLen = 1 } return &unsignedWindowMeanArrayCursor{ UnsignedArrayCursor: cur, res: cursors.NewFloatArrayLen(resLen), tmp: &cursors.UnsignedArray{}, window: window, } } func (c *unsignedWindowMeanArrayCursor) Stats() cursors.CursorStats { return c.UnsignedArrayCursor.Stats() } func (c *unsignedWindowMeanArrayCursor) Next() *cursors.FloatArray { pos := 0 c.res.Timestamps = c.res.Timestamps[:cap(c.res.Timestamps)] c.res.Values = c.res.Values[:cap(c.res.Values)] var a *cursors.UnsignedArray if c.tmp.Len() > 0 { a = c.tmp } else { a = c.UnsignedArrayCursor.Next() } if a.Len() == 0 { return &cursors.FloatArray{} } rowIdx := 0 var sum uint64 var count int64 var windowEnd int64 if !c.window.IsZero() { windowEnd = int64(c.window.GetLatestBounds(values.Time(a.Timestamps[rowIdx])).Stop()) } else { windowEnd = math.MaxInt64 } windowHasPoints := false // enumerate windows WINDOWS: for { for ; rowIdx < a.Len(); rowIdx++ { ts := a.Timestamps[rowIdx] if !c.window.IsZero() && ts >= windowEnd { // new window detected, close the current window // do not generate a point for empty windows if windowHasPoints { c.res.Timestamps[pos] = windowEnd c.res.Values[pos] = float64(sum) / float64(count) pos++ if pos >= MaxPointsPerBlock { // the output array is full, // save the remaining points in the input array in tmp. // they will be processed in the next call to Next() c.tmp.Timestamps = a.Timestamps[rowIdx:] c.tmp.Values = a.Values[rowIdx:] break WINDOWS } } // start the new window sum = 0 count = 0 windowEnd = int64(c.window.GetLatestBounds(values.Time(ts)).Stop()) windowHasPoints = false continue WINDOWS } else { sum += a.Values[rowIdx] count++ windowHasPoints = true } } // Clear buffered timestamps & values if we make it through a cursor. // The break above will skip this if a cursor is partially read. c.tmp.Timestamps = nil c.tmp.Values = nil // get the next chunk a = c.UnsignedArrayCursor.Next() if a.Len() == 0 { // write the final point // do not generate a point for empty windows if windowHasPoints { c.res.Timestamps[pos] = windowEnd c.res.Values[pos] = float64(sum) / float64(count) pos++ } break WINDOWS } rowIdx = 0 } c.res.Timestamps = c.res.Timestamps[:pos] c.res.Values = c.res.Values[:pos] return c.res } type unsignedEmptyArrayCursor struct { res cursors.UnsignedArray } var UnsignedEmptyArrayCursor cursors.UnsignedArrayCursor = &unsignedEmptyArrayCursor{} func (c *unsignedEmptyArrayCursor) Err() error { return nil } func (c *unsignedEmptyArrayCursor) Close() {} func (c *unsignedEmptyArrayCursor) Stats() cursors.CursorStats { return cursors.CursorStats{} } func (c *unsignedEmptyArrayCursor) Next() *cursors.UnsignedArray { return &c.res } // ******************** // String Array Cursor type stringArrayFilterCursor struct { cursors.StringArrayCursor cond expression m *singleValue res *cursors.StringArray tmp *cursors.StringArray } func newStringFilterArrayCursor(cond expression) *stringArrayFilterCursor { return &stringArrayFilterCursor{ cond: cond, m: &singleValue{}, res: cursors.NewStringArrayLen(MaxPointsPerBlock), tmp: &cursors.StringArray{}, } } func (c *stringArrayFilterCursor) reset(cur cursors.StringArrayCursor) { c.StringArrayCursor = cur c.tmp.Timestamps, c.tmp.Values = nil, nil } func (c *stringArrayFilterCursor) Stats() cursors.CursorStats { return c.StringArrayCursor.Stats() } func (c *stringArrayFilterCursor) Next() *cursors.StringArray { pos := 0 c.res.Timestamps = c.res.Timestamps[:cap(c.res.Timestamps)] c.res.Values = c.res.Values[:cap(c.res.Values)] var a *cursors.StringArray if c.tmp.Len() > 0 { a = c.tmp } else { a = c.StringArrayCursor.Next() } LOOP: for len(a.Timestamps) > 0 { for i, v := range a.Values { c.m.v = v if c.cond.EvalBool(c.m) { c.res.Timestamps[pos] = a.Timestamps[i] c.res.Values[pos] = v pos++ if pos >= MaxPointsPerBlock { c.tmp.Timestamps = a.Timestamps[i+1:] c.tmp.Values = a.Values[i+1:] break LOOP } } } // Clear buffered timestamps & values if we make it through a cursor. // The break above will skip this if a cursor is partially read. c.tmp.Timestamps = nil c.tmp.Values = nil a = c.StringArrayCursor.Next() } c.res.Timestamps = c.res.Timestamps[:pos] c.res.Values = c.res.Values[:pos] return c.res } type stringMultiShardArrayCursor struct { cursors.StringArrayCursor cursorContext filter *stringArrayFilterCursor } func (c *stringMultiShardArrayCursor) reset(cur cursors.StringArrayCursor, itrs cursors.CursorIterators, cond expression) { if cond != nil { if c.filter == nil { c.filter = newStringFilterArrayCursor(cond) } c.filter.reset(cur) cur = c.filter } c.StringArrayCursor = cur c.itrs = itrs c.err = nil } func (c *stringMultiShardArrayCursor) Err() error { return c.err } func (c *stringMultiShardArrayCursor) Stats() cursors.CursorStats { return c.StringArrayCursor.Stats() } func (c *stringMultiShardArrayCursor) Next() *cursors.StringArray { for { a := c.StringArrayCursor.Next() if a.Len() == 0 { if c.nextArrayCursor() { continue } } return a } } func (c *stringMultiShardArrayCursor) nextArrayCursor() bool { if len(c.itrs) == 0 { return false } c.StringArrayCursor.Close() var itr cursors.CursorIterator var cur cursors.Cursor for cur == nil && len(c.itrs) > 0 { itr, c.itrs = c.itrs[0], c.itrs[1:] cur, _ = itr.Next(c.ctx, c.req) } var ok bool if cur != nil { var next cursors.StringArrayCursor next, ok = cur.(cursors.StringArrayCursor) if !ok { cur.Close() next = StringEmptyArrayCursor c.err = errors.New("expected string cursor") } else { if c.filter != nil { c.filter.reset(next) next = c.filter } } c.StringArrayCursor = next } else { c.StringArrayCursor = StringEmptyArrayCursor } return ok } type stringLimitArrayCursor struct { cursors.StringArrayCursor res *cursors.StringArray done bool } func newStringLimitArrayCursor(cur cursors.StringArrayCursor) *stringLimitArrayCursor { return &stringLimitArrayCursor{ StringArrayCursor: cur, res: cursors.NewStringArrayLen(1), } } func (c *stringLimitArrayCursor) Stats() cursors.CursorStats { return c.StringArrayCursor.Stats() } func (c *stringLimitArrayCursor) Next() *cursors.StringArray { if c.done { return &cursors.StringArray{} } a := c.StringArrayCursor.Next() if len(a.Timestamps) == 0 { return a } c.done = true c.res.Timestamps[0] = a.Timestamps[0] c.res.Values[0] = a.Values[0] return c.res } type stringWindowLastArrayCursor struct { cursors.StringArrayCursor windowEnd int64 res *cursors.StringArray tmp *cursors.StringArray window interval.Window } // Window array cursors assume that every != 0 && every != MaxInt64. // Such a cursor will panic in the first case and possibly overflow in the second. func newStringWindowLastArrayCursor(cur cursors.StringArrayCursor, window interval.Window) *stringWindowLastArrayCursor { return &stringWindowLastArrayCursor{ StringArrayCursor: cur, windowEnd: math.MinInt64, res: cursors.NewStringArrayLen(MaxPointsPerBlock), tmp: &cursors.StringArray{}, window: window, } } func (c *stringWindowLastArrayCursor) Stats() cursors.CursorStats { return c.StringArrayCursor.Stats() } func (c *stringWindowLastArrayCursor) Next() *cursors.StringArray { cur := -1 NEXT: var a *cursors.StringArray if c.tmp.Len() > 0 { a = c.tmp } else { a = c.StringArrayCursor.Next() } if a.Len() == 0 { c.res.Timestamps = c.res.Timestamps[:cur+1] c.res.Values = c.res.Values[:cur+1] return c.res } for i, t := range a.Timestamps { if t >= c.windowEnd { cur++ } if cur == MaxPointsPerBlock { c.tmp.Timestamps = a.Timestamps[i:] c.tmp.Values = a.Values[i:] return c.res } c.res.Timestamps[cur] = t c.res.Values[cur] = a.Values[i] c.windowEnd = int64(c.window.GetLatestBounds(values.Time(t)).Stop()) } c.tmp.Timestamps = nil c.tmp.Values = nil goto NEXT } type stringWindowFirstArrayCursor struct { cursors.StringArrayCursor windowEnd int64 res *cursors.StringArray tmp *cursors.StringArray window interval.Window } // Window array cursors assume that every != 0 && every != MaxInt64. // Such a cursor will panic in the first case and possibly overflow in the second. func newStringWindowFirstArrayCursor(cur cursors.StringArrayCursor, window interval.Window) *stringWindowFirstArrayCursor { return &stringWindowFirstArrayCursor{ StringArrayCursor: cur, windowEnd: math.MinInt64, res: cursors.NewStringArrayLen(MaxPointsPerBlock), tmp: &cursors.StringArray{}, window: window, } } func (c *stringWindowFirstArrayCursor) Stats() cursors.CursorStats { return c.StringArrayCursor.Stats() } func (c *stringWindowFirstArrayCursor) Next() *cursors.StringArray { c.res.Timestamps = c.res.Timestamps[:0] c.res.Values = c.res.Values[:0] NEXT: var a *cursors.StringArray if c.tmp.Len() > 0 { a = c.tmp } else { a = c.StringArrayCursor.Next() } if a.Len() == 0 { return c.res } for i, t := range a.Timestamps { if t < c.windowEnd { continue } c.windowEnd = int64(c.window.GetLatestBounds(values.Time(t)).Stop()) c.res.Timestamps = append(c.res.Timestamps, t) c.res.Values = append(c.res.Values, a.Values[i]) if c.res.Len() == MaxPointsPerBlock { c.tmp.Timestamps = a.Timestamps[i+1:] c.tmp.Values = a.Values[i+1:] return c.res } } c.tmp.Timestamps = nil c.tmp.Values = nil goto NEXT } type stringWindowCountArrayCursor struct { cursors.StringArrayCursor res *cursors.IntegerArray tmp *cursors.StringArray window interval.Window } func newStringWindowCountArrayCursor(cur cursors.StringArrayCursor, window interval.Window) *stringWindowCountArrayCursor { resLen := MaxPointsPerBlock if window.IsZero() { resLen = 1 } return &stringWindowCountArrayCursor{ StringArrayCursor: cur, res: cursors.NewIntegerArrayLen(resLen), tmp: &cursors.StringArray{}, window: window, } } func (c *stringWindowCountArrayCursor) Stats() cursors.CursorStats { return c.StringArrayCursor.Stats() } func (c *stringWindowCountArrayCursor) Next() *cursors.IntegerArray { pos := 0 c.res.Timestamps = c.res.Timestamps[:cap(c.res.Timestamps)] c.res.Values = c.res.Values[:cap(c.res.Values)] var a *cursors.StringArray if c.tmp.Len() > 0 { a = c.tmp } else { a = c.StringArrayCursor.Next() } if a.Len() == 0 { return &cursors.IntegerArray{} } rowIdx := 0 var acc int64 = 0 var windowEnd int64 if !c.window.IsZero() { windowEnd = int64(c.window.GetLatestBounds(values.Time(a.Timestamps[rowIdx])).Stop()) } else { windowEnd = math.MaxInt64 } windowHasPoints := false // enumerate windows WINDOWS: for { for ; rowIdx < a.Len(); rowIdx++ { ts := a.Timestamps[rowIdx] if !c.window.IsZero() && ts >= windowEnd { // new window detected, close the current window // do not generate a point for empty windows if windowHasPoints { c.res.Timestamps[pos] = windowEnd c.res.Values[pos] = acc pos++ if pos >= MaxPointsPerBlock { // the output array is full, // save the remaining points in the input array in tmp. // they will be processed in the next call to Next() c.tmp.Timestamps = a.Timestamps[rowIdx:] c.tmp.Values = a.Values[rowIdx:] break WINDOWS } } // start the new window acc = 0 windowEnd = int64(c.window.GetLatestBounds(values.Time(ts)).Stop()) windowHasPoints = false continue WINDOWS } else { acc++ windowHasPoints = true } } // Clear buffered timestamps & values if we make it through a cursor. // The break above will skip this if a cursor is partially read. c.tmp.Timestamps = nil c.tmp.Values = nil // get the next chunk a = c.StringArrayCursor.Next() if a.Len() == 0 { // write the final point // do not generate a point for empty windows if windowHasPoints { c.res.Timestamps[pos] = windowEnd c.res.Values[pos] = acc pos++ } break WINDOWS } rowIdx = 0 } c.res.Timestamps = c.res.Timestamps[:pos] c.res.Values = c.res.Values[:pos] return c.res } type stringEmptyArrayCursor struct { res cursors.StringArray } var StringEmptyArrayCursor cursors.StringArrayCursor = &stringEmptyArrayCursor{} func (c *stringEmptyArrayCursor) Err() error { return nil } func (c *stringEmptyArrayCursor) Close() {} func (c *stringEmptyArrayCursor) Stats() cursors.CursorStats { return cursors.CursorStats{} } func (c *stringEmptyArrayCursor) Next() *cursors.StringArray { return &c.res } // ******************** // Boolean Array Cursor type booleanArrayFilterCursor struct { cursors.BooleanArrayCursor cond expression m *singleValue res *cursors.BooleanArray tmp *cursors.BooleanArray } func newBooleanFilterArrayCursor(cond expression) *booleanArrayFilterCursor { return &booleanArrayFilterCursor{ cond: cond, m: &singleValue{}, res: cursors.NewBooleanArrayLen(MaxPointsPerBlock), tmp: &cursors.BooleanArray{}, } } func (c *booleanArrayFilterCursor) reset(cur cursors.BooleanArrayCursor) { c.BooleanArrayCursor = cur c.tmp.Timestamps, c.tmp.Values = nil, nil } func (c *booleanArrayFilterCursor) Stats() cursors.CursorStats { return c.BooleanArrayCursor.Stats() } func (c *booleanArrayFilterCursor) Next() *cursors.BooleanArray { pos := 0 c.res.Timestamps = c.res.Timestamps[:cap(c.res.Timestamps)] c.res.Values = c.res.Values[:cap(c.res.Values)] var a *cursors.BooleanArray if c.tmp.Len() > 0 { a = c.tmp } else { a = c.BooleanArrayCursor.Next() } LOOP: for len(a.Timestamps) > 0 { for i, v := range a.Values { c.m.v = v if c.cond.EvalBool(c.m) { c.res.Timestamps[pos] = a.Timestamps[i] c.res.Values[pos] = v pos++ if pos >= MaxPointsPerBlock { c.tmp.Timestamps = a.Timestamps[i+1:] c.tmp.Values = a.Values[i+1:] break LOOP } } } // Clear buffered timestamps & values if we make it through a cursor. // The break above will skip this if a cursor is partially read. c.tmp.Timestamps = nil c.tmp.Values = nil a = c.BooleanArrayCursor.Next() } c.res.Timestamps = c.res.Timestamps[:pos] c.res.Values = c.res.Values[:pos] return c.res } type booleanMultiShardArrayCursor struct { cursors.BooleanArrayCursor cursorContext filter *booleanArrayFilterCursor } func (c *booleanMultiShardArrayCursor) reset(cur cursors.BooleanArrayCursor, itrs cursors.CursorIterators, cond expression) { if cond != nil { if c.filter == nil { c.filter = newBooleanFilterArrayCursor(cond) } c.filter.reset(cur) cur = c.filter } c.BooleanArrayCursor = cur c.itrs = itrs c.err = nil } func (c *booleanMultiShardArrayCursor) Err() error { return c.err } func (c *booleanMultiShardArrayCursor) Stats() cursors.CursorStats { return c.BooleanArrayCursor.Stats() } func (c *booleanMultiShardArrayCursor) Next() *cursors.BooleanArray { for { a := c.BooleanArrayCursor.Next() if a.Len() == 0 { if c.nextArrayCursor() { continue } } return a } } func (c *booleanMultiShardArrayCursor) nextArrayCursor() bool { if len(c.itrs) == 0 { return false } c.BooleanArrayCursor.Close() var itr cursors.CursorIterator var cur cursors.Cursor for cur == nil && len(c.itrs) > 0 { itr, c.itrs = c.itrs[0], c.itrs[1:] cur, _ = itr.Next(c.ctx, c.req) } var ok bool if cur != nil { var next cursors.BooleanArrayCursor next, ok = cur.(cursors.BooleanArrayCursor) if !ok { cur.Close() next = BooleanEmptyArrayCursor c.err = errors.New("expected boolean cursor") } else { if c.filter != nil { c.filter.reset(next) next = c.filter } } c.BooleanArrayCursor = next } else { c.BooleanArrayCursor = BooleanEmptyArrayCursor } return ok } type booleanLimitArrayCursor struct { cursors.BooleanArrayCursor res *cursors.BooleanArray done bool } func newBooleanLimitArrayCursor(cur cursors.BooleanArrayCursor) *booleanLimitArrayCursor { return &booleanLimitArrayCursor{ BooleanArrayCursor: cur, res: cursors.NewBooleanArrayLen(1), } } func (c *booleanLimitArrayCursor) Stats() cursors.CursorStats { return c.BooleanArrayCursor.Stats() } func (c *booleanLimitArrayCursor) Next() *cursors.BooleanArray { if c.done { return &cursors.BooleanArray{} } a := c.BooleanArrayCursor.Next() if len(a.Timestamps) == 0 { return a } c.done = true c.res.Timestamps[0] = a.Timestamps[0] c.res.Values[0] = a.Values[0] return c.res } type booleanWindowLastArrayCursor struct { cursors.BooleanArrayCursor windowEnd int64 res *cursors.BooleanArray tmp *cursors.BooleanArray window interval.Window } // Window array cursors assume that every != 0 && every != MaxInt64. // Such a cursor will panic in the first case and possibly overflow in the second. func newBooleanWindowLastArrayCursor(cur cursors.BooleanArrayCursor, window interval.Window) *booleanWindowLastArrayCursor { return &booleanWindowLastArrayCursor{ BooleanArrayCursor: cur, windowEnd: math.MinInt64, res: cursors.NewBooleanArrayLen(MaxPointsPerBlock), tmp: &cursors.BooleanArray{}, window: window, } } func (c *booleanWindowLastArrayCursor) Stats() cursors.CursorStats { return c.BooleanArrayCursor.Stats() } func (c *booleanWindowLastArrayCursor) Next() *cursors.BooleanArray { cur := -1 NEXT: var a *cursors.BooleanArray if c.tmp.Len() > 0 { a = c.tmp } else { a = c.BooleanArrayCursor.Next() } if a.Len() == 0 { c.res.Timestamps = c.res.Timestamps[:cur+1] c.res.Values = c.res.Values[:cur+1] return c.res } for i, t := range a.Timestamps { if t >= c.windowEnd { cur++ } if cur == MaxPointsPerBlock { c.tmp.Timestamps = a.Timestamps[i:] c.tmp.Values = a.Values[i:] return c.res } c.res.Timestamps[cur] = t c.res.Values[cur] = a.Values[i] c.windowEnd = int64(c.window.GetLatestBounds(values.Time(t)).Stop()) } c.tmp.Timestamps = nil c.tmp.Values = nil goto NEXT } type booleanWindowFirstArrayCursor struct { cursors.BooleanArrayCursor windowEnd int64 res *cursors.BooleanArray tmp *cursors.BooleanArray window interval.Window } // Window array cursors assume that every != 0 && every != MaxInt64. // Such a cursor will panic in the first case and possibly overflow in the second. func newBooleanWindowFirstArrayCursor(cur cursors.BooleanArrayCursor, window interval.Window) *booleanWindowFirstArrayCursor { return &booleanWindowFirstArrayCursor{ BooleanArrayCursor: cur, windowEnd: math.MinInt64, res: cursors.NewBooleanArrayLen(MaxPointsPerBlock), tmp: &cursors.BooleanArray{}, window: window, } } func (c *booleanWindowFirstArrayCursor) Stats() cursors.CursorStats { return c.BooleanArrayCursor.Stats() } func (c *booleanWindowFirstArrayCursor) Next() *cursors.BooleanArray { c.res.Timestamps = c.res.Timestamps[:0] c.res.Values = c.res.Values[:0] NEXT: var a *cursors.BooleanArray if c.tmp.Len() > 0 { a = c.tmp } else { a = c.BooleanArrayCursor.Next() } if a.Len() == 0 { return c.res } for i, t := range a.Timestamps { if t < c.windowEnd { continue } c.windowEnd = int64(c.window.GetLatestBounds(values.Time(t)).Stop()) c.res.Timestamps = append(c.res.Timestamps, t) c.res.Values = append(c.res.Values, a.Values[i]) if c.res.Len() == MaxPointsPerBlock { c.tmp.Timestamps = a.Timestamps[i+1:] c.tmp.Values = a.Values[i+1:] return c.res } } c.tmp.Timestamps = nil c.tmp.Values = nil goto NEXT } type booleanWindowCountArrayCursor struct { cursors.BooleanArrayCursor res *cursors.IntegerArray tmp *cursors.BooleanArray window interval.Window } func newBooleanWindowCountArrayCursor(cur cursors.BooleanArrayCursor, window interval.Window) *booleanWindowCountArrayCursor { resLen := MaxPointsPerBlock if window.IsZero() { resLen = 1 } return &booleanWindowCountArrayCursor{ BooleanArrayCursor: cur, res: cursors.NewIntegerArrayLen(resLen), tmp: &cursors.BooleanArray{}, window: window, } } func (c *booleanWindowCountArrayCursor) Stats() cursors.CursorStats { return c.BooleanArrayCursor.Stats() } func (c *booleanWindowCountArrayCursor) Next() *cursors.IntegerArray { pos := 0 c.res.Timestamps = c.res.Timestamps[:cap(c.res.Timestamps)] c.res.Values = c.res.Values[:cap(c.res.Values)] var a *cursors.BooleanArray if c.tmp.Len() > 0 { a = c.tmp } else { a = c.BooleanArrayCursor.Next() } if a.Len() == 0 { return &cursors.IntegerArray{} } rowIdx := 0 var acc int64 = 0 var windowEnd int64 if !c.window.IsZero() { windowEnd = int64(c.window.GetLatestBounds(values.Time(a.Timestamps[rowIdx])).Stop()) } else { windowEnd = math.MaxInt64 } windowHasPoints := false // enumerate windows WINDOWS: for { for ; rowIdx < a.Len(); rowIdx++ { ts := a.Timestamps[rowIdx] if !c.window.IsZero() && ts >= windowEnd { // new window detected, close the current window // do not generate a point for empty windows if windowHasPoints { c.res.Timestamps[pos] = windowEnd c.res.Values[pos] = acc pos++ if pos >= MaxPointsPerBlock { // the output array is full, // save the remaining points in the input array in tmp. // they will be processed in the next call to Next() c.tmp.Timestamps = a.Timestamps[rowIdx:] c.tmp.Values = a.Values[rowIdx:] break WINDOWS } } // start the new window acc = 0 windowEnd = int64(c.window.GetLatestBounds(values.Time(ts)).Stop()) windowHasPoints = false continue WINDOWS } else { acc++ windowHasPoints = true } } // Clear buffered timestamps & values if we make it through a cursor. // The break above will skip this if a cursor is partially read. c.tmp.Timestamps = nil c.tmp.Values = nil // get the next chunk a = c.BooleanArrayCursor.Next() if a.Len() == 0 { // write the final point // do not generate a point for empty windows if windowHasPoints { c.res.Timestamps[pos] = windowEnd c.res.Values[pos] = acc pos++ } break WINDOWS } rowIdx = 0 } c.res.Timestamps = c.res.Timestamps[:pos] c.res.Values = c.res.Values[:pos] return c.res } type booleanEmptyArrayCursor struct { res cursors.BooleanArray } var BooleanEmptyArrayCursor cursors.BooleanArrayCursor = &booleanEmptyArrayCursor{} func (c *booleanEmptyArrayCursor) Err() error { return nil } func (c *booleanEmptyArrayCursor) Close() {} func (c *booleanEmptyArrayCursor) Stats() cursors.CursorStats { return cursors.CursorStats{} } func (c *booleanEmptyArrayCursor) Next() *cursors.BooleanArray { return &c.res } func arrayCursorType(cur cursors.Cursor) string { switch cur.(type) { case cursors.FloatArrayCursor: return "float" case cursors.IntegerArrayCursor: return "integer" case cursors.UnsignedArrayCursor: return "unsigned" case cursors.StringArrayCursor: return "string" case cursors.BooleanArrayCursor: return "boolean" default: return "unknown" } }