influxdb/storage/reads/array_cursor.gen.go

3706 lines
88 KiB
Go

// 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"
}
}