github.com/influxdata/influxdb/v2@v2.7.6/influxql/query/call_iterator.go (about)

     1  package query
     2  
     3  import (
     4  	"fmt"
     5  	"math"
     6  	"sort"
     7  	"time"
     8  
     9  	"github.com/influxdata/influxdb/v2/influxql/query/internal/gota"
    10  	"github.com/influxdata/influxql"
    11  )
    12  
    13  /*
    14  This file contains iterator implementations for each function call available
    15  in InfluxQL. Call iterators are separated into two groups:
    16  
    17  1. Map/reduce-style iterators - these are passed to IteratorCreator so that
    18     processing can be at the low-level storage and aggregates are returned.
    19  
    20  2. Raw aggregate iterators - these require the full set of data for a window.
    21     These are handled by the select() function and raw points are streamed in
    22     from the low-level storage.
    23  
    24  There are helpers to aid in building aggregate iterators. For simple map/reduce
    25  iterators, you can use the reduceIterator types and pass a reduce function. This
    26  reduce function is passed a previous and current value and the new timestamp,
    27  value, and auxiliary fields are returned from it.
    28  
    29  For raw aggregate iterators, you can use the reduceSliceIterators which pass
    30  in a slice of all points to the function and return a point. For more complex
    31  iterator types, you may need to create your own iterators by hand.
    32  
    33  Once your iterator is complete, you'll need to add it to the NewCallIterator()
    34  function if it is to be available to IteratorCreators and add it to the select()
    35  function to allow it to be included during planning.
    36  */
    37  
    38  // NewCallIterator returns a new iterator for a Call.
    39  func NewCallIterator(input Iterator, opt IteratorOptions) (Iterator, error) {
    40  	name := opt.Expr.(*influxql.Call).Name
    41  	switch name {
    42  	case "count":
    43  		return newCountIterator(input, opt)
    44  	case "min":
    45  		return newMinIterator(input, opt)
    46  	case "max":
    47  		return newMaxIterator(input, opt)
    48  	case "sum":
    49  		return newSumIterator(input, opt)
    50  	case "first":
    51  		return newFirstIterator(input, opt)
    52  	case "last":
    53  		return newLastIterator(input, opt)
    54  	case "mean":
    55  		return newMeanIterator(input, opt)
    56  	case "sum_hll":
    57  		return NewSumHllIterator(input, opt)
    58  	case "merge_hll":
    59  		return NewMergeHllIterator(input, opt)
    60  	default:
    61  		return nil, fmt.Errorf("unsupported function call: %s", name)
    62  	}
    63  }
    64  
    65  // newCountIterator returns an iterator for operating on a count() call.
    66  func newCountIterator(input Iterator, opt IteratorOptions) (Iterator, error) {
    67  	// FIXME: Wrap iterator in int-type iterator and always output int value.
    68  
    69  	switch input := input.(type) {
    70  	case FloatIterator:
    71  		createFn := func() (FloatPointAggregator, IntegerPointEmitter) {
    72  			fn := NewFloatFuncIntegerReducer(FloatCountReduce, &IntegerPoint{Value: 0, Time: ZeroTime})
    73  			return fn, fn
    74  		}
    75  		return newFloatReduceIntegerIterator(input, opt, createFn), nil
    76  	case IntegerIterator:
    77  		createFn := func() (IntegerPointAggregator, IntegerPointEmitter) {
    78  			fn := NewIntegerFuncReducer(IntegerCountReduce, &IntegerPoint{Value: 0, Time: ZeroTime})
    79  			return fn, fn
    80  		}
    81  		return newIntegerReduceIntegerIterator(input, opt, createFn), nil
    82  	case UnsignedIterator:
    83  		createFn := func() (UnsignedPointAggregator, IntegerPointEmitter) {
    84  			fn := NewUnsignedFuncIntegerReducer(UnsignedCountReduce, &IntegerPoint{Value: 0, Time: ZeroTime})
    85  			return fn, fn
    86  		}
    87  		return newUnsignedReduceIntegerIterator(input, opt, createFn), nil
    88  	case StringIterator:
    89  		createFn := func() (StringPointAggregator, IntegerPointEmitter) {
    90  			fn := NewStringFuncIntegerReducer(StringCountReduce, &IntegerPoint{Value: 0, Time: ZeroTime})
    91  			return fn, fn
    92  		}
    93  		return newStringReduceIntegerIterator(input, opt, createFn), nil
    94  	case BooleanIterator:
    95  		createFn := func() (BooleanPointAggregator, IntegerPointEmitter) {
    96  			fn := NewBooleanFuncIntegerReducer(BooleanCountReduce, &IntegerPoint{Value: 0, Time: ZeroTime})
    97  			return fn, fn
    98  		}
    99  		return newBooleanReduceIntegerIterator(input, opt, createFn), nil
   100  	default:
   101  		return nil, fmt.Errorf("unsupported count iterator type: %T", input)
   102  	}
   103  }
   104  
   105  // FloatCountReduce returns the count of points.
   106  func FloatCountReduce(prev *IntegerPoint, curr *FloatPoint) (int64, int64, []interface{}) {
   107  	if prev == nil {
   108  		return ZeroTime, 1, nil
   109  	}
   110  	return ZeroTime, prev.Value + 1, nil
   111  }
   112  
   113  // IntegerCountReduce returns the count of points.
   114  func IntegerCountReduce(prev, curr *IntegerPoint) (int64, int64, []interface{}) {
   115  	if prev == nil {
   116  		return ZeroTime, 1, nil
   117  	}
   118  	return ZeroTime, prev.Value + 1, nil
   119  }
   120  
   121  // UnsignedCountReduce returns the count of points.
   122  func UnsignedCountReduce(prev *IntegerPoint, curr *UnsignedPoint) (int64, int64, []interface{}) {
   123  	if prev == nil {
   124  		return ZeroTime, 1, nil
   125  	}
   126  	return ZeroTime, prev.Value + 1, nil
   127  }
   128  
   129  // StringCountReduce returns the count of points.
   130  func StringCountReduce(prev *IntegerPoint, curr *StringPoint) (int64, int64, []interface{}) {
   131  	if prev == nil {
   132  		return ZeroTime, 1, nil
   133  	}
   134  	return ZeroTime, prev.Value + 1, nil
   135  }
   136  
   137  // BooleanCountReduce returns the count of points.
   138  func BooleanCountReduce(prev *IntegerPoint, curr *BooleanPoint) (int64, int64, []interface{}) {
   139  	if prev == nil {
   140  		return ZeroTime, 1, nil
   141  	}
   142  	return ZeroTime, prev.Value + 1, nil
   143  }
   144  
   145  // newMinIterator returns an iterator for operating on a min() call.
   146  func newMinIterator(input Iterator, opt IteratorOptions) (Iterator, error) {
   147  	switch input := input.(type) {
   148  	case FloatIterator:
   149  		createFn := func() (FloatPointAggregator, FloatPointEmitter) {
   150  			fn := NewFloatFuncReducer(FloatMinReduce, nil)
   151  			return fn, fn
   152  		}
   153  		return newFloatReduceFloatIterator(input, opt, createFn), nil
   154  	case IntegerIterator:
   155  		createFn := func() (IntegerPointAggregator, IntegerPointEmitter) {
   156  			fn := NewIntegerFuncReducer(IntegerMinReduce, nil)
   157  			return fn, fn
   158  		}
   159  		return newIntegerReduceIntegerIterator(input, opt, createFn), nil
   160  	case UnsignedIterator:
   161  		createFn := func() (UnsignedPointAggregator, UnsignedPointEmitter) {
   162  			fn := NewUnsignedFuncReducer(UnsignedMinReduce, nil)
   163  			return fn, fn
   164  		}
   165  		return newUnsignedReduceUnsignedIterator(input, opt, createFn), nil
   166  	case BooleanIterator:
   167  		createFn := func() (BooleanPointAggregator, BooleanPointEmitter) {
   168  			fn := NewBooleanFuncReducer(BooleanMinReduce, nil)
   169  			return fn, fn
   170  		}
   171  		return newBooleanReduceBooleanIterator(input, opt, createFn), nil
   172  	default:
   173  		return nil, fmt.Errorf("unsupported min iterator type: %T", input)
   174  	}
   175  }
   176  
   177  // FloatMinReduce returns the minimum value between prev & curr.
   178  func FloatMinReduce(prev, curr *FloatPoint) (int64, float64, []interface{}) {
   179  	if prev == nil || curr.Value < prev.Value || (curr.Value == prev.Value && curr.Time < prev.Time) {
   180  		return curr.Time, curr.Value, cloneAux(curr.Aux)
   181  	}
   182  	return prev.Time, prev.Value, prev.Aux
   183  }
   184  
   185  // IntegerMinReduce returns the minimum value between prev & curr.
   186  func IntegerMinReduce(prev, curr *IntegerPoint) (int64, int64, []interface{}) {
   187  	if prev == nil || curr.Value < prev.Value || (curr.Value == prev.Value && curr.Time < prev.Time) {
   188  		return curr.Time, curr.Value, cloneAux(curr.Aux)
   189  	}
   190  	return prev.Time, prev.Value, prev.Aux
   191  }
   192  
   193  // UnsignedMinReduce returns the minimum value between prev & curr.
   194  func UnsignedMinReduce(prev, curr *UnsignedPoint) (int64, uint64, []interface{}) {
   195  	if prev == nil || curr.Value < prev.Value || (curr.Value == prev.Value && curr.Time < prev.Time) {
   196  		return curr.Time, curr.Value, cloneAux(curr.Aux)
   197  	}
   198  	return prev.Time, prev.Value, prev.Aux
   199  }
   200  
   201  // BooleanMinReduce returns the minimum value between prev & curr.
   202  func BooleanMinReduce(prev, curr *BooleanPoint) (int64, bool, []interface{}) {
   203  	if prev == nil || (curr.Value != prev.Value && !curr.Value) || (curr.Value == prev.Value && curr.Time < prev.Time) {
   204  		return curr.Time, curr.Value, cloneAux(curr.Aux)
   205  	}
   206  	return prev.Time, prev.Value, prev.Aux
   207  }
   208  
   209  // newMaxIterator returns an iterator for operating on a max() call.
   210  func newMaxIterator(input Iterator, opt IteratorOptions) (Iterator, error) {
   211  	switch input := input.(type) {
   212  	case FloatIterator:
   213  		createFn := func() (FloatPointAggregator, FloatPointEmitter) {
   214  			fn := NewFloatFuncReducer(FloatMaxReduce, nil)
   215  			return fn, fn
   216  		}
   217  		return newFloatReduceFloatIterator(input, opt, createFn), nil
   218  	case IntegerIterator:
   219  		createFn := func() (IntegerPointAggregator, IntegerPointEmitter) {
   220  			fn := NewIntegerFuncReducer(IntegerMaxReduce, nil)
   221  			return fn, fn
   222  		}
   223  		return newIntegerReduceIntegerIterator(input, opt, createFn), nil
   224  	case UnsignedIterator:
   225  		createFn := func() (UnsignedPointAggregator, UnsignedPointEmitter) {
   226  			fn := NewUnsignedFuncReducer(UnsignedMaxReduce, nil)
   227  			return fn, fn
   228  		}
   229  		return newUnsignedReduceUnsignedIterator(input, opt, createFn), nil
   230  	case BooleanIterator:
   231  		createFn := func() (BooleanPointAggregator, BooleanPointEmitter) {
   232  			fn := NewBooleanFuncReducer(BooleanMaxReduce, nil)
   233  			return fn, fn
   234  		}
   235  		return newBooleanReduceBooleanIterator(input, opt, createFn), nil
   236  	default:
   237  		return nil, fmt.Errorf("unsupported max iterator type: %T", input)
   238  	}
   239  }
   240  
   241  // FloatMaxReduce returns the maximum value between prev & curr.
   242  func FloatMaxReduce(prev, curr *FloatPoint) (int64, float64, []interface{}) {
   243  	if prev == nil || curr.Value > prev.Value || (curr.Value == prev.Value && curr.Time < prev.Time) {
   244  		return curr.Time, curr.Value, cloneAux(curr.Aux)
   245  	}
   246  	return prev.Time, prev.Value, prev.Aux
   247  }
   248  
   249  // IntegerMaxReduce returns the maximum value between prev & curr.
   250  func IntegerMaxReduce(prev, curr *IntegerPoint) (int64, int64, []interface{}) {
   251  	if prev == nil || curr.Value > prev.Value || (curr.Value == prev.Value && curr.Time < prev.Time) {
   252  		return curr.Time, curr.Value, cloneAux(curr.Aux)
   253  	}
   254  	return prev.Time, prev.Value, prev.Aux
   255  }
   256  
   257  // UnsignedMaxReduce returns the maximum value between prev & curr.
   258  func UnsignedMaxReduce(prev, curr *UnsignedPoint) (int64, uint64, []interface{}) {
   259  	if prev == nil || curr.Value > prev.Value || (curr.Value == prev.Value && curr.Time < prev.Time) {
   260  		return curr.Time, curr.Value, cloneAux(curr.Aux)
   261  	}
   262  	return prev.Time, prev.Value, prev.Aux
   263  }
   264  
   265  // BooleanMaxReduce returns the minimum value between prev & curr.
   266  func BooleanMaxReduce(prev, curr *BooleanPoint) (int64, bool, []interface{}) {
   267  	if prev == nil || (curr.Value != prev.Value && curr.Value) || (curr.Value == prev.Value && curr.Time < prev.Time) {
   268  		return curr.Time, curr.Value, cloneAux(curr.Aux)
   269  	}
   270  	return prev.Time, prev.Value, prev.Aux
   271  }
   272  
   273  // newSumIterator returns an iterator for operating on a sum() call.
   274  func newSumIterator(input Iterator, opt IteratorOptions) (Iterator, error) {
   275  	switch input := input.(type) {
   276  	case FloatIterator:
   277  		createFn := func() (FloatPointAggregator, FloatPointEmitter) {
   278  			fn := NewFloatFuncReducer(FloatSumReduce, &FloatPoint{Value: 0, Time: ZeroTime})
   279  			return fn, fn
   280  		}
   281  		return newFloatReduceFloatIterator(input, opt, createFn), nil
   282  	case IntegerIterator:
   283  		createFn := func() (IntegerPointAggregator, IntegerPointEmitter) {
   284  			fn := NewIntegerFuncReducer(IntegerSumReduce, &IntegerPoint{Value: 0, Time: ZeroTime})
   285  			return fn, fn
   286  		}
   287  		return newIntegerReduceIntegerIterator(input, opt, createFn), nil
   288  	case UnsignedIterator:
   289  		createFn := func() (UnsignedPointAggregator, UnsignedPointEmitter) {
   290  			fn := NewUnsignedFuncReducer(UnsignedSumReduce, &UnsignedPoint{Value: 0, Time: ZeroTime})
   291  			return fn, fn
   292  		}
   293  		return newUnsignedReduceUnsignedIterator(input, opt, createFn), nil
   294  	default:
   295  		return nil, fmt.Errorf("unsupported sum iterator type: %T", input)
   296  	}
   297  }
   298  
   299  // FloatSumReduce returns the sum prev value & curr value.
   300  func FloatSumReduce(prev, curr *FloatPoint) (int64, float64, []interface{}) {
   301  	if prev == nil {
   302  		return ZeroTime, curr.Value, nil
   303  	}
   304  	return prev.Time, prev.Value + curr.Value, nil
   305  }
   306  
   307  // IntegerSumReduce returns the sum prev value & curr value.
   308  func IntegerSumReduce(prev, curr *IntegerPoint) (int64, int64, []interface{}) {
   309  	if prev == nil {
   310  		return ZeroTime, curr.Value, nil
   311  	}
   312  	return prev.Time, prev.Value + curr.Value, nil
   313  }
   314  
   315  // UnsignedSumReduce returns the sum prev value & curr value.
   316  func UnsignedSumReduce(prev, curr *UnsignedPoint) (int64, uint64, []interface{}) {
   317  	if prev == nil {
   318  		return ZeroTime, curr.Value, nil
   319  	}
   320  	return prev.Time, prev.Value + curr.Value, nil
   321  }
   322  
   323  // newFirstIterator returns an iterator for operating on a first() call.
   324  func newFirstIterator(input Iterator, opt IteratorOptions) (Iterator, error) {
   325  	switch input := input.(type) {
   326  	case FloatIterator:
   327  		createFn := func() (FloatPointAggregator, FloatPointEmitter) {
   328  			fn := NewFloatFuncReducer(FloatFirstReduce, nil)
   329  			return fn, fn
   330  		}
   331  		return newFloatReduceFloatIterator(input, opt, createFn), nil
   332  	case IntegerIterator:
   333  		createFn := func() (IntegerPointAggregator, IntegerPointEmitter) {
   334  			fn := NewIntegerFuncReducer(IntegerFirstReduce, nil)
   335  			return fn, fn
   336  		}
   337  		return newIntegerReduceIntegerIterator(input, opt, createFn), nil
   338  	case UnsignedIterator:
   339  		createFn := func() (UnsignedPointAggregator, UnsignedPointEmitter) {
   340  			fn := NewUnsignedFuncReducer(UnsignedFirstReduce, nil)
   341  			return fn, fn
   342  		}
   343  		return newUnsignedReduceUnsignedIterator(input, opt, createFn), nil
   344  	case StringIterator:
   345  		createFn := func() (StringPointAggregator, StringPointEmitter) {
   346  			fn := NewStringFuncReducer(StringFirstReduce, nil)
   347  			return fn, fn
   348  		}
   349  		return newStringReduceStringIterator(input, opt, createFn), nil
   350  	case BooleanIterator:
   351  		createFn := func() (BooleanPointAggregator, BooleanPointEmitter) {
   352  			fn := NewBooleanFuncReducer(BooleanFirstReduce, nil)
   353  			return fn, fn
   354  		}
   355  		return newBooleanReduceBooleanIterator(input, opt, createFn), nil
   356  	default:
   357  		return nil, fmt.Errorf("unsupported first iterator type: %T", input)
   358  	}
   359  }
   360  
   361  // FloatFirstReduce returns the first point sorted by time.
   362  func FloatFirstReduce(prev, curr *FloatPoint) (int64, float64, []interface{}) {
   363  	if prev == nil || curr.Time < prev.Time || (curr.Time == prev.Time && curr.Value > prev.Value) {
   364  		return curr.Time, curr.Value, cloneAux(curr.Aux)
   365  	}
   366  	return prev.Time, prev.Value, prev.Aux
   367  }
   368  
   369  // IntegerFirstReduce returns the first point sorted by time.
   370  func IntegerFirstReduce(prev, curr *IntegerPoint) (int64, int64, []interface{}) {
   371  	if prev == nil || curr.Time < prev.Time || (curr.Time == prev.Time && curr.Value > prev.Value) {
   372  		return curr.Time, curr.Value, cloneAux(curr.Aux)
   373  	}
   374  	return prev.Time, prev.Value, prev.Aux
   375  }
   376  
   377  // UnsignedFirstReduce returns the first point sorted by time.
   378  func UnsignedFirstReduce(prev, curr *UnsignedPoint) (int64, uint64, []interface{}) {
   379  	if prev == nil || curr.Time < prev.Time || (curr.Time == prev.Time && curr.Value > prev.Value) {
   380  		return curr.Time, curr.Value, cloneAux(curr.Aux)
   381  	}
   382  	return prev.Time, prev.Value, prev.Aux
   383  }
   384  
   385  // StringFirstReduce returns the first point sorted by time.
   386  func StringFirstReduce(prev, curr *StringPoint) (int64, string, []interface{}) {
   387  	if prev == nil || curr.Time < prev.Time || (curr.Time == prev.Time && curr.Value > prev.Value) {
   388  		return curr.Time, curr.Value, cloneAux(curr.Aux)
   389  	}
   390  	return prev.Time, prev.Value, prev.Aux
   391  }
   392  
   393  // BooleanFirstReduce returns the first point sorted by time.
   394  func BooleanFirstReduce(prev, curr *BooleanPoint) (int64, bool, []interface{}) {
   395  	if prev == nil || curr.Time < prev.Time || (curr.Time == prev.Time && !curr.Value && prev.Value) {
   396  		return curr.Time, curr.Value, cloneAux(curr.Aux)
   397  	}
   398  	return prev.Time, prev.Value, prev.Aux
   399  }
   400  
   401  // newLastIterator returns an iterator for operating on a last() call.
   402  func newLastIterator(input Iterator, opt IteratorOptions) (Iterator, error) {
   403  	switch input := input.(type) {
   404  	case FloatIterator:
   405  		createFn := func() (FloatPointAggregator, FloatPointEmitter) {
   406  			fn := NewFloatFuncReducer(FloatLastReduce, nil)
   407  			return fn, fn
   408  		}
   409  		return newFloatReduceFloatIterator(input, opt, createFn), nil
   410  	case IntegerIterator:
   411  		createFn := func() (IntegerPointAggregator, IntegerPointEmitter) {
   412  			fn := NewIntegerFuncReducer(IntegerLastReduce, nil)
   413  			return fn, fn
   414  		}
   415  		return newIntegerReduceIntegerIterator(input, opt, createFn), nil
   416  	case UnsignedIterator:
   417  		createFn := func() (UnsignedPointAggregator, UnsignedPointEmitter) {
   418  			fn := NewUnsignedFuncReducer(UnsignedLastReduce, nil)
   419  			return fn, fn
   420  		}
   421  		return newUnsignedReduceUnsignedIterator(input, opt, createFn), nil
   422  	case StringIterator:
   423  		createFn := func() (StringPointAggregator, StringPointEmitter) {
   424  			fn := NewStringFuncReducer(StringLastReduce, nil)
   425  			return fn, fn
   426  		}
   427  		return newStringReduceStringIterator(input, opt, createFn), nil
   428  	case BooleanIterator:
   429  		createFn := func() (BooleanPointAggregator, BooleanPointEmitter) {
   430  			fn := NewBooleanFuncReducer(BooleanLastReduce, nil)
   431  			return fn, fn
   432  		}
   433  		return newBooleanReduceBooleanIterator(input, opt, createFn), nil
   434  	default:
   435  		return nil, fmt.Errorf("unsupported last iterator type: %T", input)
   436  	}
   437  }
   438  
   439  // FloatLastReduce returns the last point sorted by time.
   440  func FloatLastReduce(prev, curr *FloatPoint) (int64, float64, []interface{}) {
   441  	if prev == nil || curr.Time > prev.Time || (curr.Time == prev.Time && curr.Value > prev.Value) {
   442  		return curr.Time, curr.Value, cloneAux(curr.Aux)
   443  	}
   444  	return prev.Time, prev.Value, prev.Aux
   445  }
   446  
   447  // IntegerLastReduce returns the last point sorted by time.
   448  func IntegerLastReduce(prev, curr *IntegerPoint) (int64, int64, []interface{}) {
   449  	if prev == nil || curr.Time > prev.Time || (curr.Time == prev.Time && curr.Value > prev.Value) {
   450  		return curr.Time, curr.Value, cloneAux(curr.Aux)
   451  	}
   452  	return prev.Time, prev.Value, prev.Aux
   453  }
   454  
   455  // UnsignedLastReduce returns the last point sorted by time.
   456  func UnsignedLastReduce(prev, curr *UnsignedPoint) (int64, uint64, []interface{}) {
   457  	if prev == nil || curr.Time > prev.Time || (curr.Time == prev.Time && curr.Value > prev.Value) {
   458  		return curr.Time, curr.Value, cloneAux(curr.Aux)
   459  	}
   460  	return prev.Time, prev.Value, prev.Aux
   461  }
   462  
   463  // StringLastReduce returns the first point sorted by time.
   464  func StringLastReduce(prev, curr *StringPoint) (int64, string, []interface{}) {
   465  	if prev == nil || curr.Time > prev.Time || (curr.Time == prev.Time && curr.Value > prev.Value) {
   466  		return curr.Time, curr.Value, cloneAux(curr.Aux)
   467  	}
   468  	return prev.Time, prev.Value, prev.Aux
   469  }
   470  
   471  // BooleanLastReduce returns the first point sorted by time.
   472  func BooleanLastReduce(prev, curr *BooleanPoint) (int64, bool, []interface{}) {
   473  	if prev == nil || curr.Time > prev.Time || (curr.Time == prev.Time && curr.Value && !prev.Value) {
   474  		return curr.Time, curr.Value, cloneAux(curr.Aux)
   475  	}
   476  	return prev.Time, prev.Value, prev.Aux
   477  }
   478  
   479  // NewDistinctIterator returns an iterator for operating on a distinct() call.
   480  func NewDistinctIterator(input Iterator, opt IteratorOptions) (Iterator, error) {
   481  	switch input := input.(type) {
   482  	case FloatIterator:
   483  		createFn := func() (FloatPointAggregator, FloatPointEmitter) {
   484  			fn := NewFloatDistinctReducer()
   485  			return fn, fn
   486  		}
   487  		return newFloatReduceFloatIterator(input, opt, createFn), nil
   488  	case IntegerIterator:
   489  		createFn := func() (IntegerPointAggregator, IntegerPointEmitter) {
   490  			fn := NewIntegerDistinctReducer()
   491  			return fn, fn
   492  		}
   493  		return newIntegerReduceIntegerIterator(input, opt, createFn), nil
   494  	case UnsignedIterator:
   495  		createFn := func() (UnsignedPointAggregator, UnsignedPointEmitter) {
   496  			fn := NewUnsignedDistinctReducer()
   497  			return fn, fn
   498  		}
   499  		return newUnsignedReduceUnsignedIterator(input, opt, createFn), nil
   500  	case StringIterator:
   501  		createFn := func() (StringPointAggregator, StringPointEmitter) {
   502  			fn := NewStringDistinctReducer()
   503  			return fn, fn
   504  		}
   505  		return newStringReduceStringIterator(input, opt, createFn), nil
   506  	case BooleanIterator:
   507  		createFn := func() (BooleanPointAggregator, BooleanPointEmitter) {
   508  			fn := NewBooleanDistinctReducer()
   509  			return fn, fn
   510  		}
   511  		return newBooleanReduceBooleanIterator(input, opt, createFn), nil
   512  	default:
   513  		return nil, fmt.Errorf("unsupported distinct iterator type: %T", input)
   514  	}
   515  }
   516  
   517  // newMeanIterator returns an iterator for operating on a mean() call.
   518  func newMeanIterator(input Iterator, opt IteratorOptions) (Iterator, error) {
   519  	switch input := input.(type) {
   520  	case FloatIterator:
   521  		createFn := func() (FloatPointAggregator, FloatPointEmitter) {
   522  			fn := NewFloatMeanReducer()
   523  			return fn, fn
   524  		}
   525  		return newFloatReduceFloatIterator(input, opt, createFn), nil
   526  	case IntegerIterator:
   527  		createFn := func() (IntegerPointAggregator, FloatPointEmitter) {
   528  			fn := NewIntegerMeanReducer()
   529  			return fn, fn
   530  		}
   531  		return newIntegerReduceFloatIterator(input, opt, createFn), nil
   532  	case UnsignedIterator:
   533  		createFn := func() (UnsignedPointAggregator, FloatPointEmitter) {
   534  			fn := NewUnsignedMeanReducer()
   535  			return fn, fn
   536  		}
   537  		return newUnsignedReduceFloatIterator(input, opt, createFn), nil
   538  	default:
   539  		return nil, fmt.Errorf("unsupported mean iterator type: %T", input)
   540  	}
   541  }
   542  
   543  // NewMedianIterator returns an iterator for operating on a median() call.
   544  func NewMedianIterator(input Iterator, opt IteratorOptions) (Iterator, error) {
   545  	return newMedianIterator(input, opt)
   546  }
   547  
   548  // newMedianIterator returns an iterator for operating on a median() call.
   549  func newMedianIterator(input Iterator, opt IteratorOptions) (Iterator, error) {
   550  	switch input := input.(type) {
   551  	case FloatIterator:
   552  		createFn := func() (FloatPointAggregator, FloatPointEmitter) {
   553  			fn := NewFloatSliceFuncReducer(FloatMedianReduceSlice)
   554  			return fn, fn
   555  		}
   556  		return newFloatReduceFloatIterator(input, opt, createFn), nil
   557  	case IntegerIterator:
   558  		createFn := func() (IntegerPointAggregator, FloatPointEmitter) {
   559  			fn := NewIntegerSliceFuncFloatReducer(IntegerMedianReduceSlice)
   560  			return fn, fn
   561  		}
   562  		return newIntegerReduceFloatIterator(input, opt, createFn), nil
   563  	case UnsignedIterator:
   564  		createFn := func() (UnsignedPointAggregator, FloatPointEmitter) {
   565  			fn := NewUnsignedSliceFuncFloatReducer(UnsignedMedianReduceSlice)
   566  			return fn, fn
   567  		}
   568  		return newUnsignedReduceFloatIterator(input, opt, createFn), nil
   569  	default:
   570  		return nil, fmt.Errorf("unsupported median iterator type: %T", input)
   571  	}
   572  }
   573  
   574  // FloatMedianReduceSlice returns the median value within a window.
   575  func FloatMedianReduceSlice(a []FloatPoint) []FloatPoint {
   576  	if len(a) == 1 {
   577  		return a
   578  	}
   579  
   580  	// OPTIMIZE(benbjohnson): Use getSortedRange() from v0.9.5.1.
   581  
   582  	// Return the middle value from the points.
   583  	// If there are an even number of points then return the mean of the two middle points.
   584  	sort.Sort(floatPointsByValue(a))
   585  	if len(a)%2 == 0 {
   586  		lo, hi := a[len(a)/2-1], a[(len(a)/2)]
   587  		return []FloatPoint{{Time: ZeroTime, Value: lo.Value + (hi.Value-lo.Value)/2}}
   588  	}
   589  	return []FloatPoint{{Time: ZeroTime, Value: a[len(a)/2].Value}}
   590  }
   591  
   592  // IntegerMedianReduceSlice returns the median value within a window.
   593  func IntegerMedianReduceSlice(a []IntegerPoint) []FloatPoint {
   594  	if len(a) == 1 {
   595  		return []FloatPoint{{Time: ZeroTime, Value: float64(a[0].Value)}}
   596  	}
   597  
   598  	// OPTIMIZE(benbjohnson): Use getSortedRange() from v0.9.5.1.
   599  
   600  	// Return the middle value from the points.
   601  	// If there are an even number of points then return the mean of the two middle points.
   602  	sort.Sort(integerPointsByValue(a))
   603  	if len(a)%2 == 0 {
   604  		lo, hi := a[len(a)/2-1], a[(len(a)/2)]
   605  		return []FloatPoint{{Time: ZeroTime, Value: float64(lo.Value) + float64(hi.Value-lo.Value)/2}}
   606  	}
   607  	return []FloatPoint{{Time: ZeroTime, Value: float64(a[len(a)/2].Value)}}
   608  }
   609  
   610  // UnsignedMedianReduceSlice returns the median value within a window.
   611  func UnsignedMedianReduceSlice(a []UnsignedPoint) []FloatPoint {
   612  	if len(a) == 1 {
   613  		return []FloatPoint{{Time: ZeroTime, Value: float64(a[0].Value)}}
   614  	}
   615  
   616  	// OPTIMIZE(benbjohnson): Use getSortedRange() from v0.9.5.1.
   617  
   618  	// Return the middle value from the points.
   619  	// If there are an even number of points then return the mean of the two middle points.
   620  	sort.Sort(unsignedPointsByValue(a))
   621  	if len(a)%2 == 0 {
   622  		lo, hi := a[len(a)/2-1], a[(len(a)/2)]
   623  		return []FloatPoint{{Time: ZeroTime, Value: float64(lo.Value) + float64(hi.Value-lo.Value)/2}}
   624  	}
   625  	return []FloatPoint{{Time: ZeroTime, Value: float64(a[len(a)/2].Value)}}
   626  }
   627  
   628  // newModeIterator returns an iterator for operating on a mode() call.
   629  func NewModeIterator(input Iterator, opt IteratorOptions) (Iterator, error) {
   630  	switch input := input.(type) {
   631  	case FloatIterator:
   632  		createFn := func() (FloatPointAggregator, FloatPointEmitter) {
   633  			fn := NewFloatSliceFuncReducer(FloatModeReduceSlice)
   634  			return fn, fn
   635  		}
   636  		return newFloatReduceFloatIterator(input, opt, createFn), nil
   637  	case IntegerIterator:
   638  		createFn := func() (IntegerPointAggregator, IntegerPointEmitter) {
   639  			fn := NewIntegerSliceFuncReducer(IntegerModeReduceSlice)
   640  			return fn, fn
   641  		}
   642  		return newIntegerReduceIntegerIterator(input, opt, createFn), nil
   643  	case UnsignedIterator:
   644  		createFn := func() (UnsignedPointAggregator, UnsignedPointEmitter) {
   645  			fn := NewUnsignedSliceFuncReducer(UnsignedModeReduceSlice)
   646  			return fn, fn
   647  		}
   648  		return newUnsignedReduceUnsignedIterator(input, opt, createFn), nil
   649  	case StringIterator:
   650  		createFn := func() (StringPointAggregator, StringPointEmitter) {
   651  			fn := NewStringSliceFuncReducer(StringModeReduceSlice)
   652  			return fn, fn
   653  		}
   654  		return newStringReduceStringIterator(input, opt, createFn), nil
   655  	case BooleanIterator:
   656  		createFn := func() (BooleanPointAggregator, BooleanPointEmitter) {
   657  			fn := NewBooleanSliceFuncReducer(BooleanModeReduceSlice)
   658  			return fn, fn
   659  		}
   660  		return newBooleanReduceBooleanIterator(input, opt, createFn), nil
   661  	default:
   662  		return nil, fmt.Errorf("unsupported median iterator type: %T", input)
   663  	}
   664  }
   665  
   666  // FloatModeReduceSlice returns the mode value within a window.
   667  func FloatModeReduceSlice(a []FloatPoint) []FloatPoint {
   668  	if len(a) == 1 {
   669  		return a
   670  	}
   671  
   672  	sort.Sort(floatPointsByValue(a))
   673  
   674  	mostFreq := 0
   675  	currFreq := 0
   676  	currMode := a[0].Value
   677  	mostMode := a[0].Value
   678  	mostTime := a[0].Time
   679  	currTime := a[0].Time
   680  
   681  	for _, p := range a {
   682  		if p.Value != currMode {
   683  			currFreq = 1
   684  			currMode = p.Value
   685  			currTime = p.Time
   686  			continue
   687  		}
   688  		currFreq++
   689  		if mostFreq > currFreq || (mostFreq == currFreq && currTime > mostTime) {
   690  			continue
   691  		}
   692  		mostFreq = currFreq
   693  		mostMode = p.Value
   694  		mostTime = p.Time
   695  	}
   696  
   697  	return []FloatPoint{{Time: ZeroTime, Value: mostMode}}
   698  }
   699  
   700  // IntegerModeReduceSlice returns the mode value within a window.
   701  func IntegerModeReduceSlice(a []IntegerPoint) []IntegerPoint {
   702  	if len(a) == 1 {
   703  		return a
   704  	}
   705  	sort.Sort(integerPointsByValue(a))
   706  
   707  	mostFreq := 0
   708  	currFreq := 0
   709  	currMode := a[0].Value
   710  	mostMode := a[0].Value
   711  	mostTime := a[0].Time
   712  	currTime := a[0].Time
   713  
   714  	for _, p := range a {
   715  		if p.Value != currMode {
   716  			currFreq = 1
   717  			currMode = p.Value
   718  			currTime = p.Time
   719  			continue
   720  		}
   721  		currFreq++
   722  		if mostFreq > currFreq || (mostFreq == currFreq && currTime > mostTime) {
   723  			continue
   724  		}
   725  		mostFreq = currFreq
   726  		mostMode = p.Value
   727  		mostTime = p.Time
   728  	}
   729  
   730  	return []IntegerPoint{{Time: ZeroTime, Value: mostMode}}
   731  }
   732  
   733  // UnsignedModeReduceSlice returns the mode value within a window.
   734  func UnsignedModeReduceSlice(a []UnsignedPoint) []UnsignedPoint {
   735  	if len(a) == 1 {
   736  		return a
   737  	}
   738  	sort.Sort(unsignedPointsByValue(a))
   739  
   740  	mostFreq := 0
   741  	currFreq := 0
   742  	currMode := a[0].Value
   743  	mostMode := a[0].Value
   744  	mostTime := a[0].Time
   745  	currTime := a[0].Time
   746  
   747  	for _, p := range a {
   748  		if p.Value != currMode {
   749  			currFreq = 1
   750  			currMode = p.Value
   751  			currTime = p.Time
   752  			continue
   753  		}
   754  		currFreq++
   755  		if mostFreq > currFreq || (mostFreq == currFreq && currTime > mostTime) {
   756  			continue
   757  		}
   758  		mostFreq = currFreq
   759  		mostMode = p.Value
   760  		mostTime = p.Time
   761  	}
   762  
   763  	return []UnsignedPoint{{Time: ZeroTime, Value: mostMode}}
   764  }
   765  
   766  // StringModeReduceSlice returns the mode value within a window.
   767  func StringModeReduceSlice(a []StringPoint) []StringPoint {
   768  	if len(a) == 1 {
   769  		return a
   770  	}
   771  
   772  	sort.Sort(stringPointsByValue(a))
   773  
   774  	mostFreq := 0
   775  	currFreq := 0
   776  	currMode := a[0].Value
   777  	mostMode := a[0].Value
   778  	mostTime := a[0].Time
   779  	currTime := a[0].Time
   780  
   781  	for _, p := range a {
   782  		if p.Value != currMode {
   783  			currFreq = 1
   784  			currMode = p.Value
   785  			currTime = p.Time
   786  			continue
   787  		}
   788  		currFreq++
   789  		if mostFreq > currFreq || (mostFreq == currFreq && currTime > mostTime) {
   790  			continue
   791  		}
   792  		mostFreq = currFreq
   793  		mostMode = p.Value
   794  		mostTime = p.Time
   795  	}
   796  
   797  	return []StringPoint{{Time: ZeroTime, Value: mostMode}}
   798  }
   799  
   800  // BooleanModeReduceSlice returns the mode value within a window.
   801  func BooleanModeReduceSlice(a []BooleanPoint) []BooleanPoint {
   802  	if len(a) == 1 {
   803  		return a
   804  	}
   805  
   806  	trueFreq := 0
   807  	falsFreq := 0
   808  	mostMode := false
   809  
   810  	for _, p := range a {
   811  		if p.Value {
   812  			trueFreq++
   813  		} else {
   814  			falsFreq++
   815  		}
   816  	}
   817  	// In case either of true or false are mode then retuned mode value wont be
   818  	// of metric with oldest timestamp
   819  	if trueFreq >= falsFreq {
   820  		mostMode = true
   821  	}
   822  
   823  	return []BooleanPoint{{Time: ZeroTime, Value: mostMode}}
   824  }
   825  
   826  // newStddevIterator returns an iterator for operating on a stddev() call.
   827  func newStddevIterator(input Iterator, opt IteratorOptions) (Iterator, error) {
   828  	switch input := input.(type) {
   829  	case FloatIterator:
   830  		createFn := func() (FloatPointAggregator, FloatPointEmitter) {
   831  			fn := NewFloatSliceFuncReducer(FloatStddevReduceSlice)
   832  			return fn, fn
   833  		}
   834  		return newFloatReduceFloatIterator(input, opt, createFn), nil
   835  	case IntegerIterator:
   836  		createFn := func() (IntegerPointAggregator, FloatPointEmitter) {
   837  			fn := NewIntegerSliceFuncFloatReducer(IntegerStddevReduceSlice)
   838  			return fn, fn
   839  		}
   840  		return newIntegerReduceFloatIterator(input, opt, createFn), nil
   841  	case UnsignedIterator:
   842  		createFn := func() (UnsignedPointAggregator, FloatPointEmitter) {
   843  			fn := NewUnsignedSliceFuncFloatReducer(UnsignedStddevReduceSlice)
   844  			return fn, fn
   845  		}
   846  		return newUnsignedReduceFloatIterator(input, opt, createFn), nil
   847  	default:
   848  		return nil, fmt.Errorf("unsupported stddev iterator type: %T", input)
   849  	}
   850  }
   851  
   852  // FloatStddevReduceSlice returns the stddev value within a window.
   853  func FloatStddevReduceSlice(a []FloatPoint) []FloatPoint {
   854  	// If there is only one point then return NaN.
   855  	if len(a) < 2 {
   856  		return []FloatPoint{{Time: ZeroTime, Value: math.NaN()}}
   857  	}
   858  
   859  	// Calculate the mean.
   860  	var mean float64
   861  	var count int
   862  	for _, p := range a {
   863  		if math.IsNaN(p.Value) {
   864  			continue
   865  		}
   866  		count++
   867  		mean += (p.Value - mean) / float64(count)
   868  	}
   869  
   870  	// Calculate the variance.
   871  	var variance float64
   872  	for _, p := range a {
   873  		if math.IsNaN(p.Value) {
   874  			continue
   875  		}
   876  		variance += math.Pow(p.Value-mean, 2)
   877  	}
   878  	return []FloatPoint{{
   879  		Time:  ZeroTime,
   880  		Value: math.Sqrt(variance / float64(count-1)),
   881  	}}
   882  }
   883  
   884  // IntegerStddevReduceSlice returns the stddev value within a window.
   885  func IntegerStddevReduceSlice(a []IntegerPoint) []FloatPoint {
   886  	// If there is only one point then return NaN.
   887  	if len(a) < 2 {
   888  		return []FloatPoint{{Time: ZeroTime, Value: math.NaN()}}
   889  	}
   890  
   891  	// Calculate the mean.
   892  	var mean float64
   893  	var count int
   894  	for _, p := range a {
   895  		count++
   896  		mean += (float64(p.Value) - mean) / float64(count)
   897  	}
   898  
   899  	// Calculate the variance.
   900  	var variance float64
   901  	for _, p := range a {
   902  		variance += math.Pow(float64(p.Value)-mean, 2)
   903  	}
   904  	return []FloatPoint{{
   905  		Time:  ZeroTime,
   906  		Value: math.Sqrt(variance / float64(count-1)),
   907  	}}
   908  }
   909  
   910  // UnsignedStddevReduceSlice returns the stddev value within a window.
   911  func UnsignedStddevReduceSlice(a []UnsignedPoint) []FloatPoint {
   912  	// If there is only one point then return NaN.
   913  	if len(a) < 2 {
   914  		return []FloatPoint{{Time: ZeroTime, Value: math.NaN()}}
   915  	}
   916  
   917  	// Calculate the mean.
   918  	var mean float64
   919  	var count int
   920  	for _, p := range a {
   921  		count++
   922  		mean += (float64(p.Value) - mean) / float64(count)
   923  	}
   924  
   925  	// Calculate the variance.
   926  	var variance float64
   927  	for _, p := range a {
   928  		variance += math.Pow(float64(p.Value)-mean, 2)
   929  	}
   930  	return []FloatPoint{{
   931  		Time:  ZeroTime,
   932  		Value: math.Sqrt(variance / float64(count-1)),
   933  	}}
   934  }
   935  
   936  // newSpreadIterator returns an iterator for operating on a spread() call.
   937  func newSpreadIterator(input Iterator, opt IteratorOptions) (Iterator, error) {
   938  	switch input := input.(type) {
   939  	case FloatIterator:
   940  		createFn := func() (FloatPointAggregator, FloatPointEmitter) {
   941  			fn := NewFloatSpreadReducer()
   942  			return fn, fn
   943  		}
   944  		return newFloatReduceFloatIterator(input, opt, createFn), nil
   945  	case IntegerIterator:
   946  		createFn := func() (IntegerPointAggregator, IntegerPointEmitter) {
   947  			fn := NewIntegerSpreadReducer()
   948  			return fn, fn
   949  		}
   950  		return newIntegerReduceIntegerIterator(input, opt, createFn), nil
   951  	case UnsignedIterator:
   952  		createFn := func() (UnsignedPointAggregator, UnsignedPointEmitter) {
   953  			fn := NewUnsignedSpreadReducer()
   954  			return fn, fn
   955  		}
   956  		return newUnsignedReduceUnsignedIterator(input, opt, createFn), nil
   957  	default:
   958  		return nil, fmt.Errorf("unsupported spread iterator type: %T", input)
   959  	}
   960  }
   961  
   962  func newTopIterator(input Iterator, opt IteratorOptions, n int, keepTags bool) (Iterator, error) {
   963  	switch input := input.(type) {
   964  	case FloatIterator:
   965  		createFn := func() (FloatPointAggregator, FloatPointEmitter) {
   966  			fn := NewFloatTopReducer(n)
   967  			return fn, fn
   968  		}
   969  		itr := newFloatReduceFloatIterator(input, opt, createFn)
   970  		itr.keepTags = keepTags
   971  		return itr, nil
   972  	case IntegerIterator:
   973  		createFn := func() (IntegerPointAggregator, IntegerPointEmitter) {
   974  			fn := NewIntegerTopReducer(n)
   975  			return fn, fn
   976  		}
   977  		itr := newIntegerReduceIntegerIterator(input, opt, createFn)
   978  		itr.keepTags = keepTags
   979  		return itr, nil
   980  	case UnsignedIterator:
   981  		createFn := func() (UnsignedPointAggregator, UnsignedPointEmitter) {
   982  			fn := NewUnsignedTopReducer(n)
   983  			return fn, fn
   984  		}
   985  		itr := newUnsignedReduceUnsignedIterator(input, opt, createFn)
   986  		itr.keepTags = keepTags
   987  		return itr, nil
   988  	default:
   989  		return nil, fmt.Errorf("unsupported top iterator type: %T", input)
   990  	}
   991  }
   992  
   993  func newBottomIterator(input Iterator, opt IteratorOptions, n int, keepTags bool) (Iterator, error) {
   994  	switch input := input.(type) {
   995  	case FloatIterator:
   996  		createFn := func() (FloatPointAggregator, FloatPointEmitter) {
   997  			fn := NewFloatBottomReducer(n)
   998  			return fn, fn
   999  		}
  1000  		itr := newFloatReduceFloatIterator(input, opt, createFn)
  1001  		itr.keepTags = keepTags
  1002  		return itr, nil
  1003  	case IntegerIterator:
  1004  		createFn := func() (IntegerPointAggregator, IntegerPointEmitter) {
  1005  			fn := NewIntegerBottomReducer(n)
  1006  			return fn, fn
  1007  		}
  1008  		itr := newIntegerReduceIntegerIterator(input, opt, createFn)
  1009  		itr.keepTags = keepTags
  1010  		return itr, nil
  1011  	case UnsignedIterator:
  1012  		createFn := func() (UnsignedPointAggregator, UnsignedPointEmitter) {
  1013  			fn := NewUnsignedBottomReducer(n)
  1014  			return fn, fn
  1015  		}
  1016  		itr := newUnsignedReduceUnsignedIterator(input, opt, createFn)
  1017  		itr.keepTags = keepTags
  1018  		return itr, nil
  1019  	default:
  1020  		return nil, fmt.Errorf("unsupported bottom iterator type: %T", input)
  1021  	}
  1022  }
  1023  
  1024  // newPercentileIterator returns an iterator for operating on a percentile() call.
  1025  func newPercentileIterator(input Iterator, opt IteratorOptions, percentile float64) (Iterator, error) {
  1026  	switch input := input.(type) {
  1027  	case FloatIterator:
  1028  		floatPercentileReduceSlice := NewFloatPercentileReduceSliceFunc(percentile)
  1029  		createFn := func() (FloatPointAggregator, FloatPointEmitter) {
  1030  			fn := NewFloatSliceFuncReducer(floatPercentileReduceSlice)
  1031  			return fn, fn
  1032  		}
  1033  		return newFloatReduceFloatIterator(input, opt, createFn), nil
  1034  	case IntegerIterator:
  1035  		integerPercentileReduceSlice := NewIntegerPercentileReduceSliceFunc(percentile)
  1036  		createFn := func() (IntegerPointAggregator, IntegerPointEmitter) {
  1037  			fn := NewIntegerSliceFuncReducer(integerPercentileReduceSlice)
  1038  			return fn, fn
  1039  		}
  1040  		return newIntegerReduceIntegerIterator(input, opt, createFn), nil
  1041  	case UnsignedIterator:
  1042  		unsignedPercentileReduceSlice := NewUnsignedPercentileReduceSliceFunc(percentile)
  1043  		createFn := func() (UnsignedPointAggregator, UnsignedPointEmitter) {
  1044  			fn := NewUnsignedSliceFuncReducer(unsignedPercentileReduceSlice)
  1045  			return fn, fn
  1046  		}
  1047  		return newUnsignedReduceUnsignedIterator(input, opt, createFn), nil
  1048  	default:
  1049  		return nil, fmt.Errorf("unsupported percentile iterator type: %T", input)
  1050  	}
  1051  }
  1052  
  1053  // NewFloatPercentileReduceSliceFunc returns the percentile value within a window.
  1054  func NewFloatPercentileReduceSliceFunc(percentile float64) FloatReduceSliceFunc {
  1055  	return func(a []FloatPoint) []FloatPoint {
  1056  		length := len(a)
  1057  		i := int(math.Floor(float64(length)*percentile/100.0+0.5)) - 1
  1058  
  1059  		if i < 0 || i >= length {
  1060  			return nil
  1061  		}
  1062  
  1063  		sort.Sort(floatPointsByValue(a))
  1064  		return []FloatPoint{{Time: a[i].Time, Value: a[i].Value, Aux: cloneAux(a[i].Aux)}}
  1065  	}
  1066  }
  1067  
  1068  // NewIntegerPercentileReduceSliceFunc returns the percentile value within a window.
  1069  func NewIntegerPercentileReduceSliceFunc(percentile float64) IntegerReduceSliceFunc {
  1070  	return func(a []IntegerPoint) []IntegerPoint {
  1071  		length := len(a)
  1072  		i := int(math.Floor(float64(length)*percentile/100.0+0.5)) - 1
  1073  
  1074  		if i < 0 || i >= length {
  1075  			return nil
  1076  		}
  1077  
  1078  		sort.Sort(integerPointsByValue(a))
  1079  		return []IntegerPoint{{Time: a[i].Time, Value: a[i].Value, Aux: cloneAux(a[i].Aux)}}
  1080  	}
  1081  }
  1082  
  1083  // NewUnsignedPercentileReduceSliceFunc returns the percentile value within a window.
  1084  func NewUnsignedPercentileReduceSliceFunc(percentile float64) UnsignedReduceSliceFunc {
  1085  	return func(a []UnsignedPoint) []UnsignedPoint {
  1086  		length := len(a)
  1087  		i := int(math.Floor(float64(length)*percentile/100.0+0.5)) - 1
  1088  
  1089  		if i < 0 || i >= length {
  1090  			return nil
  1091  		}
  1092  
  1093  		sort.Sort(unsignedPointsByValue(a))
  1094  		return []UnsignedPoint{{Time: a[i].Time, Value: a[i].Value, Aux: cloneAux(a[i].Aux)}}
  1095  	}
  1096  }
  1097  
  1098  // newDerivativeIterator returns an iterator for operating on a derivative() call.
  1099  func newDerivativeIterator(input Iterator, opt IteratorOptions, interval Interval, isNonNegative bool) (Iterator, error) {
  1100  	switch input := input.(type) {
  1101  	case FloatIterator:
  1102  		createFn := func() (FloatPointAggregator, FloatPointEmitter) {
  1103  			fn := NewFloatDerivativeReducer(interval, isNonNegative, opt.Ascending)
  1104  			return fn, fn
  1105  		}
  1106  		return newFloatStreamFloatIterator(input, createFn, opt), nil
  1107  	case IntegerIterator:
  1108  		createFn := func() (IntegerPointAggregator, FloatPointEmitter) {
  1109  			fn := NewIntegerDerivativeReducer(interval, isNonNegative, opt.Ascending)
  1110  			return fn, fn
  1111  		}
  1112  		return newIntegerStreamFloatIterator(input, createFn, opt), nil
  1113  	case UnsignedIterator:
  1114  		createFn := func() (UnsignedPointAggregator, FloatPointEmitter) {
  1115  			fn := NewUnsignedDerivativeReducer(interval, isNonNegative, opt.Ascending)
  1116  			return fn, fn
  1117  		}
  1118  		return newUnsignedStreamFloatIterator(input, createFn, opt), nil
  1119  	default:
  1120  		return nil, fmt.Errorf("unsupported derivative iterator type: %T", input)
  1121  	}
  1122  }
  1123  
  1124  // newDifferenceIterator returns an iterator for operating on a difference() call.
  1125  func newDifferenceIterator(input Iterator, opt IteratorOptions, isNonNegative bool) (Iterator, error) {
  1126  	switch input := input.(type) {
  1127  	case FloatIterator:
  1128  		createFn := func() (FloatPointAggregator, FloatPointEmitter) {
  1129  			fn := NewFloatDifferenceReducer(isNonNegative)
  1130  			return fn, fn
  1131  		}
  1132  		return newFloatStreamFloatIterator(input, createFn, opt), nil
  1133  	case IntegerIterator:
  1134  		createFn := func() (IntegerPointAggregator, IntegerPointEmitter) {
  1135  			fn := NewIntegerDifferenceReducer(isNonNegative)
  1136  			return fn, fn
  1137  		}
  1138  		return newIntegerStreamIntegerIterator(input, createFn, opt), nil
  1139  	case UnsignedIterator:
  1140  		createFn := func() (UnsignedPointAggregator, UnsignedPointEmitter) {
  1141  			fn := NewUnsignedDifferenceReducer(isNonNegative)
  1142  			return fn, fn
  1143  		}
  1144  		return newUnsignedStreamUnsignedIterator(input, createFn, opt), nil
  1145  	default:
  1146  		return nil, fmt.Errorf("unsupported difference iterator type: %T", input)
  1147  	}
  1148  }
  1149  
  1150  // newElapsedIterator returns an iterator for operating on a elapsed() call.
  1151  func newElapsedIterator(input Iterator, opt IteratorOptions, interval Interval) (Iterator, error) {
  1152  	switch input := input.(type) {
  1153  	case FloatIterator:
  1154  		createFn := func() (FloatPointAggregator, IntegerPointEmitter) {
  1155  			fn := NewFloatElapsedReducer(interval)
  1156  			return fn, fn
  1157  		}
  1158  		return newFloatStreamIntegerIterator(input, createFn, opt), nil
  1159  	case IntegerIterator:
  1160  		createFn := func() (IntegerPointAggregator, IntegerPointEmitter) {
  1161  			fn := NewIntegerElapsedReducer(interval)
  1162  			return fn, fn
  1163  		}
  1164  		return newIntegerStreamIntegerIterator(input, createFn, opt), nil
  1165  	case UnsignedIterator:
  1166  		createFn := func() (UnsignedPointAggregator, IntegerPointEmitter) {
  1167  			fn := NewUnsignedElapsedReducer(interval)
  1168  			return fn, fn
  1169  		}
  1170  		return newUnsignedStreamIntegerIterator(input, createFn, opt), nil
  1171  	case BooleanIterator:
  1172  		createFn := func() (BooleanPointAggregator, IntegerPointEmitter) {
  1173  			fn := NewBooleanElapsedReducer(interval)
  1174  			return fn, fn
  1175  		}
  1176  		return newBooleanStreamIntegerIterator(input, createFn, opt), nil
  1177  	case StringIterator:
  1178  		createFn := func() (StringPointAggregator, IntegerPointEmitter) {
  1179  			fn := NewStringElapsedReducer(interval)
  1180  			return fn, fn
  1181  		}
  1182  		return newStringStreamIntegerIterator(input, createFn, opt), nil
  1183  	default:
  1184  		return nil, fmt.Errorf("unsupported elapsed iterator type: %T", input)
  1185  	}
  1186  }
  1187  
  1188  // newMovingAverageIterator returns an iterator for operating on a moving_average() call.
  1189  func newMovingAverageIterator(input Iterator, n int, opt IteratorOptions) (Iterator, error) {
  1190  	switch input := input.(type) {
  1191  	case FloatIterator:
  1192  		createFn := func() (FloatPointAggregator, FloatPointEmitter) {
  1193  			fn := NewFloatMovingAverageReducer(n)
  1194  			return fn, fn
  1195  		}
  1196  		return newFloatStreamFloatIterator(input, createFn, opt), nil
  1197  	case IntegerIterator:
  1198  		createFn := func() (IntegerPointAggregator, FloatPointEmitter) {
  1199  			fn := NewIntegerMovingAverageReducer(n)
  1200  			return fn, fn
  1201  		}
  1202  		return newIntegerStreamFloatIterator(input, createFn, opt), nil
  1203  	case UnsignedIterator:
  1204  		createFn := func() (UnsignedPointAggregator, FloatPointEmitter) {
  1205  			fn := NewUnsignedMovingAverageReducer(n)
  1206  			return fn, fn
  1207  		}
  1208  		return newUnsignedStreamFloatIterator(input, createFn, opt), nil
  1209  	default:
  1210  		return nil, fmt.Errorf("unsupported moving average iterator type: %T", input)
  1211  	}
  1212  }
  1213  
  1214  // newExponentialMovingAverageIterator returns an iterator for operating on an exponential_moving_average() call.
  1215  func newExponentialMovingAverageIterator(input Iterator, n, nHold int, warmupType gota.WarmupType, opt IteratorOptions) (Iterator, error) {
  1216  	switch input := input.(type) {
  1217  	case FloatIterator:
  1218  		createFn := func() (FloatPointAggregator, FloatPointEmitter) {
  1219  			fn := NewExponentialMovingAverageReducer(n, nHold, warmupType)
  1220  			return fn, fn
  1221  		}
  1222  		return newFloatStreamFloatIterator(input, createFn, opt), nil
  1223  	case IntegerIterator:
  1224  		createFn := func() (IntegerPointAggregator, FloatPointEmitter) {
  1225  			fn := NewExponentialMovingAverageReducer(n, nHold, warmupType)
  1226  			return fn, fn
  1227  		}
  1228  		return newIntegerStreamFloatIterator(input, createFn, opt), nil
  1229  	case UnsignedIterator:
  1230  		createFn := func() (UnsignedPointAggregator, FloatPointEmitter) {
  1231  			fn := NewExponentialMovingAverageReducer(n, nHold, warmupType)
  1232  			return fn, fn
  1233  		}
  1234  		return newUnsignedStreamFloatIterator(input, createFn, opt), nil
  1235  	default:
  1236  		return nil, fmt.Errorf("unsupported exponential moving average iterator type: %T", input)
  1237  	}
  1238  }
  1239  
  1240  // newDoubleExponentialMovingAverageIterator returns an iterator for operating on a double_exponential_moving_average() call.
  1241  func newDoubleExponentialMovingAverageIterator(input Iterator, n int, nHold int, warmupType gota.WarmupType, opt IteratorOptions) (Iterator, error) {
  1242  	switch input := input.(type) {
  1243  	case FloatIterator:
  1244  		createFn := func() (FloatPointAggregator, FloatPointEmitter) {
  1245  			fn := NewDoubleExponentialMovingAverageReducer(n, nHold, warmupType)
  1246  			return fn, fn
  1247  		}
  1248  		return newFloatStreamFloatIterator(input, createFn, opt), nil
  1249  	case IntegerIterator:
  1250  		createFn := func() (IntegerPointAggregator, FloatPointEmitter) {
  1251  			fn := NewDoubleExponentialMovingAverageReducer(n, nHold, warmupType)
  1252  			return fn, fn
  1253  		}
  1254  		return newIntegerStreamFloatIterator(input, createFn, opt), nil
  1255  	case UnsignedIterator:
  1256  		createFn := func() (UnsignedPointAggregator, FloatPointEmitter) {
  1257  			fn := NewDoubleExponentialMovingAverageReducer(n, nHold, warmupType)
  1258  			return fn, fn
  1259  		}
  1260  		return newUnsignedStreamFloatIterator(input, createFn, opt), nil
  1261  	default:
  1262  		return nil, fmt.Errorf("unsupported double exponential moving average iterator type: %T", input)
  1263  	}
  1264  }
  1265  
  1266  // newTripleExponentialMovingAverageIterator returns an iterator for operating on a triple_exponential_moving_average() call.
  1267  func newTripleExponentialMovingAverageIterator(input Iterator, n int, nHold int, warmupType gota.WarmupType, opt IteratorOptions) (Iterator, error) {
  1268  	switch input := input.(type) {
  1269  	case FloatIterator:
  1270  		createFn := func() (FloatPointAggregator, FloatPointEmitter) {
  1271  			fn := NewTripleExponentialMovingAverageReducer(n, nHold, warmupType)
  1272  			return fn, fn
  1273  		}
  1274  		return newFloatStreamFloatIterator(input, createFn, opt), nil
  1275  	case IntegerIterator:
  1276  		createFn := func() (IntegerPointAggregator, FloatPointEmitter) {
  1277  			fn := NewTripleExponentialMovingAverageReducer(n, nHold, warmupType)
  1278  			return fn, fn
  1279  		}
  1280  		return newIntegerStreamFloatIterator(input, createFn, opt), nil
  1281  	case UnsignedIterator:
  1282  		createFn := func() (UnsignedPointAggregator, FloatPointEmitter) {
  1283  			fn := NewTripleExponentialMovingAverageReducer(n, nHold, warmupType)
  1284  			return fn, fn
  1285  		}
  1286  		return newUnsignedStreamFloatIterator(input, createFn, opt), nil
  1287  	default:
  1288  		return nil, fmt.Errorf("unsupported triple exponential moving average iterator type: %T", input)
  1289  	}
  1290  }
  1291  
  1292  // newRelativeStrengthIndexIterator returns an iterator for operating on a triple_exponential_moving_average() call.
  1293  func newRelativeStrengthIndexIterator(input Iterator, n int, nHold int, warmupType gota.WarmupType, opt IteratorOptions) (Iterator, error) {
  1294  	switch input := input.(type) {
  1295  	case FloatIterator:
  1296  		createFn := func() (FloatPointAggregator, FloatPointEmitter) {
  1297  			fn := NewRelativeStrengthIndexReducer(n, nHold, warmupType)
  1298  			return fn, fn
  1299  		}
  1300  		return newFloatStreamFloatIterator(input, createFn, opt), nil
  1301  	case IntegerIterator:
  1302  		createFn := func() (IntegerPointAggregator, FloatPointEmitter) {
  1303  			fn := NewRelativeStrengthIndexReducer(n, nHold, warmupType)
  1304  			return fn, fn
  1305  		}
  1306  		return newIntegerStreamFloatIterator(input, createFn, opt), nil
  1307  	case UnsignedIterator:
  1308  		createFn := func() (UnsignedPointAggregator, FloatPointEmitter) {
  1309  			fn := NewRelativeStrengthIndexReducer(n, nHold, warmupType)
  1310  			return fn, fn
  1311  		}
  1312  		return newUnsignedStreamFloatIterator(input, createFn, opt), nil
  1313  	default:
  1314  		return nil, fmt.Errorf("unsupported relative strength index iterator type: %T", input)
  1315  	}
  1316  }
  1317  
  1318  // newTripleExponentialDerivativeIterator returns an iterator for operating on a triple_exponential_moving_average() call.
  1319  func newTripleExponentialDerivativeIterator(input Iterator, n int, nHold int, warmupType gota.WarmupType, opt IteratorOptions) (Iterator, error) {
  1320  	switch input := input.(type) {
  1321  	case FloatIterator:
  1322  		createFn := func() (FloatPointAggregator, FloatPointEmitter) {
  1323  			fn := NewTripleExponentialDerivativeReducer(n, nHold, warmupType)
  1324  			return fn, fn
  1325  		}
  1326  		return newFloatStreamFloatIterator(input, createFn, opt), nil
  1327  	case IntegerIterator:
  1328  		createFn := func() (IntegerPointAggregator, FloatPointEmitter) {
  1329  			fn := NewTripleExponentialDerivativeReducer(n, nHold, warmupType)
  1330  			return fn, fn
  1331  		}
  1332  		return newIntegerStreamFloatIterator(input, createFn, opt), nil
  1333  	case UnsignedIterator:
  1334  		createFn := func() (UnsignedPointAggregator, FloatPointEmitter) {
  1335  			fn := NewTripleExponentialDerivativeReducer(n, nHold, warmupType)
  1336  			return fn, fn
  1337  		}
  1338  		return newUnsignedStreamFloatIterator(input, createFn, opt), nil
  1339  	default:
  1340  		return nil, fmt.Errorf("unsupported triple exponential derivative iterator type: %T", input)
  1341  	}
  1342  }
  1343  
  1344  // newKaufmansEfficiencyRatioIterator returns an iterator for operating on a kaufmans_efficiency_ratio() call.
  1345  func newKaufmansEfficiencyRatioIterator(input Iterator, n int, nHold int, opt IteratorOptions) (Iterator, error) {
  1346  	switch input := input.(type) {
  1347  	case FloatIterator:
  1348  		createFn := func() (FloatPointAggregator, FloatPointEmitter) {
  1349  			fn := NewKaufmansEfficiencyRatioReducer(n, nHold)
  1350  			return fn, fn
  1351  		}
  1352  		return newFloatStreamFloatIterator(input, createFn, opt), nil
  1353  	case IntegerIterator:
  1354  		createFn := func() (IntegerPointAggregator, FloatPointEmitter) {
  1355  			fn := NewKaufmansEfficiencyRatioReducer(n, nHold)
  1356  			return fn, fn
  1357  		}
  1358  		return newIntegerStreamFloatIterator(input, createFn, opt), nil
  1359  	case UnsignedIterator:
  1360  		createFn := func() (UnsignedPointAggregator, FloatPointEmitter) {
  1361  			fn := NewKaufmansEfficiencyRatioReducer(n, nHold)
  1362  			return fn, fn
  1363  		}
  1364  		return newUnsignedStreamFloatIterator(input, createFn, opt), nil
  1365  	default:
  1366  		return nil, fmt.Errorf("unsupported kaufmans efficiency ratio iterator type: %T", input)
  1367  	}
  1368  }
  1369  
  1370  // newKaufmansAdaptiveMovingAverageIterator returns an iterator for operating on a kaufmans_adaptive_moving_average() call.
  1371  func newKaufmansAdaptiveMovingAverageIterator(input Iterator, n int, nHold int, opt IteratorOptions) (Iterator, error) {
  1372  	switch input := input.(type) {
  1373  	case FloatIterator:
  1374  		createFn := func() (FloatPointAggregator, FloatPointEmitter) {
  1375  			fn := NewKaufmansAdaptiveMovingAverageReducer(n, nHold)
  1376  			return fn, fn
  1377  		}
  1378  		return newFloatStreamFloatIterator(input, createFn, opt), nil
  1379  	case IntegerIterator:
  1380  		createFn := func() (IntegerPointAggregator, FloatPointEmitter) {
  1381  			fn := NewKaufmansAdaptiveMovingAverageReducer(n, nHold)
  1382  			return fn, fn
  1383  		}
  1384  		return newIntegerStreamFloatIterator(input, createFn, opt), nil
  1385  	case UnsignedIterator:
  1386  		createFn := func() (UnsignedPointAggregator, FloatPointEmitter) {
  1387  			fn := NewKaufmansAdaptiveMovingAverageReducer(n, nHold)
  1388  			return fn, fn
  1389  		}
  1390  		return newUnsignedStreamFloatIterator(input, createFn, opt), nil
  1391  	default:
  1392  		return nil, fmt.Errorf("unsupported kaufmans adaptive moving average iterator type: %T", input)
  1393  	}
  1394  }
  1395  
  1396  // newChandeMomentumOscillatorIterator returns an iterator for operating on a triple_exponential_moving_average() call.
  1397  func newChandeMomentumOscillatorIterator(input Iterator, n int, nHold int, warmupType gota.WarmupType, opt IteratorOptions) (Iterator, error) {
  1398  	switch input := input.(type) {
  1399  	case FloatIterator:
  1400  		createFn := func() (FloatPointAggregator, FloatPointEmitter) {
  1401  			fn := NewChandeMomentumOscillatorReducer(n, nHold, warmupType)
  1402  			return fn, fn
  1403  		}
  1404  		return newFloatStreamFloatIterator(input, createFn, opt), nil
  1405  	case IntegerIterator:
  1406  		createFn := func() (IntegerPointAggregator, FloatPointEmitter) {
  1407  			fn := NewChandeMomentumOscillatorReducer(n, nHold, warmupType)
  1408  			return fn, fn
  1409  		}
  1410  		return newIntegerStreamFloatIterator(input, createFn, opt), nil
  1411  	case UnsignedIterator:
  1412  		createFn := func() (UnsignedPointAggregator, FloatPointEmitter) {
  1413  			fn := NewChandeMomentumOscillatorReducer(n, nHold, warmupType)
  1414  			return fn, fn
  1415  		}
  1416  		return newUnsignedStreamFloatIterator(input, createFn, opt), nil
  1417  	default:
  1418  		return nil, fmt.Errorf("unsupported chande momentum oscillator iterator type: %T", input)
  1419  	}
  1420  }
  1421  
  1422  // newCumulativeSumIterator returns an iterator for operating on a cumulative_sum() call.
  1423  func newCumulativeSumIterator(input Iterator, opt IteratorOptions) (Iterator, error) {
  1424  	switch input := input.(type) {
  1425  	case FloatIterator:
  1426  		createFn := func() (FloatPointAggregator, FloatPointEmitter) {
  1427  			fn := NewFloatCumulativeSumReducer()
  1428  			return fn, fn
  1429  		}
  1430  		return newFloatStreamFloatIterator(input, createFn, opt), nil
  1431  	case IntegerIterator:
  1432  		createFn := func() (IntegerPointAggregator, IntegerPointEmitter) {
  1433  			fn := NewIntegerCumulativeSumReducer()
  1434  			return fn, fn
  1435  		}
  1436  		return newIntegerStreamIntegerIterator(input, createFn, opt), nil
  1437  	case UnsignedIterator:
  1438  		createFn := func() (UnsignedPointAggregator, UnsignedPointEmitter) {
  1439  			fn := NewUnsignedCumulativeSumReducer()
  1440  			return fn, fn
  1441  		}
  1442  		return newUnsignedStreamUnsignedIterator(input, createFn, opt), nil
  1443  	default:
  1444  		return nil, fmt.Errorf("unsupported cumulative sum iterator type: %T", input)
  1445  	}
  1446  }
  1447  
  1448  // newHoltWintersIterator returns an iterator for operating on a holt_winters() call.
  1449  func newHoltWintersIterator(input Iterator, opt IteratorOptions, h, m int, includeFitData bool, interval time.Duration) (Iterator, error) {
  1450  	switch input := input.(type) {
  1451  	case FloatIterator:
  1452  		createFn := func() (FloatPointAggregator, FloatPointEmitter) {
  1453  			fn := NewFloatHoltWintersReducer(h, m, includeFitData, interval)
  1454  			return fn, fn
  1455  		}
  1456  		return newFloatReduceFloatIterator(input, opt, createFn), nil
  1457  	case IntegerIterator:
  1458  		createFn := func() (IntegerPointAggregator, FloatPointEmitter) {
  1459  			fn := NewFloatHoltWintersReducer(h, m, includeFitData, interval)
  1460  			return fn, fn
  1461  		}
  1462  		return newIntegerReduceFloatIterator(input, opt, createFn), nil
  1463  	default:
  1464  		return nil, fmt.Errorf("unsupported elapsed iterator type: %T", input)
  1465  	}
  1466  }
  1467  
  1468  // NewSampleIterator returns an iterator for operating on a sample() call (exported for use in test).
  1469  func NewSampleIterator(input Iterator, opt IteratorOptions, size int) (Iterator, error) {
  1470  	return newSampleIterator(input, opt, size)
  1471  }
  1472  
  1473  // newSampleIterator returns an iterator for operating on a sample() call.
  1474  func newSampleIterator(input Iterator, opt IteratorOptions, size int) (Iterator, error) {
  1475  	switch input := input.(type) {
  1476  	case FloatIterator:
  1477  		createFn := func() (FloatPointAggregator, FloatPointEmitter) {
  1478  			fn := NewFloatSampleReducer(size)
  1479  			return fn, fn
  1480  		}
  1481  		return newFloatReduceFloatIterator(input, opt, createFn), nil
  1482  	case IntegerIterator:
  1483  		createFn := func() (IntegerPointAggregator, IntegerPointEmitter) {
  1484  			fn := NewIntegerSampleReducer(size)
  1485  			return fn, fn
  1486  		}
  1487  		return newIntegerReduceIntegerIterator(input, opt, createFn), nil
  1488  	case UnsignedIterator:
  1489  		createFn := func() (UnsignedPointAggregator, UnsignedPointEmitter) {
  1490  			fn := NewUnsignedSampleReducer(size)
  1491  			return fn, fn
  1492  		}
  1493  		return newUnsignedReduceUnsignedIterator(input, opt, createFn), nil
  1494  	case StringIterator:
  1495  		createFn := func() (StringPointAggregator, StringPointEmitter) {
  1496  			fn := NewStringSampleReducer(size)
  1497  			return fn, fn
  1498  		}
  1499  		return newStringReduceStringIterator(input, opt, createFn), nil
  1500  	case BooleanIterator:
  1501  		createFn := func() (BooleanPointAggregator, BooleanPointEmitter) {
  1502  			fn := NewBooleanSampleReducer(size)
  1503  			return fn, fn
  1504  		}
  1505  		return newBooleanReduceBooleanIterator(input, opt, createFn), nil
  1506  	default:
  1507  		return nil, fmt.Errorf("unsupported elapsed iterator type: %T", input)
  1508  	}
  1509  }
  1510  
  1511  // newIntegralIterator returns an iterator for operating on a integral() call.
  1512  func newIntegralIterator(input Iterator, opt IteratorOptions, interval Interval) (Iterator, error) {
  1513  	switch input := input.(type) {
  1514  	case FloatIterator:
  1515  		createFn := func() (FloatPointAggregator, FloatPointEmitter) {
  1516  			fn := NewFloatIntegralReducer(interval, opt)
  1517  			return fn, fn
  1518  		}
  1519  		return newFloatStreamFloatIterator(input, createFn, opt), nil
  1520  	case IntegerIterator:
  1521  		createFn := func() (IntegerPointAggregator, FloatPointEmitter) {
  1522  			fn := NewIntegerIntegralReducer(interval, opt)
  1523  			return fn, fn
  1524  		}
  1525  		return newIntegerStreamFloatIterator(input, createFn, opt), nil
  1526  	case UnsignedIterator:
  1527  		createFn := func() (UnsignedPointAggregator, FloatPointEmitter) {
  1528  			fn := NewUnsignedIntegralReducer(interval, opt)
  1529  			return fn, fn
  1530  		}
  1531  		return newUnsignedStreamFloatIterator(input, createFn, opt), nil
  1532  	default:
  1533  		return nil, fmt.Errorf("unsupported integral iterator type: %T", input)
  1534  	}
  1535  }
  1536  
  1537  // NewSumHllIterator returns an iterator for operating on a distinct() call.
  1538  func NewSumHllIterator(input Iterator, opt IteratorOptions) (Iterator, error) {
  1539  	switch input := input.(type) {
  1540  	case FloatIterator:
  1541  		createFn := func() (FloatPointAggregator, StringPointEmitter) {
  1542  			fn := NewFloatSumHllReducer()
  1543  			return fn, fn
  1544  		}
  1545  		return newFloatReduceStringIterator(input, opt, createFn), nil
  1546  	case IntegerIterator:
  1547  		createFn := func() (IntegerPointAggregator, StringPointEmitter) {
  1548  			fn := NewIntegerSumHllReducer()
  1549  			return fn, fn
  1550  		}
  1551  		return newIntegerReduceStringIterator(input, opt, createFn), nil
  1552  	case UnsignedIterator:
  1553  		createFn := func() (UnsignedPointAggregator, StringPointEmitter) {
  1554  			fn := NewUnsignedSumHllReducer()
  1555  			return fn, fn
  1556  		}
  1557  		return newUnsignedReduceStringIterator(input, opt, createFn), nil
  1558  	case StringIterator:
  1559  		createFn := func() (StringPointAggregator, StringPointEmitter) {
  1560  			fn := NewStringSumHllReducer()
  1561  			return fn, fn
  1562  		}
  1563  		return newStringReduceStringIterator(input, opt, createFn), nil
  1564  	case BooleanIterator:
  1565  		createFn := func() (BooleanPointAggregator, StringPointEmitter) {
  1566  			fn := NewBooleanSumHllReducer()
  1567  			return fn, fn
  1568  		}
  1569  		return newBooleanReduceStringIterator(input, opt, createFn), nil
  1570  	default:
  1571  		return nil, fmt.Errorf("unsupported sum_hll iterator type: %T", input)
  1572  	}
  1573  }
  1574  
  1575  // NewSumHllIterator returns an iterator for operating on a distinct() call.
  1576  func NewMergeHllIterator(input Iterator, opt IteratorOptions) (Iterator, error) {
  1577  	switch input := input.(type) {
  1578  	case StringIterator:
  1579  		createFn := func() (StringPointAggregator, StringPointEmitter) {
  1580  			fn := NewStringMergeHllReducer()
  1581  			return fn, fn
  1582  		}
  1583  		return newStringReduceStringIterator(input, opt, createFn), nil
  1584  	default:
  1585  		return nil, fmt.Errorf("unsupported merge_hll iterator type: %T", input)
  1586  	}
  1587  }
  1588  
  1589  func NewCountHllIterator(input Iterator, opt IteratorOptions) (Iterator, error) {
  1590  	switch input := input.(type) {
  1591  	case StringIterator:
  1592  		createFn := func() (StringPointAggregator, UnsignedPointEmitter) {
  1593  			fn := NewCountHllReducer()
  1594  			return fn, fn
  1595  		}
  1596  		return newStringStreamUnsignedIterator(input, createFn, opt), nil
  1597  	default:
  1598  		return nil, fmt.Errorf("unsupported count_hll iterator type: %T", input)
  1599  	}
  1600  }