From fbf8bada5c4288586cf47ccf1316e0b82006337c Mon Sep 17 00:00:00 2001 From: Jason Song Date: Tue, 22 Sep 2020 20:23:22 +0800 Subject: [PATCH 01/19] fix: remove int8, int16 --- Makefile | 2 +- cmd/generate/main.go | 9 +- int16_sequence.go | 197 ----------- int16_sequence_test.go | 716 ---------------------------------------- int8_sequence.go | 197 ----------- int8_sequence_test.go | 716 ---------------------------------------- uint16_sequence.go | 197 ----------- uint16_sequence_test.go | 716 ---------------------------------------- uint8_sequence.go | 197 ----------- uint8_sequence_test.go | 716 ---------------------------------------- 10 files changed, 5 insertions(+), 3658 deletions(-) delete mode 100644 int16_sequence.go delete mode 100644 int16_sequence_test.go delete mode 100644 int8_sequence.go delete mode 100644 int8_sequence_test.go delete mode 100644 uint16_sequence.go delete mode 100644 uint16_sequence_test.go delete mode 100644 uint8_sequence.go delete mode 100644 uint8_sequence_test.go diff --git a/Makefile b/Makefile index b0505d0..bd771f0 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ generage: - rm -f *_sequence.go + rm -f *_sequence.go *_sequence_test.go go run cmd/generate/main.go diff --git a/cmd/generate/main.go b/cmd/generate/main.go index 4ae8696..825b28e 100644 --- a/cmd/generate/main.go +++ b/cmd/generate/main.go @@ -26,19 +26,18 @@ func main() { } types := []string{ - "uint8", - "uint16", + //"uint8", + //"uint16", "uint32", "uint64", - "int8", - "int16", + //"int8", + //"int16", "int32", "int64", "float32", "float64", "int", "uint", - "uint8", "int32", } diff --git a/int16_sequence.go b/int16_sequence.go deleted file mode 100644 index 5cf54ad..0000000 --- a/int16_sequence.go +++ /dev/null @@ -1,197 +0,0 @@ -// Code generated by cmd/generate. DO NOT EDIT. - -package timeseq - -import ( - "errors" - "sort" - "time" -) - -// Int16Item is item of Int16Sequence -type Int16Item struct { - Time time.Time - Value int16 -} - -// Int16Sequence is the implement of Sequence for int16 -type Int16Sequence []Int16Item - -// Len implements Sequence.Len -func (s Int16Sequence) Len() int { - return len(s) -} - -// Swap implements Sequence.Swap -func (s Int16Sequence) Swap(i, j int) { - s[i], s[j] = s[j], s[i] -} - -// Time implements Sequence.Time -func (s Int16Sequence) Time(i int) time.Time { - return s[i].Time -} - -// Slice implements Sequence.Slice -func (s Int16Sequence) Slice(i, j int) Sequence { - return s[i:j] -} - -// Sort will sort sequence by time -func (s Int16Sequence) Sort() { - Sort(s) -} - -// Range return sub sequence, would sort sequence if it is not sorted -func (s Int16Sequence) Range(afterOrEqual, beforeOrEqual *time.Time) Int16Sequence { - if !sort.IsSorted(sortableSequence{s}) { - s.Sort() - } - return Range(s, afterOrEqual, beforeOrEqual).(Int16Sequence) -} - -// First return the first item or nil if not exists, would sort sequence if it is not sorted -func (s Int16Sequence) First(afterOrEqual *time.Time) *Int16Item { - if !sort.IsSorted(sortableSequence{s}) { - s.Sort() - } - i := First(s, afterOrEqual) - if i < 0 { - return nil - } - ret := s[i] - return &ret -} - -// Last return the last item or nil if not exists, would sort sequence if it is not sorted -func (s Int16Sequence) Last(beforeOrEqual *time.Time) *Int16Item { - if !sort.IsSorted(sortableSequence{s}) { - s.Sort() - } - i := Last(s, beforeOrEqual) - if i < 0 { - return nil - } - ret := s[i] - return &ret -} - -// Max return the first item which has the max value, or nil if not exists -func (s Int16Sequence) Max() *Int16Item { - var max *Int16Item - for i, v := range s { - if max == nil { - max = &s[i] - } else if v.Value > max.Value { - max = &s[i] - } - } - if max != nil { - value := *max - max = &value - } - return max -} - -// Min return the first item which has the min value, or nil if not exists -func (s Int16Sequence) Min() *Int16Item { - var min *Int16Item - for i, v := range s { - if min == nil { - min = &s[i] - } else if v.Value < min.Value { - min = &s[i] - } - } - if min != nil { - value := *min - min = &value - } - return min -} - -// Sum return the value's sum -func (s Int16Sequence) Sum() int16 { - var sum int16 - for _, v := range s { - sum += v.Value - } - return sum -} - -// Average return the value's average -func (s Int16Sequence) Average() int16 { - if len(s) == 0 { - return 0 - } - - return int16(float64(s.Sum()) / float64(len(s))) -} - -// Percentile return (pct)th percentile -func (s Int16Sequence) Percentile(pct float64) int16 { - if pct > 1 || pct < 0 { - panic(errors.New("percentile must be [0, 1]")) - } - - var values []int16 - for _, v := range s { - values = append(values, v.Value) - } - sort.Slice(values, func(i, j int) bool { - return values[i] < values[j] - }) - - if len(values) == 0 { - return 0 - } - - index := int(float64(len(s))*pct - 1) - if index < 0 { - index = 0 - } - - return values[index] -} - -// MergeInt16 merge two int16} seuquence into one -func MergeInt16(seq1, seq2 Int16Sequence, fn func(item1, item2 *Int16Item) *Int16Item) Int16Sequence { - if fn == nil { - return nil - } - - var ret Int16Sequence - for i1, i2 := 0, 0; i1 < seq1.Len() || i2 < seq2.Len(); { - var item *Int16Item - switch { - case i1 == seq1.Len(): - v2 := seq2[i2] - item = fn(nil, &v2) - i2++ - case i2 == seq2.Len(): - v1 := seq1[i1] - item = fn(&v1, nil) - i1++ - case seq1[i1].Time.Equal(seq2[i2].Time): - v1 := seq1[i1] - v2 := seq2[i2] - item = fn(&v1, &v2) - i1++ - i2++ - case seq1[i1].Time.Before(seq2[i2].Time): - v1 := seq1[i1] - item = fn(&v1, nil) - i1++ - case seq1[i1].Time.After(seq2[i2].Time): - v2 := seq2[i2] - item = fn(nil, &v2) - i2++ - } - if item != nil { - ret = append(ret, *item) - } - } - - Sort(ret) - return ret -} diff --git a/int16_sequence_test.go b/int16_sequence_test.go deleted file mode 100644 index 2a20922..0000000 --- a/int16_sequence_test.go +++ /dev/null @@ -1,716 +0,0 @@ -// Code generated by cmd/generate. DO NOT EDIT. - -package timeseq - -import ( - "math" - "math/rand" - "reflect" - "sort" - "testing" - "time" - - "github.com/gochore/pt" -) - -func TestInt16Sequence_Len(t *testing.T) { - tests := []struct { - name string - s Int16Sequence - want int - }{ - { - s: RandomInt16Sequence(10), - want: 10, - }, - { - s: RandomInt16Sequence(0), - want: 0, - }, - { - s: nil, - want: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Len(); got != tt.want { - t.Errorf("Int16Sequence.Len() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestInt16Sequence_Swap(t *testing.T) { - type args struct { - i int - j int - } - tests := []struct { - name string - s Int16Sequence - args args - }{ - { - s: RandomInt16Sequence(10), - args: args{ - i: 0, - j: 5, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - ti := tt.s.Time(tt.args.i) - tj := tt.s.Time(tt.args.j) - tt.s.Swap(tt.args.i, tt.args.j) - if ti != tt.s.Time(tt.args.j) || tj != tt.s.Time(tt.args.i) { - t.Errorf("Int16Sequence.Swap() failed") - } - }) - } -} - -func TestInt16Sequence_Time(t *testing.T) { - seq := RandomInt16Sequence(10) - seq.Sort() - - type args struct { - i int - } - tests := []struct { - name string - s Int16Sequence - args args - want time.Time - }{ - { - s: seq, - args: args{ - i: 9, - }, - want: seq[9].Time, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Time(tt.args.i); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Int16Sequence.Time() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestInt16Sequence_Slice(t *testing.T) { - seq := RandomInt16Sequence(10) - - type args struct { - i int - j int - } - tests := []struct { - name string - s Int16Sequence - args args - want Sequence - }{ - { - s: seq, - args: args{ - i: 2, - j: 10, - }, - want: seq[2:10], - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Slice(tt.args.i, tt.args.j); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Int16Sequence.Slice() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestInt16Sequence_Sort(t *testing.T) { - tests := []struct { - name string - s Int16Sequence - }{ - { - s: RandomInt16Sequence(10), - }, - { - s: nil, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tt.s.Sort() - if !sort.IsSorted(sortableSequence{tt.s}) { - t.Error("Int16Sequence.Slice() failed") - } - }) - } -} - -func TestInt16Sequence_Range(t *testing.T) { - now := time.Now() - seq := RandomInt16Sequence(10) - for i := range seq { - seq[i].Time = now.Add(time.Duration(i) * time.Second) - } - rand.Shuffle(seq.Len(), func(i, j int) { - seq[i], seq[j] = seq[j], seq[i] - }) - - type args struct { - afterOrEqual *time.Time - beforeOrEqual *time.Time - } - tests := []struct { - name string - s Int16Sequence - args args - want Int16Sequence - }{ - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1 * time.Second)), - beforeOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: seq[1 : 5+1], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now), - beforeOrEqual: pt.Time(now.Add(100 * time.Second)), - }, - want: seq, - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1*time.Second + time.Millisecond)), - beforeOrEqual: pt.Time(now.Add(5*time.Second - time.Millisecond)), - }, - want: seq[2 : 4+1], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1*time.Second - time.Millisecond)), - beforeOrEqual: pt.Time(now.Add(5*time.Second + time.Millisecond)), - }, - want: seq[1 : 5+1], - }, - { - s: seq, - args: args{ - afterOrEqual: nil, - beforeOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: seq[:5+1], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1 * time.Second)), - beforeOrEqual: nil, - }, - want: seq[1:], - }, - { - s: seq, - args: args{ - afterOrEqual: nil, - beforeOrEqual: nil, - }, - want: seq, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Range(tt.args.afterOrEqual, tt.args.beforeOrEqual); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Int16Sequence.Range() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestInt16Sequence_First(t *testing.T) { - now := time.Now() - seq := RandomInt16Sequence(10) - for i := range seq { - seq[i].Time = now.Add(time.Duration(i) * time.Second) - } - rand.Shuffle(seq.Len(), func(i, j int) { - seq[i], seq[j] = seq[j], seq[i] - }) - - type args struct { - afterOrEqual *time.Time - } - tests := []struct { - name string - s Int16Sequence - args args - want *Int16Item - }{ - { - s: seq, - args: args{ - afterOrEqual: nil, - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now), - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(-1 * time.Second)), - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1 * time.Second)), - }, - want: &seq[1], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: &seq[5], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(5*time.Second - time.Millisecond)), - }, - want: &seq[5], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(5*time.Second + time.Millisecond)), - }, - want: &seq[6], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(100 * time.Second)), - }, - want: nil, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.First(tt.args.afterOrEqual); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Int16Sequence.First() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestInt16Sequence_Last(t *testing.T) { - now := time.Now() - seq := RandomInt16Sequence(10) - for i := range seq { - seq[i].Time = now.Add(time.Duration(i) * time.Second) - } - rand.Shuffle(seq.Len(), func(i, j int) { - seq[i], seq[j] = seq[j], seq[i] - }) - - type args struct { - beforeOrEqual *time.Time - } - tests := []struct { - name string - s Int16Sequence - args args - want *Int16Item - }{ - { - s: seq, - args: args{ - beforeOrEqual: nil, - }, - want: &seq[len(seq)-1], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now), - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(-1 * time.Second)), - }, - want: nil, - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(1 * time.Second)), - }, - want: &seq[1], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: &seq[5], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(5*time.Second - time.Millisecond)), - }, - want: &seq[4], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(5*time.Second + time.Millisecond)), - }, - want: &seq[5], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(100 * time.Second)), - }, - want: &seq[9], - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Last(tt.args.beforeOrEqual); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Int16Sequence.Last() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestInt16Sequence_Max(t *testing.T) { - seq1 := RandomInt16Sequence(10) - seq1.Sort() - for i := range seq1 { - if i == 0 { - seq1[i].Value = 1 - } else { - seq1[i].Value = 0 - } - } - seq2 := RandomInt16Sequence(10) - seq2.Sort() - for i := range seq2 { - if i == 0 { - seq2[i].Value = 0 - } else { - seq2[i].Value = 1 - } - } - - tests := []struct { - name string - s Int16Sequence - want *Int16Item - }{ - { - s: seq1, - want: &seq1[0], - }, - { - s: seq2, - want: &seq2[1], - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Max(); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Int16Sequence.Max() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestInt16Sequence_Min(t *testing.T) { - seq1 := RandomInt16Sequence(10) - seq1.Sort() - for i := range seq1 { - if i == 0 { - seq1[i].Value = 1 - } else { - seq1[i].Value = 0 - } - } - seq2 := RandomInt16Sequence(10) - seq2.Sort() - for i := range seq2 { - if i == 0 { - seq2[i].Value = 0 - } else { - seq2[i].Value = 1 - } - } - - tests := []struct { - name string - s Int16Sequence - want *Int16Item - }{ - { - s: seq1, - want: &seq1[1], - }, - { - s: seq2, - want: &seq2[0], - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Min(); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Int16Sequence.Min() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestInt16Sequence_Sum(t *testing.T) { - seq := RandomInt16Sequence(10) - for i := range seq { - seq[i].Value = int16(i) - } - - tests := []struct { - name string - s Int16Sequence - want int16 - }{ - { - s: seq, - want: 45, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Sum(); got != tt.want { - t.Errorf("Int16Sequence.Sum() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestInt16Sequence_Average(t *testing.T) { - seq := RandomInt16Sequence(10) - for i := range seq { - seq[i].Value = int16(i) * 2 - } - - tests := []struct { - name string - s Int16Sequence - want int16 - }{ - { - s: seq, - want: 9, - }, - { - s: nil, - want: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Average(); got != tt.want { - t.Errorf("Int16Sequence.Average() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestInt16Sequence_Percentile(t *testing.T) { - seq := RandomInt16Sequence(100) - for i := range seq { - seq[i].Value = int16(i) + 1 - } - - type args struct { - pct float64 - } - tests := []struct { - name string - s Int16Sequence - args args - want int16 - }{ - { - s: seq, - args: args{ - pct: 0, - }, - want: 1, - }, - { - s: seq, - args: args{ - pct: 0.5, - }, - want: 50, - }, - { - s: seq, - args: args{ - pct: 0.95, - }, - want: 95, - }, - { - s: seq, - args: args{ - pct: 0.955, - }, - want: 95, - }, - { - s: seq, - args: args{ - pct: 1, - }, - want: 100, - }, - { - s: seq, - args: args{ - pct: 1.1, - }, - want: 100, - }, - { - s: seq, - args: args{ - pct: -0.1, - }, - want: 1, - }, - { - s: nil, - args: args{ - pct: 1, - }, - want: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - defer func() { - if r := recover(); r != nil { - if tt.args.pct > 1 || tt.args.pct < 0 { - return - } - t.Errorf("Int16Sequence.Percentile() failed: %v", r) - } - }() - if got := tt.s.Percentile(tt.args.pct); got != tt.want { - t.Errorf("Int16Sequence.Percentile() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestMergeInt16(t *testing.T) { - seq := RandomInt16Sequence(10) - seq.Sort() - type args struct { - seq1 Int16Sequence - seq2 Int16Sequence - fn func(item1, item2 *Int16Item) *Int16Item - } - tests := []struct { - name string - args args - want Int16Sequence - }{ - { - name: "regular", - args: args{ - seq1: seq[0:7], - seq2: seq[3:10], - fn: func(item1, item2 *Int16Item) *Int16Item { - if item1 != nil { - return item1 - } - return item2 - }, - }, - want: seq, - }, - { - name: "reverse", - args: args{ - seq1: seq[3:10], - seq2: seq[0:7], - fn: func(item1, item2 *Int16Item) *Int16Item { - if item1 != nil { - return item1 - } - return item2 - }, - }, - want: seq, - }, - { - name: "nil fn", - args: args{ - seq1: seq[0:7], - seq2: seq[3:10], - fn: nil, - }, - want: nil, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := MergeInt16(tt.args.seq1, tt.args.seq2, tt.args.fn); !reflect.DeepEqual(got, tt.want) { - t.Errorf("MergeInt16() = %v, want %v", got, tt.want) - } - }) - } -} - -func RandomInt16Sequence(length int) Int16Sequence { - now := time.Now() - ret := make(Int16Sequence, length) - for i := range ret { - delta := time.Duration(i) * time.Second - if rand.Float64() < 0.5 { - delta = -delta - } - ret[i] = Int16Item{ - Time: now.Add(delta), - Value: int16(rand.Float64() * float64(math.MaxInt64)), - } - } - return ret -} diff --git a/int8_sequence.go b/int8_sequence.go deleted file mode 100644 index 6fb4928..0000000 --- a/int8_sequence.go +++ /dev/null @@ -1,197 +0,0 @@ -// Code generated by cmd/generate. DO NOT EDIT. - -package timeseq - -import ( - "errors" - "sort" - "time" -) - -// Int8Item is item of Int8Sequence -type Int8Item struct { - Time time.Time - Value int8 -} - -// Int8Sequence is the implement of Sequence for int8 -type Int8Sequence []Int8Item - -// Len implements Sequence.Len -func (s Int8Sequence) Len() int { - return len(s) -} - -// Swap implements Sequence.Swap -func (s Int8Sequence) Swap(i, j int) { - s[i], s[j] = s[j], s[i] -} - -// Time implements Sequence.Time -func (s Int8Sequence) Time(i int) time.Time { - return s[i].Time -} - -// Slice implements Sequence.Slice -func (s Int8Sequence) Slice(i, j int) Sequence { - return s[i:j] -} - -// Sort will sort sequence by time -func (s Int8Sequence) Sort() { - Sort(s) -} - -// Range return sub sequence, would sort sequence if it is not sorted -func (s Int8Sequence) Range(afterOrEqual, beforeOrEqual *time.Time) Int8Sequence { - if !sort.IsSorted(sortableSequence{s}) { - s.Sort() - } - return Range(s, afterOrEqual, beforeOrEqual).(Int8Sequence) -} - -// First return the first item or nil if not exists, would sort sequence if it is not sorted -func (s Int8Sequence) First(afterOrEqual *time.Time) *Int8Item { - if !sort.IsSorted(sortableSequence{s}) { - s.Sort() - } - i := First(s, afterOrEqual) - if i < 0 { - return nil - } - ret := s[i] - return &ret -} - -// Last return the last item or nil if not exists, would sort sequence if it is not sorted -func (s Int8Sequence) Last(beforeOrEqual *time.Time) *Int8Item { - if !sort.IsSorted(sortableSequence{s}) { - s.Sort() - } - i := Last(s, beforeOrEqual) - if i < 0 { - return nil - } - ret := s[i] - return &ret -} - -// Max return the first item which has the max value, or nil if not exists -func (s Int8Sequence) Max() *Int8Item { - var max *Int8Item - for i, v := range s { - if max == nil { - max = &s[i] - } else if v.Value > max.Value { - max = &s[i] - } - } - if max != nil { - value := *max - max = &value - } - return max -} - -// Min return the first item which has the min value, or nil if not exists -func (s Int8Sequence) Min() *Int8Item { - var min *Int8Item - for i, v := range s { - if min == nil { - min = &s[i] - } else if v.Value < min.Value { - min = &s[i] - } - } - if min != nil { - value := *min - min = &value - } - return min -} - -// Sum return the value's sum -func (s Int8Sequence) Sum() int8 { - var sum int8 - for _, v := range s { - sum += v.Value - } - return sum -} - -// Average return the value's average -func (s Int8Sequence) Average() int8 { - if len(s) == 0 { - return 0 - } - - return int8(float64(s.Sum()) / float64(len(s))) -} - -// Percentile return (pct)th percentile -func (s Int8Sequence) Percentile(pct float64) int8 { - if pct > 1 || pct < 0 { - panic(errors.New("percentile must be [0, 1]")) - } - - var values []int8 - for _, v := range s { - values = append(values, v.Value) - } - sort.Slice(values, func(i, j int) bool { - return values[i] < values[j] - }) - - if len(values) == 0 { - return 0 - } - - index := int(float64(len(s))*pct - 1) - if index < 0 { - index = 0 - } - - return values[index] -} - -// MergeInt8 merge two int8} seuquence into one -func MergeInt8(seq1, seq2 Int8Sequence, fn func(item1, item2 *Int8Item) *Int8Item) Int8Sequence { - if fn == nil { - return nil - } - - var ret Int8Sequence - for i1, i2 := 0, 0; i1 < seq1.Len() || i2 < seq2.Len(); { - var item *Int8Item - switch { - case i1 == seq1.Len(): - v2 := seq2[i2] - item = fn(nil, &v2) - i2++ - case i2 == seq2.Len(): - v1 := seq1[i1] - item = fn(&v1, nil) - i1++ - case seq1[i1].Time.Equal(seq2[i2].Time): - v1 := seq1[i1] - v2 := seq2[i2] - item = fn(&v1, &v2) - i1++ - i2++ - case seq1[i1].Time.Before(seq2[i2].Time): - v1 := seq1[i1] - item = fn(&v1, nil) - i1++ - case seq1[i1].Time.After(seq2[i2].Time): - v2 := seq2[i2] - item = fn(nil, &v2) - i2++ - } - if item != nil { - ret = append(ret, *item) - } - } - - Sort(ret) - return ret -} diff --git a/int8_sequence_test.go b/int8_sequence_test.go deleted file mode 100644 index 53fc0e3..0000000 --- a/int8_sequence_test.go +++ /dev/null @@ -1,716 +0,0 @@ -// Code generated by cmd/generate. DO NOT EDIT. - -package timeseq - -import ( - "math" - "math/rand" - "reflect" - "sort" - "testing" - "time" - - "github.com/gochore/pt" -) - -func TestInt8Sequence_Len(t *testing.T) { - tests := []struct { - name string - s Int8Sequence - want int - }{ - { - s: RandomInt8Sequence(10), - want: 10, - }, - { - s: RandomInt8Sequence(0), - want: 0, - }, - { - s: nil, - want: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Len(); got != tt.want { - t.Errorf("Int8Sequence.Len() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestInt8Sequence_Swap(t *testing.T) { - type args struct { - i int - j int - } - tests := []struct { - name string - s Int8Sequence - args args - }{ - { - s: RandomInt8Sequence(10), - args: args{ - i: 0, - j: 5, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - ti := tt.s.Time(tt.args.i) - tj := tt.s.Time(tt.args.j) - tt.s.Swap(tt.args.i, tt.args.j) - if ti != tt.s.Time(tt.args.j) || tj != tt.s.Time(tt.args.i) { - t.Errorf("Int8Sequence.Swap() failed") - } - }) - } -} - -func TestInt8Sequence_Time(t *testing.T) { - seq := RandomInt8Sequence(10) - seq.Sort() - - type args struct { - i int - } - tests := []struct { - name string - s Int8Sequence - args args - want time.Time - }{ - { - s: seq, - args: args{ - i: 9, - }, - want: seq[9].Time, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Time(tt.args.i); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Int8Sequence.Time() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestInt8Sequence_Slice(t *testing.T) { - seq := RandomInt8Sequence(10) - - type args struct { - i int - j int - } - tests := []struct { - name string - s Int8Sequence - args args - want Sequence - }{ - { - s: seq, - args: args{ - i: 2, - j: 10, - }, - want: seq[2:10], - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Slice(tt.args.i, tt.args.j); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Int8Sequence.Slice() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestInt8Sequence_Sort(t *testing.T) { - tests := []struct { - name string - s Int8Sequence - }{ - { - s: RandomInt8Sequence(10), - }, - { - s: nil, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tt.s.Sort() - if !sort.IsSorted(sortableSequence{tt.s}) { - t.Error("Int8Sequence.Slice() failed") - } - }) - } -} - -func TestInt8Sequence_Range(t *testing.T) { - now := time.Now() - seq := RandomInt8Sequence(10) - for i := range seq { - seq[i].Time = now.Add(time.Duration(i) * time.Second) - } - rand.Shuffle(seq.Len(), func(i, j int) { - seq[i], seq[j] = seq[j], seq[i] - }) - - type args struct { - afterOrEqual *time.Time - beforeOrEqual *time.Time - } - tests := []struct { - name string - s Int8Sequence - args args - want Int8Sequence - }{ - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1 * time.Second)), - beforeOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: seq[1 : 5+1], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now), - beforeOrEqual: pt.Time(now.Add(100 * time.Second)), - }, - want: seq, - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1*time.Second + time.Millisecond)), - beforeOrEqual: pt.Time(now.Add(5*time.Second - time.Millisecond)), - }, - want: seq[2 : 4+1], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1*time.Second - time.Millisecond)), - beforeOrEqual: pt.Time(now.Add(5*time.Second + time.Millisecond)), - }, - want: seq[1 : 5+1], - }, - { - s: seq, - args: args{ - afterOrEqual: nil, - beforeOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: seq[:5+1], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1 * time.Second)), - beforeOrEqual: nil, - }, - want: seq[1:], - }, - { - s: seq, - args: args{ - afterOrEqual: nil, - beforeOrEqual: nil, - }, - want: seq, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Range(tt.args.afterOrEqual, tt.args.beforeOrEqual); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Int8Sequence.Range() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestInt8Sequence_First(t *testing.T) { - now := time.Now() - seq := RandomInt8Sequence(10) - for i := range seq { - seq[i].Time = now.Add(time.Duration(i) * time.Second) - } - rand.Shuffle(seq.Len(), func(i, j int) { - seq[i], seq[j] = seq[j], seq[i] - }) - - type args struct { - afterOrEqual *time.Time - } - tests := []struct { - name string - s Int8Sequence - args args - want *Int8Item - }{ - { - s: seq, - args: args{ - afterOrEqual: nil, - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now), - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(-1 * time.Second)), - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1 * time.Second)), - }, - want: &seq[1], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: &seq[5], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(5*time.Second - time.Millisecond)), - }, - want: &seq[5], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(5*time.Second + time.Millisecond)), - }, - want: &seq[6], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(100 * time.Second)), - }, - want: nil, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.First(tt.args.afterOrEqual); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Int8Sequence.First() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestInt8Sequence_Last(t *testing.T) { - now := time.Now() - seq := RandomInt8Sequence(10) - for i := range seq { - seq[i].Time = now.Add(time.Duration(i) * time.Second) - } - rand.Shuffle(seq.Len(), func(i, j int) { - seq[i], seq[j] = seq[j], seq[i] - }) - - type args struct { - beforeOrEqual *time.Time - } - tests := []struct { - name string - s Int8Sequence - args args - want *Int8Item - }{ - { - s: seq, - args: args{ - beforeOrEqual: nil, - }, - want: &seq[len(seq)-1], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now), - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(-1 * time.Second)), - }, - want: nil, - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(1 * time.Second)), - }, - want: &seq[1], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: &seq[5], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(5*time.Second - time.Millisecond)), - }, - want: &seq[4], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(5*time.Second + time.Millisecond)), - }, - want: &seq[5], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(100 * time.Second)), - }, - want: &seq[9], - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Last(tt.args.beforeOrEqual); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Int8Sequence.Last() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestInt8Sequence_Max(t *testing.T) { - seq1 := RandomInt8Sequence(10) - seq1.Sort() - for i := range seq1 { - if i == 0 { - seq1[i].Value = 1 - } else { - seq1[i].Value = 0 - } - } - seq2 := RandomInt8Sequence(10) - seq2.Sort() - for i := range seq2 { - if i == 0 { - seq2[i].Value = 0 - } else { - seq2[i].Value = 1 - } - } - - tests := []struct { - name string - s Int8Sequence - want *Int8Item - }{ - { - s: seq1, - want: &seq1[0], - }, - { - s: seq2, - want: &seq2[1], - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Max(); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Int8Sequence.Max() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestInt8Sequence_Min(t *testing.T) { - seq1 := RandomInt8Sequence(10) - seq1.Sort() - for i := range seq1 { - if i == 0 { - seq1[i].Value = 1 - } else { - seq1[i].Value = 0 - } - } - seq2 := RandomInt8Sequence(10) - seq2.Sort() - for i := range seq2 { - if i == 0 { - seq2[i].Value = 0 - } else { - seq2[i].Value = 1 - } - } - - tests := []struct { - name string - s Int8Sequence - want *Int8Item - }{ - { - s: seq1, - want: &seq1[1], - }, - { - s: seq2, - want: &seq2[0], - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Min(); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Int8Sequence.Min() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestInt8Sequence_Sum(t *testing.T) { - seq := RandomInt8Sequence(10) - for i := range seq { - seq[i].Value = int8(i) - } - - tests := []struct { - name string - s Int8Sequence - want int8 - }{ - { - s: seq, - want: 45, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Sum(); got != tt.want { - t.Errorf("Int8Sequence.Sum() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestInt8Sequence_Average(t *testing.T) { - seq := RandomInt8Sequence(10) - for i := range seq { - seq[i].Value = int8(i) * 2 - } - - tests := []struct { - name string - s Int8Sequence - want int8 - }{ - { - s: seq, - want: 9, - }, - { - s: nil, - want: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Average(); got != tt.want { - t.Errorf("Int8Sequence.Average() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestInt8Sequence_Percentile(t *testing.T) { - seq := RandomInt8Sequence(100) - for i := range seq { - seq[i].Value = int8(i) + 1 - } - - type args struct { - pct float64 - } - tests := []struct { - name string - s Int8Sequence - args args - want int8 - }{ - { - s: seq, - args: args{ - pct: 0, - }, - want: 1, - }, - { - s: seq, - args: args{ - pct: 0.5, - }, - want: 50, - }, - { - s: seq, - args: args{ - pct: 0.95, - }, - want: 95, - }, - { - s: seq, - args: args{ - pct: 0.955, - }, - want: 95, - }, - { - s: seq, - args: args{ - pct: 1, - }, - want: 100, - }, - { - s: seq, - args: args{ - pct: 1.1, - }, - want: 100, - }, - { - s: seq, - args: args{ - pct: -0.1, - }, - want: 1, - }, - { - s: nil, - args: args{ - pct: 1, - }, - want: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - defer func() { - if r := recover(); r != nil { - if tt.args.pct > 1 || tt.args.pct < 0 { - return - } - t.Errorf("Int8Sequence.Percentile() failed: %v", r) - } - }() - if got := tt.s.Percentile(tt.args.pct); got != tt.want { - t.Errorf("Int8Sequence.Percentile() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestMergeInt8(t *testing.T) { - seq := RandomInt8Sequence(10) - seq.Sort() - type args struct { - seq1 Int8Sequence - seq2 Int8Sequence - fn func(item1, item2 *Int8Item) *Int8Item - } - tests := []struct { - name string - args args - want Int8Sequence - }{ - { - name: "regular", - args: args{ - seq1: seq[0:7], - seq2: seq[3:10], - fn: func(item1, item2 *Int8Item) *Int8Item { - if item1 != nil { - return item1 - } - return item2 - }, - }, - want: seq, - }, - { - name: "reverse", - args: args{ - seq1: seq[3:10], - seq2: seq[0:7], - fn: func(item1, item2 *Int8Item) *Int8Item { - if item1 != nil { - return item1 - } - return item2 - }, - }, - want: seq, - }, - { - name: "nil fn", - args: args{ - seq1: seq[0:7], - seq2: seq[3:10], - fn: nil, - }, - want: nil, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := MergeInt8(tt.args.seq1, tt.args.seq2, tt.args.fn); !reflect.DeepEqual(got, tt.want) { - t.Errorf("MergeInt8() = %v, want %v", got, tt.want) - } - }) - } -} - -func RandomInt8Sequence(length int) Int8Sequence { - now := time.Now() - ret := make(Int8Sequence, length) - for i := range ret { - delta := time.Duration(i) * time.Second - if rand.Float64() < 0.5 { - delta = -delta - } - ret[i] = Int8Item{ - Time: now.Add(delta), - Value: int8(rand.Float64() * float64(math.MaxInt64)), - } - } - return ret -} diff --git a/uint16_sequence.go b/uint16_sequence.go deleted file mode 100644 index c9c2d11..0000000 --- a/uint16_sequence.go +++ /dev/null @@ -1,197 +0,0 @@ -// Code generated by cmd/generate. DO NOT EDIT. - -package timeseq - -import ( - "errors" - "sort" - "time" -) - -// Uint16Item is item of Uint16Sequence -type Uint16Item struct { - Time time.Time - Value uint16 -} - -// Uint16Sequence is the implement of Sequence for uint16 -type Uint16Sequence []Uint16Item - -// Len implements Sequence.Len -func (s Uint16Sequence) Len() int { - return len(s) -} - -// Swap implements Sequence.Swap -func (s Uint16Sequence) Swap(i, j int) { - s[i], s[j] = s[j], s[i] -} - -// Time implements Sequence.Time -func (s Uint16Sequence) Time(i int) time.Time { - return s[i].Time -} - -// Slice implements Sequence.Slice -func (s Uint16Sequence) Slice(i, j int) Sequence { - return s[i:j] -} - -// Sort will sort sequence by time -func (s Uint16Sequence) Sort() { - Sort(s) -} - -// Range return sub sequence, would sort sequence if it is not sorted -func (s Uint16Sequence) Range(afterOrEqual, beforeOrEqual *time.Time) Uint16Sequence { - if !sort.IsSorted(sortableSequence{s}) { - s.Sort() - } - return Range(s, afterOrEqual, beforeOrEqual).(Uint16Sequence) -} - -// First return the first item or nil if not exists, would sort sequence if it is not sorted -func (s Uint16Sequence) First(afterOrEqual *time.Time) *Uint16Item { - if !sort.IsSorted(sortableSequence{s}) { - s.Sort() - } - i := First(s, afterOrEqual) - if i < 0 { - return nil - } - ret := s[i] - return &ret -} - -// Last return the last item or nil if not exists, would sort sequence if it is not sorted -func (s Uint16Sequence) Last(beforeOrEqual *time.Time) *Uint16Item { - if !sort.IsSorted(sortableSequence{s}) { - s.Sort() - } - i := Last(s, beforeOrEqual) - if i < 0 { - return nil - } - ret := s[i] - return &ret -} - -// Max return the first item which has the max value, or nil if not exists -func (s Uint16Sequence) Max() *Uint16Item { - var max *Uint16Item - for i, v := range s { - if max == nil { - max = &s[i] - } else if v.Value > max.Value { - max = &s[i] - } - } - if max != nil { - value := *max - max = &value - } - return max -} - -// Min return the first item which has the min value, or nil if not exists -func (s Uint16Sequence) Min() *Uint16Item { - var min *Uint16Item - for i, v := range s { - if min == nil { - min = &s[i] - } else if v.Value < min.Value { - min = &s[i] - } - } - if min != nil { - value := *min - min = &value - } - return min -} - -// Sum return the value's sum -func (s Uint16Sequence) Sum() uint16 { - var sum uint16 - for _, v := range s { - sum += v.Value - } - return sum -} - -// Average return the value's average -func (s Uint16Sequence) Average() uint16 { - if len(s) == 0 { - return 0 - } - - return uint16(float64(s.Sum()) / float64(len(s))) -} - -// Percentile return (pct)th percentile -func (s Uint16Sequence) Percentile(pct float64) uint16 { - if pct > 1 || pct < 0 { - panic(errors.New("percentile must be [0, 1]")) - } - - var values []uint16 - for _, v := range s { - values = append(values, v.Value) - } - sort.Slice(values, func(i, j int) bool { - return values[i] < values[j] - }) - - if len(values) == 0 { - return 0 - } - - index := int(float64(len(s))*pct - 1) - if index < 0 { - index = 0 - } - - return values[index] -} - -// MergeUint16 merge two uint16} seuquence into one -func MergeUint16(seq1, seq2 Uint16Sequence, fn func(item1, item2 *Uint16Item) *Uint16Item) Uint16Sequence { - if fn == nil { - return nil - } - - var ret Uint16Sequence - for i1, i2 := 0, 0; i1 < seq1.Len() || i2 < seq2.Len(); { - var item *Uint16Item - switch { - case i1 == seq1.Len(): - v2 := seq2[i2] - item = fn(nil, &v2) - i2++ - case i2 == seq2.Len(): - v1 := seq1[i1] - item = fn(&v1, nil) - i1++ - case seq1[i1].Time.Equal(seq2[i2].Time): - v1 := seq1[i1] - v2 := seq2[i2] - item = fn(&v1, &v2) - i1++ - i2++ - case seq1[i1].Time.Before(seq2[i2].Time): - v1 := seq1[i1] - item = fn(&v1, nil) - i1++ - case seq1[i1].Time.After(seq2[i2].Time): - v2 := seq2[i2] - item = fn(nil, &v2) - i2++ - } - if item != nil { - ret = append(ret, *item) - } - } - - Sort(ret) - return ret -} diff --git a/uint16_sequence_test.go b/uint16_sequence_test.go deleted file mode 100644 index b1d8767..0000000 --- a/uint16_sequence_test.go +++ /dev/null @@ -1,716 +0,0 @@ -// Code generated by cmd/generate. DO NOT EDIT. - -package timeseq - -import ( - "math" - "math/rand" - "reflect" - "sort" - "testing" - "time" - - "github.com/gochore/pt" -) - -func TestUint16Sequence_Len(t *testing.T) { - tests := []struct { - name string - s Uint16Sequence - want int - }{ - { - s: RandomUint16Sequence(10), - want: 10, - }, - { - s: RandomUint16Sequence(0), - want: 0, - }, - { - s: nil, - want: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Len(); got != tt.want { - t.Errorf("Uint16Sequence.Len() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestUint16Sequence_Swap(t *testing.T) { - type args struct { - i int - j int - } - tests := []struct { - name string - s Uint16Sequence - args args - }{ - { - s: RandomUint16Sequence(10), - args: args{ - i: 0, - j: 5, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - ti := tt.s.Time(tt.args.i) - tj := tt.s.Time(tt.args.j) - tt.s.Swap(tt.args.i, tt.args.j) - if ti != tt.s.Time(tt.args.j) || tj != tt.s.Time(tt.args.i) { - t.Errorf("Uint16Sequence.Swap() failed") - } - }) - } -} - -func TestUint16Sequence_Time(t *testing.T) { - seq := RandomUint16Sequence(10) - seq.Sort() - - type args struct { - i int - } - tests := []struct { - name string - s Uint16Sequence - args args - want time.Time - }{ - { - s: seq, - args: args{ - i: 9, - }, - want: seq[9].Time, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Time(tt.args.i); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Uint16Sequence.Time() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestUint16Sequence_Slice(t *testing.T) { - seq := RandomUint16Sequence(10) - - type args struct { - i int - j int - } - tests := []struct { - name string - s Uint16Sequence - args args - want Sequence - }{ - { - s: seq, - args: args{ - i: 2, - j: 10, - }, - want: seq[2:10], - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Slice(tt.args.i, tt.args.j); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Uint16Sequence.Slice() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestUint16Sequence_Sort(t *testing.T) { - tests := []struct { - name string - s Uint16Sequence - }{ - { - s: RandomUint16Sequence(10), - }, - { - s: nil, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tt.s.Sort() - if !sort.IsSorted(sortableSequence{tt.s}) { - t.Error("Uint16Sequence.Slice() failed") - } - }) - } -} - -func TestUint16Sequence_Range(t *testing.T) { - now := time.Now() - seq := RandomUint16Sequence(10) - for i := range seq { - seq[i].Time = now.Add(time.Duration(i) * time.Second) - } - rand.Shuffle(seq.Len(), func(i, j int) { - seq[i], seq[j] = seq[j], seq[i] - }) - - type args struct { - afterOrEqual *time.Time - beforeOrEqual *time.Time - } - tests := []struct { - name string - s Uint16Sequence - args args - want Uint16Sequence - }{ - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1 * time.Second)), - beforeOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: seq[1 : 5+1], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now), - beforeOrEqual: pt.Time(now.Add(100 * time.Second)), - }, - want: seq, - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1*time.Second + time.Millisecond)), - beforeOrEqual: pt.Time(now.Add(5*time.Second - time.Millisecond)), - }, - want: seq[2 : 4+1], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1*time.Second - time.Millisecond)), - beforeOrEqual: pt.Time(now.Add(5*time.Second + time.Millisecond)), - }, - want: seq[1 : 5+1], - }, - { - s: seq, - args: args{ - afterOrEqual: nil, - beforeOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: seq[:5+1], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1 * time.Second)), - beforeOrEqual: nil, - }, - want: seq[1:], - }, - { - s: seq, - args: args{ - afterOrEqual: nil, - beforeOrEqual: nil, - }, - want: seq, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Range(tt.args.afterOrEqual, tt.args.beforeOrEqual); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Uint16Sequence.Range() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestUint16Sequence_First(t *testing.T) { - now := time.Now() - seq := RandomUint16Sequence(10) - for i := range seq { - seq[i].Time = now.Add(time.Duration(i) * time.Second) - } - rand.Shuffle(seq.Len(), func(i, j int) { - seq[i], seq[j] = seq[j], seq[i] - }) - - type args struct { - afterOrEqual *time.Time - } - tests := []struct { - name string - s Uint16Sequence - args args - want *Uint16Item - }{ - { - s: seq, - args: args{ - afterOrEqual: nil, - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now), - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(-1 * time.Second)), - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1 * time.Second)), - }, - want: &seq[1], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: &seq[5], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(5*time.Second - time.Millisecond)), - }, - want: &seq[5], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(5*time.Second + time.Millisecond)), - }, - want: &seq[6], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(100 * time.Second)), - }, - want: nil, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.First(tt.args.afterOrEqual); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Uint16Sequence.First() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestUint16Sequence_Last(t *testing.T) { - now := time.Now() - seq := RandomUint16Sequence(10) - for i := range seq { - seq[i].Time = now.Add(time.Duration(i) * time.Second) - } - rand.Shuffle(seq.Len(), func(i, j int) { - seq[i], seq[j] = seq[j], seq[i] - }) - - type args struct { - beforeOrEqual *time.Time - } - tests := []struct { - name string - s Uint16Sequence - args args - want *Uint16Item - }{ - { - s: seq, - args: args{ - beforeOrEqual: nil, - }, - want: &seq[len(seq)-1], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now), - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(-1 * time.Second)), - }, - want: nil, - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(1 * time.Second)), - }, - want: &seq[1], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: &seq[5], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(5*time.Second - time.Millisecond)), - }, - want: &seq[4], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(5*time.Second + time.Millisecond)), - }, - want: &seq[5], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(100 * time.Second)), - }, - want: &seq[9], - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Last(tt.args.beforeOrEqual); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Uint16Sequence.Last() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestUint16Sequence_Max(t *testing.T) { - seq1 := RandomUint16Sequence(10) - seq1.Sort() - for i := range seq1 { - if i == 0 { - seq1[i].Value = 1 - } else { - seq1[i].Value = 0 - } - } - seq2 := RandomUint16Sequence(10) - seq2.Sort() - for i := range seq2 { - if i == 0 { - seq2[i].Value = 0 - } else { - seq2[i].Value = 1 - } - } - - tests := []struct { - name string - s Uint16Sequence - want *Uint16Item - }{ - { - s: seq1, - want: &seq1[0], - }, - { - s: seq2, - want: &seq2[1], - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Max(); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Uint16Sequence.Max() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestUint16Sequence_Min(t *testing.T) { - seq1 := RandomUint16Sequence(10) - seq1.Sort() - for i := range seq1 { - if i == 0 { - seq1[i].Value = 1 - } else { - seq1[i].Value = 0 - } - } - seq2 := RandomUint16Sequence(10) - seq2.Sort() - for i := range seq2 { - if i == 0 { - seq2[i].Value = 0 - } else { - seq2[i].Value = 1 - } - } - - tests := []struct { - name string - s Uint16Sequence - want *Uint16Item - }{ - { - s: seq1, - want: &seq1[1], - }, - { - s: seq2, - want: &seq2[0], - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Min(); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Uint16Sequence.Min() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestUint16Sequence_Sum(t *testing.T) { - seq := RandomUint16Sequence(10) - for i := range seq { - seq[i].Value = uint16(i) - } - - tests := []struct { - name string - s Uint16Sequence - want uint16 - }{ - { - s: seq, - want: 45, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Sum(); got != tt.want { - t.Errorf("Uint16Sequence.Sum() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestUint16Sequence_Average(t *testing.T) { - seq := RandomUint16Sequence(10) - for i := range seq { - seq[i].Value = uint16(i) * 2 - } - - tests := []struct { - name string - s Uint16Sequence - want uint16 - }{ - { - s: seq, - want: 9, - }, - { - s: nil, - want: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Average(); got != tt.want { - t.Errorf("Uint16Sequence.Average() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestUint16Sequence_Percentile(t *testing.T) { - seq := RandomUint16Sequence(100) - for i := range seq { - seq[i].Value = uint16(i) + 1 - } - - type args struct { - pct float64 - } - tests := []struct { - name string - s Uint16Sequence - args args - want uint16 - }{ - { - s: seq, - args: args{ - pct: 0, - }, - want: 1, - }, - { - s: seq, - args: args{ - pct: 0.5, - }, - want: 50, - }, - { - s: seq, - args: args{ - pct: 0.95, - }, - want: 95, - }, - { - s: seq, - args: args{ - pct: 0.955, - }, - want: 95, - }, - { - s: seq, - args: args{ - pct: 1, - }, - want: 100, - }, - { - s: seq, - args: args{ - pct: 1.1, - }, - want: 100, - }, - { - s: seq, - args: args{ - pct: -0.1, - }, - want: 1, - }, - { - s: nil, - args: args{ - pct: 1, - }, - want: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - defer func() { - if r := recover(); r != nil { - if tt.args.pct > 1 || tt.args.pct < 0 { - return - } - t.Errorf("Uint16Sequence.Percentile() failed: %v", r) - } - }() - if got := tt.s.Percentile(tt.args.pct); got != tt.want { - t.Errorf("Uint16Sequence.Percentile() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestMergeUint16(t *testing.T) { - seq := RandomUint16Sequence(10) - seq.Sort() - type args struct { - seq1 Uint16Sequence - seq2 Uint16Sequence - fn func(item1, item2 *Uint16Item) *Uint16Item - } - tests := []struct { - name string - args args - want Uint16Sequence - }{ - { - name: "regular", - args: args{ - seq1: seq[0:7], - seq2: seq[3:10], - fn: func(item1, item2 *Uint16Item) *Uint16Item { - if item1 != nil { - return item1 - } - return item2 - }, - }, - want: seq, - }, - { - name: "reverse", - args: args{ - seq1: seq[3:10], - seq2: seq[0:7], - fn: func(item1, item2 *Uint16Item) *Uint16Item { - if item1 != nil { - return item1 - } - return item2 - }, - }, - want: seq, - }, - { - name: "nil fn", - args: args{ - seq1: seq[0:7], - seq2: seq[3:10], - fn: nil, - }, - want: nil, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := MergeUint16(tt.args.seq1, tt.args.seq2, tt.args.fn); !reflect.DeepEqual(got, tt.want) { - t.Errorf("MergeUint16() = %v, want %v", got, tt.want) - } - }) - } -} - -func RandomUint16Sequence(length int) Uint16Sequence { - now := time.Now() - ret := make(Uint16Sequence, length) - for i := range ret { - delta := time.Duration(i) * time.Second - if rand.Float64() < 0.5 { - delta = -delta - } - ret[i] = Uint16Item{ - Time: now.Add(delta), - Value: uint16(rand.Float64() * float64(math.MaxInt64)), - } - } - return ret -} diff --git a/uint8_sequence.go b/uint8_sequence.go deleted file mode 100644 index 50214ba..0000000 --- a/uint8_sequence.go +++ /dev/null @@ -1,197 +0,0 @@ -// Code generated by cmd/generate. DO NOT EDIT. - -package timeseq - -import ( - "errors" - "sort" - "time" -) - -// Uint8Item is item of Uint8Sequence -type Uint8Item struct { - Time time.Time - Value uint8 -} - -// Uint8Sequence is the implement of Sequence for uint8 -type Uint8Sequence []Uint8Item - -// Len implements Sequence.Len -func (s Uint8Sequence) Len() int { - return len(s) -} - -// Swap implements Sequence.Swap -func (s Uint8Sequence) Swap(i, j int) { - s[i], s[j] = s[j], s[i] -} - -// Time implements Sequence.Time -func (s Uint8Sequence) Time(i int) time.Time { - return s[i].Time -} - -// Slice implements Sequence.Slice -func (s Uint8Sequence) Slice(i, j int) Sequence { - return s[i:j] -} - -// Sort will sort sequence by time -func (s Uint8Sequence) Sort() { - Sort(s) -} - -// Range return sub sequence, would sort sequence if it is not sorted -func (s Uint8Sequence) Range(afterOrEqual, beforeOrEqual *time.Time) Uint8Sequence { - if !sort.IsSorted(sortableSequence{s}) { - s.Sort() - } - return Range(s, afterOrEqual, beforeOrEqual).(Uint8Sequence) -} - -// First return the first item or nil if not exists, would sort sequence if it is not sorted -func (s Uint8Sequence) First(afterOrEqual *time.Time) *Uint8Item { - if !sort.IsSorted(sortableSequence{s}) { - s.Sort() - } - i := First(s, afterOrEqual) - if i < 0 { - return nil - } - ret := s[i] - return &ret -} - -// Last return the last item or nil if not exists, would sort sequence if it is not sorted -func (s Uint8Sequence) Last(beforeOrEqual *time.Time) *Uint8Item { - if !sort.IsSorted(sortableSequence{s}) { - s.Sort() - } - i := Last(s, beforeOrEqual) - if i < 0 { - return nil - } - ret := s[i] - return &ret -} - -// Max return the first item which has the max value, or nil if not exists -func (s Uint8Sequence) Max() *Uint8Item { - var max *Uint8Item - for i, v := range s { - if max == nil { - max = &s[i] - } else if v.Value > max.Value { - max = &s[i] - } - } - if max != nil { - value := *max - max = &value - } - return max -} - -// Min return the first item which has the min value, or nil if not exists -func (s Uint8Sequence) Min() *Uint8Item { - var min *Uint8Item - for i, v := range s { - if min == nil { - min = &s[i] - } else if v.Value < min.Value { - min = &s[i] - } - } - if min != nil { - value := *min - min = &value - } - return min -} - -// Sum return the value's sum -func (s Uint8Sequence) Sum() uint8 { - var sum uint8 - for _, v := range s { - sum += v.Value - } - return sum -} - -// Average return the value's average -func (s Uint8Sequence) Average() uint8 { - if len(s) == 0 { - return 0 - } - - return uint8(float64(s.Sum()) / float64(len(s))) -} - -// Percentile return (pct)th percentile -func (s Uint8Sequence) Percentile(pct float64) uint8 { - if pct > 1 || pct < 0 { - panic(errors.New("percentile must be [0, 1]")) - } - - var values []uint8 - for _, v := range s { - values = append(values, v.Value) - } - sort.Slice(values, func(i, j int) bool { - return values[i] < values[j] - }) - - if len(values) == 0 { - return 0 - } - - index := int(float64(len(s))*pct - 1) - if index < 0 { - index = 0 - } - - return values[index] -} - -// MergeUint8 merge two uint8} seuquence into one -func MergeUint8(seq1, seq2 Uint8Sequence, fn func(item1, item2 *Uint8Item) *Uint8Item) Uint8Sequence { - if fn == nil { - return nil - } - - var ret Uint8Sequence - for i1, i2 := 0, 0; i1 < seq1.Len() || i2 < seq2.Len(); { - var item *Uint8Item - switch { - case i1 == seq1.Len(): - v2 := seq2[i2] - item = fn(nil, &v2) - i2++ - case i2 == seq2.Len(): - v1 := seq1[i1] - item = fn(&v1, nil) - i1++ - case seq1[i1].Time.Equal(seq2[i2].Time): - v1 := seq1[i1] - v2 := seq2[i2] - item = fn(&v1, &v2) - i1++ - i2++ - case seq1[i1].Time.Before(seq2[i2].Time): - v1 := seq1[i1] - item = fn(&v1, nil) - i1++ - case seq1[i1].Time.After(seq2[i2].Time): - v2 := seq2[i2] - item = fn(nil, &v2) - i2++ - } - if item != nil { - ret = append(ret, *item) - } - } - - Sort(ret) - return ret -} diff --git a/uint8_sequence_test.go b/uint8_sequence_test.go deleted file mode 100644 index 068a900..0000000 --- a/uint8_sequence_test.go +++ /dev/null @@ -1,716 +0,0 @@ -// Code generated by cmd/generate. DO NOT EDIT. - -package timeseq - -import ( - "math" - "math/rand" - "reflect" - "sort" - "testing" - "time" - - "github.com/gochore/pt" -) - -func TestUint8Sequence_Len(t *testing.T) { - tests := []struct { - name string - s Uint8Sequence - want int - }{ - { - s: RandomUint8Sequence(10), - want: 10, - }, - { - s: RandomUint8Sequence(0), - want: 0, - }, - { - s: nil, - want: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Len(); got != tt.want { - t.Errorf("Uint8Sequence.Len() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestUint8Sequence_Swap(t *testing.T) { - type args struct { - i int - j int - } - tests := []struct { - name string - s Uint8Sequence - args args - }{ - { - s: RandomUint8Sequence(10), - args: args{ - i: 0, - j: 5, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - ti := tt.s.Time(tt.args.i) - tj := tt.s.Time(tt.args.j) - tt.s.Swap(tt.args.i, tt.args.j) - if ti != tt.s.Time(tt.args.j) || tj != tt.s.Time(tt.args.i) { - t.Errorf("Uint8Sequence.Swap() failed") - } - }) - } -} - -func TestUint8Sequence_Time(t *testing.T) { - seq := RandomUint8Sequence(10) - seq.Sort() - - type args struct { - i int - } - tests := []struct { - name string - s Uint8Sequence - args args - want time.Time - }{ - { - s: seq, - args: args{ - i: 9, - }, - want: seq[9].Time, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Time(tt.args.i); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Uint8Sequence.Time() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestUint8Sequence_Slice(t *testing.T) { - seq := RandomUint8Sequence(10) - - type args struct { - i int - j int - } - tests := []struct { - name string - s Uint8Sequence - args args - want Sequence - }{ - { - s: seq, - args: args{ - i: 2, - j: 10, - }, - want: seq[2:10], - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Slice(tt.args.i, tt.args.j); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Uint8Sequence.Slice() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestUint8Sequence_Sort(t *testing.T) { - tests := []struct { - name string - s Uint8Sequence - }{ - { - s: RandomUint8Sequence(10), - }, - { - s: nil, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tt.s.Sort() - if !sort.IsSorted(sortableSequence{tt.s}) { - t.Error("Uint8Sequence.Slice() failed") - } - }) - } -} - -func TestUint8Sequence_Range(t *testing.T) { - now := time.Now() - seq := RandomUint8Sequence(10) - for i := range seq { - seq[i].Time = now.Add(time.Duration(i) * time.Second) - } - rand.Shuffle(seq.Len(), func(i, j int) { - seq[i], seq[j] = seq[j], seq[i] - }) - - type args struct { - afterOrEqual *time.Time - beforeOrEqual *time.Time - } - tests := []struct { - name string - s Uint8Sequence - args args - want Uint8Sequence - }{ - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1 * time.Second)), - beforeOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: seq[1 : 5+1], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now), - beforeOrEqual: pt.Time(now.Add(100 * time.Second)), - }, - want: seq, - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1*time.Second + time.Millisecond)), - beforeOrEqual: pt.Time(now.Add(5*time.Second - time.Millisecond)), - }, - want: seq[2 : 4+1], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1*time.Second - time.Millisecond)), - beforeOrEqual: pt.Time(now.Add(5*time.Second + time.Millisecond)), - }, - want: seq[1 : 5+1], - }, - { - s: seq, - args: args{ - afterOrEqual: nil, - beforeOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: seq[:5+1], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1 * time.Second)), - beforeOrEqual: nil, - }, - want: seq[1:], - }, - { - s: seq, - args: args{ - afterOrEqual: nil, - beforeOrEqual: nil, - }, - want: seq, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Range(tt.args.afterOrEqual, tt.args.beforeOrEqual); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Uint8Sequence.Range() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestUint8Sequence_First(t *testing.T) { - now := time.Now() - seq := RandomUint8Sequence(10) - for i := range seq { - seq[i].Time = now.Add(time.Duration(i) * time.Second) - } - rand.Shuffle(seq.Len(), func(i, j int) { - seq[i], seq[j] = seq[j], seq[i] - }) - - type args struct { - afterOrEqual *time.Time - } - tests := []struct { - name string - s Uint8Sequence - args args - want *Uint8Item - }{ - { - s: seq, - args: args{ - afterOrEqual: nil, - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now), - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(-1 * time.Second)), - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1 * time.Second)), - }, - want: &seq[1], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: &seq[5], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(5*time.Second - time.Millisecond)), - }, - want: &seq[5], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(5*time.Second + time.Millisecond)), - }, - want: &seq[6], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(100 * time.Second)), - }, - want: nil, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.First(tt.args.afterOrEqual); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Uint8Sequence.First() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestUint8Sequence_Last(t *testing.T) { - now := time.Now() - seq := RandomUint8Sequence(10) - for i := range seq { - seq[i].Time = now.Add(time.Duration(i) * time.Second) - } - rand.Shuffle(seq.Len(), func(i, j int) { - seq[i], seq[j] = seq[j], seq[i] - }) - - type args struct { - beforeOrEqual *time.Time - } - tests := []struct { - name string - s Uint8Sequence - args args - want *Uint8Item - }{ - { - s: seq, - args: args{ - beforeOrEqual: nil, - }, - want: &seq[len(seq)-1], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now), - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(-1 * time.Second)), - }, - want: nil, - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(1 * time.Second)), - }, - want: &seq[1], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: &seq[5], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(5*time.Second - time.Millisecond)), - }, - want: &seq[4], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(5*time.Second + time.Millisecond)), - }, - want: &seq[5], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(100 * time.Second)), - }, - want: &seq[9], - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Last(tt.args.beforeOrEqual); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Uint8Sequence.Last() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestUint8Sequence_Max(t *testing.T) { - seq1 := RandomUint8Sequence(10) - seq1.Sort() - for i := range seq1 { - if i == 0 { - seq1[i].Value = 1 - } else { - seq1[i].Value = 0 - } - } - seq2 := RandomUint8Sequence(10) - seq2.Sort() - for i := range seq2 { - if i == 0 { - seq2[i].Value = 0 - } else { - seq2[i].Value = 1 - } - } - - tests := []struct { - name string - s Uint8Sequence - want *Uint8Item - }{ - { - s: seq1, - want: &seq1[0], - }, - { - s: seq2, - want: &seq2[1], - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Max(); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Uint8Sequence.Max() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestUint8Sequence_Min(t *testing.T) { - seq1 := RandomUint8Sequence(10) - seq1.Sort() - for i := range seq1 { - if i == 0 { - seq1[i].Value = 1 - } else { - seq1[i].Value = 0 - } - } - seq2 := RandomUint8Sequence(10) - seq2.Sort() - for i := range seq2 { - if i == 0 { - seq2[i].Value = 0 - } else { - seq2[i].Value = 1 - } - } - - tests := []struct { - name string - s Uint8Sequence - want *Uint8Item - }{ - { - s: seq1, - want: &seq1[1], - }, - { - s: seq2, - want: &seq2[0], - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Min(); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Uint8Sequence.Min() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestUint8Sequence_Sum(t *testing.T) { - seq := RandomUint8Sequence(10) - for i := range seq { - seq[i].Value = uint8(i) - } - - tests := []struct { - name string - s Uint8Sequence - want uint8 - }{ - { - s: seq, - want: 45, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Sum(); got != tt.want { - t.Errorf("Uint8Sequence.Sum() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestUint8Sequence_Average(t *testing.T) { - seq := RandomUint8Sequence(10) - for i := range seq { - seq[i].Value = uint8(i) * 2 - } - - tests := []struct { - name string - s Uint8Sequence - want uint8 - }{ - { - s: seq, - want: 9, - }, - { - s: nil, - want: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Average(); got != tt.want { - t.Errorf("Uint8Sequence.Average() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestUint8Sequence_Percentile(t *testing.T) { - seq := RandomUint8Sequence(100) - for i := range seq { - seq[i].Value = uint8(i) + 1 - } - - type args struct { - pct float64 - } - tests := []struct { - name string - s Uint8Sequence - args args - want uint8 - }{ - { - s: seq, - args: args{ - pct: 0, - }, - want: 1, - }, - { - s: seq, - args: args{ - pct: 0.5, - }, - want: 50, - }, - { - s: seq, - args: args{ - pct: 0.95, - }, - want: 95, - }, - { - s: seq, - args: args{ - pct: 0.955, - }, - want: 95, - }, - { - s: seq, - args: args{ - pct: 1, - }, - want: 100, - }, - { - s: seq, - args: args{ - pct: 1.1, - }, - want: 100, - }, - { - s: seq, - args: args{ - pct: -0.1, - }, - want: 1, - }, - { - s: nil, - args: args{ - pct: 1, - }, - want: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - defer func() { - if r := recover(); r != nil { - if tt.args.pct > 1 || tt.args.pct < 0 { - return - } - t.Errorf("Uint8Sequence.Percentile() failed: %v", r) - } - }() - if got := tt.s.Percentile(tt.args.pct); got != tt.want { - t.Errorf("Uint8Sequence.Percentile() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestMergeUint8(t *testing.T) { - seq := RandomUint8Sequence(10) - seq.Sort() - type args struct { - seq1 Uint8Sequence - seq2 Uint8Sequence - fn func(item1, item2 *Uint8Item) *Uint8Item - } - tests := []struct { - name string - args args - want Uint8Sequence - }{ - { - name: "regular", - args: args{ - seq1: seq[0:7], - seq2: seq[3:10], - fn: func(item1, item2 *Uint8Item) *Uint8Item { - if item1 != nil { - return item1 - } - return item2 - }, - }, - want: seq, - }, - { - name: "reverse", - args: args{ - seq1: seq[3:10], - seq2: seq[0:7], - fn: func(item1, item2 *Uint8Item) *Uint8Item { - if item1 != nil { - return item1 - } - return item2 - }, - }, - want: seq, - }, - { - name: "nil fn", - args: args{ - seq1: seq[0:7], - seq2: seq[3:10], - fn: nil, - }, - want: nil, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := MergeUint8(tt.args.seq1, tt.args.seq2, tt.args.fn); !reflect.DeepEqual(got, tt.want) { - t.Errorf("MergeUint8() = %v, want %v", got, tt.want) - } - }) - } -} - -func RandomUint8Sequence(length int) Uint8Sequence { - now := time.Now() - ret := make(Uint8Sequence, length) - for i := range ret { - delta := time.Duration(i) * time.Second - if rand.Float64() < 0.5 { - delta = -delta - } - ret[i] = Uint8Item{ - Time: now.Add(delta), - Value: uint8(rand.Float64() * float64(math.MaxInt64)), - } - } - return ret -} From 64b5b050136201dd260725a65b4b9075a44a112f Mon Sep 17 00:00:00 2001 From: Jason Song Date: Wed, 23 Sep 2020 10:59:19 +0800 Subject: [PATCH 02/19] chore: reset to beginning --- _example/main.go | 45 --- float32_sequence.go | 197 ----------- float32_sequence_test.go | 716 --------------------------------------- float64_sequence.go | 197 ----------- float64_sequence_test.go | 716 --------------------------------------- int32_sequence.go | 197 ----------- int32_sequence_test.go | 716 --------------------------------------- int64_sequence.go | 197 ----------- int64_sequence_test.go | 716 --------------------------------------- int_sequence.go | 197 ----------- int_sequence_test.go | 716 --------------------------------------- sequence_test.go | 54 --- timeseq.go | 40 ++- timeseq_test.go | 293 ---------------- uint32_sequence.go | 197 ----------- uint32_sequence_test.go | 716 --------------------------------------- uint64_sequence.go | 197 ----------- uint64_sequence_test.go | 716 --------------------------------------- uint_sequence.go | 197 ----------- uint_sequence_test.go | 716 --------------------------------------- 20 files changed, 24 insertions(+), 7712 deletions(-) delete mode 100644 _example/main.go delete mode 100644 float32_sequence.go delete mode 100644 float32_sequence_test.go delete mode 100644 float64_sequence.go delete mode 100644 float64_sequence_test.go delete mode 100644 int32_sequence.go delete mode 100644 int32_sequence_test.go delete mode 100644 int64_sequence.go delete mode 100644 int64_sequence_test.go delete mode 100644 int_sequence.go delete mode 100644 int_sequence_test.go delete mode 100644 sequence_test.go delete mode 100644 timeseq_test.go delete mode 100644 uint32_sequence.go delete mode 100644 uint32_sequence_test.go delete mode 100644 uint64_sequence.go delete mode 100644 uint64_sequence_test.go delete mode 100644 uint_sequence.go delete mode 100644 uint_sequence_test.go diff --git a/_example/main.go b/_example/main.go deleted file mode 100644 index c52b381..0000000 --- a/_example/main.go +++ /dev/null @@ -1,45 +0,0 @@ -package main - -import ( - "fmt" - "time" - - "github.com/gochore/timeseq" -) - -func main() { - now := time.Now() - seq := timeseq.Int64Sequence{ - { - Time: now, - Value: 0, - }, - { - Time: now.Add(time.Second), - Value: 1, - }, - { - Time: now.Add(-time.Second), - Value: 2, - }, - } - seq = append(seq, timeseq.Int64Item{ - Time: now.Add(-2 * time.Second), - Value: -1, - }) - - // sort by time - seq.Sort() - - // get the first one - fmt.Println(seq.First(nil)) - // get the last one before now - fmt.Println(seq.Last(&now)) - - // get the sub sequence after now - subSeq := seq.Range(&now, nil) - // get the sub sequence's length - fmt.Println(subSeq.Len()) - // get the first one of the sub sequence - fmt.Println(subSeq.First(nil)) -} diff --git a/float32_sequence.go b/float32_sequence.go deleted file mode 100644 index b6e36aa..0000000 --- a/float32_sequence.go +++ /dev/null @@ -1,197 +0,0 @@ -// Code generated by cmd/generate. DO NOT EDIT. - -package timeseq - -import ( - "errors" - "sort" - "time" -) - -// Float32Item is item of Float32Sequence -type Float32Item struct { - Time time.Time - Value float32 -} - -// Float32Sequence is the implement of Sequence for float32 -type Float32Sequence []Float32Item - -// Len implements Sequence.Len -func (s Float32Sequence) Len() int { - return len(s) -} - -// Swap implements Sequence.Swap -func (s Float32Sequence) Swap(i, j int) { - s[i], s[j] = s[j], s[i] -} - -// Time implements Sequence.Time -func (s Float32Sequence) Time(i int) time.Time { - return s[i].Time -} - -// Slice implements Sequence.Slice -func (s Float32Sequence) Slice(i, j int) Sequence { - return s[i:j] -} - -// Sort will sort sequence by time -func (s Float32Sequence) Sort() { - Sort(s) -} - -// Range return sub sequence, would sort sequence if it is not sorted -func (s Float32Sequence) Range(afterOrEqual, beforeOrEqual *time.Time) Float32Sequence { - if !sort.IsSorted(sortableSequence{s}) { - s.Sort() - } - return Range(s, afterOrEqual, beforeOrEqual).(Float32Sequence) -} - -// First return the first item or nil if not exists, would sort sequence if it is not sorted -func (s Float32Sequence) First(afterOrEqual *time.Time) *Float32Item { - if !sort.IsSorted(sortableSequence{s}) { - s.Sort() - } - i := First(s, afterOrEqual) - if i < 0 { - return nil - } - ret := s[i] - return &ret -} - -// Last return the last item or nil if not exists, would sort sequence if it is not sorted -func (s Float32Sequence) Last(beforeOrEqual *time.Time) *Float32Item { - if !sort.IsSorted(sortableSequence{s}) { - s.Sort() - } - i := Last(s, beforeOrEqual) - if i < 0 { - return nil - } - ret := s[i] - return &ret -} - -// Max return the first item which has the max value, or nil if not exists -func (s Float32Sequence) Max() *Float32Item { - var max *Float32Item - for i, v := range s { - if max == nil { - max = &s[i] - } else if v.Value > max.Value { - max = &s[i] - } - } - if max != nil { - value := *max - max = &value - } - return max -} - -// Min return the first item which has the min value, or nil if not exists -func (s Float32Sequence) Min() *Float32Item { - var min *Float32Item - for i, v := range s { - if min == nil { - min = &s[i] - } else if v.Value < min.Value { - min = &s[i] - } - } - if min != nil { - value := *min - min = &value - } - return min -} - -// Sum return the value's sum -func (s Float32Sequence) Sum() float32 { - var sum float32 - for _, v := range s { - sum += v.Value - } - return sum -} - -// Average return the value's average -func (s Float32Sequence) Average() float32 { - if len(s) == 0 { - return 0 - } - - return float32(float64(s.Sum()) / float64(len(s))) -} - -// Percentile return (pct)th percentile -func (s Float32Sequence) Percentile(pct float64) float32 { - if pct > 1 || pct < 0 { - panic(errors.New("percentile must be [0, 1]")) - } - - var values []float32 - for _, v := range s { - values = append(values, v.Value) - } - sort.Slice(values, func(i, j int) bool { - return values[i] < values[j] - }) - - if len(values) == 0 { - return 0 - } - - index := int(float64(len(s))*pct - 1) - if index < 0 { - index = 0 - } - - return values[index] -} - -// MergeFloat32 merge two float32} seuquence into one -func MergeFloat32(seq1, seq2 Float32Sequence, fn func(item1, item2 *Float32Item) *Float32Item) Float32Sequence { - if fn == nil { - return nil - } - - var ret Float32Sequence - for i1, i2 := 0, 0; i1 < seq1.Len() || i2 < seq2.Len(); { - var item *Float32Item - switch { - case i1 == seq1.Len(): - v2 := seq2[i2] - item = fn(nil, &v2) - i2++ - case i2 == seq2.Len(): - v1 := seq1[i1] - item = fn(&v1, nil) - i1++ - case seq1[i1].Time.Equal(seq2[i2].Time): - v1 := seq1[i1] - v2 := seq2[i2] - item = fn(&v1, &v2) - i1++ - i2++ - case seq1[i1].Time.Before(seq2[i2].Time): - v1 := seq1[i1] - item = fn(&v1, nil) - i1++ - case seq1[i1].Time.After(seq2[i2].Time): - v2 := seq2[i2] - item = fn(nil, &v2) - i2++ - } - if item != nil { - ret = append(ret, *item) - } - } - - Sort(ret) - return ret -} diff --git a/float32_sequence_test.go b/float32_sequence_test.go deleted file mode 100644 index 413a550..0000000 --- a/float32_sequence_test.go +++ /dev/null @@ -1,716 +0,0 @@ -// Code generated by cmd/generate. DO NOT EDIT. - -package timeseq - -import ( - "math" - "math/rand" - "reflect" - "sort" - "testing" - "time" - - "github.com/gochore/pt" -) - -func TestFloat32Sequence_Len(t *testing.T) { - tests := []struct { - name string - s Float32Sequence - want int - }{ - { - s: RandomFloat32Sequence(10), - want: 10, - }, - { - s: RandomFloat32Sequence(0), - want: 0, - }, - { - s: nil, - want: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Len(); got != tt.want { - t.Errorf("Float32Sequence.Len() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestFloat32Sequence_Swap(t *testing.T) { - type args struct { - i int - j int - } - tests := []struct { - name string - s Float32Sequence - args args - }{ - { - s: RandomFloat32Sequence(10), - args: args{ - i: 0, - j: 5, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - ti := tt.s.Time(tt.args.i) - tj := tt.s.Time(tt.args.j) - tt.s.Swap(tt.args.i, tt.args.j) - if ti != tt.s.Time(tt.args.j) || tj != tt.s.Time(tt.args.i) { - t.Errorf("Float32Sequence.Swap() failed") - } - }) - } -} - -func TestFloat32Sequence_Time(t *testing.T) { - seq := RandomFloat32Sequence(10) - seq.Sort() - - type args struct { - i int - } - tests := []struct { - name string - s Float32Sequence - args args - want time.Time - }{ - { - s: seq, - args: args{ - i: 9, - }, - want: seq[9].Time, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Time(tt.args.i); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Float32Sequence.Time() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestFloat32Sequence_Slice(t *testing.T) { - seq := RandomFloat32Sequence(10) - - type args struct { - i int - j int - } - tests := []struct { - name string - s Float32Sequence - args args - want Sequence - }{ - { - s: seq, - args: args{ - i: 2, - j: 10, - }, - want: seq[2:10], - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Slice(tt.args.i, tt.args.j); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Float32Sequence.Slice() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestFloat32Sequence_Sort(t *testing.T) { - tests := []struct { - name string - s Float32Sequence - }{ - { - s: RandomFloat32Sequence(10), - }, - { - s: nil, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tt.s.Sort() - if !sort.IsSorted(sortableSequence{tt.s}) { - t.Error("Float32Sequence.Slice() failed") - } - }) - } -} - -func TestFloat32Sequence_Range(t *testing.T) { - now := time.Now() - seq := RandomFloat32Sequence(10) - for i := range seq { - seq[i].Time = now.Add(time.Duration(i) * time.Second) - } - rand.Shuffle(seq.Len(), func(i, j int) { - seq[i], seq[j] = seq[j], seq[i] - }) - - type args struct { - afterOrEqual *time.Time - beforeOrEqual *time.Time - } - tests := []struct { - name string - s Float32Sequence - args args - want Float32Sequence - }{ - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1 * time.Second)), - beforeOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: seq[1 : 5+1], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now), - beforeOrEqual: pt.Time(now.Add(100 * time.Second)), - }, - want: seq, - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1*time.Second + time.Millisecond)), - beforeOrEqual: pt.Time(now.Add(5*time.Second - time.Millisecond)), - }, - want: seq[2 : 4+1], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1*time.Second - time.Millisecond)), - beforeOrEqual: pt.Time(now.Add(5*time.Second + time.Millisecond)), - }, - want: seq[1 : 5+1], - }, - { - s: seq, - args: args{ - afterOrEqual: nil, - beforeOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: seq[:5+1], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1 * time.Second)), - beforeOrEqual: nil, - }, - want: seq[1:], - }, - { - s: seq, - args: args{ - afterOrEqual: nil, - beforeOrEqual: nil, - }, - want: seq, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Range(tt.args.afterOrEqual, tt.args.beforeOrEqual); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Float32Sequence.Range() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestFloat32Sequence_First(t *testing.T) { - now := time.Now() - seq := RandomFloat32Sequence(10) - for i := range seq { - seq[i].Time = now.Add(time.Duration(i) * time.Second) - } - rand.Shuffle(seq.Len(), func(i, j int) { - seq[i], seq[j] = seq[j], seq[i] - }) - - type args struct { - afterOrEqual *time.Time - } - tests := []struct { - name string - s Float32Sequence - args args - want *Float32Item - }{ - { - s: seq, - args: args{ - afterOrEqual: nil, - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now), - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(-1 * time.Second)), - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1 * time.Second)), - }, - want: &seq[1], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: &seq[5], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(5*time.Second - time.Millisecond)), - }, - want: &seq[5], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(5*time.Second + time.Millisecond)), - }, - want: &seq[6], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(100 * time.Second)), - }, - want: nil, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.First(tt.args.afterOrEqual); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Float32Sequence.First() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestFloat32Sequence_Last(t *testing.T) { - now := time.Now() - seq := RandomFloat32Sequence(10) - for i := range seq { - seq[i].Time = now.Add(time.Duration(i) * time.Second) - } - rand.Shuffle(seq.Len(), func(i, j int) { - seq[i], seq[j] = seq[j], seq[i] - }) - - type args struct { - beforeOrEqual *time.Time - } - tests := []struct { - name string - s Float32Sequence - args args - want *Float32Item - }{ - { - s: seq, - args: args{ - beforeOrEqual: nil, - }, - want: &seq[len(seq)-1], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now), - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(-1 * time.Second)), - }, - want: nil, - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(1 * time.Second)), - }, - want: &seq[1], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: &seq[5], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(5*time.Second - time.Millisecond)), - }, - want: &seq[4], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(5*time.Second + time.Millisecond)), - }, - want: &seq[5], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(100 * time.Second)), - }, - want: &seq[9], - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Last(tt.args.beforeOrEqual); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Float32Sequence.Last() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestFloat32Sequence_Max(t *testing.T) { - seq1 := RandomFloat32Sequence(10) - seq1.Sort() - for i := range seq1 { - if i == 0 { - seq1[i].Value = 1 - } else { - seq1[i].Value = 0 - } - } - seq2 := RandomFloat32Sequence(10) - seq2.Sort() - for i := range seq2 { - if i == 0 { - seq2[i].Value = 0 - } else { - seq2[i].Value = 1 - } - } - - tests := []struct { - name string - s Float32Sequence - want *Float32Item - }{ - { - s: seq1, - want: &seq1[0], - }, - { - s: seq2, - want: &seq2[1], - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Max(); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Float32Sequence.Max() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestFloat32Sequence_Min(t *testing.T) { - seq1 := RandomFloat32Sequence(10) - seq1.Sort() - for i := range seq1 { - if i == 0 { - seq1[i].Value = 1 - } else { - seq1[i].Value = 0 - } - } - seq2 := RandomFloat32Sequence(10) - seq2.Sort() - for i := range seq2 { - if i == 0 { - seq2[i].Value = 0 - } else { - seq2[i].Value = 1 - } - } - - tests := []struct { - name string - s Float32Sequence - want *Float32Item - }{ - { - s: seq1, - want: &seq1[1], - }, - { - s: seq2, - want: &seq2[0], - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Min(); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Float32Sequence.Min() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestFloat32Sequence_Sum(t *testing.T) { - seq := RandomFloat32Sequence(10) - for i := range seq { - seq[i].Value = float32(i) - } - - tests := []struct { - name string - s Float32Sequence - want float32 - }{ - { - s: seq, - want: 45, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Sum(); got != tt.want { - t.Errorf("Float32Sequence.Sum() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestFloat32Sequence_Average(t *testing.T) { - seq := RandomFloat32Sequence(10) - for i := range seq { - seq[i].Value = float32(i) * 2 - } - - tests := []struct { - name string - s Float32Sequence - want float32 - }{ - { - s: seq, - want: 9, - }, - { - s: nil, - want: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Average(); got != tt.want { - t.Errorf("Float32Sequence.Average() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestFloat32Sequence_Percentile(t *testing.T) { - seq := RandomFloat32Sequence(100) - for i := range seq { - seq[i].Value = float32(i) + 1 - } - - type args struct { - pct float64 - } - tests := []struct { - name string - s Float32Sequence - args args - want float32 - }{ - { - s: seq, - args: args{ - pct: 0, - }, - want: 1, - }, - { - s: seq, - args: args{ - pct: 0.5, - }, - want: 50, - }, - { - s: seq, - args: args{ - pct: 0.95, - }, - want: 95, - }, - { - s: seq, - args: args{ - pct: 0.955, - }, - want: 95, - }, - { - s: seq, - args: args{ - pct: 1, - }, - want: 100, - }, - { - s: seq, - args: args{ - pct: 1.1, - }, - want: 100, - }, - { - s: seq, - args: args{ - pct: -0.1, - }, - want: 1, - }, - { - s: nil, - args: args{ - pct: 1, - }, - want: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - defer func() { - if r := recover(); r != nil { - if tt.args.pct > 1 || tt.args.pct < 0 { - return - } - t.Errorf("Float32Sequence.Percentile() failed: %v", r) - } - }() - if got := tt.s.Percentile(tt.args.pct); got != tt.want { - t.Errorf("Float32Sequence.Percentile() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestMergeFloat32(t *testing.T) { - seq := RandomFloat32Sequence(10) - seq.Sort() - type args struct { - seq1 Float32Sequence - seq2 Float32Sequence - fn func(item1, item2 *Float32Item) *Float32Item - } - tests := []struct { - name string - args args - want Float32Sequence - }{ - { - name: "regular", - args: args{ - seq1: seq[0:7], - seq2: seq[3:10], - fn: func(item1, item2 *Float32Item) *Float32Item { - if item1 != nil { - return item1 - } - return item2 - }, - }, - want: seq, - }, - { - name: "reverse", - args: args{ - seq1: seq[3:10], - seq2: seq[0:7], - fn: func(item1, item2 *Float32Item) *Float32Item { - if item1 != nil { - return item1 - } - return item2 - }, - }, - want: seq, - }, - { - name: "nil fn", - args: args{ - seq1: seq[0:7], - seq2: seq[3:10], - fn: nil, - }, - want: nil, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := MergeFloat32(tt.args.seq1, tt.args.seq2, tt.args.fn); !reflect.DeepEqual(got, tt.want) { - t.Errorf("MergeFloat32() = %v, want %v", got, tt.want) - } - }) - } -} - -func RandomFloat32Sequence(length int) Float32Sequence { - now := time.Now() - ret := make(Float32Sequence, length) - for i := range ret { - delta := time.Duration(i) * time.Second - if rand.Float64() < 0.5 { - delta = -delta - } - ret[i] = Float32Item{ - Time: now.Add(delta), - Value: float32(rand.Float64() * float64(math.MaxInt64)), - } - } - return ret -} diff --git a/float64_sequence.go b/float64_sequence.go deleted file mode 100644 index 0b49f96..0000000 --- a/float64_sequence.go +++ /dev/null @@ -1,197 +0,0 @@ -// Code generated by cmd/generate. DO NOT EDIT. - -package timeseq - -import ( - "errors" - "sort" - "time" -) - -// Float64Item is item of Float64Sequence -type Float64Item struct { - Time time.Time - Value float64 -} - -// Float64Sequence is the implement of Sequence for float64 -type Float64Sequence []Float64Item - -// Len implements Sequence.Len -func (s Float64Sequence) Len() int { - return len(s) -} - -// Swap implements Sequence.Swap -func (s Float64Sequence) Swap(i, j int) { - s[i], s[j] = s[j], s[i] -} - -// Time implements Sequence.Time -func (s Float64Sequence) Time(i int) time.Time { - return s[i].Time -} - -// Slice implements Sequence.Slice -func (s Float64Sequence) Slice(i, j int) Sequence { - return s[i:j] -} - -// Sort will sort sequence by time -func (s Float64Sequence) Sort() { - Sort(s) -} - -// Range return sub sequence, would sort sequence if it is not sorted -func (s Float64Sequence) Range(afterOrEqual, beforeOrEqual *time.Time) Float64Sequence { - if !sort.IsSorted(sortableSequence{s}) { - s.Sort() - } - return Range(s, afterOrEqual, beforeOrEqual).(Float64Sequence) -} - -// First return the first item or nil if not exists, would sort sequence if it is not sorted -func (s Float64Sequence) First(afterOrEqual *time.Time) *Float64Item { - if !sort.IsSorted(sortableSequence{s}) { - s.Sort() - } - i := First(s, afterOrEqual) - if i < 0 { - return nil - } - ret := s[i] - return &ret -} - -// Last return the last item or nil if not exists, would sort sequence if it is not sorted -func (s Float64Sequence) Last(beforeOrEqual *time.Time) *Float64Item { - if !sort.IsSorted(sortableSequence{s}) { - s.Sort() - } - i := Last(s, beforeOrEqual) - if i < 0 { - return nil - } - ret := s[i] - return &ret -} - -// Max return the first item which has the max value, or nil if not exists -func (s Float64Sequence) Max() *Float64Item { - var max *Float64Item - for i, v := range s { - if max == nil { - max = &s[i] - } else if v.Value > max.Value { - max = &s[i] - } - } - if max != nil { - value := *max - max = &value - } - return max -} - -// Min return the first item which has the min value, or nil if not exists -func (s Float64Sequence) Min() *Float64Item { - var min *Float64Item - for i, v := range s { - if min == nil { - min = &s[i] - } else if v.Value < min.Value { - min = &s[i] - } - } - if min != nil { - value := *min - min = &value - } - return min -} - -// Sum return the value's sum -func (s Float64Sequence) Sum() float64 { - var sum float64 - for _, v := range s { - sum += v.Value - } - return sum -} - -// Average return the value's average -func (s Float64Sequence) Average() float64 { - if len(s) == 0 { - return 0 - } - - return float64(float64(s.Sum()) / float64(len(s))) -} - -// Percentile return (pct)th percentile -func (s Float64Sequence) Percentile(pct float64) float64 { - if pct > 1 || pct < 0 { - panic(errors.New("percentile must be [0, 1]")) - } - - var values []float64 - for _, v := range s { - values = append(values, v.Value) - } - sort.Slice(values, func(i, j int) bool { - return values[i] < values[j] - }) - - if len(values) == 0 { - return 0 - } - - index := int(float64(len(s))*pct - 1) - if index < 0 { - index = 0 - } - - return values[index] -} - -// MergeFloat64 merge two float64} seuquence into one -func MergeFloat64(seq1, seq2 Float64Sequence, fn func(item1, item2 *Float64Item) *Float64Item) Float64Sequence { - if fn == nil { - return nil - } - - var ret Float64Sequence - for i1, i2 := 0, 0; i1 < seq1.Len() || i2 < seq2.Len(); { - var item *Float64Item - switch { - case i1 == seq1.Len(): - v2 := seq2[i2] - item = fn(nil, &v2) - i2++ - case i2 == seq2.Len(): - v1 := seq1[i1] - item = fn(&v1, nil) - i1++ - case seq1[i1].Time.Equal(seq2[i2].Time): - v1 := seq1[i1] - v2 := seq2[i2] - item = fn(&v1, &v2) - i1++ - i2++ - case seq1[i1].Time.Before(seq2[i2].Time): - v1 := seq1[i1] - item = fn(&v1, nil) - i1++ - case seq1[i1].Time.After(seq2[i2].Time): - v2 := seq2[i2] - item = fn(nil, &v2) - i2++ - } - if item != nil { - ret = append(ret, *item) - } - } - - Sort(ret) - return ret -} diff --git a/float64_sequence_test.go b/float64_sequence_test.go deleted file mode 100644 index 193c10d..0000000 --- a/float64_sequence_test.go +++ /dev/null @@ -1,716 +0,0 @@ -// Code generated by cmd/generate. DO NOT EDIT. - -package timeseq - -import ( - "math" - "math/rand" - "reflect" - "sort" - "testing" - "time" - - "github.com/gochore/pt" -) - -func TestFloat64Sequence_Len(t *testing.T) { - tests := []struct { - name string - s Float64Sequence - want int - }{ - { - s: RandomFloat64Sequence(10), - want: 10, - }, - { - s: RandomFloat64Sequence(0), - want: 0, - }, - { - s: nil, - want: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Len(); got != tt.want { - t.Errorf("Float64Sequence.Len() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestFloat64Sequence_Swap(t *testing.T) { - type args struct { - i int - j int - } - tests := []struct { - name string - s Float64Sequence - args args - }{ - { - s: RandomFloat64Sequence(10), - args: args{ - i: 0, - j: 5, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - ti := tt.s.Time(tt.args.i) - tj := tt.s.Time(tt.args.j) - tt.s.Swap(tt.args.i, tt.args.j) - if ti != tt.s.Time(tt.args.j) || tj != tt.s.Time(tt.args.i) { - t.Errorf("Float64Sequence.Swap() failed") - } - }) - } -} - -func TestFloat64Sequence_Time(t *testing.T) { - seq := RandomFloat64Sequence(10) - seq.Sort() - - type args struct { - i int - } - tests := []struct { - name string - s Float64Sequence - args args - want time.Time - }{ - { - s: seq, - args: args{ - i: 9, - }, - want: seq[9].Time, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Time(tt.args.i); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Float64Sequence.Time() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestFloat64Sequence_Slice(t *testing.T) { - seq := RandomFloat64Sequence(10) - - type args struct { - i int - j int - } - tests := []struct { - name string - s Float64Sequence - args args - want Sequence - }{ - { - s: seq, - args: args{ - i: 2, - j: 10, - }, - want: seq[2:10], - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Slice(tt.args.i, tt.args.j); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Float64Sequence.Slice() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestFloat64Sequence_Sort(t *testing.T) { - tests := []struct { - name string - s Float64Sequence - }{ - { - s: RandomFloat64Sequence(10), - }, - { - s: nil, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tt.s.Sort() - if !sort.IsSorted(sortableSequence{tt.s}) { - t.Error("Float64Sequence.Slice() failed") - } - }) - } -} - -func TestFloat64Sequence_Range(t *testing.T) { - now := time.Now() - seq := RandomFloat64Sequence(10) - for i := range seq { - seq[i].Time = now.Add(time.Duration(i) * time.Second) - } - rand.Shuffle(seq.Len(), func(i, j int) { - seq[i], seq[j] = seq[j], seq[i] - }) - - type args struct { - afterOrEqual *time.Time - beforeOrEqual *time.Time - } - tests := []struct { - name string - s Float64Sequence - args args - want Float64Sequence - }{ - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1 * time.Second)), - beforeOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: seq[1 : 5+1], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now), - beforeOrEqual: pt.Time(now.Add(100 * time.Second)), - }, - want: seq, - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1*time.Second + time.Millisecond)), - beforeOrEqual: pt.Time(now.Add(5*time.Second - time.Millisecond)), - }, - want: seq[2 : 4+1], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1*time.Second - time.Millisecond)), - beforeOrEqual: pt.Time(now.Add(5*time.Second + time.Millisecond)), - }, - want: seq[1 : 5+1], - }, - { - s: seq, - args: args{ - afterOrEqual: nil, - beforeOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: seq[:5+1], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1 * time.Second)), - beforeOrEqual: nil, - }, - want: seq[1:], - }, - { - s: seq, - args: args{ - afterOrEqual: nil, - beforeOrEqual: nil, - }, - want: seq, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Range(tt.args.afterOrEqual, tt.args.beforeOrEqual); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Float64Sequence.Range() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestFloat64Sequence_First(t *testing.T) { - now := time.Now() - seq := RandomFloat64Sequence(10) - for i := range seq { - seq[i].Time = now.Add(time.Duration(i) * time.Second) - } - rand.Shuffle(seq.Len(), func(i, j int) { - seq[i], seq[j] = seq[j], seq[i] - }) - - type args struct { - afterOrEqual *time.Time - } - tests := []struct { - name string - s Float64Sequence - args args - want *Float64Item - }{ - { - s: seq, - args: args{ - afterOrEqual: nil, - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now), - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(-1 * time.Second)), - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1 * time.Second)), - }, - want: &seq[1], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: &seq[5], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(5*time.Second - time.Millisecond)), - }, - want: &seq[5], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(5*time.Second + time.Millisecond)), - }, - want: &seq[6], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(100 * time.Second)), - }, - want: nil, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.First(tt.args.afterOrEqual); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Float64Sequence.First() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestFloat64Sequence_Last(t *testing.T) { - now := time.Now() - seq := RandomFloat64Sequence(10) - for i := range seq { - seq[i].Time = now.Add(time.Duration(i) * time.Second) - } - rand.Shuffle(seq.Len(), func(i, j int) { - seq[i], seq[j] = seq[j], seq[i] - }) - - type args struct { - beforeOrEqual *time.Time - } - tests := []struct { - name string - s Float64Sequence - args args - want *Float64Item - }{ - { - s: seq, - args: args{ - beforeOrEqual: nil, - }, - want: &seq[len(seq)-1], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now), - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(-1 * time.Second)), - }, - want: nil, - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(1 * time.Second)), - }, - want: &seq[1], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: &seq[5], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(5*time.Second - time.Millisecond)), - }, - want: &seq[4], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(5*time.Second + time.Millisecond)), - }, - want: &seq[5], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(100 * time.Second)), - }, - want: &seq[9], - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Last(tt.args.beforeOrEqual); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Float64Sequence.Last() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestFloat64Sequence_Max(t *testing.T) { - seq1 := RandomFloat64Sequence(10) - seq1.Sort() - for i := range seq1 { - if i == 0 { - seq1[i].Value = 1 - } else { - seq1[i].Value = 0 - } - } - seq2 := RandomFloat64Sequence(10) - seq2.Sort() - for i := range seq2 { - if i == 0 { - seq2[i].Value = 0 - } else { - seq2[i].Value = 1 - } - } - - tests := []struct { - name string - s Float64Sequence - want *Float64Item - }{ - { - s: seq1, - want: &seq1[0], - }, - { - s: seq2, - want: &seq2[1], - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Max(); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Float64Sequence.Max() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestFloat64Sequence_Min(t *testing.T) { - seq1 := RandomFloat64Sequence(10) - seq1.Sort() - for i := range seq1 { - if i == 0 { - seq1[i].Value = 1 - } else { - seq1[i].Value = 0 - } - } - seq2 := RandomFloat64Sequence(10) - seq2.Sort() - for i := range seq2 { - if i == 0 { - seq2[i].Value = 0 - } else { - seq2[i].Value = 1 - } - } - - tests := []struct { - name string - s Float64Sequence - want *Float64Item - }{ - { - s: seq1, - want: &seq1[1], - }, - { - s: seq2, - want: &seq2[0], - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Min(); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Float64Sequence.Min() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestFloat64Sequence_Sum(t *testing.T) { - seq := RandomFloat64Sequence(10) - for i := range seq { - seq[i].Value = float64(i) - } - - tests := []struct { - name string - s Float64Sequence - want float64 - }{ - { - s: seq, - want: 45, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Sum(); got != tt.want { - t.Errorf("Float64Sequence.Sum() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestFloat64Sequence_Average(t *testing.T) { - seq := RandomFloat64Sequence(10) - for i := range seq { - seq[i].Value = float64(i) * 2 - } - - tests := []struct { - name string - s Float64Sequence - want float64 - }{ - { - s: seq, - want: 9, - }, - { - s: nil, - want: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Average(); got != tt.want { - t.Errorf("Float64Sequence.Average() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestFloat64Sequence_Percentile(t *testing.T) { - seq := RandomFloat64Sequence(100) - for i := range seq { - seq[i].Value = float64(i) + 1 - } - - type args struct { - pct float64 - } - tests := []struct { - name string - s Float64Sequence - args args - want float64 - }{ - { - s: seq, - args: args{ - pct: 0, - }, - want: 1, - }, - { - s: seq, - args: args{ - pct: 0.5, - }, - want: 50, - }, - { - s: seq, - args: args{ - pct: 0.95, - }, - want: 95, - }, - { - s: seq, - args: args{ - pct: 0.955, - }, - want: 95, - }, - { - s: seq, - args: args{ - pct: 1, - }, - want: 100, - }, - { - s: seq, - args: args{ - pct: 1.1, - }, - want: 100, - }, - { - s: seq, - args: args{ - pct: -0.1, - }, - want: 1, - }, - { - s: nil, - args: args{ - pct: 1, - }, - want: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - defer func() { - if r := recover(); r != nil { - if tt.args.pct > 1 || tt.args.pct < 0 { - return - } - t.Errorf("Float64Sequence.Percentile() failed: %v", r) - } - }() - if got := tt.s.Percentile(tt.args.pct); got != tt.want { - t.Errorf("Float64Sequence.Percentile() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestMergeFloat64(t *testing.T) { - seq := RandomFloat64Sequence(10) - seq.Sort() - type args struct { - seq1 Float64Sequence - seq2 Float64Sequence - fn func(item1, item2 *Float64Item) *Float64Item - } - tests := []struct { - name string - args args - want Float64Sequence - }{ - { - name: "regular", - args: args{ - seq1: seq[0:7], - seq2: seq[3:10], - fn: func(item1, item2 *Float64Item) *Float64Item { - if item1 != nil { - return item1 - } - return item2 - }, - }, - want: seq, - }, - { - name: "reverse", - args: args{ - seq1: seq[3:10], - seq2: seq[0:7], - fn: func(item1, item2 *Float64Item) *Float64Item { - if item1 != nil { - return item1 - } - return item2 - }, - }, - want: seq, - }, - { - name: "nil fn", - args: args{ - seq1: seq[0:7], - seq2: seq[3:10], - fn: nil, - }, - want: nil, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := MergeFloat64(tt.args.seq1, tt.args.seq2, tt.args.fn); !reflect.DeepEqual(got, tt.want) { - t.Errorf("MergeFloat64() = %v, want %v", got, tt.want) - } - }) - } -} - -func RandomFloat64Sequence(length int) Float64Sequence { - now := time.Now() - ret := make(Float64Sequence, length) - for i := range ret { - delta := time.Duration(i) * time.Second - if rand.Float64() < 0.5 { - delta = -delta - } - ret[i] = Float64Item{ - Time: now.Add(delta), - Value: float64(rand.Float64() * float64(math.MaxInt64)), - } - } - return ret -} diff --git a/int32_sequence.go b/int32_sequence.go deleted file mode 100644 index 0f66d12..0000000 --- a/int32_sequence.go +++ /dev/null @@ -1,197 +0,0 @@ -// Code generated by cmd/generate. DO NOT EDIT. - -package timeseq - -import ( - "errors" - "sort" - "time" -) - -// Int32Item is item of Int32Sequence -type Int32Item struct { - Time time.Time - Value int32 -} - -// Int32Sequence is the implement of Sequence for int32 -type Int32Sequence []Int32Item - -// Len implements Sequence.Len -func (s Int32Sequence) Len() int { - return len(s) -} - -// Swap implements Sequence.Swap -func (s Int32Sequence) Swap(i, j int) { - s[i], s[j] = s[j], s[i] -} - -// Time implements Sequence.Time -func (s Int32Sequence) Time(i int) time.Time { - return s[i].Time -} - -// Slice implements Sequence.Slice -func (s Int32Sequence) Slice(i, j int) Sequence { - return s[i:j] -} - -// Sort will sort sequence by time -func (s Int32Sequence) Sort() { - Sort(s) -} - -// Range return sub sequence, would sort sequence if it is not sorted -func (s Int32Sequence) Range(afterOrEqual, beforeOrEqual *time.Time) Int32Sequence { - if !sort.IsSorted(sortableSequence{s}) { - s.Sort() - } - return Range(s, afterOrEqual, beforeOrEqual).(Int32Sequence) -} - -// First return the first item or nil if not exists, would sort sequence if it is not sorted -func (s Int32Sequence) First(afterOrEqual *time.Time) *Int32Item { - if !sort.IsSorted(sortableSequence{s}) { - s.Sort() - } - i := First(s, afterOrEqual) - if i < 0 { - return nil - } - ret := s[i] - return &ret -} - -// Last return the last item or nil if not exists, would sort sequence if it is not sorted -func (s Int32Sequence) Last(beforeOrEqual *time.Time) *Int32Item { - if !sort.IsSorted(sortableSequence{s}) { - s.Sort() - } - i := Last(s, beforeOrEqual) - if i < 0 { - return nil - } - ret := s[i] - return &ret -} - -// Max return the first item which has the max value, or nil if not exists -func (s Int32Sequence) Max() *Int32Item { - var max *Int32Item - for i, v := range s { - if max == nil { - max = &s[i] - } else if v.Value > max.Value { - max = &s[i] - } - } - if max != nil { - value := *max - max = &value - } - return max -} - -// Min return the first item which has the min value, or nil if not exists -func (s Int32Sequence) Min() *Int32Item { - var min *Int32Item - for i, v := range s { - if min == nil { - min = &s[i] - } else if v.Value < min.Value { - min = &s[i] - } - } - if min != nil { - value := *min - min = &value - } - return min -} - -// Sum return the value's sum -func (s Int32Sequence) Sum() int32 { - var sum int32 - for _, v := range s { - sum += v.Value - } - return sum -} - -// Average return the value's average -func (s Int32Sequence) Average() int32 { - if len(s) == 0 { - return 0 - } - - return int32(float64(s.Sum()) / float64(len(s))) -} - -// Percentile return (pct)th percentile -func (s Int32Sequence) Percentile(pct float64) int32 { - if pct > 1 || pct < 0 { - panic(errors.New("percentile must be [0, 1]")) - } - - var values []int32 - for _, v := range s { - values = append(values, v.Value) - } - sort.Slice(values, func(i, j int) bool { - return values[i] < values[j] - }) - - if len(values) == 0 { - return 0 - } - - index := int(float64(len(s))*pct - 1) - if index < 0 { - index = 0 - } - - return values[index] -} - -// MergeInt32 merge two int32} seuquence into one -func MergeInt32(seq1, seq2 Int32Sequence, fn func(item1, item2 *Int32Item) *Int32Item) Int32Sequence { - if fn == nil { - return nil - } - - var ret Int32Sequence - for i1, i2 := 0, 0; i1 < seq1.Len() || i2 < seq2.Len(); { - var item *Int32Item - switch { - case i1 == seq1.Len(): - v2 := seq2[i2] - item = fn(nil, &v2) - i2++ - case i2 == seq2.Len(): - v1 := seq1[i1] - item = fn(&v1, nil) - i1++ - case seq1[i1].Time.Equal(seq2[i2].Time): - v1 := seq1[i1] - v2 := seq2[i2] - item = fn(&v1, &v2) - i1++ - i2++ - case seq1[i1].Time.Before(seq2[i2].Time): - v1 := seq1[i1] - item = fn(&v1, nil) - i1++ - case seq1[i1].Time.After(seq2[i2].Time): - v2 := seq2[i2] - item = fn(nil, &v2) - i2++ - } - if item != nil { - ret = append(ret, *item) - } - } - - Sort(ret) - return ret -} diff --git a/int32_sequence_test.go b/int32_sequence_test.go deleted file mode 100644 index 655e237..0000000 --- a/int32_sequence_test.go +++ /dev/null @@ -1,716 +0,0 @@ -// Code generated by cmd/generate. DO NOT EDIT. - -package timeseq - -import ( - "math" - "math/rand" - "reflect" - "sort" - "testing" - "time" - - "github.com/gochore/pt" -) - -func TestInt32Sequence_Len(t *testing.T) { - tests := []struct { - name string - s Int32Sequence - want int - }{ - { - s: RandomInt32Sequence(10), - want: 10, - }, - { - s: RandomInt32Sequence(0), - want: 0, - }, - { - s: nil, - want: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Len(); got != tt.want { - t.Errorf("Int32Sequence.Len() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestInt32Sequence_Swap(t *testing.T) { - type args struct { - i int - j int - } - tests := []struct { - name string - s Int32Sequence - args args - }{ - { - s: RandomInt32Sequence(10), - args: args{ - i: 0, - j: 5, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - ti := tt.s.Time(tt.args.i) - tj := tt.s.Time(tt.args.j) - tt.s.Swap(tt.args.i, tt.args.j) - if ti != tt.s.Time(tt.args.j) || tj != tt.s.Time(tt.args.i) { - t.Errorf("Int32Sequence.Swap() failed") - } - }) - } -} - -func TestInt32Sequence_Time(t *testing.T) { - seq := RandomInt32Sequence(10) - seq.Sort() - - type args struct { - i int - } - tests := []struct { - name string - s Int32Sequence - args args - want time.Time - }{ - { - s: seq, - args: args{ - i: 9, - }, - want: seq[9].Time, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Time(tt.args.i); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Int32Sequence.Time() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestInt32Sequence_Slice(t *testing.T) { - seq := RandomInt32Sequence(10) - - type args struct { - i int - j int - } - tests := []struct { - name string - s Int32Sequence - args args - want Sequence - }{ - { - s: seq, - args: args{ - i: 2, - j: 10, - }, - want: seq[2:10], - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Slice(tt.args.i, tt.args.j); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Int32Sequence.Slice() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestInt32Sequence_Sort(t *testing.T) { - tests := []struct { - name string - s Int32Sequence - }{ - { - s: RandomInt32Sequence(10), - }, - { - s: nil, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tt.s.Sort() - if !sort.IsSorted(sortableSequence{tt.s}) { - t.Error("Int32Sequence.Slice() failed") - } - }) - } -} - -func TestInt32Sequence_Range(t *testing.T) { - now := time.Now() - seq := RandomInt32Sequence(10) - for i := range seq { - seq[i].Time = now.Add(time.Duration(i) * time.Second) - } - rand.Shuffle(seq.Len(), func(i, j int) { - seq[i], seq[j] = seq[j], seq[i] - }) - - type args struct { - afterOrEqual *time.Time - beforeOrEqual *time.Time - } - tests := []struct { - name string - s Int32Sequence - args args - want Int32Sequence - }{ - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1 * time.Second)), - beforeOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: seq[1 : 5+1], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now), - beforeOrEqual: pt.Time(now.Add(100 * time.Second)), - }, - want: seq, - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1*time.Second + time.Millisecond)), - beforeOrEqual: pt.Time(now.Add(5*time.Second - time.Millisecond)), - }, - want: seq[2 : 4+1], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1*time.Second - time.Millisecond)), - beforeOrEqual: pt.Time(now.Add(5*time.Second + time.Millisecond)), - }, - want: seq[1 : 5+1], - }, - { - s: seq, - args: args{ - afterOrEqual: nil, - beforeOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: seq[:5+1], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1 * time.Second)), - beforeOrEqual: nil, - }, - want: seq[1:], - }, - { - s: seq, - args: args{ - afterOrEqual: nil, - beforeOrEqual: nil, - }, - want: seq, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Range(tt.args.afterOrEqual, tt.args.beforeOrEqual); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Int32Sequence.Range() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestInt32Sequence_First(t *testing.T) { - now := time.Now() - seq := RandomInt32Sequence(10) - for i := range seq { - seq[i].Time = now.Add(time.Duration(i) * time.Second) - } - rand.Shuffle(seq.Len(), func(i, j int) { - seq[i], seq[j] = seq[j], seq[i] - }) - - type args struct { - afterOrEqual *time.Time - } - tests := []struct { - name string - s Int32Sequence - args args - want *Int32Item - }{ - { - s: seq, - args: args{ - afterOrEqual: nil, - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now), - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(-1 * time.Second)), - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1 * time.Second)), - }, - want: &seq[1], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: &seq[5], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(5*time.Second - time.Millisecond)), - }, - want: &seq[5], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(5*time.Second + time.Millisecond)), - }, - want: &seq[6], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(100 * time.Second)), - }, - want: nil, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.First(tt.args.afterOrEqual); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Int32Sequence.First() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestInt32Sequence_Last(t *testing.T) { - now := time.Now() - seq := RandomInt32Sequence(10) - for i := range seq { - seq[i].Time = now.Add(time.Duration(i) * time.Second) - } - rand.Shuffle(seq.Len(), func(i, j int) { - seq[i], seq[j] = seq[j], seq[i] - }) - - type args struct { - beforeOrEqual *time.Time - } - tests := []struct { - name string - s Int32Sequence - args args - want *Int32Item - }{ - { - s: seq, - args: args{ - beforeOrEqual: nil, - }, - want: &seq[len(seq)-1], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now), - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(-1 * time.Second)), - }, - want: nil, - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(1 * time.Second)), - }, - want: &seq[1], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: &seq[5], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(5*time.Second - time.Millisecond)), - }, - want: &seq[4], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(5*time.Second + time.Millisecond)), - }, - want: &seq[5], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(100 * time.Second)), - }, - want: &seq[9], - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Last(tt.args.beforeOrEqual); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Int32Sequence.Last() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestInt32Sequence_Max(t *testing.T) { - seq1 := RandomInt32Sequence(10) - seq1.Sort() - for i := range seq1 { - if i == 0 { - seq1[i].Value = 1 - } else { - seq1[i].Value = 0 - } - } - seq2 := RandomInt32Sequence(10) - seq2.Sort() - for i := range seq2 { - if i == 0 { - seq2[i].Value = 0 - } else { - seq2[i].Value = 1 - } - } - - tests := []struct { - name string - s Int32Sequence - want *Int32Item - }{ - { - s: seq1, - want: &seq1[0], - }, - { - s: seq2, - want: &seq2[1], - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Max(); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Int32Sequence.Max() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestInt32Sequence_Min(t *testing.T) { - seq1 := RandomInt32Sequence(10) - seq1.Sort() - for i := range seq1 { - if i == 0 { - seq1[i].Value = 1 - } else { - seq1[i].Value = 0 - } - } - seq2 := RandomInt32Sequence(10) - seq2.Sort() - for i := range seq2 { - if i == 0 { - seq2[i].Value = 0 - } else { - seq2[i].Value = 1 - } - } - - tests := []struct { - name string - s Int32Sequence - want *Int32Item - }{ - { - s: seq1, - want: &seq1[1], - }, - { - s: seq2, - want: &seq2[0], - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Min(); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Int32Sequence.Min() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestInt32Sequence_Sum(t *testing.T) { - seq := RandomInt32Sequence(10) - for i := range seq { - seq[i].Value = int32(i) - } - - tests := []struct { - name string - s Int32Sequence - want int32 - }{ - { - s: seq, - want: 45, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Sum(); got != tt.want { - t.Errorf("Int32Sequence.Sum() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestInt32Sequence_Average(t *testing.T) { - seq := RandomInt32Sequence(10) - for i := range seq { - seq[i].Value = int32(i) * 2 - } - - tests := []struct { - name string - s Int32Sequence - want int32 - }{ - { - s: seq, - want: 9, - }, - { - s: nil, - want: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Average(); got != tt.want { - t.Errorf("Int32Sequence.Average() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestInt32Sequence_Percentile(t *testing.T) { - seq := RandomInt32Sequence(100) - for i := range seq { - seq[i].Value = int32(i) + 1 - } - - type args struct { - pct float64 - } - tests := []struct { - name string - s Int32Sequence - args args - want int32 - }{ - { - s: seq, - args: args{ - pct: 0, - }, - want: 1, - }, - { - s: seq, - args: args{ - pct: 0.5, - }, - want: 50, - }, - { - s: seq, - args: args{ - pct: 0.95, - }, - want: 95, - }, - { - s: seq, - args: args{ - pct: 0.955, - }, - want: 95, - }, - { - s: seq, - args: args{ - pct: 1, - }, - want: 100, - }, - { - s: seq, - args: args{ - pct: 1.1, - }, - want: 100, - }, - { - s: seq, - args: args{ - pct: -0.1, - }, - want: 1, - }, - { - s: nil, - args: args{ - pct: 1, - }, - want: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - defer func() { - if r := recover(); r != nil { - if tt.args.pct > 1 || tt.args.pct < 0 { - return - } - t.Errorf("Int32Sequence.Percentile() failed: %v", r) - } - }() - if got := tt.s.Percentile(tt.args.pct); got != tt.want { - t.Errorf("Int32Sequence.Percentile() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestMergeInt32(t *testing.T) { - seq := RandomInt32Sequence(10) - seq.Sort() - type args struct { - seq1 Int32Sequence - seq2 Int32Sequence - fn func(item1, item2 *Int32Item) *Int32Item - } - tests := []struct { - name string - args args - want Int32Sequence - }{ - { - name: "regular", - args: args{ - seq1: seq[0:7], - seq2: seq[3:10], - fn: func(item1, item2 *Int32Item) *Int32Item { - if item1 != nil { - return item1 - } - return item2 - }, - }, - want: seq, - }, - { - name: "reverse", - args: args{ - seq1: seq[3:10], - seq2: seq[0:7], - fn: func(item1, item2 *Int32Item) *Int32Item { - if item1 != nil { - return item1 - } - return item2 - }, - }, - want: seq, - }, - { - name: "nil fn", - args: args{ - seq1: seq[0:7], - seq2: seq[3:10], - fn: nil, - }, - want: nil, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := MergeInt32(tt.args.seq1, tt.args.seq2, tt.args.fn); !reflect.DeepEqual(got, tt.want) { - t.Errorf("MergeInt32() = %v, want %v", got, tt.want) - } - }) - } -} - -func RandomInt32Sequence(length int) Int32Sequence { - now := time.Now() - ret := make(Int32Sequence, length) - for i := range ret { - delta := time.Duration(i) * time.Second - if rand.Float64() < 0.5 { - delta = -delta - } - ret[i] = Int32Item{ - Time: now.Add(delta), - Value: int32(rand.Float64() * float64(math.MaxInt64)), - } - } - return ret -} diff --git a/int64_sequence.go b/int64_sequence.go deleted file mode 100644 index baa00b0..0000000 --- a/int64_sequence.go +++ /dev/null @@ -1,197 +0,0 @@ -// Code generated by cmd/generate. DO NOT EDIT. - -package timeseq - -import ( - "errors" - "sort" - "time" -) - -// Int64Item is item of Int64Sequence -type Int64Item struct { - Time time.Time - Value int64 -} - -// Int64Sequence is the implement of Sequence for int64 -type Int64Sequence []Int64Item - -// Len implements Sequence.Len -func (s Int64Sequence) Len() int { - return len(s) -} - -// Swap implements Sequence.Swap -func (s Int64Sequence) Swap(i, j int) { - s[i], s[j] = s[j], s[i] -} - -// Time implements Sequence.Time -func (s Int64Sequence) Time(i int) time.Time { - return s[i].Time -} - -// Slice implements Sequence.Slice -func (s Int64Sequence) Slice(i, j int) Sequence { - return s[i:j] -} - -// Sort will sort sequence by time -func (s Int64Sequence) Sort() { - Sort(s) -} - -// Range return sub sequence, would sort sequence if it is not sorted -func (s Int64Sequence) Range(afterOrEqual, beforeOrEqual *time.Time) Int64Sequence { - if !sort.IsSorted(sortableSequence{s}) { - s.Sort() - } - return Range(s, afterOrEqual, beforeOrEqual).(Int64Sequence) -} - -// First return the first item or nil if not exists, would sort sequence if it is not sorted -func (s Int64Sequence) First(afterOrEqual *time.Time) *Int64Item { - if !sort.IsSorted(sortableSequence{s}) { - s.Sort() - } - i := First(s, afterOrEqual) - if i < 0 { - return nil - } - ret := s[i] - return &ret -} - -// Last return the last item or nil if not exists, would sort sequence if it is not sorted -func (s Int64Sequence) Last(beforeOrEqual *time.Time) *Int64Item { - if !sort.IsSorted(sortableSequence{s}) { - s.Sort() - } - i := Last(s, beforeOrEqual) - if i < 0 { - return nil - } - ret := s[i] - return &ret -} - -// Max return the first item which has the max value, or nil if not exists -func (s Int64Sequence) Max() *Int64Item { - var max *Int64Item - for i, v := range s { - if max == nil { - max = &s[i] - } else if v.Value > max.Value { - max = &s[i] - } - } - if max != nil { - value := *max - max = &value - } - return max -} - -// Min return the first item which has the min value, or nil if not exists -func (s Int64Sequence) Min() *Int64Item { - var min *Int64Item - for i, v := range s { - if min == nil { - min = &s[i] - } else if v.Value < min.Value { - min = &s[i] - } - } - if min != nil { - value := *min - min = &value - } - return min -} - -// Sum return the value's sum -func (s Int64Sequence) Sum() int64 { - var sum int64 - for _, v := range s { - sum += v.Value - } - return sum -} - -// Average return the value's average -func (s Int64Sequence) Average() int64 { - if len(s) == 0 { - return 0 - } - - return int64(float64(s.Sum()) / float64(len(s))) -} - -// Percentile return (pct)th percentile -func (s Int64Sequence) Percentile(pct float64) int64 { - if pct > 1 || pct < 0 { - panic(errors.New("percentile must be [0, 1]")) - } - - var values []int64 - for _, v := range s { - values = append(values, v.Value) - } - sort.Slice(values, func(i, j int) bool { - return values[i] < values[j] - }) - - if len(values) == 0 { - return 0 - } - - index := int(float64(len(s))*pct - 1) - if index < 0 { - index = 0 - } - - return values[index] -} - -// MergeInt64 merge two int64} seuquence into one -func MergeInt64(seq1, seq2 Int64Sequence, fn func(item1, item2 *Int64Item) *Int64Item) Int64Sequence { - if fn == nil { - return nil - } - - var ret Int64Sequence - for i1, i2 := 0, 0; i1 < seq1.Len() || i2 < seq2.Len(); { - var item *Int64Item - switch { - case i1 == seq1.Len(): - v2 := seq2[i2] - item = fn(nil, &v2) - i2++ - case i2 == seq2.Len(): - v1 := seq1[i1] - item = fn(&v1, nil) - i1++ - case seq1[i1].Time.Equal(seq2[i2].Time): - v1 := seq1[i1] - v2 := seq2[i2] - item = fn(&v1, &v2) - i1++ - i2++ - case seq1[i1].Time.Before(seq2[i2].Time): - v1 := seq1[i1] - item = fn(&v1, nil) - i1++ - case seq1[i1].Time.After(seq2[i2].Time): - v2 := seq2[i2] - item = fn(nil, &v2) - i2++ - } - if item != nil { - ret = append(ret, *item) - } - } - - Sort(ret) - return ret -} diff --git a/int64_sequence_test.go b/int64_sequence_test.go deleted file mode 100644 index 7aee779..0000000 --- a/int64_sequence_test.go +++ /dev/null @@ -1,716 +0,0 @@ -// Code generated by cmd/generate. DO NOT EDIT. - -package timeseq - -import ( - "math" - "math/rand" - "reflect" - "sort" - "testing" - "time" - - "github.com/gochore/pt" -) - -func TestInt64Sequence_Len(t *testing.T) { - tests := []struct { - name string - s Int64Sequence - want int - }{ - { - s: RandomInt64Sequence(10), - want: 10, - }, - { - s: RandomInt64Sequence(0), - want: 0, - }, - { - s: nil, - want: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Len(); got != tt.want { - t.Errorf("Int64Sequence.Len() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestInt64Sequence_Swap(t *testing.T) { - type args struct { - i int - j int - } - tests := []struct { - name string - s Int64Sequence - args args - }{ - { - s: RandomInt64Sequence(10), - args: args{ - i: 0, - j: 5, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - ti := tt.s.Time(tt.args.i) - tj := tt.s.Time(tt.args.j) - tt.s.Swap(tt.args.i, tt.args.j) - if ti != tt.s.Time(tt.args.j) || tj != tt.s.Time(tt.args.i) { - t.Errorf("Int64Sequence.Swap() failed") - } - }) - } -} - -func TestInt64Sequence_Time(t *testing.T) { - seq := RandomInt64Sequence(10) - seq.Sort() - - type args struct { - i int - } - tests := []struct { - name string - s Int64Sequence - args args - want time.Time - }{ - { - s: seq, - args: args{ - i: 9, - }, - want: seq[9].Time, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Time(tt.args.i); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Int64Sequence.Time() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestInt64Sequence_Slice(t *testing.T) { - seq := RandomInt64Sequence(10) - - type args struct { - i int - j int - } - tests := []struct { - name string - s Int64Sequence - args args - want Sequence - }{ - { - s: seq, - args: args{ - i: 2, - j: 10, - }, - want: seq[2:10], - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Slice(tt.args.i, tt.args.j); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Int64Sequence.Slice() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestInt64Sequence_Sort(t *testing.T) { - tests := []struct { - name string - s Int64Sequence - }{ - { - s: RandomInt64Sequence(10), - }, - { - s: nil, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tt.s.Sort() - if !sort.IsSorted(sortableSequence{tt.s}) { - t.Error("Int64Sequence.Slice() failed") - } - }) - } -} - -func TestInt64Sequence_Range(t *testing.T) { - now := time.Now() - seq := RandomInt64Sequence(10) - for i := range seq { - seq[i].Time = now.Add(time.Duration(i) * time.Second) - } - rand.Shuffle(seq.Len(), func(i, j int) { - seq[i], seq[j] = seq[j], seq[i] - }) - - type args struct { - afterOrEqual *time.Time - beforeOrEqual *time.Time - } - tests := []struct { - name string - s Int64Sequence - args args - want Int64Sequence - }{ - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1 * time.Second)), - beforeOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: seq[1 : 5+1], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now), - beforeOrEqual: pt.Time(now.Add(100 * time.Second)), - }, - want: seq, - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1*time.Second + time.Millisecond)), - beforeOrEqual: pt.Time(now.Add(5*time.Second - time.Millisecond)), - }, - want: seq[2 : 4+1], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1*time.Second - time.Millisecond)), - beforeOrEqual: pt.Time(now.Add(5*time.Second + time.Millisecond)), - }, - want: seq[1 : 5+1], - }, - { - s: seq, - args: args{ - afterOrEqual: nil, - beforeOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: seq[:5+1], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1 * time.Second)), - beforeOrEqual: nil, - }, - want: seq[1:], - }, - { - s: seq, - args: args{ - afterOrEqual: nil, - beforeOrEqual: nil, - }, - want: seq, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Range(tt.args.afterOrEqual, tt.args.beforeOrEqual); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Int64Sequence.Range() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestInt64Sequence_First(t *testing.T) { - now := time.Now() - seq := RandomInt64Sequence(10) - for i := range seq { - seq[i].Time = now.Add(time.Duration(i) * time.Second) - } - rand.Shuffle(seq.Len(), func(i, j int) { - seq[i], seq[j] = seq[j], seq[i] - }) - - type args struct { - afterOrEqual *time.Time - } - tests := []struct { - name string - s Int64Sequence - args args - want *Int64Item - }{ - { - s: seq, - args: args{ - afterOrEqual: nil, - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now), - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(-1 * time.Second)), - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1 * time.Second)), - }, - want: &seq[1], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: &seq[5], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(5*time.Second - time.Millisecond)), - }, - want: &seq[5], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(5*time.Second + time.Millisecond)), - }, - want: &seq[6], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(100 * time.Second)), - }, - want: nil, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.First(tt.args.afterOrEqual); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Int64Sequence.First() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestInt64Sequence_Last(t *testing.T) { - now := time.Now() - seq := RandomInt64Sequence(10) - for i := range seq { - seq[i].Time = now.Add(time.Duration(i) * time.Second) - } - rand.Shuffle(seq.Len(), func(i, j int) { - seq[i], seq[j] = seq[j], seq[i] - }) - - type args struct { - beforeOrEqual *time.Time - } - tests := []struct { - name string - s Int64Sequence - args args - want *Int64Item - }{ - { - s: seq, - args: args{ - beforeOrEqual: nil, - }, - want: &seq[len(seq)-1], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now), - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(-1 * time.Second)), - }, - want: nil, - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(1 * time.Second)), - }, - want: &seq[1], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: &seq[5], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(5*time.Second - time.Millisecond)), - }, - want: &seq[4], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(5*time.Second + time.Millisecond)), - }, - want: &seq[5], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(100 * time.Second)), - }, - want: &seq[9], - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Last(tt.args.beforeOrEqual); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Int64Sequence.Last() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestInt64Sequence_Max(t *testing.T) { - seq1 := RandomInt64Sequence(10) - seq1.Sort() - for i := range seq1 { - if i == 0 { - seq1[i].Value = 1 - } else { - seq1[i].Value = 0 - } - } - seq2 := RandomInt64Sequence(10) - seq2.Sort() - for i := range seq2 { - if i == 0 { - seq2[i].Value = 0 - } else { - seq2[i].Value = 1 - } - } - - tests := []struct { - name string - s Int64Sequence - want *Int64Item - }{ - { - s: seq1, - want: &seq1[0], - }, - { - s: seq2, - want: &seq2[1], - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Max(); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Int64Sequence.Max() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestInt64Sequence_Min(t *testing.T) { - seq1 := RandomInt64Sequence(10) - seq1.Sort() - for i := range seq1 { - if i == 0 { - seq1[i].Value = 1 - } else { - seq1[i].Value = 0 - } - } - seq2 := RandomInt64Sequence(10) - seq2.Sort() - for i := range seq2 { - if i == 0 { - seq2[i].Value = 0 - } else { - seq2[i].Value = 1 - } - } - - tests := []struct { - name string - s Int64Sequence - want *Int64Item - }{ - { - s: seq1, - want: &seq1[1], - }, - { - s: seq2, - want: &seq2[0], - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Min(); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Int64Sequence.Min() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestInt64Sequence_Sum(t *testing.T) { - seq := RandomInt64Sequence(10) - for i := range seq { - seq[i].Value = int64(i) - } - - tests := []struct { - name string - s Int64Sequence - want int64 - }{ - { - s: seq, - want: 45, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Sum(); got != tt.want { - t.Errorf("Int64Sequence.Sum() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestInt64Sequence_Average(t *testing.T) { - seq := RandomInt64Sequence(10) - for i := range seq { - seq[i].Value = int64(i) * 2 - } - - tests := []struct { - name string - s Int64Sequence - want int64 - }{ - { - s: seq, - want: 9, - }, - { - s: nil, - want: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Average(); got != tt.want { - t.Errorf("Int64Sequence.Average() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestInt64Sequence_Percentile(t *testing.T) { - seq := RandomInt64Sequence(100) - for i := range seq { - seq[i].Value = int64(i) + 1 - } - - type args struct { - pct float64 - } - tests := []struct { - name string - s Int64Sequence - args args - want int64 - }{ - { - s: seq, - args: args{ - pct: 0, - }, - want: 1, - }, - { - s: seq, - args: args{ - pct: 0.5, - }, - want: 50, - }, - { - s: seq, - args: args{ - pct: 0.95, - }, - want: 95, - }, - { - s: seq, - args: args{ - pct: 0.955, - }, - want: 95, - }, - { - s: seq, - args: args{ - pct: 1, - }, - want: 100, - }, - { - s: seq, - args: args{ - pct: 1.1, - }, - want: 100, - }, - { - s: seq, - args: args{ - pct: -0.1, - }, - want: 1, - }, - { - s: nil, - args: args{ - pct: 1, - }, - want: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - defer func() { - if r := recover(); r != nil { - if tt.args.pct > 1 || tt.args.pct < 0 { - return - } - t.Errorf("Int64Sequence.Percentile() failed: %v", r) - } - }() - if got := tt.s.Percentile(tt.args.pct); got != tt.want { - t.Errorf("Int64Sequence.Percentile() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestMergeInt64(t *testing.T) { - seq := RandomInt64Sequence(10) - seq.Sort() - type args struct { - seq1 Int64Sequence - seq2 Int64Sequence - fn func(item1, item2 *Int64Item) *Int64Item - } - tests := []struct { - name string - args args - want Int64Sequence - }{ - { - name: "regular", - args: args{ - seq1: seq[0:7], - seq2: seq[3:10], - fn: func(item1, item2 *Int64Item) *Int64Item { - if item1 != nil { - return item1 - } - return item2 - }, - }, - want: seq, - }, - { - name: "reverse", - args: args{ - seq1: seq[3:10], - seq2: seq[0:7], - fn: func(item1, item2 *Int64Item) *Int64Item { - if item1 != nil { - return item1 - } - return item2 - }, - }, - want: seq, - }, - { - name: "nil fn", - args: args{ - seq1: seq[0:7], - seq2: seq[3:10], - fn: nil, - }, - want: nil, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := MergeInt64(tt.args.seq1, tt.args.seq2, tt.args.fn); !reflect.DeepEqual(got, tt.want) { - t.Errorf("MergeInt64() = %v, want %v", got, tt.want) - } - }) - } -} - -func RandomInt64Sequence(length int) Int64Sequence { - now := time.Now() - ret := make(Int64Sequence, length) - for i := range ret { - delta := time.Duration(i) * time.Second - if rand.Float64() < 0.5 { - delta = -delta - } - ret[i] = Int64Item{ - Time: now.Add(delta), - Value: int64(rand.Float64() * float64(math.MaxInt64)), - } - } - return ret -} diff --git a/int_sequence.go b/int_sequence.go deleted file mode 100644 index dc9224d..0000000 --- a/int_sequence.go +++ /dev/null @@ -1,197 +0,0 @@ -// Code generated by cmd/generate. DO NOT EDIT. - -package timeseq - -import ( - "errors" - "sort" - "time" -) - -// IntItem is item of IntSequence -type IntItem struct { - Time time.Time - Value int -} - -// IntSequence is the implement of Sequence for int -type IntSequence []IntItem - -// Len implements Sequence.Len -func (s IntSequence) Len() int { - return len(s) -} - -// Swap implements Sequence.Swap -func (s IntSequence) Swap(i, j int) { - s[i], s[j] = s[j], s[i] -} - -// Time implements Sequence.Time -func (s IntSequence) Time(i int) time.Time { - return s[i].Time -} - -// Slice implements Sequence.Slice -func (s IntSequence) Slice(i, j int) Sequence { - return s[i:j] -} - -// Sort will sort sequence by time -func (s IntSequence) Sort() { - Sort(s) -} - -// Range return sub sequence, would sort sequence if it is not sorted -func (s IntSequence) Range(afterOrEqual, beforeOrEqual *time.Time) IntSequence { - if !sort.IsSorted(sortableSequence{s}) { - s.Sort() - } - return Range(s, afterOrEqual, beforeOrEqual).(IntSequence) -} - -// First return the first item or nil if not exists, would sort sequence if it is not sorted -func (s IntSequence) First(afterOrEqual *time.Time) *IntItem { - if !sort.IsSorted(sortableSequence{s}) { - s.Sort() - } - i := First(s, afterOrEqual) - if i < 0 { - return nil - } - ret := s[i] - return &ret -} - -// Last return the last item or nil if not exists, would sort sequence if it is not sorted -func (s IntSequence) Last(beforeOrEqual *time.Time) *IntItem { - if !sort.IsSorted(sortableSequence{s}) { - s.Sort() - } - i := Last(s, beforeOrEqual) - if i < 0 { - return nil - } - ret := s[i] - return &ret -} - -// Max return the first item which has the max value, or nil if not exists -func (s IntSequence) Max() *IntItem { - var max *IntItem - for i, v := range s { - if max == nil { - max = &s[i] - } else if v.Value > max.Value { - max = &s[i] - } - } - if max != nil { - value := *max - max = &value - } - return max -} - -// Min return the first item which has the min value, or nil if not exists -func (s IntSequence) Min() *IntItem { - var min *IntItem - for i, v := range s { - if min == nil { - min = &s[i] - } else if v.Value < min.Value { - min = &s[i] - } - } - if min != nil { - value := *min - min = &value - } - return min -} - -// Sum return the value's sum -func (s IntSequence) Sum() int { - var sum int - for _, v := range s { - sum += v.Value - } - return sum -} - -// Average return the value's average -func (s IntSequence) Average() int { - if len(s) == 0 { - return 0 - } - - return int(float64(s.Sum()) / float64(len(s))) -} - -// Percentile return (pct)th percentile -func (s IntSequence) Percentile(pct float64) int { - if pct > 1 || pct < 0 { - panic(errors.New("percentile must be [0, 1]")) - } - - var values []int - for _, v := range s { - values = append(values, v.Value) - } - sort.Slice(values, func(i, j int) bool { - return values[i] < values[j] - }) - - if len(values) == 0 { - return 0 - } - - index := int(float64(len(s))*pct - 1) - if index < 0 { - index = 0 - } - - return values[index] -} - -// MergeInt merge two int} seuquence into one -func MergeInt(seq1, seq2 IntSequence, fn func(item1, item2 *IntItem) *IntItem) IntSequence { - if fn == nil { - return nil - } - - var ret IntSequence - for i1, i2 := 0, 0; i1 < seq1.Len() || i2 < seq2.Len(); { - var item *IntItem - switch { - case i1 == seq1.Len(): - v2 := seq2[i2] - item = fn(nil, &v2) - i2++ - case i2 == seq2.Len(): - v1 := seq1[i1] - item = fn(&v1, nil) - i1++ - case seq1[i1].Time.Equal(seq2[i2].Time): - v1 := seq1[i1] - v2 := seq2[i2] - item = fn(&v1, &v2) - i1++ - i2++ - case seq1[i1].Time.Before(seq2[i2].Time): - v1 := seq1[i1] - item = fn(&v1, nil) - i1++ - case seq1[i1].Time.After(seq2[i2].Time): - v2 := seq2[i2] - item = fn(nil, &v2) - i2++ - } - if item != nil { - ret = append(ret, *item) - } - } - - Sort(ret) - return ret -} diff --git a/int_sequence_test.go b/int_sequence_test.go deleted file mode 100644 index cdbdbde..0000000 --- a/int_sequence_test.go +++ /dev/null @@ -1,716 +0,0 @@ -// Code generated by cmd/generate. DO NOT EDIT. - -package timeseq - -import ( - "math" - "math/rand" - "reflect" - "sort" - "testing" - "time" - - "github.com/gochore/pt" -) - -func TestIntSequence_Len(t *testing.T) { - tests := []struct { - name string - s IntSequence - want int - }{ - { - s: RandomIntSequence(10), - want: 10, - }, - { - s: RandomIntSequence(0), - want: 0, - }, - { - s: nil, - want: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Len(); got != tt.want { - t.Errorf("IntSequence.Len() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestIntSequence_Swap(t *testing.T) { - type args struct { - i int - j int - } - tests := []struct { - name string - s IntSequence - args args - }{ - { - s: RandomIntSequence(10), - args: args{ - i: 0, - j: 5, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - ti := tt.s.Time(tt.args.i) - tj := tt.s.Time(tt.args.j) - tt.s.Swap(tt.args.i, tt.args.j) - if ti != tt.s.Time(tt.args.j) || tj != tt.s.Time(tt.args.i) { - t.Errorf("IntSequence.Swap() failed") - } - }) - } -} - -func TestIntSequence_Time(t *testing.T) { - seq := RandomIntSequence(10) - seq.Sort() - - type args struct { - i int - } - tests := []struct { - name string - s IntSequence - args args - want time.Time - }{ - { - s: seq, - args: args{ - i: 9, - }, - want: seq[9].Time, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Time(tt.args.i); !reflect.DeepEqual(got, tt.want) { - t.Errorf("IntSequence.Time() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestIntSequence_Slice(t *testing.T) { - seq := RandomIntSequence(10) - - type args struct { - i int - j int - } - tests := []struct { - name string - s IntSequence - args args - want Sequence - }{ - { - s: seq, - args: args{ - i: 2, - j: 10, - }, - want: seq[2:10], - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Slice(tt.args.i, tt.args.j); !reflect.DeepEqual(got, tt.want) { - t.Errorf("IntSequence.Slice() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestIntSequence_Sort(t *testing.T) { - tests := []struct { - name string - s IntSequence - }{ - { - s: RandomIntSequence(10), - }, - { - s: nil, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tt.s.Sort() - if !sort.IsSorted(sortableSequence{tt.s}) { - t.Error("IntSequence.Slice() failed") - } - }) - } -} - -func TestIntSequence_Range(t *testing.T) { - now := time.Now() - seq := RandomIntSequence(10) - for i := range seq { - seq[i].Time = now.Add(time.Duration(i) * time.Second) - } - rand.Shuffle(seq.Len(), func(i, j int) { - seq[i], seq[j] = seq[j], seq[i] - }) - - type args struct { - afterOrEqual *time.Time - beforeOrEqual *time.Time - } - tests := []struct { - name string - s IntSequence - args args - want IntSequence - }{ - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1 * time.Second)), - beforeOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: seq[1 : 5+1], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now), - beforeOrEqual: pt.Time(now.Add(100 * time.Second)), - }, - want: seq, - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1*time.Second + time.Millisecond)), - beforeOrEqual: pt.Time(now.Add(5*time.Second - time.Millisecond)), - }, - want: seq[2 : 4+1], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1*time.Second - time.Millisecond)), - beforeOrEqual: pt.Time(now.Add(5*time.Second + time.Millisecond)), - }, - want: seq[1 : 5+1], - }, - { - s: seq, - args: args{ - afterOrEqual: nil, - beforeOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: seq[:5+1], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1 * time.Second)), - beforeOrEqual: nil, - }, - want: seq[1:], - }, - { - s: seq, - args: args{ - afterOrEqual: nil, - beforeOrEqual: nil, - }, - want: seq, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Range(tt.args.afterOrEqual, tt.args.beforeOrEqual); !reflect.DeepEqual(got, tt.want) { - t.Errorf("IntSequence.Range() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestIntSequence_First(t *testing.T) { - now := time.Now() - seq := RandomIntSequence(10) - for i := range seq { - seq[i].Time = now.Add(time.Duration(i) * time.Second) - } - rand.Shuffle(seq.Len(), func(i, j int) { - seq[i], seq[j] = seq[j], seq[i] - }) - - type args struct { - afterOrEqual *time.Time - } - tests := []struct { - name string - s IntSequence - args args - want *IntItem - }{ - { - s: seq, - args: args{ - afterOrEqual: nil, - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now), - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(-1 * time.Second)), - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1 * time.Second)), - }, - want: &seq[1], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: &seq[5], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(5*time.Second - time.Millisecond)), - }, - want: &seq[5], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(5*time.Second + time.Millisecond)), - }, - want: &seq[6], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(100 * time.Second)), - }, - want: nil, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.First(tt.args.afterOrEqual); !reflect.DeepEqual(got, tt.want) { - t.Errorf("IntSequence.First() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestIntSequence_Last(t *testing.T) { - now := time.Now() - seq := RandomIntSequence(10) - for i := range seq { - seq[i].Time = now.Add(time.Duration(i) * time.Second) - } - rand.Shuffle(seq.Len(), func(i, j int) { - seq[i], seq[j] = seq[j], seq[i] - }) - - type args struct { - beforeOrEqual *time.Time - } - tests := []struct { - name string - s IntSequence - args args - want *IntItem - }{ - { - s: seq, - args: args{ - beforeOrEqual: nil, - }, - want: &seq[len(seq)-1], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now), - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(-1 * time.Second)), - }, - want: nil, - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(1 * time.Second)), - }, - want: &seq[1], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: &seq[5], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(5*time.Second - time.Millisecond)), - }, - want: &seq[4], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(5*time.Second + time.Millisecond)), - }, - want: &seq[5], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(100 * time.Second)), - }, - want: &seq[9], - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Last(tt.args.beforeOrEqual); !reflect.DeepEqual(got, tt.want) { - t.Errorf("IntSequence.Last() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestIntSequence_Max(t *testing.T) { - seq1 := RandomIntSequence(10) - seq1.Sort() - for i := range seq1 { - if i == 0 { - seq1[i].Value = 1 - } else { - seq1[i].Value = 0 - } - } - seq2 := RandomIntSequence(10) - seq2.Sort() - for i := range seq2 { - if i == 0 { - seq2[i].Value = 0 - } else { - seq2[i].Value = 1 - } - } - - tests := []struct { - name string - s IntSequence - want *IntItem - }{ - { - s: seq1, - want: &seq1[0], - }, - { - s: seq2, - want: &seq2[1], - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Max(); !reflect.DeepEqual(got, tt.want) { - t.Errorf("IntSequence.Max() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestIntSequence_Min(t *testing.T) { - seq1 := RandomIntSequence(10) - seq1.Sort() - for i := range seq1 { - if i == 0 { - seq1[i].Value = 1 - } else { - seq1[i].Value = 0 - } - } - seq2 := RandomIntSequence(10) - seq2.Sort() - for i := range seq2 { - if i == 0 { - seq2[i].Value = 0 - } else { - seq2[i].Value = 1 - } - } - - tests := []struct { - name string - s IntSequence - want *IntItem - }{ - { - s: seq1, - want: &seq1[1], - }, - { - s: seq2, - want: &seq2[0], - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Min(); !reflect.DeepEqual(got, tt.want) { - t.Errorf("IntSequence.Min() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestIntSequence_Sum(t *testing.T) { - seq := RandomIntSequence(10) - for i := range seq { - seq[i].Value = int(i) - } - - tests := []struct { - name string - s IntSequence - want int - }{ - { - s: seq, - want: 45, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Sum(); got != tt.want { - t.Errorf("IntSequence.Sum() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestIntSequence_Average(t *testing.T) { - seq := RandomIntSequence(10) - for i := range seq { - seq[i].Value = int(i) * 2 - } - - tests := []struct { - name string - s IntSequence - want int - }{ - { - s: seq, - want: 9, - }, - { - s: nil, - want: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Average(); got != tt.want { - t.Errorf("IntSequence.Average() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestIntSequence_Percentile(t *testing.T) { - seq := RandomIntSequence(100) - for i := range seq { - seq[i].Value = int(i) + 1 - } - - type args struct { - pct float64 - } - tests := []struct { - name string - s IntSequence - args args - want int - }{ - { - s: seq, - args: args{ - pct: 0, - }, - want: 1, - }, - { - s: seq, - args: args{ - pct: 0.5, - }, - want: 50, - }, - { - s: seq, - args: args{ - pct: 0.95, - }, - want: 95, - }, - { - s: seq, - args: args{ - pct: 0.955, - }, - want: 95, - }, - { - s: seq, - args: args{ - pct: 1, - }, - want: 100, - }, - { - s: seq, - args: args{ - pct: 1.1, - }, - want: 100, - }, - { - s: seq, - args: args{ - pct: -0.1, - }, - want: 1, - }, - { - s: nil, - args: args{ - pct: 1, - }, - want: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - defer func() { - if r := recover(); r != nil { - if tt.args.pct > 1 || tt.args.pct < 0 { - return - } - t.Errorf("IntSequence.Percentile() failed: %v", r) - } - }() - if got := tt.s.Percentile(tt.args.pct); got != tt.want { - t.Errorf("IntSequence.Percentile() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestMergeInt(t *testing.T) { - seq := RandomIntSequence(10) - seq.Sort() - type args struct { - seq1 IntSequence - seq2 IntSequence - fn func(item1, item2 *IntItem) *IntItem - } - tests := []struct { - name string - args args - want IntSequence - }{ - { - name: "regular", - args: args{ - seq1: seq[0:7], - seq2: seq[3:10], - fn: func(item1, item2 *IntItem) *IntItem { - if item1 != nil { - return item1 - } - return item2 - }, - }, - want: seq, - }, - { - name: "reverse", - args: args{ - seq1: seq[3:10], - seq2: seq[0:7], - fn: func(item1, item2 *IntItem) *IntItem { - if item1 != nil { - return item1 - } - return item2 - }, - }, - want: seq, - }, - { - name: "nil fn", - args: args{ - seq1: seq[0:7], - seq2: seq[3:10], - fn: nil, - }, - want: nil, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := MergeInt(tt.args.seq1, tt.args.seq2, tt.args.fn); !reflect.DeepEqual(got, tt.want) { - t.Errorf("MergeInt() = %v, want %v", got, tt.want) - } - }) - } -} - -func RandomIntSequence(length int) IntSequence { - now := time.Now() - ret := make(IntSequence, length) - for i := range ret { - delta := time.Duration(i) * time.Second - if rand.Float64() < 0.5 { - delta = -delta - } - ret[i] = IntItem{ - Time: now.Add(delta), - Value: int(rand.Float64() * float64(math.MaxInt64)), - } - } - return ret -} diff --git a/sequence_test.go b/sequence_test.go deleted file mode 100644 index c12e69e..0000000 --- a/sequence_test.go +++ /dev/null @@ -1,54 +0,0 @@ -package timeseq - -import ( - "testing" -) - -func Test_sortableSequence_Less(t *testing.T) { - seq := RandomInt64Sequence(10) - - type fields struct { - Sequence Sequence - } - type args struct { - i int - j int - } - tests := []struct { - name string - fields fields - args args - want bool - }{ - { - fields: fields{ - Sequence: seq, - }, - args: args{ - i: 2, - j: 9, - }, - want: seq.Time(2).Before(seq.Time(9)), - }, - { - fields: fields{ - Sequence: seq, - }, - args: args{ - i: 8, - j: 3, - }, - want: seq.Time(8).Before(seq.Time(3)), - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := sortableSequence{ - Sequence: tt.fields.Sequence, - } - if got := s.Less(tt.args.i, tt.args.j); got != tt.want { - t.Errorf("sortableSequence.Less() = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/timeseq.go b/timeseq.go index 65ee5ad..2b096e8 100644 --- a/timeseq.go +++ b/timeseq.go @@ -13,24 +13,32 @@ func Sort(seq Sequence) { sort.Sort(sortableSequence{seq}) } -// Range return sub sequence -func Range(seq Sequence, afterOrEqual, beforeOrEqual *time.Time) Sequence { - i := 0 - if afterOrEqual != nil { - i = sort.Search(seq.Len(), func(i int) bool { - return !seq.Time(i).Before(*afterOrEqual) - }) +func TrimBefore(seq Sequence, before time.Time) Sequence { + i := sort.Search(seq.Len(), func(i int) bool { + return !seq.Time(i).Before(before) + }) + return seq.Slice(i, seq.Len()) +} + +func TrimAfter(seq Sequence, after time.Time) Sequence { + j := sort.Search(seq.Len(), func(j int) bool { + return !seq.Time(j).Before(after) + }) + if j < seq.Len() && seq.Time(j).Equal(after) { + j++ } - j := seq.Len() - if beforeOrEqual != nil { - j = sort.Search(seq.Len(), func(j int) bool { - return !seq.Time(j).Before(*beforeOrEqual) - }) - if j < seq.Len() && seq.Time(j).Equal(*beforeOrEqual) { - j++ - } + return seq.Slice(0, j) +} + +// Get return the index of the first item with specified time +func Get(seq Sequence, t time.Time) int { + i := sort.Search(seq.Len(), func(i int) bool { + return !seq.Time(i).Before(t) + }) + if i >= seq.Len() { + i = -1 } - return seq.Slice(i, j) + return i } // First return the index of the first item diff --git a/timeseq_test.go b/timeseq_test.go deleted file mode 100644 index 3790935..0000000 --- a/timeseq_test.go +++ /dev/null @@ -1,293 +0,0 @@ -package timeseq - -import ( - "reflect" - "sort" - "testing" - "time" - - "github.com/gochore/pt" -) - -func TestSort(t *testing.T) { - seq := RandomInt64Sequence(10) - - type args struct { - seq Sequence - } - tests := []struct { - name string - args args - }{ - { - args: args{ - seq: seq, - }, - }, - { - args: args{ - seq: nil, - }, - }, - { - args: args{ - seq: seq, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - Sort(tt.args.seq) - if !sort.IsSorted(sortableSequence{seq}) { - t.Errorf("Sort() failed") - } - }) - } -} - -func TestRange(t *testing.T) { - now := time.Now() - seq := RandomInt64Sequence(10) - for i := range seq { - seq[i].Time = now.Add(time.Duration(i) * time.Second) - } - - type args struct { - seq Sequence - afterOrEqual *time.Time - beforeOrEqual *time.Time - } - tests := []struct { - name string - args args - want Sequence - }{ - { - args: args{ - seq: seq, - afterOrEqual: pt.Time(now.Add(1 * time.Second)), - beforeOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: seq[1 : 5+1], - }, - { - args: args{ - seq: seq, - afterOrEqual: pt.Time(now), - beforeOrEqual: pt.Time(now.Add(100 * time.Second)), - }, - want: seq, - }, - { - args: args{ - seq: seq, - afterOrEqual: pt.Time(now.Add(1*time.Second + time.Millisecond)), - beforeOrEqual: pt.Time(now.Add(5*time.Second - time.Millisecond)), - }, - want: seq[2 : 4+1], - }, - { - args: args{ - seq: seq, - afterOrEqual: pt.Time(now.Add(1*time.Second - time.Millisecond)), - beforeOrEqual: pt.Time(now.Add(5*time.Second + time.Millisecond)), - }, - want: seq[1 : 5+1], - }, - { - args: args{ - seq: seq, - afterOrEqual: nil, - beforeOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: seq[:5+1], - }, - { - args: args{ - seq: seq, - afterOrEqual: pt.Time(now.Add(1 * time.Second)), - beforeOrEqual: nil, - }, - want: seq[1:], - }, - { - args: args{ - seq: seq, - afterOrEqual: nil, - beforeOrEqual: nil, - }, - want: seq, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := Range(tt.args.seq, tt.args.afterOrEqual, tt.args.beforeOrEqual); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Range() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestFirst(t *testing.T) { - now := time.Now() - seq := RandomInt64Sequence(10) - for i := range seq { - seq[i].Time = now.Add(time.Duration(i) * time.Second) - } - - type args struct { - seq Sequence - afterOrEqual *time.Time - } - tests := []struct { - name string - args args - want int - }{ - { - args: args{ - seq: seq, - afterOrEqual: nil, - }, - want: 0, - }, - { - args: args{ - seq: seq, - afterOrEqual: pt.Time(now), - }, - want: 0, - }, - { - args: args{ - seq: seq, - afterOrEqual: pt.Time(now.Add(-1 * time.Second)), - }, - want: 0, - }, - { - args: args{ - seq: seq, - afterOrEqual: pt.Time(now.Add(1 * time.Second)), - }, - want: 1, - }, - { - args: args{ - seq: seq, - afterOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: 5, - }, - { - args: args{ - seq: seq, - afterOrEqual: pt.Time(now.Add(5*time.Second - time.Millisecond)), - }, - want: 5, - }, - { - args: args{ - seq: seq, - afterOrEqual: pt.Time(now.Add(5*time.Second + time.Millisecond)), - }, - want: 6, - }, - { - args: args{ - seq: seq, - afterOrEqual: pt.Time(now.Add(100 * time.Second)), - }, - want: -1, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := First(tt.args.seq, tt.args.afterOrEqual); got != tt.want { - t.Errorf("First() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestLast(t *testing.T) { - now := time.Now() - seq := RandomInt64Sequence(10) - for i := range seq { - seq[i].Time = now.Add(time.Duration(i) * time.Second) - } - - type args struct { - seq Sequence - beforeOrEqual *time.Time - } - tests := []struct { - name string - args args - want int - }{ - { - args: args{ - seq: seq, - beforeOrEqual: nil, - }, - want: len(seq) - 1, - }, - { - args: args{ - seq: seq, - beforeOrEqual: pt.Time(now), - }, - want: 0, - }, - { - args: args{ - seq: seq, - beforeOrEqual: pt.Time(now.Add(-1 * time.Second)), - }, - want: -1, - }, - { - args: args{ - seq: seq, - beforeOrEqual: pt.Time(now.Add(1 * time.Second)), - }, - want: 1, - }, - { - args: args{ - seq: seq, - beforeOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: 5, - }, - { - args: args{ - seq: seq, - beforeOrEqual: pt.Time(now.Add(5*time.Second - time.Millisecond)), - }, - want: 4, - }, - { - args: args{ - seq: seq, - beforeOrEqual: pt.Time(now.Add(5*time.Second + time.Millisecond)), - }, - want: 5, - }, - { - args: args{ - seq: seq, - beforeOrEqual: pt.Time(now.Add(100 * time.Second)), - }, - want: 9, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := Last(tt.args.seq, tt.args.beforeOrEqual); got != tt.want { - t.Errorf("Last() = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/uint32_sequence.go b/uint32_sequence.go deleted file mode 100644 index 555dd01..0000000 --- a/uint32_sequence.go +++ /dev/null @@ -1,197 +0,0 @@ -// Code generated by cmd/generate. DO NOT EDIT. - -package timeseq - -import ( - "errors" - "sort" - "time" -) - -// Uint32Item is item of Uint32Sequence -type Uint32Item struct { - Time time.Time - Value uint32 -} - -// Uint32Sequence is the implement of Sequence for uint32 -type Uint32Sequence []Uint32Item - -// Len implements Sequence.Len -func (s Uint32Sequence) Len() int { - return len(s) -} - -// Swap implements Sequence.Swap -func (s Uint32Sequence) Swap(i, j int) { - s[i], s[j] = s[j], s[i] -} - -// Time implements Sequence.Time -func (s Uint32Sequence) Time(i int) time.Time { - return s[i].Time -} - -// Slice implements Sequence.Slice -func (s Uint32Sequence) Slice(i, j int) Sequence { - return s[i:j] -} - -// Sort will sort sequence by time -func (s Uint32Sequence) Sort() { - Sort(s) -} - -// Range return sub sequence, would sort sequence if it is not sorted -func (s Uint32Sequence) Range(afterOrEqual, beforeOrEqual *time.Time) Uint32Sequence { - if !sort.IsSorted(sortableSequence{s}) { - s.Sort() - } - return Range(s, afterOrEqual, beforeOrEqual).(Uint32Sequence) -} - -// First return the first item or nil if not exists, would sort sequence if it is not sorted -func (s Uint32Sequence) First(afterOrEqual *time.Time) *Uint32Item { - if !sort.IsSorted(sortableSequence{s}) { - s.Sort() - } - i := First(s, afterOrEqual) - if i < 0 { - return nil - } - ret := s[i] - return &ret -} - -// Last return the last item or nil if not exists, would sort sequence if it is not sorted -func (s Uint32Sequence) Last(beforeOrEqual *time.Time) *Uint32Item { - if !sort.IsSorted(sortableSequence{s}) { - s.Sort() - } - i := Last(s, beforeOrEqual) - if i < 0 { - return nil - } - ret := s[i] - return &ret -} - -// Max return the first item which has the max value, or nil if not exists -func (s Uint32Sequence) Max() *Uint32Item { - var max *Uint32Item - for i, v := range s { - if max == nil { - max = &s[i] - } else if v.Value > max.Value { - max = &s[i] - } - } - if max != nil { - value := *max - max = &value - } - return max -} - -// Min return the first item which has the min value, or nil if not exists -func (s Uint32Sequence) Min() *Uint32Item { - var min *Uint32Item - for i, v := range s { - if min == nil { - min = &s[i] - } else if v.Value < min.Value { - min = &s[i] - } - } - if min != nil { - value := *min - min = &value - } - return min -} - -// Sum return the value's sum -func (s Uint32Sequence) Sum() uint32 { - var sum uint32 - for _, v := range s { - sum += v.Value - } - return sum -} - -// Average return the value's average -func (s Uint32Sequence) Average() uint32 { - if len(s) == 0 { - return 0 - } - - return uint32(float64(s.Sum()) / float64(len(s))) -} - -// Percentile return (pct)th percentile -func (s Uint32Sequence) Percentile(pct float64) uint32 { - if pct > 1 || pct < 0 { - panic(errors.New("percentile must be [0, 1]")) - } - - var values []uint32 - for _, v := range s { - values = append(values, v.Value) - } - sort.Slice(values, func(i, j int) bool { - return values[i] < values[j] - }) - - if len(values) == 0 { - return 0 - } - - index := int(float64(len(s))*pct - 1) - if index < 0 { - index = 0 - } - - return values[index] -} - -// MergeUint32 merge two uint32} seuquence into one -func MergeUint32(seq1, seq2 Uint32Sequence, fn func(item1, item2 *Uint32Item) *Uint32Item) Uint32Sequence { - if fn == nil { - return nil - } - - var ret Uint32Sequence - for i1, i2 := 0, 0; i1 < seq1.Len() || i2 < seq2.Len(); { - var item *Uint32Item - switch { - case i1 == seq1.Len(): - v2 := seq2[i2] - item = fn(nil, &v2) - i2++ - case i2 == seq2.Len(): - v1 := seq1[i1] - item = fn(&v1, nil) - i1++ - case seq1[i1].Time.Equal(seq2[i2].Time): - v1 := seq1[i1] - v2 := seq2[i2] - item = fn(&v1, &v2) - i1++ - i2++ - case seq1[i1].Time.Before(seq2[i2].Time): - v1 := seq1[i1] - item = fn(&v1, nil) - i1++ - case seq1[i1].Time.After(seq2[i2].Time): - v2 := seq2[i2] - item = fn(nil, &v2) - i2++ - } - if item != nil { - ret = append(ret, *item) - } - } - - Sort(ret) - return ret -} diff --git a/uint32_sequence_test.go b/uint32_sequence_test.go deleted file mode 100644 index 463ab12..0000000 --- a/uint32_sequence_test.go +++ /dev/null @@ -1,716 +0,0 @@ -// Code generated by cmd/generate. DO NOT EDIT. - -package timeseq - -import ( - "math" - "math/rand" - "reflect" - "sort" - "testing" - "time" - - "github.com/gochore/pt" -) - -func TestUint32Sequence_Len(t *testing.T) { - tests := []struct { - name string - s Uint32Sequence - want int - }{ - { - s: RandomUint32Sequence(10), - want: 10, - }, - { - s: RandomUint32Sequence(0), - want: 0, - }, - { - s: nil, - want: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Len(); got != tt.want { - t.Errorf("Uint32Sequence.Len() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestUint32Sequence_Swap(t *testing.T) { - type args struct { - i int - j int - } - tests := []struct { - name string - s Uint32Sequence - args args - }{ - { - s: RandomUint32Sequence(10), - args: args{ - i: 0, - j: 5, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - ti := tt.s.Time(tt.args.i) - tj := tt.s.Time(tt.args.j) - tt.s.Swap(tt.args.i, tt.args.j) - if ti != tt.s.Time(tt.args.j) || tj != tt.s.Time(tt.args.i) { - t.Errorf("Uint32Sequence.Swap() failed") - } - }) - } -} - -func TestUint32Sequence_Time(t *testing.T) { - seq := RandomUint32Sequence(10) - seq.Sort() - - type args struct { - i int - } - tests := []struct { - name string - s Uint32Sequence - args args - want time.Time - }{ - { - s: seq, - args: args{ - i: 9, - }, - want: seq[9].Time, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Time(tt.args.i); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Uint32Sequence.Time() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestUint32Sequence_Slice(t *testing.T) { - seq := RandomUint32Sequence(10) - - type args struct { - i int - j int - } - tests := []struct { - name string - s Uint32Sequence - args args - want Sequence - }{ - { - s: seq, - args: args{ - i: 2, - j: 10, - }, - want: seq[2:10], - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Slice(tt.args.i, tt.args.j); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Uint32Sequence.Slice() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestUint32Sequence_Sort(t *testing.T) { - tests := []struct { - name string - s Uint32Sequence - }{ - { - s: RandomUint32Sequence(10), - }, - { - s: nil, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tt.s.Sort() - if !sort.IsSorted(sortableSequence{tt.s}) { - t.Error("Uint32Sequence.Slice() failed") - } - }) - } -} - -func TestUint32Sequence_Range(t *testing.T) { - now := time.Now() - seq := RandomUint32Sequence(10) - for i := range seq { - seq[i].Time = now.Add(time.Duration(i) * time.Second) - } - rand.Shuffle(seq.Len(), func(i, j int) { - seq[i], seq[j] = seq[j], seq[i] - }) - - type args struct { - afterOrEqual *time.Time - beforeOrEqual *time.Time - } - tests := []struct { - name string - s Uint32Sequence - args args - want Uint32Sequence - }{ - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1 * time.Second)), - beforeOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: seq[1 : 5+1], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now), - beforeOrEqual: pt.Time(now.Add(100 * time.Second)), - }, - want: seq, - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1*time.Second + time.Millisecond)), - beforeOrEqual: pt.Time(now.Add(5*time.Second - time.Millisecond)), - }, - want: seq[2 : 4+1], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1*time.Second - time.Millisecond)), - beforeOrEqual: pt.Time(now.Add(5*time.Second + time.Millisecond)), - }, - want: seq[1 : 5+1], - }, - { - s: seq, - args: args{ - afterOrEqual: nil, - beforeOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: seq[:5+1], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1 * time.Second)), - beforeOrEqual: nil, - }, - want: seq[1:], - }, - { - s: seq, - args: args{ - afterOrEqual: nil, - beforeOrEqual: nil, - }, - want: seq, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Range(tt.args.afterOrEqual, tt.args.beforeOrEqual); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Uint32Sequence.Range() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestUint32Sequence_First(t *testing.T) { - now := time.Now() - seq := RandomUint32Sequence(10) - for i := range seq { - seq[i].Time = now.Add(time.Duration(i) * time.Second) - } - rand.Shuffle(seq.Len(), func(i, j int) { - seq[i], seq[j] = seq[j], seq[i] - }) - - type args struct { - afterOrEqual *time.Time - } - tests := []struct { - name string - s Uint32Sequence - args args - want *Uint32Item - }{ - { - s: seq, - args: args{ - afterOrEqual: nil, - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now), - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(-1 * time.Second)), - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1 * time.Second)), - }, - want: &seq[1], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: &seq[5], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(5*time.Second - time.Millisecond)), - }, - want: &seq[5], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(5*time.Second + time.Millisecond)), - }, - want: &seq[6], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(100 * time.Second)), - }, - want: nil, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.First(tt.args.afterOrEqual); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Uint32Sequence.First() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestUint32Sequence_Last(t *testing.T) { - now := time.Now() - seq := RandomUint32Sequence(10) - for i := range seq { - seq[i].Time = now.Add(time.Duration(i) * time.Second) - } - rand.Shuffle(seq.Len(), func(i, j int) { - seq[i], seq[j] = seq[j], seq[i] - }) - - type args struct { - beforeOrEqual *time.Time - } - tests := []struct { - name string - s Uint32Sequence - args args - want *Uint32Item - }{ - { - s: seq, - args: args{ - beforeOrEqual: nil, - }, - want: &seq[len(seq)-1], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now), - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(-1 * time.Second)), - }, - want: nil, - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(1 * time.Second)), - }, - want: &seq[1], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: &seq[5], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(5*time.Second - time.Millisecond)), - }, - want: &seq[4], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(5*time.Second + time.Millisecond)), - }, - want: &seq[5], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(100 * time.Second)), - }, - want: &seq[9], - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Last(tt.args.beforeOrEqual); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Uint32Sequence.Last() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestUint32Sequence_Max(t *testing.T) { - seq1 := RandomUint32Sequence(10) - seq1.Sort() - for i := range seq1 { - if i == 0 { - seq1[i].Value = 1 - } else { - seq1[i].Value = 0 - } - } - seq2 := RandomUint32Sequence(10) - seq2.Sort() - for i := range seq2 { - if i == 0 { - seq2[i].Value = 0 - } else { - seq2[i].Value = 1 - } - } - - tests := []struct { - name string - s Uint32Sequence - want *Uint32Item - }{ - { - s: seq1, - want: &seq1[0], - }, - { - s: seq2, - want: &seq2[1], - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Max(); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Uint32Sequence.Max() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestUint32Sequence_Min(t *testing.T) { - seq1 := RandomUint32Sequence(10) - seq1.Sort() - for i := range seq1 { - if i == 0 { - seq1[i].Value = 1 - } else { - seq1[i].Value = 0 - } - } - seq2 := RandomUint32Sequence(10) - seq2.Sort() - for i := range seq2 { - if i == 0 { - seq2[i].Value = 0 - } else { - seq2[i].Value = 1 - } - } - - tests := []struct { - name string - s Uint32Sequence - want *Uint32Item - }{ - { - s: seq1, - want: &seq1[1], - }, - { - s: seq2, - want: &seq2[0], - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Min(); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Uint32Sequence.Min() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestUint32Sequence_Sum(t *testing.T) { - seq := RandomUint32Sequence(10) - for i := range seq { - seq[i].Value = uint32(i) - } - - tests := []struct { - name string - s Uint32Sequence - want uint32 - }{ - { - s: seq, - want: 45, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Sum(); got != tt.want { - t.Errorf("Uint32Sequence.Sum() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestUint32Sequence_Average(t *testing.T) { - seq := RandomUint32Sequence(10) - for i := range seq { - seq[i].Value = uint32(i) * 2 - } - - tests := []struct { - name string - s Uint32Sequence - want uint32 - }{ - { - s: seq, - want: 9, - }, - { - s: nil, - want: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Average(); got != tt.want { - t.Errorf("Uint32Sequence.Average() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestUint32Sequence_Percentile(t *testing.T) { - seq := RandomUint32Sequence(100) - for i := range seq { - seq[i].Value = uint32(i) + 1 - } - - type args struct { - pct float64 - } - tests := []struct { - name string - s Uint32Sequence - args args - want uint32 - }{ - { - s: seq, - args: args{ - pct: 0, - }, - want: 1, - }, - { - s: seq, - args: args{ - pct: 0.5, - }, - want: 50, - }, - { - s: seq, - args: args{ - pct: 0.95, - }, - want: 95, - }, - { - s: seq, - args: args{ - pct: 0.955, - }, - want: 95, - }, - { - s: seq, - args: args{ - pct: 1, - }, - want: 100, - }, - { - s: seq, - args: args{ - pct: 1.1, - }, - want: 100, - }, - { - s: seq, - args: args{ - pct: -0.1, - }, - want: 1, - }, - { - s: nil, - args: args{ - pct: 1, - }, - want: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - defer func() { - if r := recover(); r != nil { - if tt.args.pct > 1 || tt.args.pct < 0 { - return - } - t.Errorf("Uint32Sequence.Percentile() failed: %v", r) - } - }() - if got := tt.s.Percentile(tt.args.pct); got != tt.want { - t.Errorf("Uint32Sequence.Percentile() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestMergeUint32(t *testing.T) { - seq := RandomUint32Sequence(10) - seq.Sort() - type args struct { - seq1 Uint32Sequence - seq2 Uint32Sequence - fn func(item1, item2 *Uint32Item) *Uint32Item - } - tests := []struct { - name string - args args - want Uint32Sequence - }{ - { - name: "regular", - args: args{ - seq1: seq[0:7], - seq2: seq[3:10], - fn: func(item1, item2 *Uint32Item) *Uint32Item { - if item1 != nil { - return item1 - } - return item2 - }, - }, - want: seq, - }, - { - name: "reverse", - args: args{ - seq1: seq[3:10], - seq2: seq[0:7], - fn: func(item1, item2 *Uint32Item) *Uint32Item { - if item1 != nil { - return item1 - } - return item2 - }, - }, - want: seq, - }, - { - name: "nil fn", - args: args{ - seq1: seq[0:7], - seq2: seq[3:10], - fn: nil, - }, - want: nil, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := MergeUint32(tt.args.seq1, tt.args.seq2, tt.args.fn); !reflect.DeepEqual(got, tt.want) { - t.Errorf("MergeUint32() = %v, want %v", got, tt.want) - } - }) - } -} - -func RandomUint32Sequence(length int) Uint32Sequence { - now := time.Now() - ret := make(Uint32Sequence, length) - for i := range ret { - delta := time.Duration(i) * time.Second - if rand.Float64() < 0.5 { - delta = -delta - } - ret[i] = Uint32Item{ - Time: now.Add(delta), - Value: uint32(rand.Float64() * float64(math.MaxInt64)), - } - } - return ret -} diff --git a/uint64_sequence.go b/uint64_sequence.go deleted file mode 100644 index bf79815..0000000 --- a/uint64_sequence.go +++ /dev/null @@ -1,197 +0,0 @@ -// Code generated by cmd/generate. DO NOT EDIT. - -package timeseq - -import ( - "errors" - "sort" - "time" -) - -// Uint64Item is item of Uint64Sequence -type Uint64Item struct { - Time time.Time - Value uint64 -} - -// Uint64Sequence is the implement of Sequence for uint64 -type Uint64Sequence []Uint64Item - -// Len implements Sequence.Len -func (s Uint64Sequence) Len() int { - return len(s) -} - -// Swap implements Sequence.Swap -func (s Uint64Sequence) Swap(i, j int) { - s[i], s[j] = s[j], s[i] -} - -// Time implements Sequence.Time -func (s Uint64Sequence) Time(i int) time.Time { - return s[i].Time -} - -// Slice implements Sequence.Slice -func (s Uint64Sequence) Slice(i, j int) Sequence { - return s[i:j] -} - -// Sort will sort sequence by time -func (s Uint64Sequence) Sort() { - Sort(s) -} - -// Range return sub sequence, would sort sequence if it is not sorted -func (s Uint64Sequence) Range(afterOrEqual, beforeOrEqual *time.Time) Uint64Sequence { - if !sort.IsSorted(sortableSequence{s}) { - s.Sort() - } - return Range(s, afterOrEqual, beforeOrEqual).(Uint64Sequence) -} - -// First return the first item or nil if not exists, would sort sequence if it is not sorted -func (s Uint64Sequence) First(afterOrEqual *time.Time) *Uint64Item { - if !sort.IsSorted(sortableSequence{s}) { - s.Sort() - } - i := First(s, afterOrEqual) - if i < 0 { - return nil - } - ret := s[i] - return &ret -} - -// Last return the last item or nil if not exists, would sort sequence if it is not sorted -func (s Uint64Sequence) Last(beforeOrEqual *time.Time) *Uint64Item { - if !sort.IsSorted(sortableSequence{s}) { - s.Sort() - } - i := Last(s, beforeOrEqual) - if i < 0 { - return nil - } - ret := s[i] - return &ret -} - -// Max return the first item which has the max value, or nil if not exists -func (s Uint64Sequence) Max() *Uint64Item { - var max *Uint64Item - for i, v := range s { - if max == nil { - max = &s[i] - } else if v.Value > max.Value { - max = &s[i] - } - } - if max != nil { - value := *max - max = &value - } - return max -} - -// Min return the first item which has the min value, or nil if not exists -func (s Uint64Sequence) Min() *Uint64Item { - var min *Uint64Item - for i, v := range s { - if min == nil { - min = &s[i] - } else if v.Value < min.Value { - min = &s[i] - } - } - if min != nil { - value := *min - min = &value - } - return min -} - -// Sum return the value's sum -func (s Uint64Sequence) Sum() uint64 { - var sum uint64 - for _, v := range s { - sum += v.Value - } - return sum -} - -// Average return the value's average -func (s Uint64Sequence) Average() uint64 { - if len(s) == 0 { - return 0 - } - - return uint64(float64(s.Sum()) / float64(len(s))) -} - -// Percentile return (pct)th percentile -func (s Uint64Sequence) Percentile(pct float64) uint64 { - if pct > 1 || pct < 0 { - panic(errors.New("percentile must be [0, 1]")) - } - - var values []uint64 - for _, v := range s { - values = append(values, v.Value) - } - sort.Slice(values, func(i, j int) bool { - return values[i] < values[j] - }) - - if len(values) == 0 { - return 0 - } - - index := int(float64(len(s))*pct - 1) - if index < 0 { - index = 0 - } - - return values[index] -} - -// MergeUint64 merge two uint64} seuquence into one -func MergeUint64(seq1, seq2 Uint64Sequence, fn func(item1, item2 *Uint64Item) *Uint64Item) Uint64Sequence { - if fn == nil { - return nil - } - - var ret Uint64Sequence - for i1, i2 := 0, 0; i1 < seq1.Len() || i2 < seq2.Len(); { - var item *Uint64Item - switch { - case i1 == seq1.Len(): - v2 := seq2[i2] - item = fn(nil, &v2) - i2++ - case i2 == seq2.Len(): - v1 := seq1[i1] - item = fn(&v1, nil) - i1++ - case seq1[i1].Time.Equal(seq2[i2].Time): - v1 := seq1[i1] - v2 := seq2[i2] - item = fn(&v1, &v2) - i1++ - i2++ - case seq1[i1].Time.Before(seq2[i2].Time): - v1 := seq1[i1] - item = fn(&v1, nil) - i1++ - case seq1[i1].Time.After(seq2[i2].Time): - v2 := seq2[i2] - item = fn(nil, &v2) - i2++ - } - if item != nil { - ret = append(ret, *item) - } - } - - Sort(ret) - return ret -} diff --git a/uint64_sequence_test.go b/uint64_sequence_test.go deleted file mode 100644 index 0d0972d..0000000 --- a/uint64_sequence_test.go +++ /dev/null @@ -1,716 +0,0 @@ -// Code generated by cmd/generate. DO NOT EDIT. - -package timeseq - -import ( - "math" - "math/rand" - "reflect" - "sort" - "testing" - "time" - - "github.com/gochore/pt" -) - -func TestUint64Sequence_Len(t *testing.T) { - tests := []struct { - name string - s Uint64Sequence - want int - }{ - { - s: RandomUint64Sequence(10), - want: 10, - }, - { - s: RandomUint64Sequence(0), - want: 0, - }, - { - s: nil, - want: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Len(); got != tt.want { - t.Errorf("Uint64Sequence.Len() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestUint64Sequence_Swap(t *testing.T) { - type args struct { - i int - j int - } - tests := []struct { - name string - s Uint64Sequence - args args - }{ - { - s: RandomUint64Sequence(10), - args: args{ - i: 0, - j: 5, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - ti := tt.s.Time(tt.args.i) - tj := tt.s.Time(tt.args.j) - tt.s.Swap(tt.args.i, tt.args.j) - if ti != tt.s.Time(tt.args.j) || tj != tt.s.Time(tt.args.i) { - t.Errorf("Uint64Sequence.Swap() failed") - } - }) - } -} - -func TestUint64Sequence_Time(t *testing.T) { - seq := RandomUint64Sequence(10) - seq.Sort() - - type args struct { - i int - } - tests := []struct { - name string - s Uint64Sequence - args args - want time.Time - }{ - { - s: seq, - args: args{ - i: 9, - }, - want: seq[9].Time, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Time(tt.args.i); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Uint64Sequence.Time() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestUint64Sequence_Slice(t *testing.T) { - seq := RandomUint64Sequence(10) - - type args struct { - i int - j int - } - tests := []struct { - name string - s Uint64Sequence - args args - want Sequence - }{ - { - s: seq, - args: args{ - i: 2, - j: 10, - }, - want: seq[2:10], - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Slice(tt.args.i, tt.args.j); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Uint64Sequence.Slice() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestUint64Sequence_Sort(t *testing.T) { - tests := []struct { - name string - s Uint64Sequence - }{ - { - s: RandomUint64Sequence(10), - }, - { - s: nil, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tt.s.Sort() - if !sort.IsSorted(sortableSequence{tt.s}) { - t.Error("Uint64Sequence.Slice() failed") - } - }) - } -} - -func TestUint64Sequence_Range(t *testing.T) { - now := time.Now() - seq := RandomUint64Sequence(10) - for i := range seq { - seq[i].Time = now.Add(time.Duration(i) * time.Second) - } - rand.Shuffle(seq.Len(), func(i, j int) { - seq[i], seq[j] = seq[j], seq[i] - }) - - type args struct { - afterOrEqual *time.Time - beforeOrEqual *time.Time - } - tests := []struct { - name string - s Uint64Sequence - args args - want Uint64Sequence - }{ - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1 * time.Second)), - beforeOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: seq[1 : 5+1], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now), - beforeOrEqual: pt.Time(now.Add(100 * time.Second)), - }, - want: seq, - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1*time.Second + time.Millisecond)), - beforeOrEqual: pt.Time(now.Add(5*time.Second - time.Millisecond)), - }, - want: seq[2 : 4+1], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1*time.Second - time.Millisecond)), - beforeOrEqual: pt.Time(now.Add(5*time.Second + time.Millisecond)), - }, - want: seq[1 : 5+1], - }, - { - s: seq, - args: args{ - afterOrEqual: nil, - beforeOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: seq[:5+1], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1 * time.Second)), - beforeOrEqual: nil, - }, - want: seq[1:], - }, - { - s: seq, - args: args{ - afterOrEqual: nil, - beforeOrEqual: nil, - }, - want: seq, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Range(tt.args.afterOrEqual, tt.args.beforeOrEqual); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Uint64Sequence.Range() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestUint64Sequence_First(t *testing.T) { - now := time.Now() - seq := RandomUint64Sequence(10) - for i := range seq { - seq[i].Time = now.Add(time.Duration(i) * time.Second) - } - rand.Shuffle(seq.Len(), func(i, j int) { - seq[i], seq[j] = seq[j], seq[i] - }) - - type args struct { - afterOrEqual *time.Time - } - tests := []struct { - name string - s Uint64Sequence - args args - want *Uint64Item - }{ - { - s: seq, - args: args{ - afterOrEqual: nil, - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now), - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(-1 * time.Second)), - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1 * time.Second)), - }, - want: &seq[1], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: &seq[5], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(5*time.Second - time.Millisecond)), - }, - want: &seq[5], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(5*time.Second + time.Millisecond)), - }, - want: &seq[6], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(100 * time.Second)), - }, - want: nil, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.First(tt.args.afterOrEqual); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Uint64Sequence.First() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestUint64Sequence_Last(t *testing.T) { - now := time.Now() - seq := RandomUint64Sequence(10) - for i := range seq { - seq[i].Time = now.Add(time.Duration(i) * time.Second) - } - rand.Shuffle(seq.Len(), func(i, j int) { - seq[i], seq[j] = seq[j], seq[i] - }) - - type args struct { - beforeOrEqual *time.Time - } - tests := []struct { - name string - s Uint64Sequence - args args - want *Uint64Item - }{ - { - s: seq, - args: args{ - beforeOrEqual: nil, - }, - want: &seq[len(seq)-1], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now), - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(-1 * time.Second)), - }, - want: nil, - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(1 * time.Second)), - }, - want: &seq[1], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: &seq[5], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(5*time.Second - time.Millisecond)), - }, - want: &seq[4], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(5*time.Second + time.Millisecond)), - }, - want: &seq[5], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(100 * time.Second)), - }, - want: &seq[9], - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Last(tt.args.beforeOrEqual); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Uint64Sequence.Last() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestUint64Sequence_Max(t *testing.T) { - seq1 := RandomUint64Sequence(10) - seq1.Sort() - for i := range seq1 { - if i == 0 { - seq1[i].Value = 1 - } else { - seq1[i].Value = 0 - } - } - seq2 := RandomUint64Sequence(10) - seq2.Sort() - for i := range seq2 { - if i == 0 { - seq2[i].Value = 0 - } else { - seq2[i].Value = 1 - } - } - - tests := []struct { - name string - s Uint64Sequence - want *Uint64Item - }{ - { - s: seq1, - want: &seq1[0], - }, - { - s: seq2, - want: &seq2[1], - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Max(); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Uint64Sequence.Max() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestUint64Sequence_Min(t *testing.T) { - seq1 := RandomUint64Sequence(10) - seq1.Sort() - for i := range seq1 { - if i == 0 { - seq1[i].Value = 1 - } else { - seq1[i].Value = 0 - } - } - seq2 := RandomUint64Sequence(10) - seq2.Sort() - for i := range seq2 { - if i == 0 { - seq2[i].Value = 0 - } else { - seq2[i].Value = 1 - } - } - - tests := []struct { - name string - s Uint64Sequence - want *Uint64Item - }{ - { - s: seq1, - want: &seq1[1], - }, - { - s: seq2, - want: &seq2[0], - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Min(); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Uint64Sequence.Min() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestUint64Sequence_Sum(t *testing.T) { - seq := RandomUint64Sequence(10) - for i := range seq { - seq[i].Value = uint64(i) - } - - tests := []struct { - name string - s Uint64Sequence - want uint64 - }{ - { - s: seq, - want: 45, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Sum(); got != tt.want { - t.Errorf("Uint64Sequence.Sum() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestUint64Sequence_Average(t *testing.T) { - seq := RandomUint64Sequence(10) - for i := range seq { - seq[i].Value = uint64(i) * 2 - } - - tests := []struct { - name string - s Uint64Sequence - want uint64 - }{ - { - s: seq, - want: 9, - }, - { - s: nil, - want: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Average(); got != tt.want { - t.Errorf("Uint64Sequence.Average() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestUint64Sequence_Percentile(t *testing.T) { - seq := RandomUint64Sequence(100) - for i := range seq { - seq[i].Value = uint64(i) + 1 - } - - type args struct { - pct float64 - } - tests := []struct { - name string - s Uint64Sequence - args args - want uint64 - }{ - { - s: seq, - args: args{ - pct: 0, - }, - want: 1, - }, - { - s: seq, - args: args{ - pct: 0.5, - }, - want: 50, - }, - { - s: seq, - args: args{ - pct: 0.95, - }, - want: 95, - }, - { - s: seq, - args: args{ - pct: 0.955, - }, - want: 95, - }, - { - s: seq, - args: args{ - pct: 1, - }, - want: 100, - }, - { - s: seq, - args: args{ - pct: 1.1, - }, - want: 100, - }, - { - s: seq, - args: args{ - pct: -0.1, - }, - want: 1, - }, - { - s: nil, - args: args{ - pct: 1, - }, - want: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - defer func() { - if r := recover(); r != nil { - if tt.args.pct > 1 || tt.args.pct < 0 { - return - } - t.Errorf("Uint64Sequence.Percentile() failed: %v", r) - } - }() - if got := tt.s.Percentile(tt.args.pct); got != tt.want { - t.Errorf("Uint64Sequence.Percentile() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestMergeUint64(t *testing.T) { - seq := RandomUint64Sequence(10) - seq.Sort() - type args struct { - seq1 Uint64Sequence - seq2 Uint64Sequence - fn func(item1, item2 *Uint64Item) *Uint64Item - } - tests := []struct { - name string - args args - want Uint64Sequence - }{ - { - name: "regular", - args: args{ - seq1: seq[0:7], - seq2: seq[3:10], - fn: func(item1, item2 *Uint64Item) *Uint64Item { - if item1 != nil { - return item1 - } - return item2 - }, - }, - want: seq, - }, - { - name: "reverse", - args: args{ - seq1: seq[3:10], - seq2: seq[0:7], - fn: func(item1, item2 *Uint64Item) *Uint64Item { - if item1 != nil { - return item1 - } - return item2 - }, - }, - want: seq, - }, - { - name: "nil fn", - args: args{ - seq1: seq[0:7], - seq2: seq[3:10], - fn: nil, - }, - want: nil, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := MergeUint64(tt.args.seq1, tt.args.seq2, tt.args.fn); !reflect.DeepEqual(got, tt.want) { - t.Errorf("MergeUint64() = %v, want %v", got, tt.want) - } - }) - } -} - -func RandomUint64Sequence(length int) Uint64Sequence { - now := time.Now() - ret := make(Uint64Sequence, length) - for i := range ret { - delta := time.Duration(i) * time.Second - if rand.Float64() < 0.5 { - delta = -delta - } - ret[i] = Uint64Item{ - Time: now.Add(delta), - Value: uint64(rand.Float64() * float64(math.MaxInt64)), - } - } - return ret -} diff --git a/uint_sequence.go b/uint_sequence.go deleted file mode 100644 index 1074442..0000000 --- a/uint_sequence.go +++ /dev/null @@ -1,197 +0,0 @@ -// Code generated by cmd/generate. DO NOT EDIT. - -package timeseq - -import ( - "errors" - "sort" - "time" -) - -// UintItem is item of UintSequence -type UintItem struct { - Time time.Time - Value uint -} - -// UintSequence is the implement of Sequence for uint -type UintSequence []UintItem - -// Len implements Sequence.Len -func (s UintSequence) Len() int { - return len(s) -} - -// Swap implements Sequence.Swap -func (s UintSequence) Swap(i, j int) { - s[i], s[j] = s[j], s[i] -} - -// Time implements Sequence.Time -func (s UintSequence) Time(i int) time.Time { - return s[i].Time -} - -// Slice implements Sequence.Slice -func (s UintSequence) Slice(i, j int) Sequence { - return s[i:j] -} - -// Sort will sort sequence by time -func (s UintSequence) Sort() { - Sort(s) -} - -// Range return sub sequence, would sort sequence if it is not sorted -func (s UintSequence) Range(afterOrEqual, beforeOrEqual *time.Time) UintSequence { - if !sort.IsSorted(sortableSequence{s}) { - s.Sort() - } - return Range(s, afterOrEqual, beforeOrEqual).(UintSequence) -} - -// First return the first item or nil if not exists, would sort sequence if it is not sorted -func (s UintSequence) First(afterOrEqual *time.Time) *UintItem { - if !sort.IsSorted(sortableSequence{s}) { - s.Sort() - } - i := First(s, afterOrEqual) - if i < 0 { - return nil - } - ret := s[i] - return &ret -} - -// Last return the last item or nil if not exists, would sort sequence if it is not sorted -func (s UintSequence) Last(beforeOrEqual *time.Time) *UintItem { - if !sort.IsSorted(sortableSequence{s}) { - s.Sort() - } - i := Last(s, beforeOrEqual) - if i < 0 { - return nil - } - ret := s[i] - return &ret -} - -// Max return the first item which has the max value, or nil if not exists -func (s UintSequence) Max() *UintItem { - var max *UintItem - for i, v := range s { - if max == nil { - max = &s[i] - } else if v.Value > max.Value { - max = &s[i] - } - } - if max != nil { - value := *max - max = &value - } - return max -} - -// Min return the first item which has the min value, or nil if not exists -func (s UintSequence) Min() *UintItem { - var min *UintItem - for i, v := range s { - if min == nil { - min = &s[i] - } else if v.Value < min.Value { - min = &s[i] - } - } - if min != nil { - value := *min - min = &value - } - return min -} - -// Sum return the value's sum -func (s UintSequence) Sum() uint { - var sum uint - for _, v := range s { - sum += v.Value - } - return sum -} - -// Average return the value's average -func (s UintSequence) Average() uint { - if len(s) == 0 { - return 0 - } - - return uint(float64(s.Sum()) / float64(len(s))) -} - -// Percentile return (pct)th percentile -func (s UintSequence) Percentile(pct float64) uint { - if pct > 1 || pct < 0 { - panic(errors.New("percentile must be [0, 1]")) - } - - var values []uint - for _, v := range s { - values = append(values, v.Value) - } - sort.Slice(values, func(i, j int) bool { - return values[i] < values[j] - }) - - if len(values) == 0 { - return 0 - } - - index := int(float64(len(s))*pct - 1) - if index < 0 { - index = 0 - } - - return values[index] -} - -// MergeUint merge two uint} seuquence into one -func MergeUint(seq1, seq2 UintSequence, fn func(item1, item2 *UintItem) *UintItem) UintSequence { - if fn == nil { - return nil - } - - var ret UintSequence - for i1, i2 := 0, 0; i1 < seq1.Len() || i2 < seq2.Len(); { - var item *UintItem - switch { - case i1 == seq1.Len(): - v2 := seq2[i2] - item = fn(nil, &v2) - i2++ - case i2 == seq2.Len(): - v1 := seq1[i1] - item = fn(&v1, nil) - i1++ - case seq1[i1].Time.Equal(seq2[i2].Time): - v1 := seq1[i1] - v2 := seq2[i2] - item = fn(&v1, &v2) - i1++ - i2++ - case seq1[i1].Time.Before(seq2[i2].Time): - v1 := seq1[i1] - item = fn(&v1, nil) - i1++ - case seq1[i1].Time.After(seq2[i2].Time): - v2 := seq2[i2] - item = fn(nil, &v2) - i2++ - } - if item != nil { - ret = append(ret, *item) - } - } - - Sort(ret) - return ret -} diff --git a/uint_sequence_test.go b/uint_sequence_test.go deleted file mode 100644 index 224c110..0000000 --- a/uint_sequence_test.go +++ /dev/null @@ -1,716 +0,0 @@ -// Code generated by cmd/generate. DO NOT EDIT. - -package timeseq - -import ( - "math" - "math/rand" - "reflect" - "sort" - "testing" - "time" - - "github.com/gochore/pt" -) - -func TestUintSequence_Len(t *testing.T) { - tests := []struct { - name string - s UintSequence - want int - }{ - { - s: RandomUintSequence(10), - want: 10, - }, - { - s: RandomUintSequence(0), - want: 0, - }, - { - s: nil, - want: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Len(); got != tt.want { - t.Errorf("UintSequence.Len() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestUintSequence_Swap(t *testing.T) { - type args struct { - i int - j int - } - tests := []struct { - name string - s UintSequence - args args - }{ - { - s: RandomUintSequence(10), - args: args{ - i: 0, - j: 5, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - ti := tt.s.Time(tt.args.i) - tj := tt.s.Time(tt.args.j) - tt.s.Swap(tt.args.i, tt.args.j) - if ti != tt.s.Time(tt.args.j) || tj != tt.s.Time(tt.args.i) { - t.Errorf("UintSequence.Swap() failed") - } - }) - } -} - -func TestUintSequence_Time(t *testing.T) { - seq := RandomUintSequence(10) - seq.Sort() - - type args struct { - i int - } - tests := []struct { - name string - s UintSequence - args args - want time.Time - }{ - { - s: seq, - args: args{ - i: 9, - }, - want: seq[9].Time, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Time(tt.args.i); !reflect.DeepEqual(got, tt.want) { - t.Errorf("UintSequence.Time() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestUintSequence_Slice(t *testing.T) { - seq := RandomUintSequence(10) - - type args struct { - i int - j int - } - tests := []struct { - name string - s UintSequence - args args - want Sequence - }{ - { - s: seq, - args: args{ - i: 2, - j: 10, - }, - want: seq[2:10], - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Slice(tt.args.i, tt.args.j); !reflect.DeepEqual(got, tt.want) { - t.Errorf("UintSequence.Slice() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestUintSequence_Sort(t *testing.T) { - tests := []struct { - name string - s UintSequence - }{ - { - s: RandomUintSequence(10), - }, - { - s: nil, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tt.s.Sort() - if !sort.IsSorted(sortableSequence{tt.s}) { - t.Error("UintSequence.Slice() failed") - } - }) - } -} - -func TestUintSequence_Range(t *testing.T) { - now := time.Now() - seq := RandomUintSequence(10) - for i := range seq { - seq[i].Time = now.Add(time.Duration(i) * time.Second) - } - rand.Shuffle(seq.Len(), func(i, j int) { - seq[i], seq[j] = seq[j], seq[i] - }) - - type args struct { - afterOrEqual *time.Time - beforeOrEqual *time.Time - } - tests := []struct { - name string - s UintSequence - args args - want UintSequence - }{ - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1 * time.Second)), - beforeOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: seq[1 : 5+1], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now), - beforeOrEqual: pt.Time(now.Add(100 * time.Second)), - }, - want: seq, - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1*time.Second + time.Millisecond)), - beforeOrEqual: pt.Time(now.Add(5*time.Second - time.Millisecond)), - }, - want: seq[2 : 4+1], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1*time.Second - time.Millisecond)), - beforeOrEqual: pt.Time(now.Add(5*time.Second + time.Millisecond)), - }, - want: seq[1 : 5+1], - }, - { - s: seq, - args: args{ - afterOrEqual: nil, - beforeOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: seq[:5+1], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1 * time.Second)), - beforeOrEqual: nil, - }, - want: seq[1:], - }, - { - s: seq, - args: args{ - afterOrEqual: nil, - beforeOrEqual: nil, - }, - want: seq, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Range(tt.args.afterOrEqual, tt.args.beforeOrEqual); !reflect.DeepEqual(got, tt.want) { - t.Errorf("UintSequence.Range() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestUintSequence_First(t *testing.T) { - now := time.Now() - seq := RandomUintSequence(10) - for i := range seq { - seq[i].Time = now.Add(time.Duration(i) * time.Second) - } - rand.Shuffle(seq.Len(), func(i, j int) { - seq[i], seq[j] = seq[j], seq[i] - }) - - type args struct { - afterOrEqual *time.Time - } - tests := []struct { - name string - s UintSequence - args args - want *UintItem - }{ - { - s: seq, - args: args{ - afterOrEqual: nil, - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now), - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(-1 * time.Second)), - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1 * time.Second)), - }, - want: &seq[1], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: &seq[5], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(5*time.Second - time.Millisecond)), - }, - want: &seq[5], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(5*time.Second + time.Millisecond)), - }, - want: &seq[6], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(100 * time.Second)), - }, - want: nil, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.First(tt.args.afterOrEqual); !reflect.DeepEqual(got, tt.want) { - t.Errorf("UintSequence.First() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestUintSequence_Last(t *testing.T) { - now := time.Now() - seq := RandomUintSequence(10) - for i := range seq { - seq[i].Time = now.Add(time.Duration(i) * time.Second) - } - rand.Shuffle(seq.Len(), func(i, j int) { - seq[i], seq[j] = seq[j], seq[i] - }) - - type args struct { - beforeOrEqual *time.Time - } - tests := []struct { - name string - s UintSequence - args args - want *UintItem - }{ - { - s: seq, - args: args{ - beforeOrEqual: nil, - }, - want: &seq[len(seq)-1], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now), - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(-1 * time.Second)), - }, - want: nil, - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(1 * time.Second)), - }, - want: &seq[1], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: &seq[5], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(5*time.Second - time.Millisecond)), - }, - want: &seq[4], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(5*time.Second + time.Millisecond)), - }, - want: &seq[5], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(100 * time.Second)), - }, - want: &seq[9], - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Last(tt.args.beforeOrEqual); !reflect.DeepEqual(got, tt.want) { - t.Errorf("UintSequence.Last() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestUintSequence_Max(t *testing.T) { - seq1 := RandomUintSequence(10) - seq1.Sort() - for i := range seq1 { - if i == 0 { - seq1[i].Value = 1 - } else { - seq1[i].Value = 0 - } - } - seq2 := RandomUintSequence(10) - seq2.Sort() - for i := range seq2 { - if i == 0 { - seq2[i].Value = 0 - } else { - seq2[i].Value = 1 - } - } - - tests := []struct { - name string - s UintSequence - want *UintItem - }{ - { - s: seq1, - want: &seq1[0], - }, - { - s: seq2, - want: &seq2[1], - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Max(); !reflect.DeepEqual(got, tt.want) { - t.Errorf("UintSequence.Max() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestUintSequence_Min(t *testing.T) { - seq1 := RandomUintSequence(10) - seq1.Sort() - for i := range seq1 { - if i == 0 { - seq1[i].Value = 1 - } else { - seq1[i].Value = 0 - } - } - seq2 := RandomUintSequence(10) - seq2.Sort() - for i := range seq2 { - if i == 0 { - seq2[i].Value = 0 - } else { - seq2[i].Value = 1 - } - } - - tests := []struct { - name string - s UintSequence - want *UintItem - }{ - { - s: seq1, - want: &seq1[1], - }, - { - s: seq2, - want: &seq2[0], - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Min(); !reflect.DeepEqual(got, tt.want) { - t.Errorf("UintSequence.Min() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestUintSequence_Sum(t *testing.T) { - seq := RandomUintSequence(10) - for i := range seq { - seq[i].Value = uint(i) - } - - tests := []struct { - name string - s UintSequence - want uint - }{ - { - s: seq, - want: 45, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Sum(); got != tt.want { - t.Errorf("UintSequence.Sum() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestUintSequence_Average(t *testing.T) { - seq := RandomUintSequence(10) - for i := range seq { - seq[i].Value = uint(i) * 2 - } - - tests := []struct { - name string - s UintSequence - want uint - }{ - { - s: seq, - want: 9, - }, - { - s: nil, - want: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Average(); got != tt.want { - t.Errorf("UintSequence.Average() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestUintSequence_Percentile(t *testing.T) { - seq := RandomUintSequence(100) - for i := range seq { - seq[i].Value = uint(i) + 1 - } - - type args struct { - pct float64 - } - tests := []struct { - name string - s UintSequence - args args - want uint - }{ - { - s: seq, - args: args{ - pct: 0, - }, - want: 1, - }, - { - s: seq, - args: args{ - pct: 0.5, - }, - want: 50, - }, - { - s: seq, - args: args{ - pct: 0.95, - }, - want: 95, - }, - { - s: seq, - args: args{ - pct: 0.955, - }, - want: 95, - }, - { - s: seq, - args: args{ - pct: 1, - }, - want: 100, - }, - { - s: seq, - args: args{ - pct: 1.1, - }, - want: 100, - }, - { - s: seq, - args: args{ - pct: -0.1, - }, - want: 1, - }, - { - s: nil, - args: args{ - pct: 1, - }, - want: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - defer func() { - if r := recover(); r != nil { - if tt.args.pct > 1 || tt.args.pct < 0 { - return - } - t.Errorf("UintSequence.Percentile() failed: %v", r) - } - }() - if got := tt.s.Percentile(tt.args.pct); got != tt.want { - t.Errorf("UintSequence.Percentile() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestMergeUint(t *testing.T) { - seq := RandomUintSequence(10) - seq.Sort() - type args struct { - seq1 UintSequence - seq2 UintSequence - fn func(item1, item2 *UintItem) *UintItem - } - tests := []struct { - name string - args args - want UintSequence - }{ - { - name: "regular", - args: args{ - seq1: seq[0:7], - seq2: seq[3:10], - fn: func(item1, item2 *UintItem) *UintItem { - if item1 != nil { - return item1 - } - return item2 - }, - }, - want: seq, - }, - { - name: "reverse", - args: args{ - seq1: seq[3:10], - seq2: seq[0:7], - fn: func(item1, item2 *UintItem) *UintItem { - if item1 != nil { - return item1 - } - return item2 - }, - }, - want: seq, - }, - { - name: "nil fn", - args: args{ - seq1: seq[0:7], - seq2: seq[3:10], - fn: nil, - }, - want: nil, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := MergeUint(tt.args.seq1, tt.args.seq2, tt.args.fn); !reflect.DeepEqual(got, tt.want) { - t.Errorf("MergeUint() = %v, want %v", got, tt.want) - } - }) - } -} - -func RandomUintSequence(length int) UintSequence { - now := time.Now() - ret := make(UintSequence, length) - for i := range ret { - delta := time.Duration(i) * time.Second - if rand.Float64() < 0.5 { - delta = -delta - } - ret[i] = UintItem{ - Time: now.Add(delta), - Value: uint(rand.Float64() * float64(math.MaxInt64)), - } - } - return ret -} From 758f6e299f7b7507cdee4886b476fef284687190 Mon Sep 17 00:00:00 2001 From: Jason Song Date: Wed, 23 Sep 2020 13:41:37 +0800 Subject: [PATCH 03/19] feat: v2 interface design --- int_seq.go | 107 ++++++++++++++++++++++++++++++++++++++++++++++++++++ sequence.go | 25 ------------ timeseq.go | 87 ++++++++++++++++++------------------------ 3 files changed, 143 insertions(+), 76 deletions(-) create mode 100644 int_seq.go delete mode 100644 sequence.go diff --git a/int_seq.go b/int_seq.go new file mode 100644 index 0000000..d39acd7 --- /dev/null +++ b/int_seq.go @@ -0,0 +1,107 @@ +package timeseq + +import ( + "time" +) + +type Int struct { + Time time.Time + Value int +} + +type Ints []Int + +func (s Ints) Len() int { + return len(s) +} + +func (s Ints) Swap(i, j int) { + s[i], s[j] = s[j], s[i] +} + +func (s Ints) Time(i int) time.Time { + return s[i].Time +} + +type IntSeq struct { + slice Ints + index map[timeKey][]int +} + +func NewIntSeq(slice Ints) *IntSeq { + s := make(Ints, len(slice)) + copy(s, slice) + Sort(slice) + index := make(map[timeKey][]int, len(slice)) + key := timeKey{} + for i, v := range slice { + key.Put(v.Time) + index[key] = append(index[key], i) + } + return &IntSeq{ + slice: slice, + index: index, + } +} + +func (s *IntSeq) Ints() Ints { + slice := make(Ints, len(s.slice)) + copy(slice, s.slice) + return slice +} + +func (s *IntSeq) Index(i int) Int { + panic("TODO") +} + +func (s *IntSeq) Time(t time.Time) Ints { + panic("TODO") +} + +func (s *IntSeq) Visit(fn func(i int, v Int)) { + panic("TODO") +} + +func (s *IntSeq) Sum() int { + panic("TODO") +} + +func (s *IntSeq) Count() int { + panic("TODO") +} + +func (s *IntSeq) Max() (int, Int) { + panic("TODO") +} + +func (s *IntSeq) Min() (int, Int) { + panic("TODO") +} + +func (s *IntSeq) First() (int, Int) { + panic("TODO") +} + +func (s *IntSeq) Last() (int, Int) { + panic("TODO") +} + +func (s IntSeq) Percentile(pct float64) (int, Int) { + panic("TODO") +} + +func (s IntSeq) Range(interval Interval) IntSeq { + panic("TODO") +} + +func (s IntSeq) Merge(fn func(e1, e2 *Int) *Int, slice ...Ints) error { + panic("TODO") +} + +func (s IntSeq) Aggregate(fn func(t time.Time, es ...Int) *Int, duration time.Duration) error { + panic("TODO") +} + +func (s IntSeq) Trim(trim func(i int, v Int) bool) error { + panic("TODO") +} diff --git a/sequence.go b/sequence.go deleted file mode 100644 index 5c05cfc..0000000 --- a/sequence.go +++ /dev/null @@ -1,25 +0,0 @@ -package timeseq - -import ( - "time" -) - -// Sequence can be implemented for specific data type -type Sequence interface { - // return length - Len() int - // swap items - Swap(i, j int) - // return time of item i - Time(i int) time.Time - // return Sequence[i:j] - Slice(i, j int) Sequence -} - -type sortableSequence struct { - Sequence -} - -func (s sortableSequence) Less(i, j int) bool { - return s.Time(i).Before(s.Time(j)) -} diff --git a/timeseq.go b/timeseq.go index 2b096e8..1904617 100644 --- a/timeseq.go +++ b/timeseq.go @@ -1,70 +1,55 @@ package timeseq import ( + "encoding/binary" "sort" "time" ) -// Sort will sort sequence by time -func Sort(seq Sequence) { - if seq == nil { - return - } - sort.Sort(sortableSequence{seq}) +type Slice interface { + // return length + Len() int + // swap items + Swap(i, j int) + // return time of item i + Time(i int) time.Time } -func TrimBefore(seq Sequence, before time.Time) Sequence { - i := sort.Search(seq.Len(), func(i int) bool { - return !seq.Time(i).Before(before) - }) - return seq.Slice(i, seq.Len()) +type sortableSlice struct { + Slice } -func TrimAfter(seq Sequence, after time.Time) Sequence { - j := sort.Search(seq.Len(), func(j int) bool { - return !seq.Time(j).Before(after) - }) - if j < seq.Len() && seq.Time(j).Equal(after) { - j++ - } - return seq.Slice(0, j) +func (s sortableSlice) Less(i, j int) bool { + return s.Time(i).Before(s.Time(j)) } -// Get return the index of the first item with specified time -func Get(seq Sequence, t time.Time) int { - i := sort.Search(seq.Len(), func(i int) bool { - return !seq.Time(i).Before(t) - }) - if i >= seq.Len() { - i = -1 - } - return i +// Sort will sort seq by time +func Sort(slice Slice) { + sort.Sort(sortableSlice{Slice: slice}) } -// First return the index of the first item -func First(seq Sequence, afterOrEqual *time.Time) int { - i := 0 - if afterOrEqual != nil { - i = sort.Search(seq.Len(), func(i int) bool { - return !seq.Time(i).Before(*afterOrEqual) - }) - if i >= seq.Len() { - i = -1 - } - } - return i +type timeKey [16]byte + +func (k timeKey) Get() time.Time { + return time.Unix(int64(binary.BigEndian.Uint64(k[:8])), int64(binary.BigEndian.Uint64(k[8:]))) } -// Last return the index of the last item -func Last(seq Sequence, beforeOrEqual *time.Time) int { - j := seq.Len() - 1 - if beforeOrEqual != nil { - j = sort.Search(seq.Len(), func(i int) bool { - return !seq.Time(i).Before(*beforeOrEqual) - }) - if j == seq.Len() || j < seq.Len() && !seq.Time(j).Equal(*beforeOrEqual) { - j-- - } +func (k timeKey) Put(t time.Time) { + binary.BigEndian.PutUint64(k[:8], uint64(t.Unix())) + binary.BigEndian.PutUint64(k[8:], uint64(t.UnixNano())) +} + +type Interval struct { + NotBefore *time.Time + NotAfter *time.Time +} + +func (i Interval) Contain(t time.Time) bool { + if i.NotBefore == nil && t.Before(*i.NotBefore) { + return false + } + if i.NotAfter == nil && t.After(*i.NotAfter) { + return false } - return j + return true } From a7df80ed57925268a181f43d37a8dba8197dfd10 Mon Sep 17 00:00:00 2001 From: Jason Song Date: Wed, 23 Sep 2020 13:53:06 +0800 Subject: [PATCH 04/19] chore: use draft dir --- _draft/v1/int_sequence.go | 195 +++++++++++++++++++++++++++++ _draft/v1/sequence.go | 25 ++++ _draft/v1/timeseq.go | 62 +++++++++ int_seq.go => _draft/v2/int_seq.go | 14 ++- timeseq.go => _draft/v2/timeseq.go | 10 -- 5 files changed, 291 insertions(+), 15 deletions(-) create mode 100644 _draft/v1/int_sequence.go create mode 100644 _draft/v1/sequence.go create mode 100644 _draft/v1/timeseq.go rename int_seq.go => _draft/v2/int_seq.go (86%) rename timeseq.go => _draft/v2/timeseq.go (80%) diff --git a/_draft/v1/int_sequence.go b/_draft/v1/int_sequence.go new file mode 100644 index 0000000..2c3c1f5 --- /dev/null +++ b/_draft/v1/int_sequence.go @@ -0,0 +1,195 @@ +package timeseq + +import ( + "errors" + "sort" + "time" +) + +// IntItem is item of IntSequence +type IntItem struct { + Time time.Time + Value int +} + +// IntSequence is the implement of Sequence for int +type IntSequence []IntItem + +// Len implements Sequence.Len +func (s IntSequence) Len() int { + return len(s) +} + +// Swap implements Sequence.Swap +func (s IntSequence) Swap(i, j int) { + s[i], s[j] = s[j], s[i] +} + +// Time implements Sequence.Time +func (s IntSequence) Time(i int) time.Time { + return s[i].Time +} + +// Slice implements Sequence.Slice +func (s IntSequence) Slice(i, j int) Sequence { + return s[i:j] +} + +// Sort will sort sequence by time +func (s IntSequence) Sort() { + Sort(s) +} + +// Range return sub sequence, would sort sequence if it is not sorted +func (s IntSequence) Range(afterOrEqual, beforeOrEqual *time.Time) IntSequence { + if !sort.IsSorted(sortableSequence{s}) { + s.Sort() + } + return Range(s, afterOrEqual, beforeOrEqual).(IntSequence) +} + +// First return the first item or nil if not exists, would sort sequence if it is not sorted +func (s IntSequence) First(afterOrEqual *time.Time) *IntItem { + if !sort.IsSorted(sortableSequence{s}) { + s.Sort() + } + i := First(s, afterOrEqual) + if i < 0 { + return nil + } + ret := s[i] + return &ret +} + +// Last return the last item or nil if not exists, would sort sequence if it is not sorted +func (s IntSequence) Last(beforeOrEqual *time.Time) *IntItem { + if !sort.IsSorted(sortableSequence{s}) { + s.Sort() + } + i := Last(s, beforeOrEqual) + if i < 0 { + return nil + } + ret := s[i] + return &ret +} + +// Max return the first item which has the max value, or nil if not exists +func (s IntSequence) Max() *IntItem { + var max *IntItem + for i, v := range s { + if max == nil { + max = &s[i] + } else if v.Value > max.Value { + max = &s[i] + } + } + if max != nil { + value := *max + max = &value + } + return max +} + +// Min return the first item which has the min value, or nil if not exists +func (s IntSequence) Min() *IntItem { + var min *IntItem + for i, v := range s { + if min == nil { + min = &s[i] + } else if v.Value < min.Value { + min = &s[i] + } + } + if min != nil { + value := *min + min = &value + } + return min +} + +// Sum return the value's sum +func (s IntSequence) Sum() int { + var sum int + for _, v := range s { + sum += v.Value + } + return sum +} + +// Average return the value's average +func (s IntSequence) Average() int { + if len(s) == 0 { + return 0 + } + + return int(float64(s.Sum()) / float64(len(s))) +} + +// Percentile return (pct)th percentile +func (s IntSequence) Percentile(pct float64) int { + if pct > 1 || pct < 0 { + panic(errors.New("percentile must be [0, 1]")) + } + + var values []int + for _, v := range s { + values = append(values, v.Value) + } + sort.Slice(values, func(i, j int) bool { + return values[i] < values[j] + }) + + if len(values) == 0 { + return 0 + } + + index := int(float64(len(s))*pct - 1) + if index < 0 { + index = 0 + } + + return values[index] +} + +// MergeInt merge two int} seuquence into one +func MergeInt(seq1, seq2 IntSequence, fn func(item1, item2 *IntItem) *IntItem) IntSequence { + if fn == nil { + return nil + } + + var ret IntSequence + for i1, i2 := 0, 0; i1 < seq1.Len() || i2 < seq2.Len(); { + var item *IntItem + switch { + case i1 == seq1.Len(): + v2 := seq2[i2] + item = fn(nil, &v2) + i2++ + case i2 == seq2.Len(): + v1 := seq1[i1] + item = fn(&v1, nil) + i1++ + case seq1[i1].Time.Equal(seq2[i2].Time): + v1 := seq1[i1] + v2 := seq2[i2] + item = fn(&v1, &v2) + i1++ + i2++ + case seq1[i1].Time.Before(seq2[i2].Time): + v1 := seq1[i1] + item = fn(&v1, nil) + i1++ + case seq1[i1].Time.After(seq2[i2].Time): + v2 := seq2[i2] + item = fn(nil, &v2) + i2++ + } + if item != nil { + ret = append(ret, *item) + } + } + + Sort(ret) + return ret +} diff --git a/_draft/v1/sequence.go b/_draft/v1/sequence.go new file mode 100644 index 0000000..5c05cfc --- /dev/null +++ b/_draft/v1/sequence.go @@ -0,0 +1,25 @@ +package timeseq + +import ( + "time" +) + +// Sequence can be implemented for specific data type +type Sequence interface { + // return length + Len() int + // swap items + Swap(i, j int) + // return time of item i + Time(i int) time.Time + // return Sequence[i:j] + Slice(i, j int) Sequence +} + +type sortableSequence struct { + Sequence +} + +func (s sortableSequence) Less(i, j int) bool { + return s.Time(i).Before(s.Time(j)) +} diff --git a/_draft/v1/timeseq.go b/_draft/v1/timeseq.go new file mode 100644 index 0000000..65ee5ad --- /dev/null +++ b/_draft/v1/timeseq.go @@ -0,0 +1,62 @@ +package timeseq + +import ( + "sort" + "time" +) + +// Sort will sort sequence by time +func Sort(seq Sequence) { + if seq == nil { + return + } + sort.Sort(sortableSequence{seq}) +} + +// Range return sub sequence +func Range(seq Sequence, afterOrEqual, beforeOrEqual *time.Time) Sequence { + i := 0 + if afterOrEqual != nil { + i = sort.Search(seq.Len(), func(i int) bool { + return !seq.Time(i).Before(*afterOrEqual) + }) + } + j := seq.Len() + if beforeOrEqual != nil { + j = sort.Search(seq.Len(), func(j int) bool { + return !seq.Time(j).Before(*beforeOrEqual) + }) + if j < seq.Len() && seq.Time(j).Equal(*beforeOrEqual) { + j++ + } + } + return seq.Slice(i, j) +} + +// First return the index of the first item +func First(seq Sequence, afterOrEqual *time.Time) int { + i := 0 + if afterOrEqual != nil { + i = sort.Search(seq.Len(), func(i int) bool { + return !seq.Time(i).Before(*afterOrEqual) + }) + if i >= seq.Len() { + i = -1 + } + } + return i +} + +// Last return the index of the last item +func Last(seq Sequence, beforeOrEqual *time.Time) int { + j := seq.Len() - 1 + if beforeOrEqual != nil { + j = sort.Search(seq.Len(), func(i int) bool { + return !seq.Time(i).Before(*beforeOrEqual) + }) + if j == seq.Len() || j < seq.Len() && !seq.Time(j).Equal(*beforeOrEqual) { + j-- + } + } + return j +} diff --git a/int_seq.go b/_draft/v2/int_seq.go similarity index 86% rename from int_seq.go rename to _draft/v2/int_seq.go index d39acd7..5b1b171 100644 --- a/int_seq.go +++ b/_draft/v2/int_seq.go @@ -58,6 +58,10 @@ func (s *IntSeq) Time(t time.Time) Ints { panic("TODO") } +func (s *IntSeq) Value(v int) Ints { + panic("TODO") +} + func (s *IntSeq) Visit(fn func(i int, v Int)) { panic("TODO") } @@ -70,23 +74,23 @@ func (s *IntSeq) Count() int { panic("TODO") } -func (s *IntSeq) Max() (int, Int) { +func (s *IntSeq) Max() Int { panic("TODO") } -func (s *IntSeq) Min() (int, Int) { +func (s *IntSeq) Min() Int { panic("TODO") } -func (s *IntSeq) First() (int, Int) { +func (s *IntSeq) First() Int { panic("TODO") } -func (s *IntSeq) Last() (int, Int) { +func (s *IntSeq) Last() Int { panic("TODO") } -func (s IntSeq) Percentile(pct float64) (int, Int) { +func (s IntSeq) Percentile(pct float64) Int { panic("TODO") } diff --git a/timeseq.go b/_draft/v2/timeseq.go similarity index 80% rename from timeseq.go rename to _draft/v2/timeseq.go index 1904617..987404d 100644 --- a/timeseq.go +++ b/_draft/v2/timeseq.go @@ -43,13 +43,3 @@ type Interval struct { NotBefore *time.Time NotAfter *time.Time } - -func (i Interval) Contain(t time.Time) bool { - if i.NotBefore == nil && t.Before(*i.NotBefore) { - return false - } - if i.NotAfter == nil && t.After(*i.NotAfter) { - return false - } - return true -} From 05c930863ad966986ef37052ec7d3ac2007fb090 Mon Sep 17 00:00:00 2001 From: Jason Song Date: Wed, 23 Sep 2020 14:55:50 +0800 Subject: [PATCH 05/19] feat: implement methods --- _draft/v2/int_seq.go | 216 +++++++++++++++++++++++++++++++++++-------- _draft/v2/timeseq.go | 37 ++------ 2 files changed, 187 insertions(+), 66 deletions(-) diff --git a/_draft/v2/int_seq.go b/_draft/v2/int_seq.go index 5b1b171..62569c0 100644 --- a/_draft/v2/int_seq.go +++ b/_draft/v2/int_seq.go @@ -1,6 +1,8 @@ package timeseq import ( + "fmt" + "sort" "time" ) @@ -11,36 +13,40 @@ type Int struct { type Ints []Int -func (s Ints) Len() int { - return len(s) -} - -func (s Ints) Swap(i, j int) { - s[i], s[j] = s[j], s[i] -} - -func (s Ints) Time(i int) time.Time { - return s[i].Time -} - type IntSeq struct { - slice Ints - index map[timeKey][]int + slice Ints + timeIndex map[timeKey][]int + valueIndex map[int][]int + valueSlice []int } func NewIntSeq(slice Ints) *IntSeq { s := make(Ints, len(slice)) copy(s, slice) - Sort(slice) - index := make(map[timeKey][]int, len(slice)) - key := timeKey{} + sort.SliceStable(slice, func(i, j int) bool { + return slice[i].Time.Before(slice[j].Time) + }) + return newIntSeq(slice) +} + +func newIntSeq(slice Ints) *IntSeq { + timeIndex := make(map[timeKey][]int, len(slice)) + valueIndex := make(map[int][]int, len(slice)) + valueSlice := make([]int, len(slice)) for i, v := range slice { - key.Put(v.Time) - index[key] = append(index[key], i) + k := newTimeKey(v.Time) + timeIndex[k] = append(timeIndex[k], i) + valueIndex[v.Value] = append(valueIndex[v.Value], i) + valueSlice[i] = i } + sort.SliceStable(valueSlice, func(i, j int) bool { + return slice[valueSlice[i]].Value < slice[valueSlice[j]].Value + }) return &IntSeq{ - slice: slice, - index: index, + slice: slice, + timeIndex: timeIndex, + valueIndex: valueIndex, + valueSlice: valueSlice, } } @@ -51,55 +57,191 @@ func (s *IntSeq) Ints() Ints { } func (s *IntSeq) Index(i int) Int { - panic("TODO") + if i < 0 || i >= len(s.slice) { + return Int{} + } + return s.slice[i] } func (s *IntSeq) Time(t time.Time) Ints { - panic("TODO") + index := s.timeIndex[newTimeKey(t)] + if len(index) == 0 { + return nil + } + ret := make(Ints, len(index)) + for _, i := range index { + ret[i] = s.slice[i] + } + return ret } func (s *IntSeq) Value(v int) Ints { - panic("TODO") + index := s.valueIndex[v] + if len(index) == 0 { + return nil + } + ret := make(Ints, len(index)) + for _, i := range index { + ret[i] = s.slice[i] + } + return ret } -func (s *IntSeq) Visit(fn func(i int, v Int)) { - panic("TODO") +func (s *IntSeq) Visit(fn func(i int, v Int) (stop bool)) { + for i, v := range s.slice { + if fn != nil && fn(i, v) { + break + } + } } func (s *IntSeq) Sum() int { - panic("TODO") + var ret int + for _, v := range s.slice { + ret += v.Value + } + return ret } func (s *IntSeq) Count() int { - panic("TODO") + return len(s.slice) } func (s *IntSeq) Max() Int { - panic("TODO") + var max Int + found := false + for _, v := range s.slice { + if !found { + max = v + found = true + } else if v.Value < max.Value { + max = v + } + } + return max } func (s *IntSeq) Min() Int { - panic("TODO") + var min Int + found := false + for _, v := range s.slice { + if !found { + min = v + found = true + } else if v.Value < min.Value { + min = v + } + } + return min } func (s *IntSeq) First() Int { - panic("TODO") + if len(s.slice) == 0 { + return Int{} + } + return s.slice[0] } func (s *IntSeq) Last() Int { - panic("TODO") + if len(s.slice) == 0 { + return Int{} + } + return s.slice[len(s.slice)-1] } func (s IntSeq) Percentile(pct float64) Int { - panic("TODO") + if len(s.slice) == 0 { + return Int{} + } + if pct > 1 { + pct = 1 + } + if pct < 0 { + pct = 0 + } + i := int(float64(len(s.slice))*pct - 1) + if i < 0 { + i = 0 + } + return s.slice[s.valueSlice[i]] } -func (s IntSeq) Range(interval Interval) IntSeq { - panic("TODO") +func (s IntSeq) Range(interval Interval) *IntSeq { + i := 0 + if interval.NotBefore != nil { + i = sort.Search(len(s.slice), func(i int) bool { + return !s.slice[i].Time.Before(*interval.NotBefore) + }) + } + j := len(s.slice) + if interval.NotAfter != nil { + j = sort.Search(len(s.slice), func(j int) bool { + return !s.slice[j].Time.Before(*interval.NotBefore) + }) + if j < len(s.slice) && s.slice[j].Time.Equal(*interval.NotBefore) { + j++ + } + } + return newIntSeq(s.slice[i:j]) } -func (s IntSeq) Merge(fn func(e1, e2 *Int) *Int, slice ...Ints) error { - panic("TODO") +func (s IntSeq) Merge(fn func(t time.Time, v1, v2 *int) *int, slices ...Ints) error { + if len(slices) == 0 { + return nil + } + + if fn == nil { + return fmt.Errorf("nil fn") + } + + seq1 := s.slice + for _, seq2 := range slices { + var got Ints + for i1, i2 := 0, 0; i1 < len(seq1) || i2 < len(seq2); { + var ( + t time.Time + v *int + ) + switch { + case i1 == len(seq1): + t = seq2[i2].Time + v2 := seq2[i2].Value + v = fn(t, nil, &v2) + i2++ + case i2 == len(seq2): + t = seq2[i1].Time + v1 := seq1[i1].Value + v = fn(t, &v1, nil) + i1++ + case seq1[i1].Time.Equal(seq2[i2].Time): + t = seq1[i1].Time + v1 := seq1[i1].Value + v2 := seq2[i2].Value + v = fn(t, &v1, &v2) + i1++ + i2++ + case seq1[i1].Time.Before(seq2[i2].Time): + t = seq1[i1].Time + v1 := seq1[i1].Value + v = fn(t, &v1, nil) + i1++ + case seq1[i1].Time.After(seq2[i2].Time): + t = seq1[i2].Time + v2 := seq2[i2].Value + v = fn(t, nil, &v2) + i2++ + } + if v != nil { + got = append(got, Int{ + Time: t, + Value: *v, + }) + } + } + seq1 = got + } + + return got } func (s IntSeq) Aggregate(fn func(t time.Time, es ...Int) *Int, duration time.Duration) error { diff --git a/_draft/v2/timeseq.go b/_draft/v2/timeseq.go index 987404d..a7c9bd2 100644 --- a/_draft/v2/timeseq.go +++ b/_draft/v2/timeseq.go @@ -2,30 +2,12 @@ package timeseq import ( "encoding/binary" - "sort" "time" ) -type Slice interface { - // return length - Len() int - // swap items - Swap(i, j int) - // return time of item i - Time(i int) time.Time -} - -type sortableSlice struct { - Slice -} - -func (s sortableSlice) Less(i, j int) bool { - return s.Time(i).Before(s.Time(j)) -} - -// Sort will sort seq by time -func Sort(slice Slice) { - sort.Sort(sortableSlice{Slice: slice}) +type Interval struct { + NotBefore *time.Time + NotAfter *time.Time } type timeKey [16]byte @@ -34,12 +16,9 @@ func (k timeKey) Get() time.Time { return time.Unix(int64(binary.BigEndian.Uint64(k[:8])), int64(binary.BigEndian.Uint64(k[8:]))) } -func (k timeKey) Put(t time.Time) { - binary.BigEndian.PutUint64(k[:8], uint64(t.Unix())) - binary.BigEndian.PutUint64(k[8:], uint64(t.UnixNano())) -} - -type Interval struct { - NotBefore *time.Time - NotAfter *time.Time +func newTimeKey(t time.Time) timeKey { + var ret [16]byte + binary.BigEndian.PutUint64(ret[:8], uint64(t.Unix())) + binary.BigEndian.PutUint64(ret[8:], uint64(t.UnixNano())) + return ret } From a4b4d8a366d0414fa0d91c7cb7a12e5193aeefcb Mon Sep 17 00:00:00 2001 From: Jason Song Date: Wed, 23 Sep 2020 16:33:08 +0800 Subject: [PATCH 06/19] feat: v2 proto --- _draft/v1/int_sequence_test.go | 714 +++++++++++++++++++++++++++++++++ _draft/v2/int_seq.go | 212 ++++++---- _draft/v2/int_seq_test.go | 569 ++++++++++++++++++++++++++ _draft/v2/timeseq.go | 48 +++ 4 files changed, 1475 insertions(+), 68 deletions(-) create mode 100644 _draft/v1/int_sequence_test.go create mode 100644 _draft/v2/int_seq_test.go diff --git a/_draft/v1/int_sequence_test.go b/_draft/v1/int_sequence_test.go new file mode 100644 index 0000000..cb718a4 --- /dev/null +++ b/_draft/v1/int_sequence_test.go @@ -0,0 +1,714 @@ +package timeseq + +import ( + "math" + "math/rand" + "reflect" + "sort" + "testing" + "time" + + "github.com/gochore/pt" +) + +func TestIntSequence_Len(t *testing.T) { + tests := []struct { + name string + s IntSequence + want int + }{ + { + s: RandomIntSequence(10), + want: 10, + }, + { + s: RandomIntSequence(0), + want: 0, + }, + { + s: nil, + want: 0, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := tt.s.Len(); got != tt.want { + t.Errorf("IntSequence.Len() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestIntSequence_Swap(t *testing.T) { + type args struct { + i int + j int + } + tests := []struct { + name string + s IntSequence + args args + }{ + { + s: RandomIntSequence(10), + args: args{ + i: 0, + j: 5, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ti := tt.s.Time(tt.args.i) + tj := tt.s.Time(tt.args.j) + tt.s.Swap(tt.args.i, tt.args.j) + if ti != tt.s.Time(tt.args.j) || tj != tt.s.Time(tt.args.i) { + t.Errorf("IntSequence.Swap() failed") + } + }) + } +} + +func TestIntSequence_Time(t *testing.T) { + seq := RandomIntSequence(10) + seq.Sort() + + type args struct { + i int + } + tests := []struct { + name string + s IntSequence + args args + want time.Time + }{ + { + s: seq, + args: args{ + i: 9, + }, + want: seq[9].Time, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := tt.s.Time(tt.args.i); !reflect.DeepEqual(got, tt.want) { + t.Errorf("IntSequence.Time() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestIntSequence_Slice(t *testing.T) { + seq := RandomIntSequence(10) + + type args struct { + i int + j int + } + tests := []struct { + name string + s IntSequence + args args + want Sequence + }{ + { + s: seq, + args: args{ + i: 2, + j: 10, + }, + want: seq[2:10], + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := tt.s.Slice(tt.args.i, tt.args.j); !reflect.DeepEqual(got, tt.want) { + t.Errorf("IntSequence.Slice() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestIntSequence_Sort(t *testing.T) { + tests := []struct { + name string + s IntSequence + }{ + { + s: RandomIntSequence(10), + }, + { + s: nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt.s.Sort() + if !sort.IsSorted(sortableSequence{tt.s}) { + t.Error("IntSequence.Slice() failed") + } + }) + } +} + +func TestIntSequence_Range(t *testing.T) { + now := time.Now() + seq := RandomIntSequence(10) + for i := range seq { + seq[i].Time = now.Add(time.Duration(i) * time.Second) + } + rand.Shuffle(seq.Len(), func(i, j int) { + seq[i], seq[j] = seq[j], seq[i] + }) + + type args struct { + afterOrEqual *time.Time + beforeOrEqual *time.Time + } + tests := []struct { + name string + s IntSequence + args args + want IntSequence + }{ + { + s: seq, + args: args{ + afterOrEqual: pt.Time(now.Add(1 * time.Second)), + beforeOrEqual: pt.Time(now.Add(5 * time.Second)), + }, + want: seq[1 : 5+1], + }, + { + s: seq, + args: args{ + afterOrEqual: pt.Time(now), + beforeOrEqual: pt.Time(now.Add(100 * time.Second)), + }, + want: seq, + }, + { + s: seq, + args: args{ + afterOrEqual: pt.Time(now.Add(1*time.Second + time.Millisecond)), + beforeOrEqual: pt.Time(now.Add(5*time.Second - time.Millisecond)), + }, + want: seq[2 : 4+1], + }, + { + s: seq, + args: args{ + afterOrEqual: pt.Time(now.Add(1*time.Second - time.Millisecond)), + beforeOrEqual: pt.Time(now.Add(5*time.Second + time.Millisecond)), + }, + want: seq[1 : 5+1], + }, + { + s: seq, + args: args{ + afterOrEqual: nil, + beforeOrEqual: pt.Time(now.Add(5 * time.Second)), + }, + want: seq[:5+1], + }, + { + s: seq, + args: args{ + afterOrEqual: pt.Time(now.Add(1 * time.Second)), + beforeOrEqual: nil, + }, + want: seq[1:], + }, + { + s: seq, + args: args{ + afterOrEqual: nil, + beforeOrEqual: nil, + }, + want: seq, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := tt.s.Range(tt.args.afterOrEqual, tt.args.beforeOrEqual); !reflect.DeepEqual(got, tt.want) { + t.Errorf("IntSequence.Range() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestIntSequence_First(t *testing.T) { + now := time.Now() + seq := RandomIntSequence(10) + for i := range seq { + seq[i].Time = now.Add(time.Duration(i) * time.Second) + } + rand.Shuffle(seq.Len(), func(i, j int) { + seq[i], seq[j] = seq[j], seq[i] + }) + + type args struct { + afterOrEqual *time.Time + } + tests := []struct { + name string + s IntSequence + args args + want *IntItem + }{ + { + s: seq, + args: args{ + afterOrEqual: nil, + }, + want: &seq[0], + }, + { + s: seq, + args: args{ + afterOrEqual: pt.Time(now), + }, + want: &seq[0], + }, + { + s: seq, + args: args{ + afterOrEqual: pt.Time(now.Add(-1 * time.Second)), + }, + want: &seq[0], + }, + { + s: seq, + args: args{ + afterOrEqual: pt.Time(now.Add(1 * time.Second)), + }, + want: &seq[1], + }, + { + s: seq, + args: args{ + afterOrEqual: pt.Time(now.Add(5 * time.Second)), + }, + want: &seq[5], + }, + { + s: seq, + args: args{ + afterOrEqual: pt.Time(now.Add(5*time.Second - time.Millisecond)), + }, + want: &seq[5], + }, + { + s: seq, + args: args{ + afterOrEqual: pt.Time(now.Add(5*time.Second + time.Millisecond)), + }, + want: &seq[6], + }, + { + s: seq, + args: args{ + afterOrEqual: pt.Time(now.Add(100 * time.Second)), + }, + want: nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := tt.s.First(tt.args.afterOrEqual); !reflect.DeepEqual(got, tt.want) { + t.Errorf("IntSequence.First() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestIntSequence_Last(t *testing.T) { + now := time.Now() + seq := RandomIntSequence(10) + for i := range seq { + seq[i].Time = now.Add(time.Duration(i) * time.Second) + } + rand.Shuffle(seq.Len(), func(i, j int) { + seq[i], seq[j] = seq[j], seq[i] + }) + + type args struct { + beforeOrEqual *time.Time + } + tests := []struct { + name string + s IntSequence + args args + want *IntItem + }{ + { + s: seq, + args: args{ + beforeOrEqual: nil, + }, + want: &seq[len(seq)-1], + }, + { + s: seq, + args: args{ + beforeOrEqual: pt.Time(now), + }, + want: &seq[0], + }, + { + s: seq, + args: args{ + beforeOrEqual: pt.Time(now.Add(-1 * time.Second)), + }, + want: nil, + }, + { + s: seq, + args: args{ + beforeOrEqual: pt.Time(now.Add(1 * time.Second)), + }, + want: &seq[1], + }, + { + s: seq, + args: args{ + beforeOrEqual: pt.Time(now.Add(5 * time.Second)), + }, + want: &seq[5], + }, + { + s: seq, + args: args{ + beforeOrEqual: pt.Time(now.Add(5*time.Second - time.Millisecond)), + }, + want: &seq[4], + }, + { + s: seq, + args: args{ + beforeOrEqual: pt.Time(now.Add(5*time.Second + time.Millisecond)), + }, + want: &seq[5], + }, + { + s: seq, + args: args{ + beforeOrEqual: pt.Time(now.Add(100 * time.Second)), + }, + want: &seq[9], + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := tt.s.Last(tt.args.beforeOrEqual); !reflect.DeepEqual(got, tt.want) { + t.Errorf("IntSequence.Last() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestIntSequence_Max(t *testing.T) { + seq1 := RandomIntSequence(10) + seq1.Sort() + for i := range seq1 { + if i == 0 { + seq1[i].Value = 1 + } else { + seq1[i].Value = 0 + } + } + seq2 := RandomIntSequence(10) + seq2.Sort() + for i := range seq2 { + if i == 0 { + seq2[i].Value = 0 + } else { + seq2[i].Value = 1 + } + } + + tests := []struct { + name string + s IntSequence + want *IntItem + }{ + { + s: seq1, + want: &seq1[0], + }, + { + s: seq2, + want: &seq2[1], + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := tt.s.Max(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("IntSequence.Max() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestIntSequence_Min(t *testing.T) { + seq1 := RandomIntSequence(10) + seq1.Sort() + for i := range seq1 { + if i == 0 { + seq1[i].Value = 1 + } else { + seq1[i].Value = 0 + } + } + seq2 := RandomIntSequence(10) + seq2.Sort() + for i := range seq2 { + if i == 0 { + seq2[i].Value = 0 + } else { + seq2[i].Value = 1 + } + } + + tests := []struct { + name string + s IntSequence + want *IntItem + }{ + { + s: seq1, + want: &seq1[1], + }, + { + s: seq2, + want: &seq2[0], + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := tt.s.Min(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("IntSequence.Min() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestIntSequence_Sum(t *testing.T) { + seq := RandomIntSequence(10) + for i := range seq { + seq[i].Value = int(i) + } + + tests := []struct { + name string + s IntSequence + want int + }{ + { + s: seq, + want: 45, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := tt.s.Sum(); got != tt.want { + t.Errorf("IntSequence.Sum() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestIntSequence_Average(t *testing.T) { + seq := RandomIntSequence(10) + for i := range seq { + seq[i].Value = int(i) * 2 + } + + tests := []struct { + name string + s IntSequence + want int + }{ + { + s: seq, + want: 9, + }, + { + s: nil, + want: 0, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := tt.s.Average(); got != tt.want { + t.Errorf("IntSequence.Average() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestIntSequence_Percentile(t *testing.T) { + seq := RandomIntSequence(100) + for i := range seq { + seq[i].Value = int(i) + 1 + } + + type args struct { + pct float64 + } + tests := []struct { + name string + s IntSequence + args args + want int + }{ + { + s: seq, + args: args{ + pct: 0, + }, + want: 1, + }, + { + s: seq, + args: args{ + pct: 0.5, + }, + want: 50, + }, + { + s: seq, + args: args{ + pct: 0.95, + }, + want: 95, + }, + { + s: seq, + args: args{ + pct: 0.955, + }, + want: 95, + }, + { + s: seq, + args: args{ + pct: 1, + }, + want: 100, + }, + { + s: seq, + args: args{ + pct: 1.1, + }, + want: 100, + }, + { + s: seq, + args: args{ + pct: -0.1, + }, + want: 1, + }, + { + s: nil, + args: args{ + pct: 1, + }, + want: 0, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + defer func() { + if r := recover(); r != nil { + if tt.args.pct > 1 || tt.args.pct < 0 { + return + } + t.Errorf("IntSequence.Percentile() failed: %v", r) + } + }() + if got := tt.s.Percentile(tt.args.pct); got != tt.want { + t.Errorf("IntSequence.Percentile() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestMergeInt(t *testing.T) { + seq := RandomIntSequence(10) + seq.Sort() + type args struct { + seq1 IntSequence + seq2 IntSequence + fn func(item1, item2 *IntItem) *IntItem + } + tests := []struct { + name string + args args + want IntSequence + }{ + { + name: "regular", + args: args{ + seq1: seq[0:7], + seq2: seq[3:10], + fn: func(item1, item2 *IntItem) *IntItem { + if item1 != nil { + return item1 + } + return item2 + }, + }, + want: seq, + }, + { + name: "reverse", + args: args{ + seq1: seq[3:10], + seq2: seq[0:7], + fn: func(item1, item2 *IntItem) *IntItem { + if item1 != nil { + return item1 + } + return item2 + }, + }, + want: seq, + }, + { + name: "nil fn", + args: args{ + seq1: seq[0:7], + seq2: seq[3:10], + fn: nil, + }, + want: nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := MergeInt(tt.args.seq1, tt.args.seq2, tt.args.fn); !reflect.DeepEqual(got, tt.want) { + t.Errorf("MergeInt() = %v, want %v", got, tt.want) + } + }) + } +} + +func RandomIntSequence(length int) IntSequence { + now := time.Now() + ret := make(IntSequence, length) + for i := range ret { + delta := time.Duration(i) * time.Second + if rand.Float64() < 0.5 { + delta = -delta + } + ret[i] = IntItem{ + Time: now.Add(delta), + Value: int(rand.Float64() * float64(math.MaxInt64)), + } + } + return ret +} diff --git a/_draft/v2/int_seq.go b/_draft/v2/int_seq.go index 62569c0..768521d 100644 --- a/_draft/v2/int_seq.go +++ b/_draft/v2/int_seq.go @@ -1,7 +1,7 @@ package timeseq import ( - "fmt" + "errors" "sort" "time" ) @@ -13,6 +13,22 @@ type Int struct { type Ints []Int +func (s Ints) Len() int { + return len(s) +} + +func (s Ints) Swap(i, j int) { + s[i], s[j] = s[j], s[i] +} + +func (s Ints) Time(i int) time.Time { + return s[i].Time +} + +func (s Ints) Slice(i, j int) Slice { + return s[i:j] +} + type IntSeq struct { slice Ints timeIndex map[timeKey][]int @@ -20,9 +36,10 @@ type IntSeq struct { valueSlice []int } -func NewIntSeq(slice Ints) *IntSeq { - s := make(Ints, len(slice)) - copy(s, slice) +func NewIntSeq(ints Ints) *IntSeq { + slice := make(Ints, len(ints)) + copy(slice, ints) + Sort(slice) sort.SliceStable(slice, func(i, j int) bool { return slice[i].Time.Before(slice[j].Time) }) @@ -30,24 +47,29 @@ func NewIntSeq(slice Ints) *IntSeq { } func newIntSeq(slice Ints) *IntSeq { - timeIndex := make(map[timeKey][]int, len(slice)) - valueIndex := make(map[int][]int, len(slice)) - valueSlice := make([]int, len(slice)) - for i, v := range slice { + ret := &IntSeq{ + slice: slice, + } + ret.buildIndex() + return ret +} + +func (s *IntSeq) buildIndex() { + timeIndex := make(map[timeKey][]int, len(s.slice)) + valueIndex := make(map[int][]int, len(s.slice)) + valueSlice := s.valueSlice[:0] + for i, v := range s.slice { k := newTimeKey(v.Time) timeIndex[k] = append(timeIndex[k], i) valueIndex[v.Value] = append(valueIndex[v.Value], i) - valueSlice[i] = i + valueSlice = append(valueSlice, i) } sort.SliceStable(valueSlice, func(i, j int) bool { - return slice[valueSlice[i]].Value < slice[valueSlice[j]].Value + return s.slice[valueSlice[i]].Value < s.slice[valueSlice[j]].Value }) - return &IntSeq{ - slice: slice, - timeIndex: timeIndex, - valueIndex: valueIndex, - valueSlice: valueSlice, - } + s.timeIndex = timeIndex + s.valueIndex = valueIndex + s.valueSlice = valueSlice } func (s *IntSeq) Ints() Ints { @@ -69,8 +91,8 @@ func (s *IntSeq) Time(t time.Time) Ints { return nil } ret := make(Ints, len(index)) - for _, i := range index { - ret[i] = s.slice[i] + for i, v := range index { + ret[i] = s.slice[v] } return ret } @@ -81,8 +103,8 @@ func (s *IntSeq) Value(v int) Ints { return nil } ret := make(Ints, len(index)) - for _, i := range index { - ret[i] = s.slice[i] + for i, v := range index { + ret[i] = s.slice[v] } return ret } @@ -149,7 +171,7 @@ func (s *IntSeq) Last() Int { return s.slice[len(s.slice)-1] } -func (s IntSeq) Percentile(pct float64) Int { +func (s *IntSeq) Percentile(pct float64) Int { if len(s.slice) == 0 { return Int{} } @@ -166,68 +188,60 @@ func (s IntSeq) Percentile(pct float64) Int { return s.slice[s.valueSlice[i]] } -func (s IntSeq) Range(interval Interval) *IntSeq { - i := 0 - if interval.NotBefore != nil { - i = sort.Search(len(s.slice), func(i int) bool { - return !s.slice[i].Time.Before(*interval.NotBefore) - }) - } - j := len(s.slice) - if interval.NotAfter != nil { - j = sort.Search(len(s.slice), func(j int) bool { - return !s.slice[j].Time.Before(*interval.NotBefore) - }) - if j < len(s.slice) && s.slice[j].Time.Equal(*interval.NotBefore) { - j++ - } - } - return newIntSeq(s.slice[i:j]) +func (s *IntSeq) Range(interval Interval) *IntSeq { + slice := Range(s.slice, interval).(Ints) + return newIntSeq(slice) } -func (s IntSeq) Merge(fn func(t time.Time, v1, v2 *int) *int, slices ...Ints) error { - if len(slices) == 0 { - return nil +func (s *IntSeq) Merge(fn func(t time.Time, v1, v2 *int) *int, ints ...Ints) error { + if fn == nil { + return errors.New("nil fn") } - if fn == nil { - return fmt.Errorf("nil fn") + if len(ints) == 0 { + return nil } - seq1 := s.slice - for _, seq2 := range slices { + slice1 := s.slice + for _, slice2 := range ints { + if !IsSorted(slice2) { + temp := make(Ints, len(slice2)) + copy(temp, slice2) + Sort(temp) + slice2 = temp + } var got Ints - for i1, i2 := 0, 0; i1 < len(seq1) || i2 < len(seq2); { + for i1, i2 := 0, 0; i1 < len(slice1) || i2 < len(slice2); { var ( t time.Time v *int ) switch { - case i1 == len(seq1): - t = seq2[i2].Time - v2 := seq2[i2].Value + case i1 == len(slice1): + t = slice2[i2].Time + v2 := slice2[i2].Value v = fn(t, nil, &v2) i2++ - case i2 == len(seq2): - t = seq2[i1].Time - v1 := seq1[i1].Value + case i2 == len(slice2): + t = slice2[i1].Time + v1 := slice1[i1].Value v = fn(t, &v1, nil) i1++ - case seq1[i1].Time.Equal(seq2[i2].Time): - t = seq1[i1].Time - v1 := seq1[i1].Value - v2 := seq2[i2].Value + case slice1[i1].Time.Equal(slice2[i2].Time): + t = slice1[i1].Time + v1 := slice1[i1].Value + v2 := slice2[i2].Value v = fn(t, &v1, &v2) i1++ i2++ - case seq1[i1].Time.Before(seq2[i2].Time): - t = seq1[i1].Time - v1 := seq1[i1].Value + case slice1[i1].Time.Before(slice2[i2].Time): + t = slice1[i1].Time + v1 := slice1[i1].Value v = fn(t, &v1, nil) i1++ - case seq1[i1].Time.After(seq2[i2].Time): - t = seq1[i2].Time - v2 := seq2[i2].Value + case slice1[i1].Time.After(slice2[i2].Time): + t = slice1[i2].Time + v2 := slice2[i2].Value v = fn(t, nil, &v2) i2++ } @@ -238,16 +252,78 @@ func (s IntSeq) Merge(fn func(t time.Time, v1, v2 *int) *int, slices ...Ints) er }) } } - seq1 = got + slice1 = got } - return got + s.slice = slice1 + s.buildIndex() + return nil } -func (s IntSeq) Aggregate(fn func(t time.Time, es ...Int) *Int, duration time.Duration) error { - panic("TODO") +func (s *IntSeq) Aggregate(fn func(t time.Time, ints Ints) *int, duration time.Duration, begin, end *time.Time) error { + if fn == nil { + return errors.New("nil fn") + } + + if duration <= 0 { + return errors.New("invalid duration") + } + + var bg, ed time.Time + if len(s.slice) > 0 { + bg = s.slice[0].Time.Truncate(duration) + ed = s.slice[len(s.slice)-1].Time + } + if begin != nil { + bg = (*begin).Truncate(duration) + } + if end != nil { + ed = *end + } + + slice := Ints{} + ints := Ints{} + i := 0 + for t := bg; t.Before(ed); t = t.Add(duration) { + ints = ints[:0] + for i < s.slice.Len() && + !s.slice[i].Time.After(t) && + s.slice[i].Time.Before(t.Add(duration)) { + ints = append(ints, s.slice[i]) + i++ + } + v := fn(t, ints) + if v != nil { + slice = append(slice, Int{ + Time: t, + Value: *v, + }) + } + } + + s.slice = slice + s.buildIndex() + return nil } -func (s IntSeq) Trim(trim func(i int, v Int) bool) error { - panic("TODO") +func (s *IntSeq) Trim(fn func(i int, v Int) bool) error { + if fn == nil { + return errors.New("nil fn") + } + + updated := false + slice := s.slice[:0] + for i, v := range s.slice { + if fn(i, v) { + updated = true + } else { + slice = append(slice, v) + } + } + + if !updated { + s.slice = slice + s.buildIndex() + } + return nil } diff --git a/_draft/v2/int_seq_test.go b/_draft/v2/int_seq_test.go new file mode 100644 index 0000000..617fd59 --- /dev/null +++ b/_draft/v2/int_seq_test.go @@ -0,0 +1,569 @@ +package timeseq + +import ( + "math" + "math/rand" + "reflect" + "testing" + "time" +) + +func RandomInts(length int) Ints { + now := time.Now() + ret := make(Ints, length) + for i := range ret { + delta := time.Duration(i) * time.Second + if rand.Float64() < 0.5 { + delta = -delta + } + ret[i] = Int{ + Time: now.Add(delta), + Value: int(rand.Float64() * float64(math.MaxInt64)), + } + } + return ret +} + +func TestIntSeq_Ints(t *testing.T) { + data := RandomInts(100) + Sort(data) + + tests := []struct { + name string + want Ints + }{ + { + name: "regular", + want: data, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewIntSeq(data) + if got := s.Ints(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Ints() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestIntSeq_Index(t *testing.T) { + data := RandomInts(100) + Sort(data) + + type args struct { + i int + } + tests := []struct { + name string + args args + want Int + }{ + { + name: "regular", + args: args{ + i: 1, + }, + want: data[1], + }, + { + name: "less than zero", + args: args{ + i: -1, + }, + want: Int{}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewIntSeq(data) + if got := s.Index(tt.args.i); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Index() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestIntSeq_Time(t *testing.T) { + now := time.Now() + yesterday := now.AddDate(0, 0, -1) + lastMonth := now.AddDate(0, -1, 0) + lastYear := now.AddDate(-1, 0, 0) + + data := RandomInts(100) + data[0].Time = lastMonth + data[1].Time = lastMonth + data[2].Time = lastMonth + data[3].Time = yesterday + Sort(data) + + type args struct { + t time.Time + } + tests := []struct { + name string + args args + length int + }{ + { + name: "regular", + args: args{ + t: yesterday, + }, + length: 1, + }, + { + name: "multiple", + args: args{ + t: lastMonth, + }, + length: 3, + }, + { + name: "none", + args: args{ + t: lastYear, + }, + length: 0, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewIntSeq(data) + if got := s.Time(tt.args.t); len(got) != tt.length { + t.Errorf("Time() = %v, want %v", got, tt.length) + } + }) + } +} + +func TestIntSeq_Value(t *testing.T) { + data := RandomInts(100) + Sort(data) + + value1 := data[0].Value + value2 := data[1].Value + value3 := data[2].Value + + data[0].Value = value1 + data[1].Value = value2 + data[2].Value = value2 + data[3].Value = value2 + + type args struct { + v int + } + tests := []struct { + name string + args args + length int + }{ + { + name: "regular", + args: args{ + v: value1, + }, + length: 1, + }, + { + name: "multiple", + args: args{ + v: value2, + }, + length: 3, + }, + { + name: "none", + args: args{ + v: value3, + }, + length: 0, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewIntSeq(data) + if got := s.Value(tt.args.v); len(got) != tt.length { + t.Errorf("Value() = %v, want %v", got, tt.length) + } + }) + } +} + +func TestIntSeq_Visit(t *testing.T) { + data := RandomInts(100) + + type args struct { + fn func(i int, v Int) (stop bool) + } + tests := []struct { + name string + args args + }{ + { + name: "regular", + args: args{ + fn: func(i int, v Int) (stop bool) { + return false + }, + }, + }, + { + name: "stop", + args: args{ + fn: func(i int, v Int) (stop bool) { + return i > 10 + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewIntSeq(data) + s.Visit(tt.args.fn) + }) + } +} + +func TestIntSeq_Sum(t *testing.T) { + type fields struct { + slice Ints + timeIndex map[timeKey][]int + valueIndex map[int][]int + valueSlice []int + } + tests := []struct { + name string + fields fields + want int + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := &IntSeq{ + slice: tt.fields.slice, + timeIndex: tt.fields.timeIndex, + valueIndex: tt.fields.valueIndex, + valueSlice: tt.fields.valueSlice, + } + if got := s.Sum(); got != tt.want { + t.Errorf("Sum() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestIntSeq_Count(t *testing.T) { + type fields struct { + slice Ints + timeIndex map[timeKey][]int + valueIndex map[int][]int + valueSlice []int + } + tests := []struct { + name string + fields fields + want int + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := &IntSeq{ + slice: tt.fields.slice, + timeIndex: tt.fields.timeIndex, + valueIndex: tt.fields.valueIndex, + valueSlice: tt.fields.valueSlice, + } + if got := s.Count(); got != tt.want { + t.Errorf("Count() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestIntSeq_Max(t *testing.T) { + type fields struct { + slice Ints + timeIndex map[timeKey][]int + valueIndex map[int][]int + valueSlice []int + } + tests := []struct { + name string + fields fields + want Int + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := &IntSeq{ + slice: tt.fields.slice, + timeIndex: tt.fields.timeIndex, + valueIndex: tt.fields.valueIndex, + valueSlice: tt.fields.valueSlice, + } + if got := s.Max(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Max() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestIntSeq_Min(t *testing.T) { + type fields struct { + slice Ints + timeIndex map[timeKey][]int + valueIndex map[int][]int + valueSlice []int + } + tests := []struct { + name string + fields fields + want Int + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := &IntSeq{ + slice: tt.fields.slice, + timeIndex: tt.fields.timeIndex, + valueIndex: tt.fields.valueIndex, + valueSlice: tt.fields.valueSlice, + } + if got := s.Min(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Min() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestIntSeq_First(t *testing.T) { + type fields struct { + slice Ints + timeIndex map[timeKey][]int + valueIndex map[int][]int + valueSlice []int + } + tests := []struct { + name string + fields fields + want Int + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := &IntSeq{ + slice: tt.fields.slice, + timeIndex: tt.fields.timeIndex, + valueIndex: tt.fields.valueIndex, + valueSlice: tt.fields.valueSlice, + } + if got := s.First(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("First() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestIntSeq_Last(t *testing.T) { + type fields struct { + slice Ints + timeIndex map[timeKey][]int + valueIndex map[int][]int + valueSlice []int + } + tests := []struct { + name string + fields fields + want Int + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := &IntSeq{ + slice: tt.fields.slice, + timeIndex: tt.fields.timeIndex, + valueIndex: tt.fields.valueIndex, + valueSlice: tt.fields.valueSlice, + } + if got := s.Last(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Last() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestIntSeq_Percentile(t *testing.T) { + type fields struct { + slice Ints + timeIndex map[timeKey][]int + valueIndex map[int][]int + valueSlice []int + } + type args struct { + pct float64 + } + tests := []struct { + name string + fields fields + args args + want Int + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := &IntSeq{ + slice: tt.fields.slice, + timeIndex: tt.fields.timeIndex, + valueIndex: tt.fields.valueIndex, + valueSlice: tt.fields.valueSlice, + } + if got := s.Percentile(tt.args.pct); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Percentile() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestIntSeq_Range(t *testing.T) { + type fields struct { + slice Ints + timeIndex map[timeKey][]int + valueIndex map[int][]int + valueSlice []int + } + type args struct { + interval Interval + } + tests := []struct { + name string + fields fields + args args + want *IntSeq + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := &IntSeq{ + slice: tt.fields.slice, + timeIndex: tt.fields.timeIndex, + valueIndex: tt.fields.valueIndex, + valueSlice: tt.fields.valueSlice, + } + if got := s.Range(tt.args.interval); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Range() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestIntSeq_Merge(t *testing.T) { + type fields struct { + slice Ints + timeIndex map[timeKey][]int + valueIndex map[int][]int + valueSlice []int + } + type args struct { + fn func(t time.Time, v1, v2 *int) *int + ints []Ints + } + tests := []struct { + name string + fields fields + args args + wantErr bool + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := &IntSeq{ + slice: tt.fields.slice, + timeIndex: tt.fields.timeIndex, + valueIndex: tt.fields.valueIndex, + valueSlice: tt.fields.valueSlice, + } + if err := s.Merge(tt.args.fn, tt.args.ints...); (err != nil) != tt.wantErr { + t.Errorf("Merge() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} + +func TestIntSeq_Aggregate(t *testing.T) { + type fields struct { + slice Ints + timeIndex map[timeKey][]int + valueIndex map[int][]int + valueSlice []int + } + type args struct { + fn func(t time.Time, ints Ints) *int + duration time.Duration + begin *time.Time + end *time.Time + } + tests := []struct { + name string + fields fields + args args + wantErr bool + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := &IntSeq{ + slice: tt.fields.slice, + timeIndex: tt.fields.timeIndex, + valueIndex: tt.fields.valueIndex, + valueSlice: tt.fields.valueSlice, + } + if err := s.Aggregate(tt.args.fn, tt.args.duration, tt.args.begin, tt.args.end); (err != nil) != tt.wantErr { + t.Errorf("Aggregate() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} + +func TestIntSeq_Trim(t *testing.T) { + type fields struct { + slice Ints + timeIndex map[timeKey][]int + valueIndex map[int][]int + valueSlice []int + } + type args struct { + fn func(i int, v Int) bool + } + tests := []struct { + name string + fields fields + args args + wantErr bool + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := &IntSeq{ + slice: tt.fields.slice, + timeIndex: tt.fields.timeIndex, + valueIndex: tt.fields.valueIndex, + valueSlice: tt.fields.valueSlice, + } + if err := s.Trim(tt.args.fn); (err != nil) != tt.wantErr { + t.Errorf("Trim() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} diff --git a/_draft/v2/timeseq.go b/_draft/v2/timeseq.go index a7c9bd2..9d9915a 100644 --- a/_draft/v2/timeseq.go +++ b/_draft/v2/timeseq.go @@ -2,9 +2,57 @@ package timeseq import ( "encoding/binary" + "sort" "time" ) +type Slice interface { + // return length + Len() int + // swap items + Swap(i, j int) + // return time of item i + Time(i int) time.Time + // return Slice[i:j] + Slice(i, j int) Slice +} + +type sortableSlice struct { + Slice +} + +func (s sortableSlice) Less(i, j int) bool { + return s.Time(i).Before(s.Time(j)) +} + +// Sort will sort slice by time +func Sort(slice Slice) { + sort.Stable(sortableSlice{Slice: slice}) +} + +func IsSorted(slice Slice) bool { + return sort.IsSorted(sortableSlice{Slice: slice}) +} + +func Range(slice Slice, interval Interval) Slice { + i := 0 + if interval.NotBefore != nil { + i = sort.Search(slice.Len(), func(i int) bool { + return !slice.Time(i).Before(*interval.NotBefore) + }) + } + j := slice.Len() + if interval.NotAfter != nil { + j = sort.Search(slice.Len(), func(j int) bool { + return !slice.Time(j).Before(*interval.NotAfter) + }) + if j < slice.Len() && slice.Time(j).Equal(*interval.NotAfter) { + j++ + } + } + return slice.Slice(i, j) +} + type Interval struct { NotBefore *time.Time NotAfter *time.Time From a5ed8cdd15ddce58a0926022e05c5c646ef484b2 Mon Sep 17 00:00:00 2001 From: Jason Song Date: Wed, 23 Sep 2020 17:05:16 +0800 Subject: [PATCH 07/19] feat: generate --- Makefile | 2 +- _draft/v2/int64_seq.go | 331 ++++++++++ _draft/v2/int64_seq_test.go | 225 +++++++ _draft/v2/int_seq_test.go | 569 ------------------ cmd/generate/gen_x_seq.go.tmpl | 331 ++++++++++ ...ce_test.go.tmpl => gen_x_seq_test.go.tmpl} | 0 cmd/generate/main.go | 81 +-- cmd/generate/x_sequence.go.tmpl | 198 ------ gen_float64_seq.go | 332 ++++++++++ gen_int64_seq.go | 332 ++++++++++ _draft/v2/int_seq.go => gen_int_seq.go | 29 +- timeseq.go | 72 +++ 12 files changed, 1681 insertions(+), 821 deletions(-) create mode 100644 _draft/v2/int64_seq.go create mode 100644 _draft/v2/int64_seq_test.go delete mode 100644 _draft/v2/int_seq_test.go create mode 100644 cmd/generate/gen_x_seq.go.tmpl rename cmd/generate/{x_sequence_test.go.tmpl => gen_x_seq_test.go.tmpl} (100%) delete mode 100644 cmd/generate/x_sequence.go.tmpl create mode 100644 gen_float64_seq.go create mode 100644 gen_int64_seq.go rename _draft/v2/int_seq.go => gen_int_seq.go (90%) create mode 100644 timeseq.go diff --git a/Makefile b/Makefile index bd771f0..6ccf521 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ generage: - rm -f *_sequence.go *_sequence_test.go + rm -f gen_*.go go run cmd/generate/main.go diff --git a/_draft/v2/int64_seq.go b/_draft/v2/int64_seq.go new file mode 100644 index 0000000..b889cc9 --- /dev/null +++ b/_draft/v2/int64_seq.go @@ -0,0 +1,331 @@ +package timeseq + +import ( + "errors" + "sort" + "time" +) + +type Int64 struct { + Time time.Time + Value int64 +} + +type Int64s []Int64 + +func (s Int64s) Len() int { + return len(s) +} + +func (s Int64s) Swap(i, j int) { + s[i], s[j] = s[j], s[i] +} + +func (s Int64s) Time(i int) time.Time { + return s[i].Time +} + +func (s Int64s) Slice(i, j int) Slice { + return s[i:j] +} + +type Int64Seq struct { + slice Int64s + timeIndex map[timeKey][]int + valueIndex map[int64][]int + valueSlice []int +} + +func NewInt64Seq(slice Int64s) *Int64Seq { + temp := make(Int64s, len(slice)) + copy(temp, slice) + slice = temp + + Sort(slice) + sort.SliceStable(slice, func(i, j int) bool { + return slice[i].Time.Before(slice[j].Time) + }) + return newInt64Seq(slice) +} + +func newInt64Seq(slice Int64s) *Int64Seq { + ret := &Int64Seq{ + slice: slice, + } + ret.buildIndex() + return ret +} + +func (s *Int64Seq) buildIndex() { + timeIndex := make(map[timeKey][]int, len(s.slice)) + valueIndex := make(map[int64][]int, len(s.slice)) + valueSlice := s.valueSlice[:0] + for i, v := range s.slice { + k := newTimeKey(v.Time) + timeIndex[k] = append(timeIndex[k], i) + valueIndex[v.Value] = append(valueIndex[v.Value], i) + valueSlice = append(valueSlice, i) + } + sort.SliceStable(valueSlice, func(i, j int) bool { + return s.slice[valueSlice[i]].Value < s.slice[valueSlice[j]].Value + }) + s.timeIndex = timeIndex + s.valueIndex = valueIndex + s.valueSlice = valueSlice +} + +func (s *Int64Seq) Int64s() Int64s { + slice := make(Int64s, len(s.slice)) + copy(slice, s.slice) + return slice +} + +func (s *Int64Seq) Index(i int) Int64 { + if i < 0 || i >= len(s.slice) { + return Int64{} + } + return s.slice[i] +} + +func (s *Int64Seq) Time(t time.Time) Int64s { + index := s.timeIndex[newTimeKey(t)] + if len(index) == 0 { + return nil + } + ret := make(Int64s, len(index)) + for i, v := range index { + ret[i] = s.slice[v] + } + return ret +} + +func (s *Int64Seq) Value(v int64) Int64s { + index := s.valueIndex[v] + if len(index) == 0 { + return nil + } + ret := make(Int64s, len(index)) + for i, v := range index { + ret[i] = s.slice[v] + } + return ret +} + +func (s *Int64Seq) Visit(fn func(i int, v Int64) (stop bool)) { + for i, v := range s.slice { + if fn != nil && fn(i, v) { + break + } + } +} + +func (s *Int64Seq) Sum() int64 { + var ret int64 + for _, v := range s.slice { + ret += v.Value + } + return ret +} + +func (s *Int64Seq) Count() int { + return len(s.slice) +} + +func (s *Int64Seq) Max() Int64 { + var max Int64 + found := false + for _, v := range s.slice { + if !found { + max = v + found = true + } else if v.Value < max.Value { + max = v + } + } + return max +} + +func (s *Int64Seq) Min() Int64 { + var min Int64 + found := false + for _, v := range s.slice { + if !found { + min = v + found = true + } else if v.Value < min.Value { + min = v + } + } + return min +} + +func (s *Int64Seq) First() Int64 { + if len(s.slice) == 0 { + return Int64{} + } + return s.slice[0] +} + +func (s *Int64Seq) Last() Int64 { + if len(s.slice) == 0 { + return Int64{} + } + return s.slice[len(s.slice)-1] +} + +func (s *Int64Seq) Percentile(pct float64) Int64 { + if len(s.slice) == 0 { + return Int64{} + } + if pct > 1 { + pct = 1 + } + if pct < 0 { + pct = 0 + } + i := int(float64(len(s.slice))*pct - 1) + if i < 0 { + i = 0 + } + return s.slice[s.valueSlice[i]] +} + +func (s *Int64Seq) Range(interval Interval) *Int64Seq { + slice := Range(s.slice, interval).(Int64s) + return newInt64Seq(slice) +} + +func (s *Int64Seq) Merge(fn func(t time.Time, v1, v2 *int64) *int64, slices ...Int64s) error { + if fn == nil { + return errors.New("nil fn") + } + + if len(slices) == 0 { + return nil + } + + slice1 := s.slice + for _, slice2 := range slices { + if !IsSorted(slice2) { + temp := make(Int64s, len(slice2)) + copy(temp, slice2) + Sort(temp) + slice2 = temp + } + var got Int64s + for i1, i2 := 0, 0; i1 < len(slice1) || i2 < len(slice2); { + var ( + t time.Time + v *int64 + ) + switch { + case i1 == len(slice1): + t = slice2[i2].Time + v2 := slice2[i2].Value + v = fn(t, nil, &v2) + i2++ + case i2 == len(slice2): + t = slice2[i1].Time + v1 := slice1[i1].Value + v = fn(t, &v1, nil) + i1++ + case slice1[i1].Time.Equal(slice2[i2].Time): + t = slice1[i1].Time + v1 := slice1[i1].Value + v2 := slice2[i2].Value + v = fn(t, &v1, &v2) + i1++ + i2++ + case slice1[i1].Time.Before(slice2[i2].Time): + t = slice1[i1].Time + v1 := slice1[i1].Value + v = fn(t, &v1, nil) + i1++ + case slice1[i1].Time.After(slice2[i2].Time): + t = slice1[i2].Time + v2 := slice2[i2].Value + v = fn(t, nil, &v2) + i2++ + } + if v != nil { + got = append(got, Int64{ + Time: t, + Value: *v, + }) + } + } + slice1 = got + } + + s.slice = slice1 + s.buildIndex() + return nil +} + +func (s *Int64Seq) Aggregate(fn func(t time.Time, slice Int64s) *int64, duration time.Duration, begin, end *time.Time) error { + if fn == nil { + return errors.New("nil fn") + } + + if duration <= 0 { + return errors.New("invalid duration") + } + + var bg, ed time.Time + if len(s.slice) > 0 { + bg = s.slice[0].Time.Truncate(duration) + ed = s.slice[len(s.slice)-1].Time + } + if begin != nil { + bg = (*begin).Truncate(duration) + } + if end != nil { + ed = *end + } + + got := Int64s{} + slice := Int64s{} + i := 0 + for t := bg; t.Before(ed); t = t.Add(duration) { + slice = slice[:0] + for i < s.slice.Len() && + !s.slice[i].Time.After(t) && + s.slice[i].Time.Before(t.Add(duration)) { + slice = append(slice, s.slice[i]) + i++ + } + v := fn(t, slice) + if v != nil { + got = append(got, Int64{ + Time: t, + Value: *v, + }) + } + } + + s.slice = got + s.buildIndex() + return nil +} + +func (s *Int64Seq) Trim(fn func(i int, v Int64) bool) error { + if fn == nil { + return errors.New("nil fn") + } + + updated := false + slice := s.slice[:0] + for i, v := range s.slice { + if fn(i, v) { + updated = true + } else { + slice = append(slice, v) + } + } + + if !updated { + s.slice = slice + s.buildIndex() + } + return nil +} diff --git a/_draft/v2/int64_seq_test.go b/_draft/v2/int64_seq_test.go new file mode 100644 index 0000000..7da9d38 --- /dev/null +++ b/_draft/v2/int64_seq_test.go @@ -0,0 +1,225 @@ +package timeseq + +import ( + "math/rand" + "reflect" + "testing" + "time" +) + +func RandomInt64s(length int) Int64s { + now := time.Now() + ret := make(Int64s, length) + for i := range ret { + delta := time.Duration(i) * time.Second + if rand.Float64() < 0.5 { + delta = -delta + } + ret[i] = Int64{ + Time: now.Add(delta), + Value: rand.Int63(), + } + } + return ret +} + +func TestInt64Seq_Int64s(t *testing.T) { + data := RandomInt64s(100) + Sort(data) + + tests := []struct { + name string + want Int64s + }{ + { + name: "regular", + want: data, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewInt64Seq(data) + if got := s.Int64s(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Int64s() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestInt64Seq_Index(t *testing.T) { + data := RandomInt64s(100) + Sort(data) + + type args struct { + i int + } + tests := []struct { + name string + args args + want Int64 + }{ + { + name: "regular", + args: args{ + i: 1, + }, + want: data[1], + }, + { + name: "less than zero", + args: args{ + i: -1, + }, + want: Int64{}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewInt64Seq(data) + if got := s.Index(tt.args.i); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Index() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestInt64Seq_Time(t *testing.T) { + now := time.Now() + yesterday := now.AddDate(0, 0, -1) + lastMonth := now.AddDate(0, -1, 0) + lastYear := now.AddDate(-1, 0, 0) + + data := RandomInt64s(100) + data[0].Time = lastMonth + data[1].Time = lastMonth + data[2].Time = lastMonth + data[3].Time = yesterday + Sort(data) + + type args struct { + t time.Time + } + tests := []struct { + name string + args args + length int + }{ + { + name: "regular", + args: args{ + t: yesterday, + }, + length: 1, + }, + { + name: "multiple", + args: args{ + t: lastMonth, + }, + length: 3, + }, + { + name: "none", + args: args{ + t: lastYear, + }, + length: 0, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewInt64Seq(data) + if got := s.Time(tt.args.t); len(got) != tt.length { + t.Errorf("Time() = %v, want %v", got, tt.length) + } + }) + } +} + +func TestInt64Seq_Value(t *testing.T) { + data := RandomInt64s(100) + Sort(data) + + value1 := data[0].Value + value2 := data[1].Value + value3 := data[2].Value + + data[0].Value = value1 + data[1].Value = value2 + data[2].Value = value2 + data[3].Value = value2 + + type args struct { + v int64 + } + tests := []struct { + name string + args args + length int + }{ + { + name: "regular", + args: args{ + v: value1, + }, + length: 1, + }, + { + name: "multiple", + args: args{ + v: value2, + }, + length: 3, + }, + { + name: "none", + args: args{ + v: value3, + }, + length: 0, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewInt64Seq(data) + if got := s.Value(tt.args.v); len(got) != tt.length { + t.Errorf("Value() = %v, want %v", got, tt.length) + } + }) + } +} + +func TestInt64Seq_Visit(t *testing.T) { + data := RandomInt64s(100) + + type args struct { + fn func(i int, v Int64) (stop bool) + } + tests := []struct { + name string + args args + }{ + { + name: "regular", + args: args{ + fn: func(i int, v Int64) (stop bool) { + return false + }, + }, + }, + { + name: "stop", + args: args{ + fn: func(i int, v Int64) (stop bool) { + return i > 10 + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewInt64Seq(data) + s.Visit(tt.args.fn) + }) + } +} diff --git a/_draft/v2/int_seq_test.go b/_draft/v2/int_seq_test.go deleted file mode 100644 index 617fd59..0000000 --- a/_draft/v2/int_seq_test.go +++ /dev/null @@ -1,569 +0,0 @@ -package timeseq - -import ( - "math" - "math/rand" - "reflect" - "testing" - "time" -) - -func RandomInts(length int) Ints { - now := time.Now() - ret := make(Ints, length) - for i := range ret { - delta := time.Duration(i) * time.Second - if rand.Float64() < 0.5 { - delta = -delta - } - ret[i] = Int{ - Time: now.Add(delta), - Value: int(rand.Float64() * float64(math.MaxInt64)), - } - } - return ret -} - -func TestIntSeq_Ints(t *testing.T) { - data := RandomInts(100) - Sort(data) - - tests := []struct { - name string - want Ints - }{ - { - name: "regular", - want: data, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := NewIntSeq(data) - if got := s.Ints(); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Ints() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestIntSeq_Index(t *testing.T) { - data := RandomInts(100) - Sort(data) - - type args struct { - i int - } - tests := []struct { - name string - args args - want Int - }{ - { - name: "regular", - args: args{ - i: 1, - }, - want: data[1], - }, - { - name: "less than zero", - args: args{ - i: -1, - }, - want: Int{}, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := NewIntSeq(data) - if got := s.Index(tt.args.i); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Index() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestIntSeq_Time(t *testing.T) { - now := time.Now() - yesterday := now.AddDate(0, 0, -1) - lastMonth := now.AddDate(0, -1, 0) - lastYear := now.AddDate(-1, 0, 0) - - data := RandomInts(100) - data[0].Time = lastMonth - data[1].Time = lastMonth - data[2].Time = lastMonth - data[3].Time = yesterday - Sort(data) - - type args struct { - t time.Time - } - tests := []struct { - name string - args args - length int - }{ - { - name: "regular", - args: args{ - t: yesterday, - }, - length: 1, - }, - { - name: "multiple", - args: args{ - t: lastMonth, - }, - length: 3, - }, - { - name: "none", - args: args{ - t: lastYear, - }, - length: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := NewIntSeq(data) - if got := s.Time(tt.args.t); len(got) != tt.length { - t.Errorf("Time() = %v, want %v", got, tt.length) - } - }) - } -} - -func TestIntSeq_Value(t *testing.T) { - data := RandomInts(100) - Sort(data) - - value1 := data[0].Value - value2 := data[1].Value - value3 := data[2].Value - - data[0].Value = value1 - data[1].Value = value2 - data[2].Value = value2 - data[3].Value = value2 - - type args struct { - v int - } - tests := []struct { - name string - args args - length int - }{ - { - name: "regular", - args: args{ - v: value1, - }, - length: 1, - }, - { - name: "multiple", - args: args{ - v: value2, - }, - length: 3, - }, - { - name: "none", - args: args{ - v: value3, - }, - length: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := NewIntSeq(data) - if got := s.Value(tt.args.v); len(got) != tt.length { - t.Errorf("Value() = %v, want %v", got, tt.length) - } - }) - } -} - -func TestIntSeq_Visit(t *testing.T) { - data := RandomInts(100) - - type args struct { - fn func(i int, v Int) (stop bool) - } - tests := []struct { - name string - args args - }{ - { - name: "regular", - args: args{ - fn: func(i int, v Int) (stop bool) { - return false - }, - }, - }, - { - name: "stop", - args: args{ - fn: func(i int, v Int) (stop bool) { - return i > 10 - }, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := NewIntSeq(data) - s.Visit(tt.args.fn) - }) - } -} - -func TestIntSeq_Sum(t *testing.T) { - type fields struct { - slice Ints - timeIndex map[timeKey][]int - valueIndex map[int][]int - valueSlice []int - } - tests := []struct { - name string - fields fields - want int - }{ - // TODO: Add test cases. - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := &IntSeq{ - slice: tt.fields.slice, - timeIndex: tt.fields.timeIndex, - valueIndex: tt.fields.valueIndex, - valueSlice: tt.fields.valueSlice, - } - if got := s.Sum(); got != tt.want { - t.Errorf("Sum() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestIntSeq_Count(t *testing.T) { - type fields struct { - slice Ints - timeIndex map[timeKey][]int - valueIndex map[int][]int - valueSlice []int - } - tests := []struct { - name string - fields fields - want int - }{ - // TODO: Add test cases. - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := &IntSeq{ - slice: tt.fields.slice, - timeIndex: tt.fields.timeIndex, - valueIndex: tt.fields.valueIndex, - valueSlice: tt.fields.valueSlice, - } - if got := s.Count(); got != tt.want { - t.Errorf("Count() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestIntSeq_Max(t *testing.T) { - type fields struct { - slice Ints - timeIndex map[timeKey][]int - valueIndex map[int][]int - valueSlice []int - } - tests := []struct { - name string - fields fields - want Int - }{ - // TODO: Add test cases. - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := &IntSeq{ - slice: tt.fields.slice, - timeIndex: tt.fields.timeIndex, - valueIndex: tt.fields.valueIndex, - valueSlice: tt.fields.valueSlice, - } - if got := s.Max(); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Max() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestIntSeq_Min(t *testing.T) { - type fields struct { - slice Ints - timeIndex map[timeKey][]int - valueIndex map[int][]int - valueSlice []int - } - tests := []struct { - name string - fields fields - want Int - }{ - // TODO: Add test cases. - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := &IntSeq{ - slice: tt.fields.slice, - timeIndex: tt.fields.timeIndex, - valueIndex: tt.fields.valueIndex, - valueSlice: tt.fields.valueSlice, - } - if got := s.Min(); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Min() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestIntSeq_First(t *testing.T) { - type fields struct { - slice Ints - timeIndex map[timeKey][]int - valueIndex map[int][]int - valueSlice []int - } - tests := []struct { - name string - fields fields - want Int - }{ - // TODO: Add test cases. - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := &IntSeq{ - slice: tt.fields.slice, - timeIndex: tt.fields.timeIndex, - valueIndex: tt.fields.valueIndex, - valueSlice: tt.fields.valueSlice, - } - if got := s.First(); !reflect.DeepEqual(got, tt.want) { - t.Errorf("First() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestIntSeq_Last(t *testing.T) { - type fields struct { - slice Ints - timeIndex map[timeKey][]int - valueIndex map[int][]int - valueSlice []int - } - tests := []struct { - name string - fields fields - want Int - }{ - // TODO: Add test cases. - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := &IntSeq{ - slice: tt.fields.slice, - timeIndex: tt.fields.timeIndex, - valueIndex: tt.fields.valueIndex, - valueSlice: tt.fields.valueSlice, - } - if got := s.Last(); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Last() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestIntSeq_Percentile(t *testing.T) { - type fields struct { - slice Ints - timeIndex map[timeKey][]int - valueIndex map[int][]int - valueSlice []int - } - type args struct { - pct float64 - } - tests := []struct { - name string - fields fields - args args - want Int - }{ - // TODO: Add test cases. - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := &IntSeq{ - slice: tt.fields.slice, - timeIndex: tt.fields.timeIndex, - valueIndex: tt.fields.valueIndex, - valueSlice: tt.fields.valueSlice, - } - if got := s.Percentile(tt.args.pct); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Percentile() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestIntSeq_Range(t *testing.T) { - type fields struct { - slice Ints - timeIndex map[timeKey][]int - valueIndex map[int][]int - valueSlice []int - } - type args struct { - interval Interval - } - tests := []struct { - name string - fields fields - args args - want *IntSeq - }{ - // TODO: Add test cases. - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := &IntSeq{ - slice: tt.fields.slice, - timeIndex: tt.fields.timeIndex, - valueIndex: tt.fields.valueIndex, - valueSlice: tt.fields.valueSlice, - } - if got := s.Range(tt.args.interval); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Range() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestIntSeq_Merge(t *testing.T) { - type fields struct { - slice Ints - timeIndex map[timeKey][]int - valueIndex map[int][]int - valueSlice []int - } - type args struct { - fn func(t time.Time, v1, v2 *int) *int - ints []Ints - } - tests := []struct { - name string - fields fields - args args - wantErr bool - }{ - // TODO: Add test cases. - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := &IntSeq{ - slice: tt.fields.slice, - timeIndex: tt.fields.timeIndex, - valueIndex: tt.fields.valueIndex, - valueSlice: tt.fields.valueSlice, - } - if err := s.Merge(tt.args.fn, tt.args.ints...); (err != nil) != tt.wantErr { - t.Errorf("Merge() error = %v, wantErr %v", err, tt.wantErr) - } - }) - } -} - -func TestIntSeq_Aggregate(t *testing.T) { - type fields struct { - slice Ints - timeIndex map[timeKey][]int - valueIndex map[int][]int - valueSlice []int - } - type args struct { - fn func(t time.Time, ints Ints) *int - duration time.Duration - begin *time.Time - end *time.Time - } - tests := []struct { - name string - fields fields - args args - wantErr bool - }{ - // TODO: Add test cases. - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := &IntSeq{ - slice: tt.fields.slice, - timeIndex: tt.fields.timeIndex, - valueIndex: tt.fields.valueIndex, - valueSlice: tt.fields.valueSlice, - } - if err := s.Aggregate(tt.args.fn, tt.args.duration, tt.args.begin, tt.args.end); (err != nil) != tt.wantErr { - t.Errorf("Aggregate() error = %v, wantErr %v", err, tt.wantErr) - } - }) - } -} - -func TestIntSeq_Trim(t *testing.T) { - type fields struct { - slice Ints - timeIndex map[timeKey][]int - valueIndex map[int][]int - valueSlice []int - } - type args struct { - fn func(i int, v Int) bool - } - tests := []struct { - name string - fields fields - args args - wantErr bool - }{ - // TODO: Add test cases. - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := &IntSeq{ - slice: tt.fields.slice, - timeIndex: tt.fields.timeIndex, - valueIndex: tt.fields.valueIndex, - valueSlice: tt.fields.valueSlice, - } - if err := s.Trim(tt.args.fn); (err != nil) != tt.wantErr { - t.Errorf("Trim() error = %v, wantErr %v", err, tt.wantErr) - } - }) - } -} diff --git a/cmd/generate/gen_x_seq.go.tmpl b/cmd/generate/gen_x_seq.go.tmpl new file mode 100644 index 0000000..648f545 --- /dev/null +++ b/cmd/generate/gen_x_seq.go.tmpl @@ -0,0 +1,331 @@ +package timeseq + +import ( + "errors" + "sort" + "time" +) + +type {{.Name}} struct { + Time time.Time + Value {{.Type}} +} + +type {{.Name}}s []{{.Name}} + +func (s {{.Name}}s) Len() int { + return len(s) +} + +func (s {{.Name}}s) Swap(i, j int) { + s[i], s[j] = s[j], s[i] +} + +func (s {{.Name}}s) Time(i int) time.Time { + return s[i].Time +} + +func (s {{.Name}}s) Slice(i, j int) Slice { + return s[i:j] +} + +type {{.Name}}Seq struct { + slice {{.Name}}s + timeIndex map[timeKey][]int + valueIndex map[{{.Type}}][]int + valueSlice []int +} + +func New{{.Name}}Seq(slice {{.Name}}s) *{{.Name}}Seq { + temp := make({{.Name}}s, len(slice)) + copy(temp, slice) + slice = temp + + Sort(slice) + sort.SliceStable(slice, func(i, j int) bool { + return slice[i].Time.Before(slice[j].Time) + }) + return new{{.Name}}Seq(slice) +} + +func new{{.Name}}Seq(slice {{.Name}}s) *{{.Name}}Seq { + ret := &{{.Name}}Seq{ + slice: slice, + } + ret.buildIndex() + return ret +} + +func (s *{{.Name}}Seq) buildIndex() { + timeIndex := make(map[timeKey][]int, len(s.slice)) + valueIndex := make(map[{{.Type}}][]int, len(s.slice)) + valueSlice := s.valueSlice[:0] + for i, v := range s.slice { + k := newTimeKey(v.Time) + timeIndex[k] = append(timeIndex[k], i) + valueIndex[v.Value] = append(valueIndex[v.Value], i) + valueSlice = append(valueSlice, i) + } + sort.SliceStable(valueSlice, func(i, j int) bool { + return s.slice[valueSlice[i]].Value < s.slice[valueSlice[j]].Value + }) + s.timeIndex = timeIndex + s.valueIndex = valueIndex + s.valueSlice = valueSlice +} + +func (s *{{.Name}}Seq) {{.Name}}s() {{.Name}}s { + slice := make({{.Name}}s, len(s.slice)) + copy(slice, s.slice) + return slice +} + +func (s *{{.Name}}Seq) Index(i int) {{.Name}} { + if i < 0 || i >= len(s.slice) { + return {{.Name}}{} + } + return s.slice[i] +} + +func (s *{{.Name}}Seq) Time(t time.Time) {{.Name}}s { + index := s.timeIndex[newTimeKey(t)] + if len(index) == 0 { + return nil + } + ret := make({{.Name}}s, len(index)) + for i, v := range index { + ret[i] = s.slice[v] + } + return ret +} + +func (s *{{.Name}}Seq) Value(v {{.Type}}) {{.Name}}s { + index := s.valueIndex[v] + if len(index) == 0 { + return nil + } + ret := make({{.Name}}s, len(index)) + for i, v := range index { + ret[i] = s.slice[v] + } + return ret +} + +func (s *{{.Name}}Seq) Visit(fn func(i int, v {{.Name}}) (stop bool)) { + for i, v := range s.slice { + if fn != nil && fn(i, v) { + break + } + } +} + +func (s *{{.Name}}Seq) Sum() {{.Type}} { + var ret {{.Type}} + for _, v := range s.slice { + ret += v.Value + } + return ret +} + +func (s *{{.Name}}Seq) Count() int { + return len(s.slice) +} + +func (s *{{.Name}}Seq) Max() {{.Name}} { + var max {{.Name}} + found := false + for _, v := range s.slice { + if !found { + max = v + found = true + } else if v.Value < max.Value { + max = v + } + } + return max +} + +func (s *{{.Name}}Seq) Min() {{.Name}} { + var min {{.Name}} + found := false + for _, v := range s.slice { + if !found { + min = v + found = true + } else if v.Value < min.Value { + min = v + } + } + return min +} + +func (s *{{.Name}}Seq) First() {{.Name}} { + if len(s.slice) == 0 { + return {{.Name}}{} + } + return s.slice[0] +} + +func (s *{{.Name}}Seq) Last() {{.Name}} { + if len(s.slice) == 0 { + return {{.Name}}{} + } + return s.slice[len(s.slice)-1] +} + +func (s *{{.Name}}Seq) Percentile(pct float64) {{.Name}} { + if len(s.slice) == 0 { + return {{.Name}}{} + } + if pct > 1 { + pct = 1 + } + if pct < 0 { + pct = 0 + } + i := int(float64(len(s.slice))*pct - 1) + if i < 0 { + i = 0 + } + return s.slice[s.valueSlice[i]] +} + +func (s *{{.Name}}Seq) Range(interval Interval) *{{.Name}}Seq { + slice := Range(s.slice, interval).({{.Name}}s) + return new{{.Name}}Seq(slice) +} + +func (s *{{.Name}}Seq) Merge(fn func(t time.Time, v1, v2 *{{.Type}}) *{{.Type}}, slices ...{{.Name}}s) error { + if fn == nil { + return errors.New("nil fn") + } + + if len(slices) == 0 { + return nil + } + + slice1 := s.slice + for _, slice2 := range slices { + if !IsSorted(slice2) { + temp := make({{.Name}}s, len(slice2)) + copy(temp, slice2) + Sort(temp) + slice2 = temp + } + var got {{.Name}}s + for i1, i2 := 0, 0; i1 < len(slice1) || i2 < len(slice2); { + var ( + t time.Time + v *{{.Type}} + ) + switch { + case i1 == len(slice1): + t = slice2[i2].Time + v2 := slice2[i2].Value + v = fn(t, nil, &v2) + i2++ + case i2 == len(slice2): + t = slice2[i1].Time + v1 := slice1[i1].Value + v = fn(t, &v1, nil) + i1++ + case slice1[i1].Time.Equal(slice2[i2].Time): + t = slice1[i1].Time + v1 := slice1[i1].Value + v2 := slice2[i2].Value + v = fn(t, &v1, &v2) + i1++ + i2++ + case slice1[i1].Time.Before(slice2[i2].Time): + t = slice1[i1].Time + v1 := slice1[i1].Value + v = fn(t, &v1, nil) + i1++ + case slice1[i1].Time.After(slice2[i2].Time): + t = slice1[i2].Time + v2 := slice2[i2].Value + v = fn(t, nil, &v2) + i2++ + } + if v != nil { + got = append(got, {{.Name}}{ + Time: t, + Value: *v, + }) + } + } + slice1 = got + } + + s.slice = slice1 + s.buildIndex() + return nil +} + +func (s *{{.Name}}Seq) Aggregate(fn func(t time.Time, slice {{.Name}}s) *{{.Type}}, duration time.Duration, begin, end *time.Time) error { + if fn == nil { + return errors.New("nil fn") + } + + if duration <= 0 { + return errors.New("invalid duration") + } + + var bg, ed time.Time + if len(s.slice) > 0 { + bg = s.slice[0].Time.Truncate(duration) + ed = s.slice[len(s.slice)-1].Time + } + if begin != nil { + bg = (*begin).Truncate(duration) + } + if end != nil { + ed = *end + } + + got := {{.Name}}s{} + slice := {{.Name}}s{} + i := 0 + for t := bg; t.Before(ed); t = t.Add(duration) { + slice = slice[:0] + for i < s.slice.Len() && + !s.slice[i].Time.After(t) && + s.slice[i].Time.Before(t.Add(duration)) { + slice = append(slice, s.slice[i]) + i++ + } + v := fn(t, slice) + if v != nil { + got = append(got, {{.Name}}{ + Time: t, + Value: *v, + }) + } + } + + s.slice = got + s.buildIndex() + return nil +} + +func (s *{{.Name}}Seq) Trim(fn func(i int, v {{.Name}}) bool) error { + if fn == nil { + return errors.New("nil fn") + } + + updated := false + slice := s.slice[:0] + for i, v := range s.slice { + if fn(i, v) { + updated = true + } else { + slice = append(slice, v) + } + } + + if !updated { + s.slice = slice + s.buildIndex() + } + return nil +} diff --git a/cmd/generate/x_sequence_test.go.tmpl b/cmd/generate/gen_x_seq_test.go.tmpl similarity index 100% rename from cmd/generate/x_sequence_test.go.tmpl rename to cmd/generate/gen_x_seq_test.go.tmpl diff --git a/cmd/generate/main.go b/cmd/generate/main.go index 825b28e..3742049 100644 --- a/cmd/generate/main.go +++ b/cmd/generate/main.go @@ -5,53 +5,54 @@ import ( "fmt" "go/format" "io/ioutil" - "strings" "text/template" ) type Meta struct { - Name string - Type string + Name string + Type string + Random string } func main() { - tmpl, err := template.ParseFiles("cmd/generate/x_sequence.go.tmpl") + tmpl, err := template.ParseFiles("cmd/generate/gen_x_seq.go.tmpl") if err != nil { panic(err) } - testTmpl, err := template.ParseFiles("cmd/generate/x_sequence_test.go.tmpl") + testTmpl, err := template.ParseFiles("cmd/generate/gen_x_seq_test.go.tmpl") if err != nil { panic(err) } - types := []string{ - //"uint8", - //"uint16", - "uint32", - "uint64", - //"int8", - //"int16", - "int32", - "int64", - "float32", - "float64", - "int", - "uint", - "int32", + metas := []Meta{ + { + Name: "Int64", + Type: "int64", + Random: "rand.Int63()", + }, + { + Name: "Float64", + Type: "float64", + Random: "rand.Float64()", + }, + { + Name: "Int", + Type: "int", + Random: "rand.Int()", + }, + // TODO more types } - for _, v := range types { - generate(tmpl, testTmpl, Meta{ - Name: strings.Title(v), - Type: v, - }) + for _, v := range metas { + generate(tmpl, testTmpl, v) } } func generate(tmpl, testTmpl *template.Template, meta Meta) { { output := &bytes.Buffer{} + output.WriteString("// Code generated by cmd/generate. DO NOT EDIT.\n") if err := tmpl.Execute(output, meta); err != nil { panic(err) } @@ -61,23 +62,23 @@ func generate(tmpl, testTmpl *template.Template, meta Meta) { panic(err) } - if err := ioutil.WriteFile(fmt.Sprintf("%s_sequence.go", meta.Type), src, 0666); err != nil { - panic(err) - } - } - { - output := &bytes.Buffer{} - if err := testTmpl.Execute(output, meta); err != nil { - panic(err) - } - - src, err := format.Source(output.Bytes()) - if err != nil { - panic(err) - } - - if err := ioutil.WriteFile(fmt.Sprintf("%s_sequence_test.go", meta.Type), src, 0666); err != nil { + if err := ioutil.WriteFile(fmt.Sprintf("gen_%s_seq.go", meta.Type), src, 0666); err != nil { panic(err) } } + //{ + // output := &bytes.Buffer{} + // if err := testTmpl.Execute(output, meta); err != nil { + // panic(err) + // } + // + // src, err := format.Source(output.Bytes()) + // if err != nil { + // panic(err) + // } + // + // if err := ioutil.WriteFile(fmt.Sprintf("%s_sequence_test.go", meta.Type), src, 0666); err != nil { + // panic(err) + // } + //} } diff --git a/cmd/generate/x_sequence.go.tmpl b/cmd/generate/x_sequence.go.tmpl deleted file mode 100644 index 3d3b00b..0000000 --- a/cmd/generate/x_sequence.go.tmpl +++ /dev/null @@ -1,198 +0,0 @@ -// Code generated by cmd/generate. DO NOT EDIT. - -package timeseq - -import ( - "errors" - "sort" - "time" -) - -// {{.Name}}Item is item of {{.Name}}Sequence -type {{.Name}}Item struct { - Time time.Time - Value {{.Type}} -} - -// {{.Name}}Sequence is the implement of Sequence for {{.Type}} -type {{.Name}}Sequence []{{.Name}}Item - -// Len implements Sequence.Len -func (s {{.Name}}Sequence) Len() int { - return len(s) -} - -// Swap implements Sequence.Swap -func (s {{.Name}}Sequence) Swap(i, j int) { - s[i], s[j] = s[j], s[i] -} - -// Time implements Sequence.Time -func (s {{.Name}}Sequence) Time(i int) time.Time { - return s[i].Time -} - -// Slice implements Sequence.Slice -func (s {{.Name}}Sequence) Slice(i, j int) Sequence { - return s[i:j] -} - -// Sort will sort sequence by time -func (s {{.Name}}Sequence) Sort() { - Sort(s) -} - -// Range return sub sequence, would sort sequence if it is not sorted -func (s {{.Name}}Sequence) Range(afterOrEqual, beforeOrEqual *time.Time) {{.Name}}Sequence { - if !sort.IsSorted(sortableSequence{s}) { - s.Sort() - } - return Range(s, afterOrEqual, beforeOrEqual).({{.Name}}Sequence) -} - -// First return the first item or nil if not exists, would sort sequence if it is not sorted -func (s {{.Name}}Sequence) First(afterOrEqual *time.Time) *{{.Name}}Item { - if !sort.IsSorted(sortableSequence{s}) { - s.Sort() - } - i := First(s, afterOrEqual) - if i < 0 { - return nil - } - ret := s[i] - return &ret -} - -// Last return the last item or nil if not exists, would sort sequence if it is not sorted -func (s {{.Name}}Sequence) Last(beforeOrEqual *time.Time) *{{.Name}}Item { - if !sort.IsSorted(sortableSequence{s}) { - s.Sort() - } - i := Last(s, beforeOrEqual) - if i < 0 { - return nil - } - ret := s[i] - return &ret -} - -// Max return the first item which has the max value, or nil if not exists -func (s {{.Name}}Sequence) Max() *{{.Name}}Item { - var max *{{.Name}}Item - for i, v := range s { - if max == nil { - max = &s[i] - } else if v.Value > max.Value { - max = &s[i] - } - } - if max != nil { - value := *max - max = &value - } - return max -} - -// Min return the first item which has the min value, or nil if not exists -func (s {{.Name}}Sequence) Min() *{{.Name}}Item { - var min *{{.Name}}Item - for i, v := range s { - if min == nil { - min = &s[i] - } else if v.Value < min.Value { - min = &s[i] - } - } - if min != nil { - value := *min - min = &value - } - return min -} - -// Sum return the value's sum -func (s {{.Name}}Sequence) Sum() {{.Type}} { - var sum {{.Type}} - for _, v := range s { - sum += v.Value - } - return sum -} - -// Average return the value's average -func (s {{.Name}}Sequence) Average() {{.Type}} { - if len(s) == 0 { - return 0 - } - - return {{.Type}}(float64(s.Sum()) / float64(len(s))) -} - -// Percentile return (pct)th percentile -func (s {{.Name}}Sequence) Percentile(pct float64) {{.Type}} { - if pct > 1 || pct < 0 { - panic(errors.New("percentile must be [0, 1]")) - } - - var values []{{.Type}} - for _, v := range s { - values = append(values, v.Value) - } - sort.Slice(values, func(i, j int) bool { - return values[i] < values[j] - }) - - if len(values) == 0 { - return 0 - } - - index := int(float64(len(s))*pct - 1) - if index < 0 { - index = 0 - } - - return values[index] -} - - -// Merge{{.Name}} merge two {{.Type}}} seuquence into one -func Merge{{.Name}}(seq1, seq2 {{.Name}}Sequence, fn func(item1, item2 *{{.Name}}Item) *{{.Name}}Item) {{.Name}}Sequence { - if fn == nil { - return nil - } - - var ret {{.Name}}Sequence - for i1, i2 := 0, 0; i1 < seq1.Len() || i2 < seq2.Len(); { - var item *{{.Name}}Item - switch { - case i1 == seq1.Len(): - v2 := seq2[i2] - item = fn(nil, &v2) - i2++ - case i2 == seq2.Len(): - v1 := seq1[i1] - item = fn(&v1, nil) - i1++ - case seq1[i1].Time.Equal(seq2[i2].Time): - v1 := seq1[i1] - v2 := seq2[i2] - item = fn(&v1, &v2) - i1++ - i2++ - case seq1[i1].Time.Before(seq2[i2].Time): - v1 := seq1[i1] - item = fn(&v1, nil) - i1++ - case seq1[i1].Time.After(seq2[i2].Time): - v2 := seq2[i2] - item = fn(nil, &v2) - i2++ - } - if item != nil { - ret = append(ret, *item) - } - } - - Sort(ret) - return ret -} diff --git a/gen_float64_seq.go b/gen_float64_seq.go new file mode 100644 index 0000000..c85765c --- /dev/null +++ b/gen_float64_seq.go @@ -0,0 +1,332 @@ +// Code generated by cmd/generate. DO NOT EDIT. +package timeseq + +import ( + "errors" + "sort" + "time" +) + +type Float64 struct { + Time time.Time + Value float64 +} + +type Float64s []Float64 + +func (s Float64s) Len() int { + return len(s) +} + +func (s Float64s) Swap(i, j int) { + s[i], s[j] = s[j], s[i] +} + +func (s Float64s) Time(i int) time.Time { + return s[i].Time +} + +func (s Float64s) Slice(i, j int) Slice { + return s[i:j] +} + +type Float64Seq struct { + slice Float64s + timeIndex map[timeKey][]int + valueIndex map[float64][]int + valueSlice []int +} + +func NewFloat64Seq(slice Float64s) *Float64Seq { + temp := make(Float64s, len(slice)) + copy(temp, slice) + slice = temp + + Sort(slice) + sort.SliceStable(slice, func(i, j int) bool { + return slice[i].Time.Before(slice[j].Time) + }) + return newFloat64Seq(slice) +} + +func newFloat64Seq(slice Float64s) *Float64Seq { + ret := &Float64Seq{ + slice: slice, + } + ret.buildIndex() + return ret +} + +func (s *Float64Seq) buildIndex() { + timeIndex := make(map[timeKey][]int, len(s.slice)) + valueIndex := make(map[float64][]int, len(s.slice)) + valueSlice := s.valueSlice[:0] + for i, v := range s.slice { + k := newTimeKey(v.Time) + timeIndex[k] = append(timeIndex[k], i) + valueIndex[v.Value] = append(valueIndex[v.Value], i) + valueSlice = append(valueSlice, i) + } + sort.SliceStable(valueSlice, func(i, j int) bool { + return s.slice[valueSlice[i]].Value < s.slice[valueSlice[j]].Value + }) + s.timeIndex = timeIndex + s.valueIndex = valueIndex + s.valueSlice = valueSlice +} + +func (s *Float64Seq) Float64s() Float64s { + slice := make(Float64s, len(s.slice)) + copy(slice, s.slice) + return slice +} + +func (s *Float64Seq) Index(i int) Float64 { + if i < 0 || i >= len(s.slice) { + return Float64{} + } + return s.slice[i] +} + +func (s *Float64Seq) Time(t time.Time) Float64s { + index := s.timeIndex[newTimeKey(t)] + if len(index) == 0 { + return nil + } + ret := make(Float64s, len(index)) + for i, v := range index { + ret[i] = s.slice[v] + } + return ret +} + +func (s *Float64Seq) Value(v float64) Float64s { + index := s.valueIndex[v] + if len(index) == 0 { + return nil + } + ret := make(Float64s, len(index)) + for i, v := range index { + ret[i] = s.slice[v] + } + return ret +} + +func (s *Float64Seq) Visit(fn func(i int, v Float64) (stop bool)) { + for i, v := range s.slice { + if fn != nil && fn(i, v) { + break + } + } +} + +func (s *Float64Seq) Sum() float64 { + var ret float64 + for _, v := range s.slice { + ret += v.Value + } + return ret +} + +func (s *Float64Seq) Count() int { + return len(s.slice) +} + +func (s *Float64Seq) Max() Float64 { + var max Float64 + found := false + for _, v := range s.slice { + if !found { + max = v + found = true + } else if v.Value < max.Value { + max = v + } + } + return max +} + +func (s *Float64Seq) Min() Float64 { + var min Float64 + found := false + for _, v := range s.slice { + if !found { + min = v + found = true + } else if v.Value < min.Value { + min = v + } + } + return min +} + +func (s *Float64Seq) First() Float64 { + if len(s.slice) == 0 { + return Float64{} + } + return s.slice[0] +} + +func (s *Float64Seq) Last() Float64 { + if len(s.slice) == 0 { + return Float64{} + } + return s.slice[len(s.slice)-1] +} + +func (s *Float64Seq) Percentile(pct float64) Float64 { + if len(s.slice) == 0 { + return Float64{} + } + if pct > 1 { + pct = 1 + } + if pct < 0 { + pct = 0 + } + i := int(float64(len(s.slice))*pct - 1) + if i < 0 { + i = 0 + } + return s.slice[s.valueSlice[i]] +} + +func (s *Float64Seq) Range(interval Interval) *Float64Seq { + slice := Range(s.slice, interval).(Float64s) + return newFloat64Seq(slice) +} + +func (s *Float64Seq) Merge(fn func(t time.Time, v1, v2 *float64) *float64, slices ...Float64s) error { + if fn == nil { + return errors.New("nil fn") + } + + if len(slices) == 0 { + return nil + } + + slice1 := s.slice + for _, slice2 := range slices { + if !IsSorted(slice2) { + temp := make(Float64s, len(slice2)) + copy(temp, slice2) + Sort(temp) + slice2 = temp + } + var got Float64s + for i1, i2 := 0, 0; i1 < len(slice1) || i2 < len(slice2); { + var ( + t time.Time + v *float64 + ) + switch { + case i1 == len(slice1): + t = slice2[i2].Time + v2 := slice2[i2].Value + v = fn(t, nil, &v2) + i2++ + case i2 == len(slice2): + t = slice2[i1].Time + v1 := slice1[i1].Value + v = fn(t, &v1, nil) + i1++ + case slice1[i1].Time.Equal(slice2[i2].Time): + t = slice1[i1].Time + v1 := slice1[i1].Value + v2 := slice2[i2].Value + v = fn(t, &v1, &v2) + i1++ + i2++ + case slice1[i1].Time.Before(slice2[i2].Time): + t = slice1[i1].Time + v1 := slice1[i1].Value + v = fn(t, &v1, nil) + i1++ + case slice1[i1].Time.After(slice2[i2].Time): + t = slice1[i2].Time + v2 := slice2[i2].Value + v = fn(t, nil, &v2) + i2++ + } + if v != nil { + got = append(got, Float64{ + Time: t, + Value: *v, + }) + } + } + slice1 = got + } + + s.slice = slice1 + s.buildIndex() + return nil +} + +func (s *Float64Seq) Aggregate(fn func(t time.Time, slice Float64s) *float64, duration time.Duration, begin, end *time.Time) error { + if fn == nil { + return errors.New("nil fn") + } + + if duration <= 0 { + return errors.New("invalid duration") + } + + var bg, ed time.Time + if len(s.slice) > 0 { + bg = s.slice[0].Time.Truncate(duration) + ed = s.slice[len(s.slice)-1].Time + } + if begin != nil { + bg = (*begin).Truncate(duration) + } + if end != nil { + ed = *end + } + + got := Float64s{} + slice := Float64s{} + i := 0 + for t := bg; t.Before(ed); t = t.Add(duration) { + slice = slice[:0] + for i < s.slice.Len() && + !s.slice[i].Time.After(t) && + s.slice[i].Time.Before(t.Add(duration)) { + slice = append(slice, s.slice[i]) + i++ + } + v := fn(t, slice) + if v != nil { + got = append(got, Float64{ + Time: t, + Value: *v, + }) + } + } + + s.slice = got + s.buildIndex() + return nil +} + +func (s *Float64Seq) Trim(fn func(i int, v Float64) bool) error { + if fn == nil { + return errors.New("nil fn") + } + + updated := false + slice := s.slice[:0] + for i, v := range s.slice { + if fn(i, v) { + updated = true + } else { + slice = append(slice, v) + } + } + + if !updated { + s.slice = slice + s.buildIndex() + } + return nil +} diff --git a/gen_int64_seq.go b/gen_int64_seq.go new file mode 100644 index 0000000..efd7523 --- /dev/null +++ b/gen_int64_seq.go @@ -0,0 +1,332 @@ +// Code generated by cmd/generate. DO NOT EDIT. +package timeseq + +import ( + "errors" + "sort" + "time" +) + +type Int64 struct { + Time time.Time + Value int64 +} + +type Int64s []Int64 + +func (s Int64s) Len() int { + return len(s) +} + +func (s Int64s) Swap(i, j int) { + s[i], s[j] = s[j], s[i] +} + +func (s Int64s) Time(i int) time.Time { + return s[i].Time +} + +func (s Int64s) Slice(i, j int) Slice { + return s[i:j] +} + +type Int64Seq struct { + slice Int64s + timeIndex map[timeKey][]int + valueIndex map[int64][]int + valueSlice []int +} + +func NewInt64Seq(slice Int64s) *Int64Seq { + temp := make(Int64s, len(slice)) + copy(temp, slice) + slice = temp + + Sort(slice) + sort.SliceStable(slice, func(i, j int) bool { + return slice[i].Time.Before(slice[j].Time) + }) + return newInt64Seq(slice) +} + +func newInt64Seq(slice Int64s) *Int64Seq { + ret := &Int64Seq{ + slice: slice, + } + ret.buildIndex() + return ret +} + +func (s *Int64Seq) buildIndex() { + timeIndex := make(map[timeKey][]int, len(s.slice)) + valueIndex := make(map[int64][]int, len(s.slice)) + valueSlice := s.valueSlice[:0] + for i, v := range s.slice { + k := newTimeKey(v.Time) + timeIndex[k] = append(timeIndex[k], i) + valueIndex[v.Value] = append(valueIndex[v.Value], i) + valueSlice = append(valueSlice, i) + } + sort.SliceStable(valueSlice, func(i, j int) bool { + return s.slice[valueSlice[i]].Value < s.slice[valueSlice[j]].Value + }) + s.timeIndex = timeIndex + s.valueIndex = valueIndex + s.valueSlice = valueSlice +} + +func (s *Int64Seq) Int64s() Int64s { + slice := make(Int64s, len(s.slice)) + copy(slice, s.slice) + return slice +} + +func (s *Int64Seq) Index(i int) Int64 { + if i < 0 || i >= len(s.slice) { + return Int64{} + } + return s.slice[i] +} + +func (s *Int64Seq) Time(t time.Time) Int64s { + index := s.timeIndex[newTimeKey(t)] + if len(index) == 0 { + return nil + } + ret := make(Int64s, len(index)) + for i, v := range index { + ret[i] = s.slice[v] + } + return ret +} + +func (s *Int64Seq) Value(v int64) Int64s { + index := s.valueIndex[v] + if len(index) == 0 { + return nil + } + ret := make(Int64s, len(index)) + for i, v := range index { + ret[i] = s.slice[v] + } + return ret +} + +func (s *Int64Seq) Visit(fn func(i int, v Int64) (stop bool)) { + for i, v := range s.slice { + if fn != nil && fn(i, v) { + break + } + } +} + +func (s *Int64Seq) Sum() int64 { + var ret int64 + for _, v := range s.slice { + ret += v.Value + } + return ret +} + +func (s *Int64Seq) Count() int { + return len(s.slice) +} + +func (s *Int64Seq) Max() Int64 { + var max Int64 + found := false + for _, v := range s.slice { + if !found { + max = v + found = true + } else if v.Value < max.Value { + max = v + } + } + return max +} + +func (s *Int64Seq) Min() Int64 { + var min Int64 + found := false + for _, v := range s.slice { + if !found { + min = v + found = true + } else if v.Value < min.Value { + min = v + } + } + return min +} + +func (s *Int64Seq) First() Int64 { + if len(s.slice) == 0 { + return Int64{} + } + return s.slice[0] +} + +func (s *Int64Seq) Last() Int64 { + if len(s.slice) == 0 { + return Int64{} + } + return s.slice[len(s.slice)-1] +} + +func (s *Int64Seq) Percentile(pct float64) Int64 { + if len(s.slice) == 0 { + return Int64{} + } + if pct > 1 { + pct = 1 + } + if pct < 0 { + pct = 0 + } + i := int(float64(len(s.slice))*pct - 1) + if i < 0 { + i = 0 + } + return s.slice[s.valueSlice[i]] +} + +func (s *Int64Seq) Range(interval Interval) *Int64Seq { + slice := Range(s.slice, interval).(Int64s) + return newInt64Seq(slice) +} + +func (s *Int64Seq) Merge(fn func(t time.Time, v1, v2 *int64) *int64, slices ...Int64s) error { + if fn == nil { + return errors.New("nil fn") + } + + if len(slices) == 0 { + return nil + } + + slice1 := s.slice + for _, slice2 := range slices { + if !IsSorted(slice2) { + temp := make(Int64s, len(slice2)) + copy(temp, slice2) + Sort(temp) + slice2 = temp + } + var got Int64s + for i1, i2 := 0, 0; i1 < len(slice1) || i2 < len(slice2); { + var ( + t time.Time + v *int64 + ) + switch { + case i1 == len(slice1): + t = slice2[i2].Time + v2 := slice2[i2].Value + v = fn(t, nil, &v2) + i2++ + case i2 == len(slice2): + t = slice2[i1].Time + v1 := slice1[i1].Value + v = fn(t, &v1, nil) + i1++ + case slice1[i1].Time.Equal(slice2[i2].Time): + t = slice1[i1].Time + v1 := slice1[i1].Value + v2 := slice2[i2].Value + v = fn(t, &v1, &v2) + i1++ + i2++ + case slice1[i1].Time.Before(slice2[i2].Time): + t = slice1[i1].Time + v1 := slice1[i1].Value + v = fn(t, &v1, nil) + i1++ + case slice1[i1].Time.After(slice2[i2].Time): + t = slice1[i2].Time + v2 := slice2[i2].Value + v = fn(t, nil, &v2) + i2++ + } + if v != nil { + got = append(got, Int64{ + Time: t, + Value: *v, + }) + } + } + slice1 = got + } + + s.slice = slice1 + s.buildIndex() + return nil +} + +func (s *Int64Seq) Aggregate(fn func(t time.Time, slice Int64s) *int64, duration time.Duration, begin, end *time.Time) error { + if fn == nil { + return errors.New("nil fn") + } + + if duration <= 0 { + return errors.New("invalid duration") + } + + var bg, ed time.Time + if len(s.slice) > 0 { + bg = s.slice[0].Time.Truncate(duration) + ed = s.slice[len(s.slice)-1].Time + } + if begin != nil { + bg = (*begin).Truncate(duration) + } + if end != nil { + ed = *end + } + + got := Int64s{} + slice := Int64s{} + i := 0 + for t := bg; t.Before(ed); t = t.Add(duration) { + slice = slice[:0] + for i < s.slice.Len() && + !s.slice[i].Time.After(t) && + s.slice[i].Time.Before(t.Add(duration)) { + slice = append(slice, s.slice[i]) + i++ + } + v := fn(t, slice) + if v != nil { + got = append(got, Int64{ + Time: t, + Value: *v, + }) + } + } + + s.slice = got + s.buildIndex() + return nil +} + +func (s *Int64Seq) Trim(fn func(i int, v Int64) bool) error { + if fn == nil { + return errors.New("nil fn") + } + + updated := false + slice := s.slice[:0] + for i, v := range s.slice { + if fn(i, v) { + updated = true + } else { + slice = append(slice, v) + } + } + + if !updated { + s.slice = slice + s.buildIndex() + } + return nil +} diff --git a/_draft/v2/int_seq.go b/gen_int_seq.go similarity index 90% rename from _draft/v2/int_seq.go rename to gen_int_seq.go index 768521d..fa61d3a 100644 --- a/_draft/v2/int_seq.go +++ b/gen_int_seq.go @@ -1,3 +1,4 @@ +// Code generated by cmd/generate. DO NOT EDIT. package timeseq import ( @@ -36,9 +37,11 @@ type IntSeq struct { valueSlice []int } -func NewIntSeq(ints Ints) *IntSeq { - slice := make(Ints, len(ints)) - copy(slice, ints) +func NewIntSeq(slice Ints) *IntSeq { + temp := make(Ints, len(slice)) + copy(temp, slice) + slice = temp + Sort(slice) sort.SliceStable(slice, func(i, j int) bool { return slice[i].Time.Before(slice[j].Time) @@ -193,17 +196,17 @@ func (s *IntSeq) Range(interval Interval) *IntSeq { return newIntSeq(slice) } -func (s *IntSeq) Merge(fn func(t time.Time, v1, v2 *int) *int, ints ...Ints) error { +func (s *IntSeq) Merge(fn func(t time.Time, v1, v2 *int) *int, slices ...Ints) error { if fn == nil { return errors.New("nil fn") } - if len(ints) == 0 { + if len(slices) == 0 { return nil } slice1 := s.slice - for _, slice2 := range ints { + for _, slice2 := range slices { if !IsSorted(slice2) { temp := make(Ints, len(slice2)) copy(temp, slice2) @@ -260,7 +263,7 @@ func (s *IntSeq) Merge(fn func(t time.Time, v1, v2 *int) *int, ints ...Ints) err return nil } -func (s *IntSeq) Aggregate(fn func(t time.Time, ints Ints) *int, duration time.Duration, begin, end *time.Time) error { +func (s *IntSeq) Aggregate(fn func(t time.Time, slice Ints) *int, duration time.Duration, begin, end *time.Time) error { if fn == nil { return errors.New("nil fn") } @@ -281,27 +284,27 @@ func (s *IntSeq) Aggregate(fn func(t time.Time, ints Ints) *int, duration time.D ed = *end } + got := Ints{} slice := Ints{} - ints := Ints{} i := 0 for t := bg; t.Before(ed); t = t.Add(duration) { - ints = ints[:0] + slice = slice[:0] for i < s.slice.Len() && !s.slice[i].Time.After(t) && s.slice[i].Time.Before(t.Add(duration)) { - ints = append(ints, s.slice[i]) + slice = append(slice, s.slice[i]) i++ } - v := fn(t, ints) + v := fn(t, slice) if v != nil { - slice = append(slice, Int{ + got = append(got, Int{ Time: t, Value: *v, }) } } - s.slice = slice + s.slice = got s.buildIndex() return nil } diff --git a/timeseq.go b/timeseq.go new file mode 100644 index 0000000..9d9915a --- /dev/null +++ b/timeseq.go @@ -0,0 +1,72 @@ +package timeseq + +import ( + "encoding/binary" + "sort" + "time" +) + +type Slice interface { + // return length + Len() int + // swap items + Swap(i, j int) + // return time of item i + Time(i int) time.Time + // return Slice[i:j] + Slice(i, j int) Slice +} + +type sortableSlice struct { + Slice +} + +func (s sortableSlice) Less(i, j int) bool { + return s.Time(i).Before(s.Time(j)) +} + +// Sort will sort slice by time +func Sort(slice Slice) { + sort.Stable(sortableSlice{Slice: slice}) +} + +func IsSorted(slice Slice) bool { + return sort.IsSorted(sortableSlice{Slice: slice}) +} + +func Range(slice Slice, interval Interval) Slice { + i := 0 + if interval.NotBefore != nil { + i = sort.Search(slice.Len(), func(i int) bool { + return !slice.Time(i).Before(*interval.NotBefore) + }) + } + j := slice.Len() + if interval.NotAfter != nil { + j = sort.Search(slice.Len(), func(j int) bool { + return !slice.Time(j).Before(*interval.NotAfter) + }) + if j < slice.Len() && slice.Time(j).Equal(*interval.NotAfter) { + j++ + } + } + return slice.Slice(i, j) +} + +type Interval struct { + NotBefore *time.Time + NotAfter *time.Time +} + +type timeKey [16]byte + +func (k timeKey) Get() time.Time { + return time.Unix(int64(binary.BigEndian.Uint64(k[:8])), int64(binary.BigEndian.Uint64(k[8:]))) +} + +func newTimeKey(t time.Time) timeKey { + var ret [16]byte + binary.BigEndian.PutUint64(ret[:8], uint64(t.Unix())) + binary.BigEndian.PutUint64(ret[8:], uint64(t.UnixNano())) + return ret +} From 5c318f8dd079680bf8651361a6b9384022b9d608 Mon Sep 17 00:00:00 2001 From: Jason Song Date: Wed, 23 Sep 2020 17:09:13 +0800 Subject: [PATCH 08/19] feat: support string --- cmd/generate/main.go | 5 + gen_string_seq.go | 332 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 337 insertions(+) create mode 100644 gen_string_seq.go diff --git a/cmd/generate/main.go b/cmd/generate/main.go index 3742049..d62890d 100644 --- a/cmd/generate/main.go +++ b/cmd/generate/main.go @@ -36,6 +36,11 @@ func main() { Type: "float64", Random: "rand.Float64()", }, + { + Name: "String", + Type: "string", + Random: "// TODO", + }, { Name: "Int", Type: "int", diff --git a/gen_string_seq.go b/gen_string_seq.go new file mode 100644 index 0000000..7996714 --- /dev/null +++ b/gen_string_seq.go @@ -0,0 +1,332 @@ +// Code generated by cmd/generate. DO NOT EDIT. +package timeseq + +import ( + "errors" + "sort" + "time" +) + +type String struct { + Time time.Time + Value string +} + +type Strings []String + +func (s Strings) Len() int { + return len(s) +} + +func (s Strings) Swap(i, j int) { + s[i], s[j] = s[j], s[i] +} + +func (s Strings) Time(i int) time.Time { + return s[i].Time +} + +func (s Strings) Slice(i, j int) Slice { + return s[i:j] +} + +type StringSeq struct { + slice Strings + timeIndex map[timeKey][]int + valueIndex map[string][]int + valueSlice []int +} + +func NewStringSeq(slice Strings) *StringSeq { + temp := make(Strings, len(slice)) + copy(temp, slice) + slice = temp + + Sort(slice) + sort.SliceStable(slice, func(i, j int) bool { + return slice[i].Time.Before(slice[j].Time) + }) + return newStringSeq(slice) +} + +func newStringSeq(slice Strings) *StringSeq { + ret := &StringSeq{ + slice: slice, + } + ret.buildIndex() + return ret +} + +func (s *StringSeq) buildIndex() { + timeIndex := make(map[timeKey][]int, len(s.slice)) + valueIndex := make(map[string][]int, len(s.slice)) + valueSlice := s.valueSlice[:0] + for i, v := range s.slice { + k := newTimeKey(v.Time) + timeIndex[k] = append(timeIndex[k], i) + valueIndex[v.Value] = append(valueIndex[v.Value], i) + valueSlice = append(valueSlice, i) + } + sort.SliceStable(valueSlice, func(i, j int) bool { + return s.slice[valueSlice[i]].Value < s.slice[valueSlice[j]].Value + }) + s.timeIndex = timeIndex + s.valueIndex = valueIndex + s.valueSlice = valueSlice +} + +func (s *StringSeq) Strings() Strings { + slice := make(Strings, len(s.slice)) + copy(slice, s.slice) + return slice +} + +func (s *StringSeq) Index(i int) String { + if i < 0 || i >= len(s.slice) { + return String{} + } + return s.slice[i] +} + +func (s *StringSeq) Time(t time.Time) Strings { + index := s.timeIndex[newTimeKey(t)] + if len(index) == 0 { + return nil + } + ret := make(Strings, len(index)) + for i, v := range index { + ret[i] = s.slice[v] + } + return ret +} + +func (s *StringSeq) Value(v string) Strings { + index := s.valueIndex[v] + if len(index) == 0 { + return nil + } + ret := make(Strings, len(index)) + for i, v := range index { + ret[i] = s.slice[v] + } + return ret +} + +func (s *StringSeq) Visit(fn func(i int, v String) (stop bool)) { + for i, v := range s.slice { + if fn != nil && fn(i, v) { + break + } + } +} + +func (s *StringSeq) Sum() string { + var ret string + for _, v := range s.slice { + ret += v.Value + } + return ret +} + +func (s *StringSeq) Count() int { + return len(s.slice) +} + +func (s *StringSeq) Max() String { + var max String + found := false + for _, v := range s.slice { + if !found { + max = v + found = true + } else if v.Value < max.Value { + max = v + } + } + return max +} + +func (s *StringSeq) Min() String { + var min String + found := false + for _, v := range s.slice { + if !found { + min = v + found = true + } else if v.Value < min.Value { + min = v + } + } + return min +} + +func (s *StringSeq) First() String { + if len(s.slice) == 0 { + return String{} + } + return s.slice[0] +} + +func (s *StringSeq) Last() String { + if len(s.slice) == 0 { + return String{} + } + return s.slice[len(s.slice)-1] +} + +func (s *StringSeq) Percentile(pct float64) String { + if len(s.slice) == 0 { + return String{} + } + if pct > 1 { + pct = 1 + } + if pct < 0 { + pct = 0 + } + i := int(float64(len(s.slice))*pct - 1) + if i < 0 { + i = 0 + } + return s.slice[s.valueSlice[i]] +} + +func (s *StringSeq) Range(interval Interval) *StringSeq { + slice := Range(s.slice, interval).(Strings) + return newStringSeq(slice) +} + +func (s *StringSeq) Merge(fn func(t time.Time, v1, v2 *string) *string, slices ...Strings) error { + if fn == nil { + return errors.New("nil fn") + } + + if len(slices) == 0 { + return nil + } + + slice1 := s.slice + for _, slice2 := range slices { + if !IsSorted(slice2) { + temp := make(Strings, len(slice2)) + copy(temp, slice2) + Sort(temp) + slice2 = temp + } + var got Strings + for i1, i2 := 0, 0; i1 < len(slice1) || i2 < len(slice2); { + var ( + t time.Time + v *string + ) + switch { + case i1 == len(slice1): + t = slice2[i2].Time + v2 := slice2[i2].Value + v = fn(t, nil, &v2) + i2++ + case i2 == len(slice2): + t = slice2[i1].Time + v1 := slice1[i1].Value + v = fn(t, &v1, nil) + i1++ + case slice1[i1].Time.Equal(slice2[i2].Time): + t = slice1[i1].Time + v1 := slice1[i1].Value + v2 := slice2[i2].Value + v = fn(t, &v1, &v2) + i1++ + i2++ + case slice1[i1].Time.Before(slice2[i2].Time): + t = slice1[i1].Time + v1 := slice1[i1].Value + v = fn(t, &v1, nil) + i1++ + case slice1[i1].Time.After(slice2[i2].Time): + t = slice1[i2].Time + v2 := slice2[i2].Value + v = fn(t, nil, &v2) + i2++ + } + if v != nil { + got = append(got, String{ + Time: t, + Value: *v, + }) + } + } + slice1 = got + } + + s.slice = slice1 + s.buildIndex() + return nil +} + +func (s *StringSeq) Aggregate(fn func(t time.Time, slice Strings) *string, duration time.Duration, begin, end *time.Time) error { + if fn == nil { + return errors.New("nil fn") + } + + if duration <= 0 { + return errors.New("invalid duration") + } + + var bg, ed time.Time + if len(s.slice) > 0 { + bg = s.slice[0].Time.Truncate(duration) + ed = s.slice[len(s.slice)-1].Time + } + if begin != nil { + bg = (*begin).Truncate(duration) + } + if end != nil { + ed = *end + } + + got := Strings{} + slice := Strings{} + i := 0 + for t := bg; t.Before(ed); t = t.Add(duration) { + slice = slice[:0] + for i < s.slice.Len() && + !s.slice[i].Time.After(t) && + s.slice[i].Time.Before(t.Add(duration)) { + slice = append(slice, s.slice[i]) + i++ + } + v := fn(t, slice) + if v != nil { + got = append(got, String{ + Time: t, + Value: *v, + }) + } + } + + s.slice = got + s.buildIndex() + return nil +} + +func (s *StringSeq) Trim(fn func(i int, v String) bool) error { + if fn == nil { + return errors.New("nil fn") + } + + updated := false + slice := s.slice[:0] + for i, v := range s.slice { + if fn(i, v) { + updated = true + } else { + slice = append(slice, v) + } + } + + if !updated { + s.slice = slice + s.buildIndex() + } + return nil +} From f7de064e2a401f36432c1f31888b93822facee9c Mon Sep 17 00:00:00 2001 From: Jason Song Date: Wed, 23 Sep 2020 18:20:33 +0800 Subject: [PATCH 09/19] feat: mort work for v2 --- _draft/v2/int64_seq.go | 10 +- _draft/v2/int64_seq_test.go | 548 +++++++++++++++++ cmd/generate/gen_x_seq.go.tmpl | 10 +- cmd/generate/gen_x_seq_test.go.tmpl | 921 +++++++++++++++------------- cmd/generate/main.go | 33 +- gen_float64_seq.go | 10 +- gen_float64_seq_test.go | 774 +++++++++++++++++++++++ gen_int64_seq.go | 10 +- gen_int64_seq_test.go | 774 +++++++++++++++++++++++ gen_int_seq.go | 10 +- gen_int_seq_test.go | 774 +++++++++++++++++++++++ gen_string_seq.go | 10 +- gen_string_seq_test.go | 774 +++++++++++++++++++++++ 13 files changed, 4180 insertions(+), 478 deletions(-) create mode 100644 gen_float64_seq_test.go create mode 100644 gen_int64_seq_test.go create mode 100644 gen_int_seq_test.go create mode 100644 gen_string_seq_test.go diff --git a/_draft/v2/int64_seq.go b/_draft/v2/int64_seq.go index b889cc9..5a2e5c6 100644 --- a/_draft/v2/int64_seq.go +++ b/_draft/v2/int64_seq.go @@ -138,7 +138,7 @@ func (s *Int64Seq) Max() Int64 { if !found { max = v found = true - } else if v.Value < max.Value { + } else if v.Value > max.Value { max = v } } @@ -225,7 +225,7 @@ func (s *Int64Seq) Merge(fn func(t time.Time, v1, v2 *int64) *int64, slices ...I v = fn(t, nil, &v2) i2++ case i2 == len(slice2): - t = slice2[i1].Time + t = slice1[i1].Time v1 := slice1[i1].Value v = fn(t, &v1, nil) i1++ @@ -242,7 +242,7 @@ func (s *Int64Seq) Merge(fn func(t time.Time, v1, v2 *int64) *int64, slices ...I v = fn(t, &v1, nil) i1++ case slice1[i1].Time.After(slice2[i2].Time): - t = slice1[i2].Time + t = slice2[i2].Time v2 := slice2[i2].Value v = fn(t, nil, &v2) i2++ @@ -314,7 +314,7 @@ func (s *Int64Seq) Trim(fn func(i int, v Int64) bool) error { } updated := false - slice := s.slice[:0] + slice := make(Int64s, 0) for i, v := range s.slice { if fn(i, v) { updated = true @@ -323,7 +323,7 @@ func (s *Int64Seq) Trim(fn func(i int, v Int64) bool) error { } } - if !updated { + if updated { s.slice = slice s.buildIndex() } diff --git a/_draft/v2/int64_seq_test.go b/_draft/v2/int64_seq_test.go index 7da9d38..848a3af 100644 --- a/_draft/v2/int64_seq_test.go +++ b/_draft/v2/int64_seq_test.go @@ -1,6 +1,7 @@ package timeseq import ( + "fmt" "math/rand" "reflect" "testing" @@ -223,3 +224,550 @@ func TestInt64Seq_Visit(t *testing.T) { }) } } + +func TestInt64Seq_Sum(t *testing.T) { + data := RandomInt64s(100) + var sum int64 + for _, v := range data { + sum += v.Value + } + tests := []struct { + name string + want int64 + }{ + { + name: "regular", + want: sum, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewInt64Seq(data) + if got := s.Sum(); got != tt.want { + t.Errorf("Sum() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestInt64Seq_Count(t *testing.T) { + data := RandomInt64s(100) + + tests := []struct { + name string + want int + }{ + { + name: "regular", + want: len(data), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewInt64Seq(data) + if got := s.Count(); got != tt.want { + t.Errorf("Count() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestInt64Seq_Max(t *testing.T) { + data := RandomInt64s(100) + max := data[0] + for _, v := range data { + if v.Value > max.Value { + max = v + } + } + + tests := []struct { + name string + want Int64 + }{ + { + name: "regular", + want: max, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewInt64Seq(data) + if got := s.Max(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Max() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestInt64Seq_Min(t *testing.T) { + data := RandomInt64s(100) + min := data[0] + for _, v := range data { + if v.Value < min.Value { + min = v + } + } + + tests := []struct { + name string + want Int64 + }{ + { + name: "regular", + want: min, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewInt64Seq(data) + if got := s.Min(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Min() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestInt64Seq_First(t *testing.T) { + data := RandomInt64s(100) + Sort(data) + + tests := []struct { + name string + data Int64s + want Int64 + }{ + { + + name: "regular", + data: data, + want: data[0], + }, + { + name: "emtpy", + data: nil, + want: Int64{}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewInt64Seq(tt.data) + if got := s.First(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("First() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestInt64Seq_Last(t *testing.T) { + data := RandomInt64s(100) + Sort(data) + tests := []struct { + name string + data Int64s + want Int64 + }{ + { + + name: "regular", + data: data, + want: data[len(data)-1], + }, + { + name: "emtpy", + data: nil, + want: Int64{}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewInt64Seq(tt.data) + if got := s.Last(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Last() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestInt64Seq_Percentile(t *testing.T) { + data := RandomInt64s(100) + Sort(data) + for i := range data { + data[i].Value = int64(i) + } + + type args struct { + pct float64 + } + tests := []struct { + name string + data Int64s + args args + want Int64 + }{ + { + name: "data[0]", + data: data, + args: args{ + pct: 0, + }, + want: data[0], + }, + { + name: "data[49]", + data: data, + args: args{ + pct: 0.5, + }, + want: data[49], + }, + { + name: "0.95", + data: data, + args: args{ + pct: 0.95, + }, + want: data[94], + }, + { + name: "0.955", + data: data, + args: args{ + pct: 0.955, + }, + want: data[94], + }, + { + name: "1", + data: data, + args: args{ + pct: 1, + }, + want: data[99], + }, + { + name: "1.1", + data: data, + args: args{ + pct: 1.1, + }, + want: data[99], + }, + { + name: "-0.1", + data: data, + args: args{ + pct: -0.1, + }, + want: data[0], + }, + { + name: "empty", + data: nil, + args: args{ + pct: 1, + }, + want: Int64{}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewInt64Seq(tt.data) + if got := s.Percentile(tt.args.pct); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Percentile() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestInt64Seq_Range(t *testing.T) { + data := RandomInt64s(100) + Sort(data) + + type args struct { + interval Interval + } + tests := []struct { + name string + data Int64s + args args + want Int64s + }{ + { + name: "regular", + data: data, + args: args{ + interval: Interval{ + NotBefore: &data[10].Time, + NotAfter: &data[89].Time, + }, + }, + want: data[10:90], + }, + { + name: "nil NotBefore", + data: data, + args: args{ + interval: Interval{ + NotAfter: &data[89].Time, + }, + }, + want: data[:90], + }, + { + name: "nil NotAfter", + data: data, + args: args{ + interval: Interval{ + NotBefore: &data[10].Time, + }, + }, + want: data[10:], + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewInt64Seq(data) + if got := s.Range(tt.args.interval).slice; !reflect.DeepEqual(got, tt.want) { + t.Errorf("Range() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestInt64Seq_Merge(t *testing.T) { + data := RandomInt64s(10) + Sort(data) + + type args struct { + fn func(t time.Time, v1, v2 *int64) *int64 + slices []Int64s + } + tests := []struct { + name string + data Int64s + args args + want Int64s + wantErr bool + }{ + { + name: "regular", + data: data[0:7], + args: args{ + fn: func(t time.Time, v1, v2 *int64) *int64 { + if v1 != nil { + return v1 + } + return v2 + }, + slices: []Int64s{data[3:10]}, + }, + want: data, + }, + { + name: "reverse", + data: data[3:10], + args: args{ + fn: func(t time.Time, v1, v2 *int64) *int64 { + if v1 != nil { + return v1 + } + return v2 + }, + slices: []Int64s{data[0:7]}, + }, + want: data, + }, + { + name: "nil fn", + data: nil, + args: args{ + fn: nil, + }, + wantErr: true, + }, + { + name: "multiple", + data: nil, + args: args{ + fn: func(t time.Time, v1, v2 *int64) *int64 { + if v1 != nil { + return v1 + } + return v2 + }, + slices: []Int64s{ + data[1:2], + data[0:4], + nil, + data[2:9], + data[9:], + }, + }, + want: data, + }, + { + name: "not sorted", + data: data[0:7], + args: args{ + fn: func(t time.Time, v1, v2 *int64) *int64 { + if v1 != nil { + return v1 + } + return v2 + }, + slices: []Int64s{ + append(Int64s{data[9]}, data[3:9]...), + }, + }, + want: data, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewInt64Seq(tt.data) + if err := s.Merge(tt.args.fn, tt.args.slices...); (err != nil) != tt.wantErr { + t.Errorf("Merge() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !tt.wantErr { + if got := s.slice; !reflect.DeepEqual(got, tt.want) { + t.Errorf("Merge() = %v, want %v", got, tt.want) + } + } + }) + } +} + +func TestInt64Seq_Aggregate(t *testing.T) { + data := RandomInt64s(100) + now := time.Now() + begin := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()) + end := begin.Add(24*time.Hour - 1) + + type args struct { + fn func(t time.Time, slice Int64s) *int64 + duration time.Duration + begin *time.Time + end *time.Time + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "regular", + args: args{ + fn: func(t time.Time, slice Int64s) *int64 { + ret := int64(t.Hour()) + if len(slice) != 0 { + ret = 0 + } + for _, v := range slice { + ret += v.Value + } + return &ret + }, + duration: time.Hour, + begin: &begin, + end: &end, + }, + wantErr: false, + }, + { + name: "nil fn", + args: args{ + fn: nil, + duration: time.Hour, + begin: &begin, + end: &end, + }, + wantErr: true, + }, + { + name: "zero duration", + args: args{ + fn: func(t time.Time, slice Int64s) *int64 { + ret := int64(t.Hour()) + if len(slice) != 0 { + ret = 0 + } + for _, v := range slice { + ret += v.Value + } + return &ret + }, + duration: 0, + begin: &begin, + end: &end, + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewInt64Seq(data) + if err := s.Aggregate(tt.args.fn, tt.args.duration, tt.args.begin, tt.args.end); (err != nil) != tt.wantErr { + t.Errorf("Aggregate() error = %v, wantErr %v", err, tt.wantErr) + } + for i, v := range s.slice { + fmt.Println(i, v.Value, v.Time) + } + }) + } +} + +func TestInt64Seq_Trim(t *testing.T) { + data := RandomInt64s(10) + Sort(data) + + type args struct { + fn func(i int, v Int64) bool + } + tests := []struct { + name string + args args + want Int64s + wantErr bool + }{ + { + name: "regular", + args: args{ + fn: func(i int, v Int64) bool { + return i >= 5 + }, + }, + want: data[:5], + wantErr: false, + }, + { + name: "nil fn", + args: args{ + fn: nil, + }, + want: data[:5], + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewInt64Seq(data) + if err := s.Trim(tt.args.fn); (err != nil) != tt.wantErr { + t.Errorf("Trim() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !tt.wantErr { + if got := s.slice; !reflect.DeepEqual(got, tt.want) { + t.Errorf("Trim() = %v, want %v", got, tt.want) + for i, v := range got { + fmt.Println(i, v) + } + for i, v := range tt.want { + fmt.Println(i, v) + } + } + } + }) + } +} diff --git a/cmd/generate/gen_x_seq.go.tmpl b/cmd/generate/gen_x_seq.go.tmpl index 648f545..7867927 100644 --- a/cmd/generate/gen_x_seq.go.tmpl +++ b/cmd/generate/gen_x_seq.go.tmpl @@ -138,7 +138,7 @@ func (s *{{.Name}}Seq) Max() {{.Name}} { if !found { max = v found = true - } else if v.Value < max.Value { + } else if v.Value > max.Value { max = v } } @@ -225,7 +225,7 @@ func (s *{{.Name}}Seq) Merge(fn func(t time.Time, v1, v2 *{{.Type}}) *{{.Type}}, v = fn(t, nil, &v2) i2++ case i2 == len(slice2): - t = slice2[i1].Time + t = slice1[i1].Time v1 := slice1[i1].Value v = fn(t, &v1, nil) i1++ @@ -242,7 +242,7 @@ func (s *{{.Name}}Seq) Merge(fn func(t time.Time, v1, v2 *{{.Type}}) *{{.Type}}, v = fn(t, &v1, nil) i1++ case slice1[i1].Time.After(slice2[i2].Time): - t = slice1[i2].Time + t = slice2[i2].Time v2 := slice2[i2].Value v = fn(t, nil, &v2) i2++ @@ -314,7 +314,7 @@ func (s *{{.Name}}Seq) Trim(fn func(i int, v {{.Name}}) bool) error { } updated := false - slice := s.slice[:0] + slice := make({{.Name}}s, 0) for i, v := range s.slice { if fn(i, v) { updated = true @@ -323,7 +323,7 @@ func (s *{{.Name}}Seq) Trim(fn func(i int, v {{.Name}}) bool) error { } } - if !updated { + if updated { s.slice = slice s.buildIndex() } diff --git a/cmd/generate/gen_x_seq_test.go.tmpl b/cmd/generate/gen_x_seq_test.go.tmpl index 5b7ecab..5760218 100644 --- a/cmd/generate/gen_x_seq_test.go.tmpl +++ b/cmd/generate/gen_x_seq_test.go.tmpl @@ -1,559 +1,399 @@ -// Code generated by cmd/generate. DO NOT EDIT. - package timeseq import ( - "math" + "fmt" "math/rand" "reflect" - "sort" "testing" "time" - - "github.com/gochore/pt" ) -func Test{{.Name}}Sequence_Len(t *testing.T) { - tests := []struct { - name string - s {{.Name}}Sequence - want int - }{ - { - s: Random{{.Name}}Sequence(10), - want: 10, - }, - { - s: Random{{.Name}}Sequence(0), - want: 0, - }, - { - s: nil, - want: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Len(); got != tt.want { - t.Errorf("{{.Name}}Sequence.Len() = %v, want %v", got, tt.want) - } - }) +func Random{{.Name}}s(length int) {{.Name}}s { + now := time.Now() + ret := make({{.Name}}s, length) + for i := range ret { + delta := time.Duration(i) * time.Second + if rand.Float64() < 0.5 { + delta = -delta + } + ret[i] = {{.Name}}{ + Time: now.Add(delta), + Value: {{.Random}}, + } } + return ret } -func Test{{.Name}}Sequence_Swap(t *testing.T) { - type args struct { - i int - j int - } +func Test{{.Name}}Seq_{{.Name}}s(t *testing.T) { + data := Random{{.Name}}s(100) + Sort(data) + tests := []struct { name string - s {{.Name}}Sequence - args args + want {{.Name}}s }{ { - s: Random{{.Name}}Sequence(10), - args: args{ - i: 0, - j: 5, - }, + name: "regular", + want: data, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - ti := tt.s.Time(tt.args.i) - tj := tt.s.Time(tt.args.j) - tt.s.Swap(tt.args.i, tt.args.j) - if ti != tt.s.Time(tt.args.j) || tj != tt.s.Time(tt.args.i) { - t.Errorf("{{.Name}}Sequence.Swap() failed") + s := New{{.Name}}Seq(data) + if got := s.{{.Name}}s(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("{{.Name}}s() = %v, want %v", got, tt.want) } }) } } -func Test{{.Name}}Sequence_Time(t *testing.T) { - seq := Random{{.Name}}Sequence(10) - seq.Sort() +func Test{{.Name}}Seq_Index(t *testing.T) { + data := Random{{.Name}}s(100) + Sort(data) type args struct { i int } tests := []struct { name string - s {{.Name}}Sequence args args - want time.Time + want {{.Name}} }{ { - s: seq, + name: "regular", args: args{ - i: 9, + i: 1, }, - want: seq[9].Time, + want: data[1], + }, + { + name: "less than zero", + args: args{ + i: -1, + }, + want: {{.Name}}{}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Time(tt.args.i); !reflect.DeepEqual(got, tt.want) { - t.Errorf("{{.Name}}Sequence.Time() = %v, want %v", got, tt.want) + s := New{{.Name}}Seq(data) + if got := s.Index(tt.args.i); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Index() = %v, want %v", got, tt.want) } }) } } -func Test{{.Name}}Sequence_Slice(t *testing.T) { - seq := Random{{.Name}}Sequence(10) +func Test{{.Name}}Seq_Time(t *testing.T) { + now := time.Now() + yesterday := now.AddDate(0, 0, -1) + lastMonth := now.AddDate(0, -1, 0) + lastYear := now.AddDate(-1, 0, 0) + + data := Random{{.Name}}s(100) + data[0].Time = lastMonth + data[1].Time = lastMonth + data[2].Time = lastMonth + data[3].Time = yesterday + Sort(data) type args struct { - i int - j int + t time.Time } tests := []struct { - name string - s {{.Name}}Sequence - args args - want Sequence + name string + args args + length int }{ { - s: seq, + name: "regular", args: args{ - i: 2, - j: 10, + t: yesterday, }, - want: seq[2:10], + length: 1, }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Slice(tt.args.i, tt.args.j); !reflect.DeepEqual(got, tt.want) { - t.Errorf("{{.Name}}Sequence.Slice() = %v, want %v", got, tt.want) - } - }) - } -} - -func Test{{.Name}}Sequence_Sort(t *testing.T) { - tests := []struct { - name string - s {{.Name}}Sequence - }{ { - s: Random{{.Name}}Sequence(10), + name: "multiple", + args: args{ + t: lastMonth, + }, + length: 3, }, { - s: nil, + name: "none", + args: args{ + t: lastYear, + }, + length: 0, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - tt.s.Sort() - if !sort.IsSorted(sortableSequence{tt.s}) { - t.Error("{{.Name}}Sequence.Slice() failed") + s := New{{.Name}}Seq(data) + if got := s.Time(tt.args.t); len(got) != tt.length { + t.Errorf("Time() = %v, want %v", got, tt.length) } }) } } -func Test{{.Name}}Sequence_Range(t *testing.T) { - now := time.Now() - seq := Random{{.Name}}Sequence(10) - for i := range seq { - seq[i].Time = now.Add(time.Duration(i) * time.Second) - } - rand.Shuffle(seq.Len(), func(i, j int) { - seq[i], seq[j] = seq[j], seq[i] - }) +func Test{{.Name}}Seq_Value(t *testing.T) { + data := Random{{.Name}}s(100) + Sort(data) + + value1 := data[0].Value + value2 := data[1].Value + value3 := data[2].Value + + data[0].Value = value1 + data[1].Value = value2 + data[2].Value = value2 + data[3].Value = value2 type args struct { - afterOrEqual *time.Time - beforeOrEqual *time.Time + v {{.Type}} } tests := []struct { - name string - s {{.Name}}Sequence - args args - want {{.Name}}Sequence + name string + args args + length int }{ { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1 * time.Second)), - beforeOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: seq[1 : 5+1], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now), - beforeOrEqual: pt.Time(now.Add(100 * time.Second)), - }, - want: seq, - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1*time.Second + time.Millisecond)), - beforeOrEqual: pt.Time(now.Add(5*time.Second - time.Millisecond)), - }, - want: seq[2 : 4+1], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1*time.Second - time.Millisecond)), - beforeOrEqual: pt.Time(now.Add(5*time.Second + time.Millisecond)), - }, - want: seq[1 : 5+1], - }, - { - s: seq, + name: "regular", args: args{ - afterOrEqual: nil, - beforeOrEqual: pt.Time(now.Add(5 * time.Second)), + v: value1, }, - want: seq[:5+1], + length: 1, }, { - s: seq, + name: "multiple", args: args{ - afterOrEqual: pt.Time(now.Add(1 * time.Second)), - beforeOrEqual: nil, + v: value2, }, - want: seq[1:], + length: 3, }, { - s: seq, + name: "none", args: args{ - afterOrEqual: nil, - beforeOrEqual: nil, + v: value3, }, - want: seq, + length: 0, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Range(tt.args.afterOrEqual, tt.args.beforeOrEqual); !reflect.DeepEqual(got, tt.want) { - t.Errorf("{{.Name}}Sequence.Range() = %v, want %v", got, tt.want) + s := New{{.Name}}Seq(data) + if got := s.Value(tt.args.v); len(got) != tt.length { + t.Errorf("Value() = %v, want %v", got, tt.length) } }) } } -func Test{{.Name}}Sequence_First(t *testing.T) { - now := time.Now() - seq := Random{{.Name}}Sequence(10) - for i := range seq { - seq[i].Time = now.Add(time.Duration(i) * time.Second) - } - rand.Shuffle(seq.Len(), func(i, j int) { - seq[i], seq[j] = seq[j], seq[i] - }) +func Test{{.Name}}Seq_Visit(t *testing.T) { + data := Random{{.Name}}s(100) type args struct { - afterOrEqual *time.Time + fn func(i int, v {{.Name}}) (stop bool) } tests := []struct { name string - s {{.Name}}Sequence args args - want *{{.Name}}Item }{ { - s: seq, - args: args{ - afterOrEqual: nil, - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now), - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(-1 * time.Second)), - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(1 * time.Second)), - }, - want: &seq[1], - }, - { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: &seq[5], - }, - { - s: seq, + name: "regular", args: args{ - afterOrEqual: pt.Time(now.Add(5*time.Second - time.Millisecond)), + fn: func(i int, v {{.Name}}) (stop bool) { + return false + }, }, - want: &seq[5], }, { - s: seq, + name: "stop", args: args{ - afterOrEqual: pt.Time(now.Add(5*time.Second + time.Millisecond)), + fn: func(i int, v {{.Name}}) (stop bool) { + return i > 10 + }, }, - want: &seq[6], }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := New{{.Name}}Seq(data) + s.Visit(tt.args.fn) + }) + } +} + +func Test{{.Name}}Seq_Sum(t *testing.T) { + data := Random{{.Name}}s(100) + var sum {{.Type}} + for _, v := range data { + sum += v.Value + } + tests := []struct { + name string + want {{.Type}} + }{ { - s: seq, - args: args{ - afterOrEqual: pt.Time(now.Add(100 * time.Second)), - }, - want: nil, + name: "regular", + want: sum, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if got := tt.s.First(tt.args.afterOrEqual); !reflect.DeepEqual(got, tt.want) { - t.Errorf("{{.Name}}Sequence.First() = %v, want %v", got, tt.want) + s := New{{.Name}}Seq(data) + if got := s.Sum(); got != tt.want { + t.Errorf("Sum() = %v, want %v", got, tt.want) } }) } } -func Test{{.Name}}Sequence_Last(t *testing.T) { - now := time.Now() - seq := Random{{.Name}}Sequence(10) - for i := range seq { - seq[i].Time = now.Add(time.Duration(i) * time.Second) - } - rand.Shuffle(seq.Len(), func(i, j int) { - seq[i], seq[j] = seq[j], seq[i] - }) +func Test{{.Name}}Seq_Count(t *testing.T) { + data := Random{{.Name}}s(100) - type args struct { - beforeOrEqual *time.Time - } tests := []struct { name string - s {{.Name}}Sequence - args args - want *{{.Name}}Item + want int }{ { - s: seq, - args: args{ - beforeOrEqual: nil, - }, - want: &seq[len(seq)-1], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now), - }, - want: &seq[0], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(-1 * time.Second)), - }, - want: nil, - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(1 * time.Second)), - }, - want: &seq[1], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(5 * time.Second)), - }, - want: &seq[5], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(5*time.Second - time.Millisecond)), - }, - want: &seq[4], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(5*time.Second + time.Millisecond)), - }, - want: &seq[5], - }, - { - s: seq, - args: args{ - beforeOrEqual: pt.Time(now.Add(100 * time.Second)), - }, - want: &seq[9], + name: "regular", + want: len(data), }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Last(tt.args.beforeOrEqual); !reflect.DeepEqual(got, tt.want) { - t.Errorf("{{.Name}}Sequence.Last() = %v, want %v", got, tt.want) + s := New{{.Name}}Seq(data) + if got := s.Count(); got != tt.want { + t.Errorf("Count() = %v, want %v", got, tt.want) } }) } } -func Test{{.Name}}Sequence_Max(t *testing.T) { - seq1 := Random{{.Name}}Sequence(10) - seq1.Sort() - for i := range seq1 { - if i == 0 { - seq1[i].Value = 1 - } else { - seq1[i].Value = 0 - } - } - seq2 := Random{{.Name}}Sequence(10) - seq2.Sort() - for i := range seq2 { - if i == 0 { - seq2[i].Value = 0 - } else { - seq2[i].Value = 1 +func Test{{.Name}}Seq_Max(t *testing.T) { + data := Random{{.Name}}s(100) + max := data[0] + for _, v := range data { + if v.Value > max.Value { + max = v } } tests := []struct { name string - s {{.Name}}Sequence - want *{{.Name}}Item + want {{.Name}} }{ { - s: seq1, - want: &seq1[0], - }, - { - s: seq2, - want: &seq2[1], + name: "regular", + want: max, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Max(); !reflect.DeepEqual(got, tt.want) { - t.Errorf("{{.Name}}Sequence.Max() = %v, want %v", got, tt.want) + s := New{{.Name}}Seq(data) + if got := s.Max(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Max() = %v, want %v", got, tt.want) } }) } } -func Test{{.Name}}Sequence_Min(t *testing.T) { - seq1 := Random{{.Name}}Sequence(10) - seq1.Sort() - for i := range seq1 { - if i == 0 { - seq1[i].Value = 1 - } else { - seq1[i].Value = 0 - } - } - seq2 := Random{{.Name}}Sequence(10) - seq2.Sort() - for i := range seq2 { - if i == 0 { - seq2[i].Value = 0 - } else { - seq2[i].Value = 1 +func Test{{.Name}}Seq_Min(t *testing.T) { + data := Random{{.Name}}s(100) + min := data[0] + for _, v := range data { + if v.Value < min.Value { + min = v } } tests := []struct { name string - s {{.Name}}Sequence - want *{{.Name}}Item + want {{.Name}} }{ { - s: seq1, - want: &seq1[1], - }, - { - s: seq2, - want: &seq2[0], + name: "regular", + want: min, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Min(); !reflect.DeepEqual(got, tt.want) { - t.Errorf("{{.Name}}Sequence.Min() = %v, want %v", got, tt.want) + s := New{{.Name}}Seq(data) + if got := s.Min(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Min() = %v, want %v", got, tt.want) } }) } } -func Test{{.Name}}Sequence_Sum(t *testing.T) { - seq := Random{{.Name}}Sequence(10) - for i := range seq { - seq[i].Value = {{.Type}}(i) - } +func Test{{.Name}}Seq_First(t *testing.T) { + data := Random{{.Name}}s(100) + Sort(data) tests := []struct { name string - s {{.Name}}Sequence - want {{.Type}} + data {{.Name}}s + want {{.Name}} }{ { - s: seq, - want: 45, + + name: "regular", + data: data, + want: data[0], + }, + { + name: "emtpy", + data: nil, + want: {{.Name}}{}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Sum(); got != tt.want { - t.Errorf("{{.Name}}Sequence.Sum() = %v, want %v", got, tt.want) + s := New{{.Name}}Seq(tt.data) + if got := s.First(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("First() = %v, want %v", got, tt.want) } }) } } -func Test{{.Name}}Sequence_Average(t *testing.T) { - seq := Random{{.Name}}Sequence(10) - for i := range seq { - seq[i].Value = {{.Type}}(i) * 2 - } - +func Test{{.Name}}Seq_Last(t *testing.T) { + data := Random{{.Name}}s(100) + Sort(data) tests := []struct { name string - s {{.Name}}Sequence - want {{.Type}} + data {{.Name}}s + want {{.Name}} }{ { - s: seq, - want: 9, + + name: "regular", + data: data, + want: data[len(data)-1], }, { - s: nil, - want: 0, + name: "emtpy", + data: nil, + want: {{.Name}}{}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if got := tt.s.Average(); got != tt.want { - t.Errorf("{{.Name}}Sequence.Average() = %v, want %v", got, tt.want) + s := New{{.Name}}Seq(tt.data) + if got := s.Last(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Last() = %v, want %v", got, tt.want) } }) } } -func Test{{.Name}}Sequence_Percentile(t *testing.T) { - seq := Random{{.Name}}Sequence(100) - for i := range seq { - seq[i].Value = {{.Type}}(i) + 1 +func Test{{.Name}}Seq_Percentile(t *testing.T) { + data := Random{{.Name}}s(100) + Sort(data) + for i := range data { + data[i].Value = {{.Type}}(i) } type args struct { @@ -561,156 +401,373 @@ func Test{{.Name}}Sequence_Percentile(t *testing.T) { } tests := []struct { name string - s {{.Name}}Sequence + data {{.Name}}s args args - want {{.Type}} + want {{.Name}} }{ { - s: seq, + name: "data[0]", + data: data, args: args{ pct: 0, }, - want: 1, + want: data[0], }, { - s: seq, + name: "data[49]", + data: data, args: args{ pct: 0.5, }, - want: 50, + want: data[49], }, { - s: seq, + name: "0.95", + data: data, args: args{ pct: 0.95, }, - want: 95, + want: data[94], }, { - s: seq, + name: "0.955", + data: data, args: args{ pct: 0.955, }, - want: 95, + want: data[94], }, { - s: seq, + name: "1", + data: data, args: args{ pct: 1, }, - want: 100, + want: data[99], }, { - s: seq, + name: "1.1", + data: data, args: args{ pct: 1.1, }, - want: 100, + want: data[99], }, { - s: seq, + name: "-0.1", + data: data, args: args{ pct: -0.1, }, - want: 1, + want: data[0], }, { - s: nil, + name: "empty", + data: nil, args: args{ pct: 1, }, - want: 0, + want: {{.Name}}{}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - defer func() { - if r := recover(); r != nil { - if tt.args.pct > 1 || tt.args.pct < 0 { - return - } - t.Errorf("{{.Name}}Sequence.Percentile() failed: %v", r) - } - }() - if got := tt.s.Percentile(tt.args.pct); got != tt.want { - t.Errorf("{{.Name}}Sequence.Percentile() = %v, want %v", got, tt.want) + s := New{{.Name}}Seq(tt.data) + if got := s.Percentile(tt.args.pct); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Percentile() = %v, want %v", got, tt.want) } }) } } -func TestMerge{{.Name}}(t *testing.T) { - seq := Random{{.Name}}Sequence(10) - seq.Sort() +func Test{{.Name}}Seq_Range(t *testing.T) { + data := Random{{.Name}}s(100) + Sort(data) + type args struct { - seq1 {{.Name}}Sequence - seq2 {{.Name}}Sequence - fn func(item1, item2 *{{.Name}}Item) *{{.Name}}Item + interval Interval } tests := []struct { name string + data {{.Name}}s args args - want {{.Name}}Sequence + want {{.Name}}s + }{ + { + name: "regular", + data: data, + args: args{ + interval: Interval{ + NotBefore: &data[10].Time, + NotAfter: &data[89].Time, + }, + }, + want: data[10:90], + }, + { + name: "nil NotBefore", + data: data, + args: args{ + interval: Interval{ + NotAfter: &data[89].Time, + }, + }, + want: data[:90], + }, + { + name: "nil NotAfter", + data: data, + args: args{ + interval: Interval{ + NotBefore: &data[10].Time, + }, + }, + want: data[10:], + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := New{{.Name}}Seq(data) + if got := s.Range(tt.args.interval).slice; !reflect.DeepEqual(got, tt.want) { + t.Errorf("Range() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test{{.Name}}Seq_Merge(t *testing.T) { + data := Random{{.Name}}s(10) + Sort(data) + + type args struct { + fn func(t time.Time, v1, v2 *{{.Type}}) *{{.Type}} + slices []{{.Name}}s + } + tests := []struct { + name string + data {{.Name}}s + args args + want {{.Name}}s + wantErr bool }{ { name: "regular", + data: data[0:7], args: args{ - seq1: seq[0:7], - seq2: seq[3:10], - fn: func(item1, item2 *{{.Name}}Item) *{{.Name}}Item { - if item1 != nil { - return item1 + fn: func(t time.Time, v1, v2 *{{.Type}}) *{{.Type}} { + if v1 != nil { + return v1 } - return item2 + return v2 }, + slices: []{{.Name}}s{data[3:10]}, }, - want: seq, + want: data, }, { name: "reverse", + data: data[3:10], args: args{ - seq1: seq[3:10], - seq2: seq[0:7], - fn: func(item1, item2 *{{.Name}}Item) *{{.Name}}Item { - if item1 != nil { - return item1 + fn: func(t time.Time, v1, v2 *{{.Type}}) *{{.Type}} { + if v1 != nil { + return v1 } - return item2 + return v2 }, + slices: []{{.Name}}s{data[0:7]}, }, - want: seq, + want: data, }, { name: "nil fn", + data: nil, + args: args{ + fn: nil, + }, + wantErr: true, + }, + { + name: "multiple", + data: nil, + args: args{ + fn: func(t time.Time, v1, v2 *{{.Type}}) *{{.Type}} { + if v1 != nil { + return v1 + } + return v2 + }, + slices: []{{.Name}}s{ + data[1:2], + data[0:4], + nil, + data[2:9], + data[9:], + }, + }, + want: data, + }, + { + name: "not sorted", + data: data[0:7], args: args{ - seq1: seq[0:7], - seq2: seq[3:10], - fn: nil, + fn: func(t time.Time, v1, v2 *{{.Type}}) *{{.Type}} { + if v1 != nil { + return v1 + } + return v2 + }, + slices: []{{.Name}}s{ + append({{.Name}}s{data[9]}, data[3:9]...), + }, }, - want: nil, + want: data, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if got := Merge{{.Name}}(tt.args.seq1, tt.args.seq2, tt.args.fn); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Merge{{.Name}}() = %v, want %v", got, tt.want) + s := New{{.Name}}Seq(tt.data) + if err := s.Merge(tt.args.fn, tt.args.slices...); (err != nil) != tt.wantErr { + t.Errorf("Merge() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !tt.wantErr { + if got := s.slice; !reflect.DeepEqual(got, tt.want) { + t.Errorf("Merge() = %v, want %v", got, tt.want) + } } }) } } -func Random{{.Name}}Sequence(length int) {{.Name}}Sequence { +func Test{{.Name}}Seq_Aggregate(t *testing.T) { + data := Random{{.Name}}s(100) now := time.Now() - ret := make({{.Name}}Sequence, length) - for i := range ret { - delta := time.Duration(i) * time.Second - if rand.Float64() < 0.5 { - delta = -delta - } - ret[i] = {{.Name}}Item{ - Time: now.Add(delta), - Value: {{.Type}}(rand.Float64()*float64(math.MaxInt64)), - } + begin := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()) + end := begin.Add(24*time.Hour - 1) + + type args struct { + fn func(t time.Time, slice {{.Name}}s) *{{.Type}} + duration time.Duration + begin *time.Time + end *time.Time + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "regular", + args: args{ + fn: func(t time.Time, slice {{.Name}}s) *{{.Type}} { + ret := {{.Type}}(t.Hour()) + if len(slice) != 0 { + ret = 0 + } + for _, v := range slice { + ret += v.Value + } + return &ret + }, + duration: time.Hour, + begin: &begin, + end: &end, + }, + wantErr: false, + }, + { + name: "nil fn", + args: args{ + fn: nil, + duration: time.Hour, + begin: &begin, + end: &end, + }, + wantErr: true, + }, + { + name: "zero duration", + args: args{ + fn: func(t time.Time, slice {{.Name}}s) *{{.Type}} { + ret := {{.Type}}(t.Hour()) + if len(slice) != 0 { + ret = 0 + } + for _, v := range slice { + ret += v.Value + } + return &ret + }, + duration: 0, + begin: &begin, + end: &end, + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := New{{.Name}}Seq(data) + if err := s.Aggregate(tt.args.fn, tt.args.duration, tt.args.begin, tt.args.end); (err != nil) != tt.wantErr { + t.Errorf("Aggregate() error = %v, wantErr %v", err, tt.wantErr) + } + for i, v := range s.slice { + fmt.Println(i, v.Value, v.Time) + } + }) + } +} + +func Test{{.Name}}Seq_Trim(t *testing.T) { + data := Random{{.Name}}s(10) + Sort(data) + + type args struct { + fn func(i int, v {{.Name}}) bool + } + tests := []struct { + name string + args args + want {{.Name}}s + wantErr bool + }{ + { + name: "regular", + args: args{ + fn: func(i int, v {{.Name}}) bool { + return i >= 5 + }, + }, + want: data[:5], + wantErr: false, + }, + { + name: "nil fn", + args: args{ + fn: nil, + }, + want: data[:5], + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := New{{.Name}}Seq(data) + if err := s.Trim(tt.args.fn); (err != nil) != tt.wantErr { + t.Errorf("Trim() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !tt.wantErr { + if got := s.slice; !reflect.DeepEqual(got, tt.want) { + t.Errorf("Trim() = %v, want %v", got, tt.want) + for i, v := range got { + fmt.Println(i, v) + } + for i, v := range tt.want { + fmt.Println(i, v) + } + } + } + }) } - return ret } diff --git a/cmd/generate/main.go b/cmd/generate/main.go index d62890d..8f70607 100644 --- a/cmd/generate/main.go +++ b/cmd/generate/main.go @@ -39,7 +39,7 @@ func main() { { Name: "String", Type: "string", - Random: "// TODO", + Random: "0", }, { Name: "Int", @@ -71,19 +71,20 @@ func generate(tmpl, testTmpl *template.Template, meta Meta) { panic(err) } } - //{ - // output := &bytes.Buffer{} - // if err := testTmpl.Execute(output, meta); err != nil { - // panic(err) - // } - // - // src, err := format.Source(output.Bytes()) - // if err != nil { - // panic(err) - // } - // - // if err := ioutil.WriteFile(fmt.Sprintf("%s_sequence_test.go", meta.Type), src, 0666); err != nil { - // panic(err) - // } - //} + { + output := &bytes.Buffer{} + output.WriteString("// Code generated by cmd/generate. DO NOT EDIT.\n") + if err := testTmpl.Execute(output, meta); err != nil { + panic(err) + } + + src, err := format.Source(output.Bytes()) + if err != nil { + panic(err) + } + + if err := ioutil.WriteFile(fmt.Sprintf("gen_%s_seq_test.go", meta.Type), src, 0666); err != nil { + panic(err) + } + } } diff --git a/gen_float64_seq.go b/gen_float64_seq.go index c85765c..79f3d30 100644 --- a/gen_float64_seq.go +++ b/gen_float64_seq.go @@ -139,7 +139,7 @@ func (s *Float64Seq) Max() Float64 { if !found { max = v found = true - } else if v.Value < max.Value { + } else if v.Value > max.Value { max = v } } @@ -226,7 +226,7 @@ func (s *Float64Seq) Merge(fn func(t time.Time, v1, v2 *float64) *float64, slice v = fn(t, nil, &v2) i2++ case i2 == len(slice2): - t = slice2[i1].Time + t = slice1[i1].Time v1 := slice1[i1].Value v = fn(t, &v1, nil) i1++ @@ -243,7 +243,7 @@ func (s *Float64Seq) Merge(fn func(t time.Time, v1, v2 *float64) *float64, slice v = fn(t, &v1, nil) i1++ case slice1[i1].Time.After(slice2[i2].Time): - t = slice1[i2].Time + t = slice2[i2].Time v2 := slice2[i2].Value v = fn(t, nil, &v2) i2++ @@ -315,7 +315,7 @@ func (s *Float64Seq) Trim(fn func(i int, v Float64) bool) error { } updated := false - slice := s.slice[:0] + slice := make(Float64s, 0) for i, v := range s.slice { if fn(i, v) { updated = true @@ -324,7 +324,7 @@ func (s *Float64Seq) Trim(fn func(i int, v Float64) bool) error { } } - if !updated { + if updated { s.slice = slice s.buildIndex() } diff --git a/gen_float64_seq_test.go b/gen_float64_seq_test.go new file mode 100644 index 0000000..69a2475 --- /dev/null +++ b/gen_float64_seq_test.go @@ -0,0 +1,774 @@ +// Code generated by cmd/generate. DO NOT EDIT. +package timeseq + +import ( + "fmt" + "math/rand" + "reflect" + "testing" + "time" +) + +func RandomFloat64s(length int) Float64s { + now := time.Now() + ret := make(Float64s, length) + for i := range ret { + delta := time.Duration(i) * time.Second + if rand.Float64() < 0.5 { + delta = -delta + } + ret[i] = Float64{ + Time: now.Add(delta), + Value: rand.Float64(), + } + } + return ret +} + +func TestFloat64Seq_Float64s(t *testing.T) { + data := RandomFloat64s(100) + Sort(data) + + tests := []struct { + name string + want Float64s + }{ + { + name: "regular", + want: data, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewFloat64Seq(data) + if got := s.Float64s(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Float64s() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestFloat64Seq_Index(t *testing.T) { + data := RandomFloat64s(100) + Sort(data) + + type args struct { + i int + } + tests := []struct { + name string + args args + want Float64 + }{ + { + name: "regular", + args: args{ + i: 1, + }, + want: data[1], + }, + { + name: "less than zero", + args: args{ + i: -1, + }, + want: Float64{}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewFloat64Seq(data) + if got := s.Index(tt.args.i); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Index() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestFloat64Seq_Time(t *testing.T) { + now := time.Now() + yesterday := now.AddDate(0, 0, -1) + lastMonth := now.AddDate(0, -1, 0) + lastYear := now.AddDate(-1, 0, 0) + + data := RandomFloat64s(100) + data[0].Time = lastMonth + data[1].Time = lastMonth + data[2].Time = lastMonth + data[3].Time = yesterday + Sort(data) + + type args struct { + t time.Time + } + tests := []struct { + name string + args args + length int + }{ + { + name: "regular", + args: args{ + t: yesterday, + }, + length: 1, + }, + { + name: "multiple", + args: args{ + t: lastMonth, + }, + length: 3, + }, + { + name: "none", + args: args{ + t: lastYear, + }, + length: 0, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewFloat64Seq(data) + if got := s.Time(tt.args.t); len(got) != tt.length { + t.Errorf("Time() = %v, want %v", got, tt.length) + } + }) + } +} + +func TestFloat64Seq_Value(t *testing.T) { + data := RandomFloat64s(100) + Sort(data) + + value1 := data[0].Value + value2 := data[1].Value + value3 := data[2].Value + + data[0].Value = value1 + data[1].Value = value2 + data[2].Value = value2 + data[3].Value = value2 + + type args struct { + v float64 + } + tests := []struct { + name string + args args + length int + }{ + { + name: "regular", + args: args{ + v: value1, + }, + length: 1, + }, + { + name: "multiple", + args: args{ + v: value2, + }, + length: 3, + }, + { + name: "none", + args: args{ + v: value3, + }, + length: 0, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewFloat64Seq(data) + if got := s.Value(tt.args.v); len(got) != tt.length { + t.Errorf("Value() = %v, want %v", got, tt.length) + } + }) + } +} + +func TestFloat64Seq_Visit(t *testing.T) { + data := RandomFloat64s(100) + + type args struct { + fn func(i int, v Float64) (stop bool) + } + tests := []struct { + name string + args args + }{ + { + name: "regular", + args: args{ + fn: func(i int, v Float64) (stop bool) { + return false + }, + }, + }, + { + name: "stop", + args: args{ + fn: func(i int, v Float64) (stop bool) { + return i > 10 + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewFloat64Seq(data) + s.Visit(tt.args.fn) + }) + } +} + +func TestFloat64Seq_Sum(t *testing.T) { + data := RandomFloat64s(100) + var sum float64 + for _, v := range data { + sum += v.Value + } + tests := []struct { + name string + want float64 + }{ + { + name: "regular", + want: sum, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewFloat64Seq(data) + if got := s.Sum(); got != tt.want { + t.Errorf("Sum() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestFloat64Seq_Count(t *testing.T) { + data := RandomFloat64s(100) + + tests := []struct { + name string + want int + }{ + { + name: "regular", + want: len(data), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewFloat64Seq(data) + if got := s.Count(); got != tt.want { + t.Errorf("Count() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestFloat64Seq_Max(t *testing.T) { + data := RandomFloat64s(100) + max := data[0] + for _, v := range data { + if v.Value > max.Value { + max = v + } + } + + tests := []struct { + name string + want Float64 + }{ + { + name: "regular", + want: max, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewFloat64Seq(data) + if got := s.Max(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Max() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestFloat64Seq_Min(t *testing.T) { + data := RandomFloat64s(100) + min := data[0] + for _, v := range data { + if v.Value < min.Value { + min = v + } + } + + tests := []struct { + name string + want Float64 + }{ + { + name: "regular", + want: min, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewFloat64Seq(data) + if got := s.Min(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Min() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestFloat64Seq_First(t *testing.T) { + data := RandomFloat64s(100) + Sort(data) + + tests := []struct { + name string + data Float64s + want Float64 + }{ + { + + name: "regular", + data: data, + want: data[0], + }, + { + name: "emtpy", + data: nil, + want: Float64{}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewFloat64Seq(tt.data) + if got := s.First(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("First() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestFloat64Seq_Last(t *testing.T) { + data := RandomFloat64s(100) + Sort(data) + tests := []struct { + name string + data Float64s + want Float64 + }{ + { + + name: "regular", + data: data, + want: data[len(data)-1], + }, + { + name: "emtpy", + data: nil, + want: Float64{}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewFloat64Seq(tt.data) + if got := s.Last(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Last() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestFloat64Seq_Percentile(t *testing.T) { + data := RandomFloat64s(100) + Sort(data) + for i := range data { + data[i].Value = float64(i) + } + + type args struct { + pct float64 + } + tests := []struct { + name string + data Float64s + args args + want Float64 + }{ + { + name: "data[0]", + data: data, + args: args{ + pct: 0, + }, + want: data[0], + }, + { + name: "data[49]", + data: data, + args: args{ + pct: 0.5, + }, + want: data[49], + }, + { + name: "0.95", + data: data, + args: args{ + pct: 0.95, + }, + want: data[94], + }, + { + name: "0.955", + data: data, + args: args{ + pct: 0.955, + }, + want: data[94], + }, + { + name: "1", + data: data, + args: args{ + pct: 1, + }, + want: data[99], + }, + { + name: "1.1", + data: data, + args: args{ + pct: 1.1, + }, + want: data[99], + }, + { + name: "-0.1", + data: data, + args: args{ + pct: -0.1, + }, + want: data[0], + }, + { + name: "empty", + data: nil, + args: args{ + pct: 1, + }, + want: Float64{}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewFloat64Seq(tt.data) + if got := s.Percentile(tt.args.pct); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Percentile() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestFloat64Seq_Range(t *testing.T) { + data := RandomFloat64s(100) + Sort(data) + + type args struct { + interval Interval + } + tests := []struct { + name string + data Float64s + args args + want Float64s + }{ + { + name: "regular", + data: data, + args: args{ + interval: Interval{ + NotBefore: &data[10].Time, + NotAfter: &data[89].Time, + }, + }, + want: data[10:90], + }, + { + name: "nil NotBefore", + data: data, + args: args{ + interval: Interval{ + NotAfter: &data[89].Time, + }, + }, + want: data[:90], + }, + { + name: "nil NotAfter", + data: data, + args: args{ + interval: Interval{ + NotBefore: &data[10].Time, + }, + }, + want: data[10:], + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewFloat64Seq(data) + if got := s.Range(tt.args.interval).slice; !reflect.DeepEqual(got, tt.want) { + t.Errorf("Range() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestFloat64Seq_Merge(t *testing.T) { + data := RandomFloat64s(10) + Sort(data) + + type args struct { + fn func(t time.Time, v1, v2 *float64) *float64 + slices []Float64s + } + tests := []struct { + name string + data Float64s + args args + want Float64s + wantErr bool + }{ + { + name: "regular", + data: data[0:7], + args: args{ + fn: func(t time.Time, v1, v2 *float64) *float64 { + if v1 != nil { + return v1 + } + return v2 + }, + slices: []Float64s{data[3:10]}, + }, + want: data, + }, + { + name: "reverse", + data: data[3:10], + args: args{ + fn: func(t time.Time, v1, v2 *float64) *float64 { + if v1 != nil { + return v1 + } + return v2 + }, + slices: []Float64s{data[0:7]}, + }, + want: data, + }, + { + name: "nil fn", + data: nil, + args: args{ + fn: nil, + }, + wantErr: true, + }, + { + name: "multiple", + data: nil, + args: args{ + fn: func(t time.Time, v1, v2 *float64) *float64 { + if v1 != nil { + return v1 + } + return v2 + }, + slices: []Float64s{ + data[1:2], + data[0:4], + nil, + data[2:9], + data[9:], + }, + }, + want: data, + }, + { + name: "not sorted", + data: data[0:7], + args: args{ + fn: func(t time.Time, v1, v2 *float64) *float64 { + if v1 != nil { + return v1 + } + return v2 + }, + slices: []Float64s{ + append(Float64s{data[9]}, data[3:9]...), + }, + }, + want: data, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewFloat64Seq(tt.data) + if err := s.Merge(tt.args.fn, tt.args.slices...); (err != nil) != tt.wantErr { + t.Errorf("Merge() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !tt.wantErr { + if got := s.slice; !reflect.DeepEqual(got, tt.want) { + t.Errorf("Merge() = %v, want %v", got, tt.want) + } + } + }) + } +} + +func TestFloat64Seq_Aggregate(t *testing.T) { + data := RandomFloat64s(100) + now := time.Now() + begin := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()) + end := begin.Add(24*time.Hour - 1) + + type args struct { + fn func(t time.Time, slice Float64s) *float64 + duration time.Duration + begin *time.Time + end *time.Time + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "regular", + args: args{ + fn: func(t time.Time, slice Float64s) *float64 { + ret := float64(t.Hour()) + if len(slice) != 0 { + ret = 0 + } + for _, v := range slice { + ret += v.Value + } + return &ret + }, + duration: time.Hour, + begin: &begin, + end: &end, + }, + wantErr: false, + }, + { + name: "nil fn", + args: args{ + fn: nil, + duration: time.Hour, + begin: &begin, + end: &end, + }, + wantErr: true, + }, + { + name: "zero duration", + args: args{ + fn: func(t time.Time, slice Float64s) *float64 { + ret := float64(t.Hour()) + if len(slice) != 0 { + ret = 0 + } + for _, v := range slice { + ret += v.Value + } + return &ret + }, + duration: 0, + begin: &begin, + end: &end, + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewFloat64Seq(data) + if err := s.Aggregate(tt.args.fn, tt.args.duration, tt.args.begin, tt.args.end); (err != nil) != tt.wantErr { + t.Errorf("Aggregate() error = %v, wantErr %v", err, tt.wantErr) + } + for i, v := range s.slice { + fmt.Println(i, v.Value, v.Time) + } + }) + } +} + +func TestFloat64Seq_Trim(t *testing.T) { + data := RandomFloat64s(10) + Sort(data) + + type args struct { + fn func(i int, v Float64) bool + } + tests := []struct { + name string + args args + want Float64s + wantErr bool + }{ + { + name: "regular", + args: args{ + fn: func(i int, v Float64) bool { + return i >= 5 + }, + }, + want: data[:5], + wantErr: false, + }, + { + name: "nil fn", + args: args{ + fn: nil, + }, + want: data[:5], + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewFloat64Seq(data) + if err := s.Trim(tt.args.fn); (err != nil) != tt.wantErr { + t.Errorf("Trim() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !tt.wantErr { + if got := s.slice; !reflect.DeepEqual(got, tt.want) { + t.Errorf("Trim() = %v, want %v", got, tt.want) + for i, v := range got { + fmt.Println(i, v) + } + for i, v := range tt.want { + fmt.Println(i, v) + } + } + } + }) + } +} diff --git a/gen_int64_seq.go b/gen_int64_seq.go index efd7523..ec4e227 100644 --- a/gen_int64_seq.go +++ b/gen_int64_seq.go @@ -139,7 +139,7 @@ func (s *Int64Seq) Max() Int64 { if !found { max = v found = true - } else if v.Value < max.Value { + } else if v.Value > max.Value { max = v } } @@ -226,7 +226,7 @@ func (s *Int64Seq) Merge(fn func(t time.Time, v1, v2 *int64) *int64, slices ...I v = fn(t, nil, &v2) i2++ case i2 == len(slice2): - t = slice2[i1].Time + t = slice1[i1].Time v1 := slice1[i1].Value v = fn(t, &v1, nil) i1++ @@ -243,7 +243,7 @@ func (s *Int64Seq) Merge(fn func(t time.Time, v1, v2 *int64) *int64, slices ...I v = fn(t, &v1, nil) i1++ case slice1[i1].Time.After(slice2[i2].Time): - t = slice1[i2].Time + t = slice2[i2].Time v2 := slice2[i2].Value v = fn(t, nil, &v2) i2++ @@ -315,7 +315,7 @@ func (s *Int64Seq) Trim(fn func(i int, v Int64) bool) error { } updated := false - slice := s.slice[:0] + slice := make(Int64s, 0) for i, v := range s.slice { if fn(i, v) { updated = true @@ -324,7 +324,7 @@ func (s *Int64Seq) Trim(fn func(i int, v Int64) bool) error { } } - if !updated { + if updated { s.slice = slice s.buildIndex() } diff --git a/gen_int64_seq_test.go b/gen_int64_seq_test.go new file mode 100644 index 0000000..7433423 --- /dev/null +++ b/gen_int64_seq_test.go @@ -0,0 +1,774 @@ +// Code generated by cmd/generate. DO NOT EDIT. +package timeseq + +import ( + "fmt" + "math/rand" + "reflect" + "testing" + "time" +) + +func RandomInt64s(length int) Int64s { + now := time.Now() + ret := make(Int64s, length) + for i := range ret { + delta := time.Duration(i) * time.Second + if rand.Float64() < 0.5 { + delta = -delta + } + ret[i] = Int64{ + Time: now.Add(delta), + Value: rand.Int63(), + } + } + return ret +} + +func TestInt64Seq_Int64s(t *testing.T) { + data := RandomInt64s(100) + Sort(data) + + tests := []struct { + name string + want Int64s + }{ + { + name: "regular", + want: data, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewInt64Seq(data) + if got := s.Int64s(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Int64s() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestInt64Seq_Index(t *testing.T) { + data := RandomInt64s(100) + Sort(data) + + type args struct { + i int + } + tests := []struct { + name string + args args + want Int64 + }{ + { + name: "regular", + args: args{ + i: 1, + }, + want: data[1], + }, + { + name: "less than zero", + args: args{ + i: -1, + }, + want: Int64{}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewInt64Seq(data) + if got := s.Index(tt.args.i); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Index() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestInt64Seq_Time(t *testing.T) { + now := time.Now() + yesterday := now.AddDate(0, 0, -1) + lastMonth := now.AddDate(0, -1, 0) + lastYear := now.AddDate(-1, 0, 0) + + data := RandomInt64s(100) + data[0].Time = lastMonth + data[1].Time = lastMonth + data[2].Time = lastMonth + data[3].Time = yesterday + Sort(data) + + type args struct { + t time.Time + } + tests := []struct { + name string + args args + length int + }{ + { + name: "regular", + args: args{ + t: yesterday, + }, + length: 1, + }, + { + name: "multiple", + args: args{ + t: lastMonth, + }, + length: 3, + }, + { + name: "none", + args: args{ + t: lastYear, + }, + length: 0, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewInt64Seq(data) + if got := s.Time(tt.args.t); len(got) != tt.length { + t.Errorf("Time() = %v, want %v", got, tt.length) + } + }) + } +} + +func TestInt64Seq_Value(t *testing.T) { + data := RandomInt64s(100) + Sort(data) + + value1 := data[0].Value + value2 := data[1].Value + value3 := data[2].Value + + data[0].Value = value1 + data[1].Value = value2 + data[2].Value = value2 + data[3].Value = value2 + + type args struct { + v int64 + } + tests := []struct { + name string + args args + length int + }{ + { + name: "regular", + args: args{ + v: value1, + }, + length: 1, + }, + { + name: "multiple", + args: args{ + v: value2, + }, + length: 3, + }, + { + name: "none", + args: args{ + v: value3, + }, + length: 0, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewInt64Seq(data) + if got := s.Value(tt.args.v); len(got) != tt.length { + t.Errorf("Value() = %v, want %v", got, tt.length) + } + }) + } +} + +func TestInt64Seq_Visit(t *testing.T) { + data := RandomInt64s(100) + + type args struct { + fn func(i int, v Int64) (stop bool) + } + tests := []struct { + name string + args args + }{ + { + name: "regular", + args: args{ + fn: func(i int, v Int64) (stop bool) { + return false + }, + }, + }, + { + name: "stop", + args: args{ + fn: func(i int, v Int64) (stop bool) { + return i > 10 + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewInt64Seq(data) + s.Visit(tt.args.fn) + }) + } +} + +func TestInt64Seq_Sum(t *testing.T) { + data := RandomInt64s(100) + var sum int64 + for _, v := range data { + sum += v.Value + } + tests := []struct { + name string + want int64 + }{ + { + name: "regular", + want: sum, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewInt64Seq(data) + if got := s.Sum(); got != tt.want { + t.Errorf("Sum() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestInt64Seq_Count(t *testing.T) { + data := RandomInt64s(100) + + tests := []struct { + name string + want int + }{ + { + name: "regular", + want: len(data), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewInt64Seq(data) + if got := s.Count(); got != tt.want { + t.Errorf("Count() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestInt64Seq_Max(t *testing.T) { + data := RandomInt64s(100) + max := data[0] + for _, v := range data { + if v.Value > max.Value { + max = v + } + } + + tests := []struct { + name string + want Int64 + }{ + { + name: "regular", + want: max, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewInt64Seq(data) + if got := s.Max(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Max() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestInt64Seq_Min(t *testing.T) { + data := RandomInt64s(100) + min := data[0] + for _, v := range data { + if v.Value < min.Value { + min = v + } + } + + tests := []struct { + name string + want Int64 + }{ + { + name: "regular", + want: min, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewInt64Seq(data) + if got := s.Min(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Min() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestInt64Seq_First(t *testing.T) { + data := RandomInt64s(100) + Sort(data) + + tests := []struct { + name string + data Int64s + want Int64 + }{ + { + + name: "regular", + data: data, + want: data[0], + }, + { + name: "emtpy", + data: nil, + want: Int64{}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewInt64Seq(tt.data) + if got := s.First(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("First() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestInt64Seq_Last(t *testing.T) { + data := RandomInt64s(100) + Sort(data) + tests := []struct { + name string + data Int64s + want Int64 + }{ + { + + name: "regular", + data: data, + want: data[len(data)-1], + }, + { + name: "emtpy", + data: nil, + want: Int64{}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewInt64Seq(tt.data) + if got := s.Last(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Last() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestInt64Seq_Percentile(t *testing.T) { + data := RandomInt64s(100) + Sort(data) + for i := range data { + data[i].Value = int64(i) + } + + type args struct { + pct float64 + } + tests := []struct { + name string + data Int64s + args args + want Int64 + }{ + { + name: "data[0]", + data: data, + args: args{ + pct: 0, + }, + want: data[0], + }, + { + name: "data[49]", + data: data, + args: args{ + pct: 0.5, + }, + want: data[49], + }, + { + name: "0.95", + data: data, + args: args{ + pct: 0.95, + }, + want: data[94], + }, + { + name: "0.955", + data: data, + args: args{ + pct: 0.955, + }, + want: data[94], + }, + { + name: "1", + data: data, + args: args{ + pct: 1, + }, + want: data[99], + }, + { + name: "1.1", + data: data, + args: args{ + pct: 1.1, + }, + want: data[99], + }, + { + name: "-0.1", + data: data, + args: args{ + pct: -0.1, + }, + want: data[0], + }, + { + name: "empty", + data: nil, + args: args{ + pct: 1, + }, + want: Int64{}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewInt64Seq(tt.data) + if got := s.Percentile(tt.args.pct); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Percentile() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestInt64Seq_Range(t *testing.T) { + data := RandomInt64s(100) + Sort(data) + + type args struct { + interval Interval + } + tests := []struct { + name string + data Int64s + args args + want Int64s + }{ + { + name: "regular", + data: data, + args: args{ + interval: Interval{ + NotBefore: &data[10].Time, + NotAfter: &data[89].Time, + }, + }, + want: data[10:90], + }, + { + name: "nil NotBefore", + data: data, + args: args{ + interval: Interval{ + NotAfter: &data[89].Time, + }, + }, + want: data[:90], + }, + { + name: "nil NotAfter", + data: data, + args: args{ + interval: Interval{ + NotBefore: &data[10].Time, + }, + }, + want: data[10:], + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewInt64Seq(data) + if got := s.Range(tt.args.interval).slice; !reflect.DeepEqual(got, tt.want) { + t.Errorf("Range() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestInt64Seq_Merge(t *testing.T) { + data := RandomInt64s(10) + Sort(data) + + type args struct { + fn func(t time.Time, v1, v2 *int64) *int64 + slices []Int64s + } + tests := []struct { + name string + data Int64s + args args + want Int64s + wantErr bool + }{ + { + name: "regular", + data: data[0:7], + args: args{ + fn: func(t time.Time, v1, v2 *int64) *int64 { + if v1 != nil { + return v1 + } + return v2 + }, + slices: []Int64s{data[3:10]}, + }, + want: data, + }, + { + name: "reverse", + data: data[3:10], + args: args{ + fn: func(t time.Time, v1, v2 *int64) *int64 { + if v1 != nil { + return v1 + } + return v2 + }, + slices: []Int64s{data[0:7]}, + }, + want: data, + }, + { + name: "nil fn", + data: nil, + args: args{ + fn: nil, + }, + wantErr: true, + }, + { + name: "multiple", + data: nil, + args: args{ + fn: func(t time.Time, v1, v2 *int64) *int64 { + if v1 != nil { + return v1 + } + return v2 + }, + slices: []Int64s{ + data[1:2], + data[0:4], + nil, + data[2:9], + data[9:], + }, + }, + want: data, + }, + { + name: "not sorted", + data: data[0:7], + args: args{ + fn: func(t time.Time, v1, v2 *int64) *int64 { + if v1 != nil { + return v1 + } + return v2 + }, + slices: []Int64s{ + append(Int64s{data[9]}, data[3:9]...), + }, + }, + want: data, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewInt64Seq(tt.data) + if err := s.Merge(tt.args.fn, tt.args.slices...); (err != nil) != tt.wantErr { + t.Errorf("Merge() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !tt.wantErr { + if got := s.slice; !reflect.DeepEqual(got, tt.want) { + t.Errorf("Merge() = %v, want %v", got, tt.want) + } + } + }) + } +} + +func TestInt64Seq_Aggregate(t *testing.T) { + data := RandomInt64s(100) + now := time.Now() + begin := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()) + end := begin.Add(24*time.Hour - 1) + + type args struct { + fn func(t time.Time, slice Int64s) *int64 + duration time.Duration + begin *time.Time + end *time.Time + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "regular", + args: args{ + fn: func(t time.Time, slice Int64s) *int64 { + ret := int64(t.Hour()) + if len(slice) != 0 { + ret = 0 + } + for _, v := range slice { + ret += v.Value + } + return &ret + }, + duration: time.Hour, + begin: &begin, + end: &end, + }, + wantErr: false, + }, + { + name: "nil fn", + args: args{ + fn: nil, + duration: time.Hour, + begin: &begin, + end: &end, + }, + wantErr: true, + }, + { + name: "zero duration", + args: args{ + fn: func(t time.Time, slice Int64s) *int64 { + ret := int64(t.Hour()) + if len(slice) != 0 { + ret = 0 + } + for _, v := range slice { + ret += v.Value + } + return &ret + }, + duration: 0, + begin: &begin, + end: &end, + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewInt64Seq(data) + if err := s.Aggregate(tt.args.fn, tt.args.duration, tt.args.begin, tt.args.end); (err != nil) != tt.wantErr { + t.Errorf("Aggregate() error = %v, wantErr %v", err, tt.wantErr) + } + for i, v := range s.slice { + fmt.Println(i, v.Value, v.Time) + } + }) + } +} + +func TestInt64Seq_Trim(t *testing.T) { + data := RandomInt64s(10) + Sort(data) + + type args struct { + fn func(i int, v Int64) bool + } + tests := []struct { + name string + args args + want Int64s + wantErr bool + }{ + { + name: "regular", + args: args{ + fn: func(i int, v Int64) bool { + return i >= 5 + }, + }, + want: data[:5], + wantErr: false, + }, + { + name: "nil fn", + args: args{ + fn: nil, + }, + want: data[:5], + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewInt64Seq(data) + if err := s.Trim(tt.args.fn); (err != nil) != tt.wantErr { + t.Errorf("Trim() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !tt.wantErr { + if got := s.slice; !reflect.DeepEqual(got, tt.want) { + t.Errorf("Trim() = %v, want %v", got, tt.want) + for i, v := range got { + fmt.Println(i, v) + } + for i, v := range tt.want { + fmt.Println(i, v) + } + } + } + }) + } +} diff --git a/gen_int_seq.go b/gen_int_seq.go index fa61d3a..65dbe54 100644 --- a/gen_int_seq.go +++ b/gen_int_seq.go @@ -139,7 +139,7 @@ func (s *IntSeq) Max() Int { if !found { max = v found = true - } else if v.Value < max.Value { + } else if v.Value > max.Value { max = v } } @@ -226,7 +226,7 @@ func (s *IntSeq) Merge(fn func(t time.Time, v1, v2 *int) *int, slices ...Ints) e v = fn(t, nil, &v2) i2++ case i2 == len(slice2): - t = slice2[i1].Time + t = slice1[i1].Time v1 := slice1[i1].Value v = fn(t, &v1, nil) i1++ @@ -243,7 +243,7 @@ func (s *IntSeq) Merge(fn func(t time.Time, v1, v2 *int) *int, slices ...Ints) e v = fn(t, &v1, nil) i1++ case slice1[i1].Time.After(slice2[i2].Time): - t = slice1[i2].Time + t = slice2[i2].Time v2 := slice2[i2].Value v = fn(t, nil, &v2) i2++ @@ -315,7 +315,7 @@ func (s *IntSeq) Trim(fn func(i int, v Int) bool) error { } updated := false - slice := s.slice[:0] + slice := make(Ints, 0) for i, v := range s.slice { if fn(i, v) { updated = true @@ -324,7 +324,7 @@ func (s *IntSeq) Trim(fn func(i int, v Int) bool) error { } } - if !updated { + if updated { s.slice = slice s.buildIndex() } diff --git a/gen_int_seq_test.go b/gen_int_seq_test.go new file mode 100644 index 0000000..a0fe95e --- /dev/null +++ b/gen_int_seq_test.go @@ -0,0 +1,774 @@ +// Code generated by cmd/generate. DO NOT EDIT. +package timeseq + +import ( + "fmt" + "math/rand" + "reflect" + "testing" + "time" +) + +func RandomInts(length int) Ints { + now := time.Now() + ret := make(Ints, length) + for i := range ret { + delta := time.Duration(i) * time.Second + if rand.Float64() < 0.5 { + delta = -delta + } + ret[i] = Int{ + Time: now.Add(delta), + Value: rand.Int(), + } + } + return ret +} + +func TestIntSeq_Ints(t *testing.T) { + data := RandomInts(100) + Sort(data) + + tests := []struct { + name string + want Ints + }{ + { + name: "regular", + want: data, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewIntSeq(data) + if got := s.Ints(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Ints() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestIntSeq_Index(t *testing.T) { + data := RandomInts(100) + Sort(data) + + type args struct { + i int + } + tests := []struct { + name string + args args + want Int + }{ + { + name: "regular", + args: args{ + i: 1, + }, + want: data[1], + }, + { + name: "less than zero", + args: args{ + i: -1, + }, + want: Int{}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewIntSeq(data) + if got := s.Index(tt.args.i); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Index() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestIntSeq_Time(t *testing.T) { + now := time.Now() + yesterday := now.AddDate(0, 0, -1) + lastMonth := now.AddDate(0, -1, 0) + lastYear := now.AddDate(-1, 0, 0) + + data := RandomInts(100) + data[0].Time = lastMonth + data[1].Time = lastMonth + data[2].Time = lastMonth + data[3].Time = yesterday + Sort(data) + + type args struct { + t time.Time + } + tests := []struct { + name string + args args + length int + }{ + { + name: "regular", + args: args{ + t: yesterday, + }, + length: 1, + }, + { + name: "multiple", + args: args{ + t: lastMonth, + }, + length: 3, + }, + { + name: "none", + args: args{ + t: lastYear, + }, + length: 0, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewIntSeq(data) + if got := s.Time(tt.args.t); len(got) != tt.length { + t.Errorf("Time() = %v, want %v", got, tt.length) + } + }) + } +} + +func TestIntSeq_Value(t *testing.T) { + data := RandomInts(100) + Sort(data) + + value1 := data[0].Value + value2 := data[1].Value + value3 := data[2].Value + + data[0].Value = value1 + data[1].Value = value2 + data[2].Value = value2 + data[3].Value = value2 + + type args struct { + v int + } + tests := []struct { + name string + args args + length int + }{ + { + name: "regular", + args: args{ + v: value1, + }, + length: 1, + }, + { + name: "multiple", + args: args{ + v: value2, + }, + length: 3, + }, + { + name: "none", + args: args{ + v: value3, + }, + length: 0, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewIntSeq(data) + if got := s.Value(tt.args.v); len(got) != tt.length { + t.Errorf("Value() = %v, want %v", got, tt.length) + } + }) + } +} + +func TestIntSeq_Visit(t *testing.T) { + data := RandomInts(100) + + type args struct { + fn func(i int, v Int) (stop bool) + } + tests := []struct { + name string + args args + }{ + { + name: "regular", + args: args{ + fn: func(i int, v Int) (stop bool) { + return false + }, + }, + }, + { + name: "stop", + args: args{ + fn: func(i int, v Int) (stop bool) { + return i > 10 + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewIntSeq(data) + s.Visit(tt.args.fn) + }) + } +} + +func TestIntSeq_Sum(t *testing.T) { + data := RandomInts(100) + var sum int + for _, v := range data { + sum += v.Value + } + tests := []struct { + name string + want int + }{ + { + name: "regular", + want: sum, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewIntSeq(data) + if got := s.Sum(); got != tt.want { + t.Errorf("Sum() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestIntSeq_Count(t *testing.T) { + data := RandomInts(100) + + tests := []struct { + name string + want int + }{ + { + name: "regular", + want: len(data), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewIntSeq(data) + if got := s.Count(); got != tt.want { + t.Errorf("Count() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestIntSeq_Max(t *testing.T) { + data := RandomInts(100) + max := data[0] + for _, v := range data { + if v.Value > max.Value { + max = v + } + } + + tests := []struct { + name string + want Int + }{ + { + name: "regular", + want: max, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewIntSeq(data) + if got := s.Max(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Max() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestIntSeq_Min(t *testing.T) { + data := RandomInts(100) + min := data[0] + for _, v := range data { + if v.Value < min.Value { + min = v + } + } + + tests := []struct { + name string + want Int + }{ + { + name: "regular", + want: min, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewIntSeq(data) + if got := s.Min(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Min() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestIntSeq_First(t *testing.T) { + data := RandomInts(100) + Sort(data) + + tests := []struct { + name string + data Ints + want Int + }{ + { + + name: "regular", + data: data, + want: data[0], + }, + { + name: "emtpy", + data: nil, + want: Int{}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewIntSeq(tt.data) + if got := s.First(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("First() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestIntSeq_Last(t *testing.T) { + data := RandomInts(100) + Sort(data) + tests := []struct { + name string + data Ints + want Int + }{ + { + + name: "regular", + data: data, + want: data[len(data)-1], + }, + { + name: "emtpy", + data: nil, + want: Int{}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewIntSeq(tt.data) + if got := s.Last(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Last() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestIntSeq_Percentile(t *testing.T) { + data := RandomInts(100) + Sort(data) + for i := range data { + data[i].Value = int(i) + } + + type args struct { + pct float64 + } + tests := []struct { + name string + data Ints + args args + want Int + }{ + { + name: "data[0]", + data: data, + args: args{ + pct: 0, + }, + want: data[0], + }, + { + name: "data[49]", + data: data, + args: args{ + pct: 0.5, + }, + want: data[49], + }, + { + name: "0.95", + data: data, + args: args{ + pct: 0.95, + }, + want: data[94], + }, + { + name: "0.955", + data: data, + args: args{ + pct: 0.955, + }, + want: data[94], + }, + { + name: "1", + data: data, + args: args{ + pct: 1, + }, + want: data[99], + }, + { + name: "1.1", + data: data, + args: args{ + pct: 1.1, + }, + want: data[99], + }, + { + name: "-0.1", + data: data, + args: args{ + pct: -0.1, + }, + want: data[0], + }, + { + name: "empty", + data: nil, + args: args{ + pct: 1, + }, + want: Int{}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewIntSeq(tt.data) + if got := s.Percentile(tt.args.pct); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Percentile() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestIntSeq_Range(t *testing.T) { + data := RandomInts(100) + Sort(data) + + type args struct { + interval Interval + } + tests := []struct { + name string + data Ints + args args + want Ints + }{ + { + name: "regular", + data: data, + args: args{ + interval: Interval{ + NotBefore: &data[10].Time, + NotAfter: &data[89].Time, + }, + }, + want: data[10:90], + }, + { + name: "nil NotBefore", + data: data, + args: args{ + interval: Interval{ + NotAfter: &data[89].Time, + }, + }, + want: data[:90], + }, + { + name: "nil NotAfter", + data: data, + args: args{ + interval: Interval{ + NotBefore: &data[10].Time, + }, + }, + want: data[10:], + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewIntSeq(data) + if got := s.Range(tt.args.interval).slice; !reflect.DeepEqual(got, tt.want) { + t.Errorf("Range() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestIntSeq_Merge(t *testing.T) { + data := RandomInts(10) + Sort(data) + + type args struct { + fn func(t time.Time, v1, v2 *int) *int + slices []Ints + } + tests := []struct { + name string + data Ints + args args + want Ints + wantErr bool + }{ + { + name: "regular", + data: data[0:7], + args: args{ + fn: func(t time.Time, v1, v2 *int) *int { + if v1 != nil { + return v1 + } + return v2 + }, + slices: []Ints{data[3:10]}, + }, + want: data, + }, + { + name: "reverse", + data: data[3:10], + args: args{ + fn: func(t time.Time, v1, v2 *int) *int { + if v1 != nil { + return v1 + } + return v2 + }, + slices: []Ints{data[0:7]}, + }, + want: data, + }, + { + name: "nil fn", + data: nil, + args: args{ + fn: nil, + }, + wantErr: true, + }, + { + name: "multiple", + data: nil, + args: args{ + fn: func(t time.Time, v1, v2 *int) *int { + if v1 != nil { + return v1 + } + return v2 + }, + slices: []Ints{ + data[1:2], + data[0:4], + nil, + data[2:9], + data[9:], + }, + }, + want: data, + }, + { + name: "not sorted", + data: data[0:7], + args: args{ + fn: func(t time.Time, v1, v2 *int) *int { + if v1 != nil { + return v1 + } + return v2 + }, + slices: []Ints{ + append(Ints{data[9]}, data[3:9]...), + }, + }, + want: data, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewIntSeq(tt.data) + if err := s.Merge(tt.args.fn, tt.args.slices...); (err != nil) != tt.wantErr { + t.Errorf("Merge() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !tt.wantErr { + if got := s.slice; !reflect.DeepEqual(got, tt.want) { + t.Errorf("Merge() = %v, want %v", got, tt.want) + } + } + }) + } +} + +func TestIntSeq_Aggregate(t *testing.T) { + data := RandomInts(100) + now := time.Now() + begin := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()) + end := begin.Add(24*time.Hour - 1) + + type args struct { + fn func(t time.Time, slice Ints) *int + duration time.Duration + begin *time.Time + end *time.Time + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "regular", + args: args{ + fn: func(t time.Time, slice Ints) *int { + ret := int(t.Hour()) + if len(slice) != 0 { + ret = 0 + } + for _, v := range slice { + ret += v.Value + } + return &ret + }, + duration: time.Hour, + begin: &begin, + end: &end, + }, + wantErr: false, + }, + { + name: "nil fn", + args: args{ + fn: nil, + duration: time.Hour, + begin: &begin, + end: &end, + }, + wantErr: true, + }, + { + name: "zero duration", + args: args{ + fn: func(t time.Time, slice Ints) *int { + ret := int(t.Hour()) + if len(slice) != 0 { + ret = 0 + } + for _, v := range slice { + ret += v.Value + } + return &ret + }, + duration: 0, + begin: &begin, + end: &end, + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewIntSeq(data) + if err := s.Aggregate(tt.args.fn, tt.args.duration, tt.args.begin, tt.args.end); (err != nil) != tt.wantErr { + t.Errorf("Aggregate() error = %v, wantErr %v", err, tt.wantErr) + } + for i, v := range s.slice { + fmt.Println(i, v.Value, v.Time) + } + }) + } +} + +func TestIntSeq_Trim(t *testing.T) { + data := RandomInts(10) + Sort(data) + + type args struct { + fn func(i int, v Int) bool + } + tests := []struct { + name string + args args + want Ints + wantErr bool + }{ + { + name: "regular", + args: args{ + fn: func(i int, v Int) bool { + return i >= 5 + }, + }, + want: data[:5], + wantErr: false, + }, + { + name: "nil fn", + args: args{ + fn: nil, + }, + want: data[:5], + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewIntSeq(data) + if err := s.Trim(tt.args.fn); (err != nil) != tt.wantErr { + t.Errorf("Trim() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !tt.wantErr { + if got := s.slice; !reflect.DeepEqual(got, tt.want) { + t.Errorf("Trim() = %v, want %v", got, tt.want) + for i, v := range got { + fmt.Println(i, v) + } + for i, v := range tt.want { + fmt.Println(i, v) + } + } + } + }) + } +} diff --git a/gen_string_seq.go b/gen_string_seq.go index 7996714..cef2589 100644 --- a/gen_string_seq.go +++ b/gen_string_seq.go @@ -139,7 +139,7 @@ func (s *StringSeq) Max() String { if !found { max = v found = true - } else if v.Value < max.Value { + } else if v.Value > max.Value { max = v } } @@ -226,7 +226,7 @@ func (s *StringSeq) Merge(fn func(t time.Time, v1, v2 *string) *string, slices . v = fn(t, nil, &v2) i2++ case i2 == len(slice2): - t = slice2[i1].Time + t = slice1[i1].Time v1 := slice1[i1].Value v = fn(t, &v1, nil) i1++ @@ -243,7 +243,7 @@ func (s *StringSeq) Merge(fn func(t time.Time, v1, v2 *string) *string, slices . v = fn(t, &v1, nil) i1++ case slice1[i1].Time.After(slice2[i2].Time): - t = slice1[i2].Time + t = slice2[i2].Time v2 := slice2[i2].Value v = fn(t, nil, &v2) i2++ @@ -315,7 +315,7 @@ func (s *StringSeq) Trim(fn func(i int, v String) bool) error { } updated := false - slice := s.slice[:0] + slice := make(Strings, 0) for i, v := range s.slice { if fn(i, v) { updated = true @@ -324,7 +324,7 @@ func (s *StringSeq) Trim(fn func(i int, v String) bool) error { } } - if !updated { + if updated { s.slice = slice s.buildIndex() } diff --git a/gen_string_seq_test.go b/gen_string_seq_test.go new file mode 100644 index 0000000..1c650a0 --- /dev/null +++ b/gen_string_seq_test.go @@ -0,0 +1,774 @@ +// Code generated by cmd/generate. DO NOT EDIT. +package timeseq + +import ( + "fmt" + "math/rand" + "reflect" + "testing" + "time" +) + +func RandomStrings(length int) Strings { + now := time.Now() + ret := make(Strings, length) + for i := range ret { + delta := time.Duration(i) * time.Second + if rand.Float64() < 0.5 { + delta = -delta + } + ret[i] = String{ + Time: now.Add(delta), + Value: 0, + } + } + return ret +} + +func TestStringSeq_Strings(t *testing.T) { + data := RandomStrings(100) + Sort(data) + + tests := []struct { + name string + want Strings + }{ + { + name: "regular", + want: data, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewStringSeq(data) + if got := s.Strings(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Strings() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestStringSeq_Index(t *testing.T) { + data := RandomStrings(100) + Sort(data) + + type args struct { + i int + } + tests := []struct { + name string + args args + want String + }{ + { + name: "regular", + args: args{ + i: 1, + }, + want: data[1], + }, + { + name: "less than zero", + args: args{ + i: -1, + }, + want: String{}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewStringSeq(data) + if got := s.Index(tt.args.i); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Index() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestStringSeq_Time(t *testing.T) { + now := time.Now() + yesterday := now.AddDate(0, 0, -1) + lastMonth := now.AddDate(0, -1, 0) + lastYear := now.AddDate(-1, 0, 0) + + data := RandomStrings(100) + data[0].Time = lastMonth + data[1].Time = lastMonth + data[2].Time = lastMonth + data[3].Time = yesterday + Sort(data) + + type args struct { + t time.Time + } + tests := []struct { + name string + args args + length int + }{ + { + name: "regular", + args: args{ + t: yesterday, + }, + length: 1, + }, + { + name: "multiple", + args: args{ + t: lastMonth, + }, + length: 3, + }, + { + name: "none", + args: args{ + t: lastYear, + }, + length: 0, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewStringSeq(data) + if got := s.Time(tt.args.t); len(got) != tt.length { + t.Errorf("Time() = %v, want %v", got, tt.length) + } + }) + } +} + +func TestStringSeq_Value(t *testing.T) { + data := RandomStrings(100) + Sort(data) + + value1 := data[0].Value + value2 := data[1].Value + value3 := data[2].Value + + data[0].Value = value1 + data[1].Value = value2 + data[2].Value = value2 + data[3].Value = value2 + + type args struct { + v string + } + tests := []struct { + name string + args args + length int + }{ + { + name: "regular", + args: args{ + v: value1, + }, + length: 1, + }, + { + name: "multiple", + args: args{ + v: value2, + }, + length: 3, + }, + { + name: "none", + args: args{ + v: value3, + }, + length: 0, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewStringSeq(data) + if got := s.Value(tt.args.v); len(got) != tt.length { + t.Errorf("Value() = %v, want %v", got, tt.length) + } + }) + } +} + +func TestStringSeq_Visit(t *testing.T) { + data := RandomStrings(100) + + type args struct { + fn func(i int, v String) (stop bool) + } + tests := []struct { + name string + args args + }{ + { + name: "regular", + args: args{ + fn: func(i int, v String) (stop bool) { + return false + }, + }, + }, + { + name: "stop", + args: args{ + fn: func(i int, v String) (stop bool) { + return i > 10 + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewStringSeq(data) + s.Visit(tt.args.fn) + }) + } +} + +func TestStringSeq_Sum(t *testing.T) { + data := RandomStrings(100) + var sum string + for _, v := range data { + sum += v.Value + } + tests := []struct { + name string + want string + }{ + { + name: "regular", + want: sum, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewStringSeq(data) + if got := s.Sum(); got != tt.want { + t.Errorf("Sum() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestStringSeq_Count(t *testing.T) { + data := RandomStrings(100) + + tests := []struct { + name string + want int + }{ + { + name: "regular", + want: len(data), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewStringSeq(data) + if got := s.Count(); got != tt.want { + t.Errorf("Count() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestStringSeq_Max(t *testing.T) { + data := RandomStrings(100) + max := data[0] + for _, v := range data { + if v.Value > max.Value { + max = v + } + } + + tests := []struct { + name string + want String + }{ + { + name: "regular", + want: max, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewStringSeq(data) + if got := s.Max(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Max() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestStringSeq_Min(t *testing.T) { + data := RandomStrings(100) + min := data[0] + for _, v := range data { + if v.Value < min.Value { + min = v + } + } + + tests := []struct { + name string + want String + }{ + { + name: "regular", + want: min, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewStringSeq(data) + if got := s.Min(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Min() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestStringSeq_First(t *testing.T) { + data := RandomStrings(100) + Sort(data) + + tests := []struct { + name string + data Strings + want String + }{ + { + + name: "regular", + data: data, + want: data[0], + }, + { + name: "emtpy", + data: nil, + want: String{}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewStringSeq(tt.data) + if got := s.First(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("First() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestStringSeq_Last(t *testing.T) { + data := RandomStrings(100) + Sort(data) + tests := []struct { + name string + data Strings + want String + }{ + { + + name: "regular", + data: data, + want: data[len(data)-1], + }, + { + name: "emtpy", + data: nil, + want: String{}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewStringSeq(tt.data) + if got := s.Last(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Last() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestStringSeq_Percentile(t *testing.T) { + data := RandomStrings(100) + Sort(data) + for i := range data { + data[i].Value = string(i) + } + + type args struct { + pct float64 + } + tests := []struct { + name string + data Strings + args args + want String + }{ + { + name: "data[0]", + data: data, + args: args{ + pct: 0, + }, + want: data[0], + }, + { + name: "data[49]", + data: data, + args: args{ + pct: 0.5, + }, + want: data[49], + }, + { + name: "0.95", + data: data, + args: args{ + pct: 0.95, + }, + want: data[94], + }, + { + name: "0.955", + data: data, + args: args{ + pct: 0.955, + }, + want: data[94], + }, + { + name: "1", + data: data, + args: args{ + pct: 1, + }, + want: data[99], + }, + { + name: "1.1", + data: data, + args: args{ + pct: 1.1, + }, + want: data[99], + }, + { + name: "-0.1", + data: data, + args: args{ + pct: -0.1, + }, + want: data[0], + }, + { + name: "empty", + data: nil, + args: args{ + pct: 1, + }, + want: String{}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewStringSeq(tt.data) + if got := s.Percentile(tt.args.pct); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Percentile() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestStringSeq_Range(t *testing.T) { + data := RandomStrings(100) + Sort(data) + + type args struct { + interval Interval + } + tests := []struct { + name string + data Strings + args args + want Strings + }{ + { + name: "regular", + data: data, + args: args{ + interval: Interval{ + NotBefore: &data[10].Time, + NotAfter: &data[89].Time, + }, + }, + want: data[10:90], + }, + { + name: "nil NotBefore", + data: data, + args: args{ + interval: Interval{ + NotAfter: &data[89].Time, + }, + }, + want: data[:90], + }, + { + name: "nil NotAfter", + data: data, + args: args{ + interval: Interval{ + NotBefore: &data[10].Time, + }, + }, + want: data[10:], + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewStringSeq(data) + if got := s.Range(tt.args.interval).slice; !reflect.DeepEqual(got, tt.want) { + t.Errorf("Range() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestStringSeq_Merge(t *testing.T) { + data := RandomStrings(10) + Sort(data) + + type args struct { + fn func(t time.Time, v1, v2 *string) *string + slices []Strings + } + tests := []struct { + name string + data Strings + args args + want Strings + wantErr bool + }{ + { + name: "regular", + data: data[0:7], + args: args{ + fn: func(t time.Time, v1, v2 *string) *string { + if v1 != nil { + return v1 + } + return v2 + }, + slices: []Strings{data[3:10]}, + }, + want: data, + }, + { + name: "reverse", + data: data[3:10], + args: args{ + fn: func(t time.Time, v1, v2 *string) *string { + if v1 != nil { + return v1 + } + return v2 + }, + slices: []Strings{data[0:7]}, + }, + want: data, + }, + { + name: "nil fn", + data: nil, + args: args{ + fn: nil, + }, + wantErr: true, + }, + { + name: "multiple", + data: nil, + args: args{ + fn: func(t time.Time, v1, v2 *string) *string { + if v1 != nil { + return v1 + } + return v2 + }, + slices: []Strings{ + data[1:2], + data[0:4], + nil, + data[2:9], + data[9:], + }, + }, + want: data, + }, + { + name: "not sorted", + data: data[0:7], + args: args{ + fn: func(t time.Time, v1, v2 *string) *string { + if v1 != nil { + return v1 + } + return v2 + }, + slices: []Strings{ + append(Strings{data[9]}, data[3:9]...), + }, + }, + want: data, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewStringSeq(tt.data) + if err := s.Merge(tt.args.fn, tt.args.slices...); (err != nil) != tt.wantErr { + t.Errorf("Merge() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !tt.wantErr { + if got := s.slice; !reflect.DeepEqual(got, tt.want) { + t.Errorf("Merge() = %v, want %v", got, tt.want) + } + } + }) + } +} + +func TestStringSeq_Aggregate(t *testing.T) { + data := RandomStrings(100) + now := time.Now() + begin := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()) + end := begin.Add(24*time.Hour - 1) + + type args struct { + fn func(t time.Time, slice Strings) *string + duration time.Duration + begin *time.Time + end *time.Time + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "regular", + args: args{ + fn: func(t time.Time, slice Strings) *string { + ret := string(t.Hour()) + if len(slice) != 0 { + ret = 0 + } + for _, v := range slice { + ret += v.Value + } + return &ret + }, + duration: time.Hour, + begin: &begin, + end: &end, + }, + wantErr: false, + }, + { + name: "nil fn", + args: args{ + fn: nil, + duration: time.Hour, + begin: &begin, + end: &end, + }, + wantErr: true, + }, + { + name: "zero duration", + args: args{ + fn: func(t time.Time, slice Strings) *string { + ret := string(t.Hour()) + if len(slice) != 0 { + ret = 0 + } + for _, v := range slice { + ret += v.Value + } + return &ret + }, + duration: 0, + begin: &begin, + end: &end, + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewStringSeq(data) + if err := s.Aggregate(tt.args.fn, tt.args.duration, tt.args.begin, tt.args.end); (err != nil) != tt.wantErr { + t.Errorf("Aggregate() error = %v, wantErr %v", err, tt.wantErr) + } + for i, v := range s.slice { + fmt.Println(i, v.Value, v.Time) + } + }) + } +} + +func TestStringSeq_Trim(t *testing.T) { + data := RandomStrings(10) + Sort(data) + + type args struct { + fn func(i int, v String) bool + } + tests := []struct { + name string + args args + want Strings + wantErr bool + }{ + { + name: "regular", + args: args{ + fn: func(i int, v String) bool { + return i >= 5 + }, + }, + want: data[:5], + wantErr: false, + }, + { + name: "nil fn", + args: args{ + fn: nil, + }, + want: data[:5], + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewStringSeq(data) + if err := s.Trim(tt.args.fn); (err != nil) != tt.wantErr { + t.Errorf("Trim() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !tt.wantErr { + if got := s.slice; !reflect.DeepEqual(got, tt.want) { + t.Errorf("Trim() = %v, want %v", got, tt.want) + for i, v := range got { + fmt.Println(i, v) + } + for i, v := range tt.want { + fmt.Println(i, v) + } + } + } + }) + } +} From 905e8bbdafb873c9b429ce480d59f1d0a01fe489 Mon Sep 17 00:00:00 2001 From: Jason Song Date: Wed, 23 Sep 2020 18:25:57 +0800 Subject: [PATCH 10/19] fix: give up string --- Makefile | 3 +- _draft/v2/int64_seq_test.go | 8 +- cmd/generate/gen_x_seq_test.go.tmpl | 8 +- cmd/generate/main.go | 5 - gen_float64_seq_test.go | 8 +- gen_int64_seq_test.go | 8 +- gen_int_seq_test.go | 8 +- gen_string_seq.go | 332 ------------ gen_string_seq_test.go | 774 ---------------------------- 9 files changed, 32 insertions(+), 1122 deletions(-) delete mode 100644 gen_string_seq.go delete mode 100644 gen_string_seq_test.go diff --git a/Makefile b/Makefile index 6ccf521..091889d 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,5 @@ generage: rm -f gen_*.go go run cmd/generate/main.go - +test: + go test -v diff --git a/_draft/v2/int64_seq_test.go b/_draft/v2/int64_seq_test.go index 848a3af..790cc44 100644 --- a/_draft/v2/int64_seq_test.go +++ b/_draft/v2/int64_seq_test.go @@ -227,6 +227,7 @@ func TestInt64Seq_Visit(t *testing.T) { func TestInt64Seq_Sum(t *testing.T) { data := RandomInt64s(100) + Sort(data) var sum int64 for _, v := range data { sum += v.Value @@ -710,9 +711,12 @@ func TestInt64Seq_Aggregate(t *testing.T) { s := NewInt64Seq(data) if err := s.Aggregate(tt.args.fn, tt.args.duration, tt.args.begin, tt.args.end); (err != nil) != tt.wantErr { t.Errorf("Aggregate() error = %v, wantErr %v", err, tt.wantErr) + return } - for i, v := range s.slice { - fmt.Println(i, v.Value, v.Time) + if !tt.wantErr { + for i, v := range s.slice { + fmt.Println(i, v.Value, v.Time) + } } }) } diff --git a/cmd/generate/gen_x_seq_test.go.tmpl b/cmd/generate/gen_x_seq_test.go.tmpl index 5760218..e40002c 100644 --- a/cmd/generate/gen_x_seq_test.go.tmpl +++ b/cmd/generate/gen_x_seq_test.go.tmpl @@ -227,6 +227,7 @@ func Test{{.Name}}Seq_Visit(t *testing.T) { func Test{{.Name}}Seq_Sum(t *testing.T) { data := Random{{.Name}}s(100) + Sort(data) var sum {{.Type}} for _, v := range data { sum += v.Value @@ -710,9 +711,12 @@ func Test{{.Name}}Seq_Aggregate(t *testing.T) { s := New{{.Name}}Seq(data) if err := s.Aggregate(tt.args.fn, tt.args.duration, tt.args.begin, tt.args.end); (err != nil) != tt.wantErr { t.Errorf("Aggregate() error = %v, wantErr %v", err, tt.wantErr) + return } - for i, v := range s.slice { - fmt.Println(i, v.Value, v.Time) + if !tt.wantErr { + for i, v := range s.slice { + fmt.Println(i, v.Value, v.Time) + } } }) } diff --git a/cmd/generate/main.go b/cmd/generate/main.go index 8f70607..507f31f 100644 --- a/cmd/generate/main.go +++ b/cmd/generate/main.go @@ -36,11 +36,6 @@ func main() { Type: "float64", Random: "rand.Float64()", }, - { - Name: "String", - Type: "string", - Random: "0", - }, { Name: "Int", Type: "int", diff --git a/gen_float64_seq_test.go b/gen_float64_seq_test.go index 69a2475..70113ec 100644 --- a/gen_float64_seq_test.go +++ b/gen_float64_seq_test.go @@ -228,6 +228,7 @@ func TestFloat64Seq_Visit(t *testing.T) { func TestFloat64Seq_Sum(t *testing.T) { data := RandomFloat64s(100) + Sort(data) var sum float64 for _, v := range data { sum += v.Value @@ -711,9 +712,12 @@ func TestFloat64Seq_Aggregate(t *testing.T) { s := NewFloat64Seq(data) if err := s.Aggregate(tt.args.fn, tt.args.duration, tt.args.begin, tt.args.end); (err != nil) != tt.wantErr { t.Errorf("Aggregate() error = %v, wantErr %v", err, tt.wantErr) + return } - for i, v := range s.slice { - fmt.Println(i, v.Value, v.Time) + if !tt.wantErr { + for i, v := range s.slice { + fmt.Println(i, v.Value, v.Time) + } } }) } diff --git a/gen_int64_seq_test.go b/gen_int64_seq_test.go index 7433423..165acef 100644 --- a/gen_int64_seq_test.go +++ b/gen_int64_seq_test.go @@ -228,6 +228,7 @@ func TestInt64Seq_Visit(t *testing.T) { func TestInt64Seq_Sum(t *testing.T) { data := RandomInt64s(100) + Sort(data) var sum int64 for _, v := range data { sum += v.Value @@ -711,9 +712,12 @@ func TestInt64Seq_Aggregate(t *testing.T) { s := NewInt64Seq(data) if err := s.Aggregate(tt.args.fn, tt.args.duration, tt.args.begin, tt.args.end); (err != nil) != tt.wantErr { t.Errorf("Aggregate() error = %v, wantErr %v", err, tt.wantErr) + return } - for i, v := range s.slice { - fmt.Println(i, v.Value, v.Time) + if !tt.wantErr { + for i, v := range s.slice { + fmt.Println(i, v.Value, v.Time) + } } }) } diff --git a/gen_int_seq_test.go b/gen_int_seq_test.go index a0fe95e..1967faa 100644 --- a/gen_int_seq_test.go +++ b/gen_int_seq_test.go @@ -228,6 +228,7 @@ func TestIntSeq_Visit(t *testing.T) { func TestIntSeq_Sum(t *testing.T) { data := RandomInts(100) + Sort(data) var sum int for _, v := range data { sum += v.Value @@ -711,9 +712,12 @@ func TestIntSeq_Aggregate(t *testing.T) { s := NewIntSeq(data) if err := s.Aggregate(tt.args.fn, tt.args.duration, tt.args.begin, tt.args.end); (err != nil) != tt.wantErr { t.Errorf("Aggregate() error = %v, wantErr %v", err, tt.wantErr) + return } - for i, v := range s.slice { - fmt.Println(i, v.Value, v.Time) + if !tt.wantErr { + for i, v := range s.slice { + fmt.Println(i, v.Value, v.Time) + } } }) } diff --git a/gen_string_seq.go b/gen_string_seq.go deleted file mode 100644 index cef2589..0000000 --- a/gen_string_seq.go +++ /dev/null @@ -1,332 +0,0 @@ -// Code generated by cmd/generate. DO NOT EDIT. -package timeseq - -import ( - "errors" - "sort" - "time" -) - -type String struct { - Time time.Time - Value string -} - -type Strings []String - -func (s Strings) Len() int { - return len(s) -} - -func (s Strings) Swap(i, j int) { - s[i], s[j] = s[j], s[i] -} - -func (s Strings) Time(i int) time.Time { - return s[i].Time -} - -func (s Strings) Slice(i, j int) Slice { - return s[i:j] -} - -type StringSeq struct { - slice Strings - timeIndex map[timeKey][]int - valueIndex map[string][]int - valueSlice []int -} - -func NewStringSeq(slice Strings) *StringSeq { - temp := make(Strings, len(slice)) - copy(temp, slice) - slice = temp - - Sort(slice) - sort.SliceStable(slice, func(i, j int) bool { - return slice[i].Time.Before(slice[j].Time) - }) - return newStringSeq(slice) -} - -func newStringSeq(slice Strings) *StringSeq { - ret := &StringSeq{ - slice: slice, - } - ret.buildIndex() - return ret -} - -func (s *StringSeq) buildIndex() { - timeIndex := make(map[timeKey][]int, len(s.slice)) - valueIndex := make(map[string][]int, len(s.slice)) - valueSlice := s.valueSlice[:0] - for i, v := range s.slice { - k := newTimeKey(v.Time) - timeIndex[k] = append(timeIndex[k], i) - valueIndex[v.Value] = append(valueIndex[v.Value], i) - valueSlice = append(valueSlice, i) - } - sort.SliceStable(valueSlice, func(i, j int) bool { - return s.slice[valueSlice[i]].Value < s.slice[valueSlice[j]].Value - }) - s.timeIndex = timeIndex - s.valueIndex = valueIndex - s.valueSlice = valueSlice -} - -func (s *StringSeq) Strings() Strings { - slice := make(Strings, len(s.slice)) - copy(slice, s.slice) - return slice -} - -func (s *StringSeq) Index(i int) String { - if i < 0 || i >= len(s.slice) { - return String{} - } - return s.slice[i] -} - -func (s *StringSeq) Time(t time.Time) Strings { - index := s.timeIndex[newTimeKey(t)] - if len(index) == 0 { - return nil - } - ret := make(Strings, len(index)) - for i, v := range index { - ret[i] = s.slice[v] - } - return ret -} - -func (s *StringSeq) Value(v string) Strings { - index := s.valueIndex[v] - if len(index) == 0 { - return nil - } - ret := make(Strings, len(index)) - for i, v := range index { - ret[i] = s.slice[v] - } - return ret -} - -func (s *StringSeq) Visit(fn func(i int, v String) (stop bool)) { - for i, v := range s.slice { - if fn != nil && fn(i, v) { - break - } - } -} - -func (s *StringSeq) Sum() string { - var ret string - for _, v := range s.slice { - ret += v.Value - } - return ret -} - -func (s *StringSeq) Count() int { - return len(s.slice) -} - -func (s *StringSeq) Max() String { - var max String - found := false - for _, v := range s.slice { - if !found { - max = v - found = true - } else if v.Value > max.Value { - max = v - } - } - return max -} - -func (s *StringSeq) Min() String { - var min String - found := false - for _, v := range s.slice { - if !found { - min = v - found = true - } else if v.Value < min.Value { - min = v - } - } - return min -} - -func (s *StringSeq) First() String { - if len(s.slice) == 0 { - return String{} - } - return s.slice[0] -} - -func (s *StringSeq) Last() String { - if len(s.slice) == 0 { - return String{} - } - return s.slice[len(s.slice)-1] -} - -func (s *StringSeq) Percentile(pct float64) String { - if len(s.slice) == 0 { - return String{} - } - if pct > 1 { - pct = 1 - } - if pct < 0 { - pct = 0 - } - i := int(float64(len(s.slice))*pct - 1) - if i < 0 { - i = 0 - } - return s.slice[s.valueSlice[i]] -} - -func (s *StringSeq) Range(interval Interval) *StringSeq { - slice := Range(s.slice, interval).(Strings) - return newStringSeq(slice) -} - -func (s *StringSeq) Merge(fn func(t time.Time, v1, v2 *string) *string, slices ...Strings) error { - if fn == nil { - return errors.New("nil fn") - } - - if len(slices) == 0 { - return nil - } - - slice1 := s.slice - for _, slice2 := range slices { - if !IsSorted(slice2) { - temp := make(Strings, len(slice2)) - copy(temp, slice2) - Sort(temp) - slice2 = temp - } - var got Strings - for i1, i2 := 0, 0; i1 < len(slice1) || i2 < len(slice2); { - var ( - t time.Time - v *string - ) - switch { - case i1 == len(slice1): - t = slice2[i2].Time - v2 := slice2[i2].Value - v = fn(t, nil, &v2) - i2++ - case i2 == len(slice2): - t = slice1[i1].Time - v1 := slice1[i1].Value - v = fn(t, &v1, nil) - i1++ - case slice1[i1].Time.Equal(slice2[i2].Time): - t = slice1[i1].Time - v1 := slice1[i1].Value - v2 := slice2[i2].Value - v = fn(t, &v1, &v2) - i1++ - i2++ - case slice1[i1].Time.Before(slice2[i2].Time): - t = slice1[i1].Time - v1 := slice1[i1].Value - v = fn(t, &v1, nil) - i1++ - case slice1[i1].Time.After(slice2[i2].Time): - t = slice2[i2].Time - v2 := slice2[i2].Value - v = fn(t, nil, &v2) - i2++ - } - if v != nil { - got = append(got, String{ - Time: t, - Value: *v, - }) - } - } - slice1 = got - } - - s.slice = slice1 - s.buildIndex() - return nil -} - -func (s *StringSeq) Aggregate(fn func(t time.Time, slice Strings) *string, duration time.Duration, begin, end *time.Time) error { - if fn == nil { - return errors.New("nil fn") - } - - if duration <= 0 { - return errors.New("invalid duration") - } - - var bg, ed time.Time - if len(s.slice) > 0 { - bg = s.slice[0].Time.Truncate(duration) - ed = s.slice[len(s.slice)-1].Time - } - if begin != nil { - bg = (*begin).Truncate(duration) - } - if end != nil { - ed = *end - } - - got := Strings{} - slice := Strings{} - i := 0 - for t := bg; t.Before(ed); t = t.Add(duration) { - slice = slice[:0] - for i < s.slice.Len() && - !s.slice[i].Time.After(t) && - s.slice[i].Time.Before(t.Add(duration)) { - slice = append(slice, s.slice[i]) - i++ - } - v := fn(t, slice) - if v != nil { - got = append(got, String{ - Time: t, - Value: *v, - }) - } - } - - s.slice = got - s.buildIndex() - return nil -} - -func (s *StringSeq) Trim(fn func(i int, v String) bool) error { - if fn == nil { - return errors.New("nil fn") - } - - updated := false - slice := make(Strings, 0) - for i, v := range s.slice { - if fn(i, v) { - updated = true - } else { - slice = append(slice, v) - } - } - - if updated { - s.slice = slice - s.buildIndex() - } - return nil -} diff --git a/gen_string_seq_test.go b/gen_string_seq_test.go deleted file mode 100644 index 1c650a0..0000000 --- a/gen_string_seq_test.go +++ /dev/null @@ -1,774 +0,0 @@ -// Code generated by cmd/generate. DO NOT EDIT. -package timeseq - -import ( - "fmt" - "math/rand" - "reflect" - "testing" - "time" -) - -func RandomStrings(length int) Strings { - now := time.Now() - ret := make(Strings, length) - for i := range ret { - delta := time.Duration(i) * time.Second - if rand.Float64() < 0.5 { - delta = -delta - } - ret[i] = String{ - Time: now.Add(delta), - Value: 0, - } - } - return ret -} - -func TestStringSeq_Strings(t *testing.T) { - data := RandomStrings(100) - Sort(data) - - tests := []struct { - name string - want Strings - }{ - { - name: "regular", - want: data, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := NewStringSeq(data) - if got := s.Strings(); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Strings() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestStringSeq_Index(t *testing.T) { - data := RandomStrings(100) - Sort(data) - - type args struct { - i int - } - tests := []struct { - name string - args args - want String - }{ - { - name: "regular", - args: args{ - i: 1, - }, - want: data[1], - }, - { - name: "less than zero", - args: args{ - i: -1, - }, - want: String{}, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := NewStringSeq(data) - if got := s.Index(tt.args.i); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Index() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestStringSeq_Time(t *testing.T) { - now := time.Now() - yesterday := now.AddDate(0, 0, -1) - lastMonth := now.AddDate(0, -1, 0) - lastYear := now.AddDate(-1, 0, 0) - - data := RandomStrings(100) - data[0].Time = lastMonth - data[1].Time = lastMonth - data[2].Time = lastMonth - data[3].Time = yesterday - Sort(data) - - type args struct { - t time.Time - } - tests := []struct { - name string - args args - length int - }{ - { - name: "regular", - args: args{ - t: yesterday, - }, - length: 1, - }, - { - name: "multiple", - args: args{ - t: lastMonth, - }, - length: 3, - }, - { - name: "none", - args: args{ - t: lastYear, - }, - length: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := NewStringSeq(data) - if got := s.Time(tt.args.t); len(got) != tt.length { - t.Errorf("Time() = %v, want %v", got, tt.length) - } - }) - } -} - -func TestStringSeq_Value(t *testing.T) { - data := RandomStrings(100) - Sort(data) - - value1 := data[0].Value - value2 := data[1].Value - value3 := data[2].Value - - data[0].Value = value1 - data[1].Value = value2 - data[2].Value = value2 - data[3].Value = value2 - - type args struct { - v string - } - tests := []struct { - name string - args args - length int - }{ - { - name: "regular", - args: args{ - v: value1, - }, - length: 1, - }, - { - name: "multiple", - args: args{ - v: value2, - }, - length: 3, - }, - { - name: "none", - args: args{ - v: value3, - }, - length: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := NewStringSeq(data) - if got := s.Value(tt.args.v); len(got) != tt.length { - t.Errorf("Value() = %v, want %v", got, tt.length) - } - }) - } -} - -func TestStringSeq_Visit(t *testing.T) { - data := RandomStrings(100) - - type args struct { - fn func(i int, v String) (stop bool) - } - tests := []struct { - name string - args args - }{ - { - name: "regular", - args: args{ - fn: func(i int, v String) (stop bool) { - return false - }, - }, - }, - { - name: "stop", - args: args{ - fn: func(i int, v String) (stop bool) { - return i > 10 - }, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := NewStringSeq(data) - s.Visit(tt.args.fn) - }) - } -} - -func TestStringSeq_Sum(t *testing.T) { - data := RandomStrings(100) - var sum string - for _, v := range data { - sum += v.Value - } - tests := []struct { - name string - want string - }{ - { - name: "regular", - want: sum, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := NewStringSeq(data) - if got := s.Sum(); got != tt.want { - t.Errorf("Sum() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestStringSeq_Count(t *testing.T) { - data := RandomStrings(100) - - tests := []struct { - name string - want int - }{ - { - name: "regular", - want: len(data), - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := NewStringSeq(data) - if got := s.Count(); got != tt.want { - t.Errorf("Count() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestStringSeq_Max(t *testing.T) { - data := RandomStrings(100) - max := data[0] - for _, v := range data { - if v.Value > max.Value { - max = v - } - } - - tests := []struct { - name string - want String - }{ - { - name: "regular", - want: max, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := NewStringSeq(data) - if got := s.Max(); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Max() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestStringSeq_Min(t *testing.T) { - data := RandomStrings(100) - min := data[0] - for _, v := range data { - if v.Value < min.Value { - min = v - } - } - - tests := []struct { - name string - want String - }{ - { - name: "regular", - want: min, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := NewStringSeq(data) - if got := s.Min(); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Min() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestStringSeq_First(t *testing.T) { - data := RandomStrings(100) - Sort(data) - - tests := []struct { - name string - data Strings - want String - }{ - { - - name: "regular", - data: data, - want: data[0], - }, - { - name: "emtpy", - data: nil, - want: String{}, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := NewStringSeq(tt.data) - if got := s.First(); !reflect.DeepEqual(got, tt.want) { - t.Errorf("First() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestStringSeq_Last(t *testing.T) { - data := RandomStrings(100) - Sort(data) - tests := []struct { - name string - data Strings - want String - }{ - { - - name: "regular", - data: data, - want: data[len(data)-1], - }, - { - name: "emtpy", - data: nil, - want: String{}, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := NewStringSeq(tt.data) - if got := s.Last(); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Last() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestStringSeq_Percentile(t *testing.T) { - data := RandomStrings(100) - Sort(data) - for i := range data { - data[i].Value = string(i) - } - - type args struct { - pct float64 - } - tests := []struct { - name string - data Strings - args args - want String - }{ - { - name: "data[0]", - data: data, - args: args{ - pct: 0, - }, - want: data[0], - }, - { - name: "data[49]", - data: data, - args: args{ - pct: 0.5, - }, - want: data[49], - }, - { - name: "0.95", - data: data, - args: args{ - pct: 0.95, - }, - want: data[94], - }, - { - name: "0.955", - data: data, - args: args{ - pct: 0.955, - }, - want: data[94], - }, - { - name: "1", - data: data, - args: args{ - pct: 1, - }, - want: data[99], - }, - { - name: "1.1", - data: data, - args: args{ - pct: 1.1, - }, - want: data[99], - }, - { - name: "-0.1", - data: data, - args: args{ - pct: -0.1, - }, - want: data[0], - }, - { - name: "empty", - data: nil, - args: args{ - pct: 1, - }, - want: String{}, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := NewStringSeq(tt.data) - if got := s.Percentile(tt.args.pct); !reflect.DeepEqual(got, tt.want) { - t.Errorf("Percentile() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestStringSeq_Range(t *testing.T) { - data := RandomStrings(100) - Sort(data) - - type args struct { - interval Interval - } - tests := []struct { - name string - data Strings - args args - want Strings - }{ - { - name: "regular", - data: data, - args: args{ - interval: Interval{ - NotBefore: &data[10].Time, - NotAfter: &data[89].Time, - }, - }, - want: data[10:90], - }, - { - name: "nil NotBefore", - data: data, - args: args{ - interval: Interval{ - NotAfter: &data[89].Time, - }, - }, - want: data[:90], - }, - { - name: "nil NotAfter", - data: data, - args: args{ - interval: Interval{ - NotBefore: &data[10].Time, - }, - }, - want: data[10:], - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := NewStringSeq(data) - if got := s.Range(tt.args.interval).slice; !reflect.DeepEqual(got, tt.want) { - t.Errorf("Range() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestStringSeq_Merge(t *testing.T) { - data := RandomStrings(10) - Sort(data) - - type args struct { - fn func(t time.Time, v1, v2 *string) *string - slices []Strings - } - tests := []struct { - name string - data Strings - args args - want Strings - wantErr bool - }{ - { - name: "regular", - data: data[0:7], - args: args{ - fn: func(t time.Time, v1, v2 *string) *string { - if v1 != nil { - return v1 - } - return v2 - }, - slices: []Strings{data[3:10]}, - }, - want: data, - }, - { - name: "reverse", - data: data[3:10], - args: args{ - fn: func(t time.Time, v1, v2 *string) *string { - if v1 != nil { - return v1 - } - return v2 - }, - slices: []Strings{data[0:7]}, - }, - want: data, - }, - { - name: "nil fn", - data: nil, - args: args{ - fn: nil, - }, - wantErr: true, - }, - { - name: "multiple", - data: nil, - args: args{ - fn: func(t time.Time, v1, v2 *string) *string { - if v1 != nil { - return v1 - } - return v2 - }, - slices: []Strings{ - data[1:2], - data[0:4], - nil, - data[2:9], - data[9:], - }, - }, - want: data, - }, - { - name: "not sorted", - data: data[0:7], - args: args{ - fn: func(t time.Time, v1, v2 *string) *string { - if v1 != nil { - return v1 - } - return v2 - }, - slices: []Strings{ - append(Strings{data[9]}, data[3:9]...), - }, - }, - want: data, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := NewStringSeq(tt.data) - if err := s.Merge(tt.args.fn, tt.args.slices...); (err != nil) != tt.wantErr { - t.Errorf("Merge() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !tt.wantErr { - if got := s.slice; !reflect.DeepEqual(got, tt.want) { - t.Errorf("Merge() = %v, want %v", got, tt.want) - } - } - }) - } -} - -func TestStringSeq_Aggregate(t *testing.T) { - data := RandomStrings(100) - now := time.Now() - begin := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()) - end := begin.Add(24*time.Hour - 1) - - type args struct { - fn func(t time.Time, slice Strings) *string - duration time.Duration - begin *time.Time - end *time.Time - } - tests := []struct { - name string - args args - wantErr bool - }{ - { - name: "regular", - args: args{ - fn: func(t time.Time, slice Strings) *string { - ret := string(t.Hour()) - if len(slice) != 0 { - ret = 0 - } - for _, v := range slice { - ret += v.Value - } - return &ret - }, - duration: time.Hour, - begin: &begin, - end: &end, - }, - wantErr: false, - }, - { - name: "nil fn", - args: args{ - fn: nil, - duration: time.Hour, - begin: &begin, - end: &end, - }, - wantErr: true, - }, - { - name: "zero duration", - args: args{ - fn: func(t time.Time, slice Strings) *string { - ret := string(t.Hour()) - if len(slice) != 0 { - ret = 0 - } - for _, v := range slice { - ret += v.Value - } - return &ret - }, - duration: 0, - begin: &begin, - end: &end, - }, - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := NewStringSeq(data) - if err := s.Aggregate(tt.args.fn, tt.args.duration, tt.args.begin, tt.args.end); (err != nil) != tt.wantErr { - t.Errorf("Aggregate() error = %v, wantErr %v", err, tt.wantErr) - } - for i, v := range s.slice { - fmt.Println(i, v.Value, v.Time) - } - }) - } -} - -func TestStringSeq_Trim(t *testing.T) { - data := RandomStrings(10) - Sort(data) - - type args struct { - fn func(i int, v String) bool - } - tests := []struct { - name string - args args - want Strings - wantErr bool - }{ - { - name: "regular", - args: args{ - fn: func(i int, v String) bool { - return i >= 5 - }, - }, - want: data[:5], - wantErr: false, - }, - { - name: "nil fn", - args: args{ - fn: nil, - }, - want: data[:5], - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := NewStringSeq(data) - if err := s.Trim(tt.args.fn); (err != nil) != tt.wantErr { - t.Errorf("Trim() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !tt.wantErr { - if got := s.slice; !reflect.DeepEqual(got, tt.want) { - t.Errorf("Trim() = %v, want %v", got, tt.want) - for i, v := range got { - fmt.Println(i, v) - } - for i, v := range tt.want { - fmt.Println(i, v) - } - } - } - }) - } -} From 6af46944d762f1e633959dbeb75bb1aa3157454c Mon Sep 17 00:00:00 2001 From: Jason Song Date: Thu, 24 Sep 2020 14:55:57 +0800 Subject: [PATCH 11/19] fix: rename Slice to Interface --- _draft/v1/int_sequence_test.go | 4 ++-- _draft/v2/int64_seq.go | 2 +- _draft/v2/timeseq.go | 20 ++++++++++---------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/_draft/v1/int_sequence_test.go b/_draft/v1/int_sequence_test.go index cb718a4..048eabc 100644 --- a/_draft/v1/int_sequence_test.go +++ b/_draft/v1/int_sequence_test.go @@ -124,7 +124,7 @@ func TestIntSequence_Slice(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := tt.s.Slice(tt.args.i, tt.args.j); !reflect.DeepEqual(got, tt.want) { - t.Errorf("IntSequence.Slice() = %v, want %v", got, tt.want) + t.Errorf("IntSequence.Interface() = %v, want %v", got, tt.want) } }) } @@ -146,7 +146,7 @@ func TestIntSequence_Sort(t *testing.T) { t.Run(tt.name, func(t *testing.T) { tt.s.Sort() if !sort.IsSorted(sortableSequence{tt.s}) { - t.Error("IntSequence.Slice() failed") + t.Error("IntSequence.Interface() failed") } }) } diff --git a/_draft/v2/int64_seq.go b/_draft/v2/int64_seq.go index 5a2e5c6..02b5571 100644 --- a/_draft/v2/int64_seq.go +++ b/_draft/v2/int64_seq.go @@ -25,7 +25,7 @@ func (s Int64s) Time(i int) time.Time { return s[i].Time } -func (s Int64s) Slice(i, j int) Slice { +func (s Int64s) Slice(i, j int) Interface { return s[i:j] } diff --git a/_draft/v2/timeseq.go b/_draft/v2/timeseq.go index 9d9915a..269c2db 100644 --- a/_draft/v2/timeseq.go +++ b/_draft/v2/timeseq.go @@ -6,7 +6,7 @@ import ( "time" ) -type Slice interface { +type Interface interface { // return length Len() int // swap items @@ -14,27 +14,27 @@ type Slice interface { // return time of item i Time(i int) time.Time // return Slice[i:j] - Slice(i, j int) Slice + Slice(i, j int) Interface } -type sortableSlice struct { - Slice +type sortable struct { + Interface } -func (s sortableSlice) Less(i, j int) bool { +func (s sortable) Less(i, j int) bool { return s.Time(i).Before(s.Time(j)) } // Sort will sort slice by time -func Sort(slice Slice) { - sort.Stable(sortableSlice{Slice: slice}) +func Sort(slice Interface) { + sort.Stable(sortable{Interface: slice}) } -func IsSorted(slice Slice) bool { - return sort.IsSorted(sortableSlice{Slice: slice}) +func IsSorted(slice Interface) bool { + return sort.IsSorted(sortable{Interface: slice}) } -func Range(slice Slice, interval Interval) Slice { +func Range(slice Interface, interval Interval) Interface { i := 0 if interval.NotBefore != nil { i = sort.Search(slice.Len(), func(i int) bool { From be5da7e363b0c1c6303804659c131f5ae731d6c2 Mon Sep 17 00:00:00 2001 From: Jason Song Date: Thu, 24 Sep 2020 14:58:17 +0800 Subject: [PATCH 12/19] feat: IsZero --- _draft/v2/int64_seq.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/_draft/v2/int64_seq.go b/_draft/v2/int64_seq.go index 02b5571..e0adaaf 100644 --- a/_draft/v2/int64_seq.go +++ b/_draft/v2/int64_seq.go @@ -11,6 +11,10 @@ type Int64 struct { Value int64 } +func (v Int64) IsZero() bool { + return v.Value == 0 && v.Time.IsZero() +} + type Int64s []Int64 func (s Int64s) Len() int { From 339d38b85586a901f3e257e59e8c3a7690dbe4be Mon Sep 17 00:00:00 2001 From: Jason Song Date: Thu, 24 Sep 2020 18:42:49 +0800 Subject: [PATCH 13/19] feat: interval method --- _draft/v2/int64_seq.go | 49 ++++++++++++++++++------------ _draft/v2/int64_seq_test.go | 51 ++++++++++++++++++++++++++++++++ _draft/v2/timeseq.go | 59 +++++++++++++++++++++++++++++++++++-- _draft/v2/timeseq_test.go | 35 ++++++++++++++++++++++ 4 files changed, 172 insertions(+), 22 deletions(-) create mode 100644 _draft/v2/timeseq_test.go diff --git a/_draft/v2/int64_seq.go b/_draft/v2/int64_seq.go index e0adaaf..adc0e0e 100644 --- a/_draft/v2/int64_seq.go +++ b/_draft/v2/int64_seq.go @@ -3,6 +3,7 @@ package timeseq import ( "errors" "sort" + "sync" "time" ) @@ -34,7 +35,9 @@ func (s Int64s) Slice(i, j int) Interface { } type Int64Seq struct { - slice Int64s + slice Int64s + + indexOnce sync.Once timeIndex map[timeKey][]int valueIndex map[int64][]int valueSlice []int @@ -56,26 +59,31 @@ func newInt64Seq(slice Int64s) *Int64Seq { ret := &Int64Seq{ slice: slice, } - ret.buildIndex() return ret } func (s *Int64Seq) buildIndex() { - timeIndex := make(map[timeKey][]int, len(s.slice)) - valueIndex := make(map[int64][]int, len(s.slice)) - valueSlice := s.valueSlice[:0] - for i, v := range s.slice { - k := newTimeKey(v.Time) - timeIndex[k] = append(timeIndex[k], i) - valueIndex[v.Value] = append(valueIndex[v.Value], i) - valueSlice = append(valueSlice, i) - } - sort.SliceStable(valueSlice, func(i, j int) bool { - return s.slice[valueSlice[i]].Value < s.slice[valueSlice[j]].Value + s.indexOnce.Do(func() { + timeIndex := make(map[timeKey][]int, len(s.slice)) + valueIndex := make(map[int64][]int, len(s.slice)) + valueSlice := s.valueSlice[:0] + for i, v := range s.slice { + k := newTimeKey(v.Time) + timeIndex[k] = append(timeIndex[k], i) + valueIndex[v.Value] = append(valueIndex[v.Value], i) + valueSlice = append(valueSlice, i) + } + sort.SliceStable(valueSlice, func(i, j int) bool { + return s.slice[valueSlice[i]].Value < s.slice[valueSlice[j]].Value + }) + s.timeIndex = timeIndex + s.valueIndex = valueIndex + s.valueSlice = valueSlice }) - s.timeIndex = timeIndex - s.valueIndex = valueIndex - s.valueSlice = valueSlice +} + +func (s *Int64Seq) resetIndex() { + s.indexOnce = sync.Once{} } func (s *Int64Seq) Int64s() Int64s { @@ -92,6 +100,7 @@ func (s *Int64Seq) Index(i int) Int64 { } func (s *Int64Seq) Time(t time.Time) Int64s { + s.buildIndex() index := s.timeIndex[newTimeKey(t)] if len(index) == 0 { return nil @@ -104,6 +113,7 @@ func (s *Int64Seq) Time(t time.Time) Int64s { } func (s *Int64Seq) Value(v int64) Int64s { + s.buildIndex() index := s.valueIndex[v] if len(index) == 0 { return nil @@ -178,6 +188,7 @@ func (s *Int64Seq) Last() Int64 { } func (s *Int64Seq) Percentile(pct float64) Int64 { + s.buildIndex() if len(s.slice) == 0 { return Int64{} } @@ -262,7 +273,7 @@ func (s *Int64Seq) Merge(fn func(t time.Time, v1, v2 *int64) *int64, slices ...I } s.slice = slice1 - s.buildIndex() + s.resetIndex() return nil } @@ -308,7 +319,7 @@ func (s *Int64Seq) Aggregate(fn func(t time.Time, slice Int64s) *int64, duration } s.slice = got - s.buildIndex() + s.resetIndex() return nil } @@ -329,7 +340,7 @@ func (s *Int64Seq) Trim(fn func(i int, v Int64) bool) error { if updated { s.slice = slice - s.buildIndex() + s.resetIndex() } return nil } diff --git a/_draft/v2/int64_seq_test.go b/_draft/v2/int64_seq_test.go index 790cc44..33e9944 100644 --- a/_draft/v2/int64_seq_test.go +++ b/_draft/v2/int64_seq_test.go @@ -24,6 +24,43 @@ func RandomInt64s(length int) Int64s { return ret } +func TestInt64_IsZero(t *testing.T) { + type fields struct { + Time time.Time + Value int64 + } + tests := []struct { + name string + fields fields + want bool + }{ + { + name: "zero", + fields: fields{}, + want: true, + }, + { + name: "not zero", + fields: fields{ + Time: time.Now(), + Value: 1, + }, + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + v := Int64{ + Time: tt.fields.Time, + Value: tt.fields.Value, + } + if got := v.IsZero(); got != tt.want { + t.Errorf("IsZero() = %v, want %v", got, tt.want) + } + }) + } +} + func TestInt64Seq_Int64s(t *testing.T) { data := RandomInt64s(100) Sort(data) @@ -623,6 +660,20 @@ func TestInt64Seq_Merge(t *testing.T) { }, want: data, }, + { + name: "empty slices", + data: data[0:7], + args: args{ + fn: func(t time.Time, v1, v2 *int64) *int64 { + if v1 != nil { + return v1 + } + return v2 + }, + slices: []Int64s{}, + }, + want: data, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/_draft/v2/timeseq.go b/_draft/v2/timeseq.go index 269c2db..1936748 100644 --- a/_draft/v2/timeseq.go +++ b/_draft/v2/timeseq.go @@ -58,12 +58,65 @@ type Interval struct { NotAfter *time.Time } -type timeKey [16]byte +func (i Interval) Contain(t time.Time) bool { + if i.NotAfter != nil && t.After(*i.NotAfter) { + return false + } + if i.NotBefore != nil && t.Before(*i.NotBefore) { + return false + } + return true +} + +func (i Interval) Merge(i2 Interval) Interval { + ret := i + if i2.NotBefore != nil { + t := *i2.NotBefore + if ret.NotBefore == nil || ret.NotBefore.Before(t) { + ret.NotBefore = &t + } + } + if i2.NotAfter != nil { + t := *i2.NotAfter + if ret.NotAfter == nil || ret.NotAfter.After(t) { + ret.NotAfter = &t + } + } + return ret +} + +func (i Interval) BeforeOrEqual(t time.Time) Interval { + return Interval{ + NotAfter: &t, + } +} + +func (i Interval) AfterOrEqual(t time.Time) Interval { + return Interval{ + NotBefore: &t, + } +} + +func (i Interval) Before(t time.Time) Interval { + t = t.Add(-1) + return Interval{ + NotAfter: &t, + } +} -func (k timeKey) Get() time.Time { - return time.Unix(int64(binary.BigEndian.Uint64(k[:8])), int64(binary.BigEndian.Uint64(k[8:]))) +func (i Interval) After(t time.Time) Interval { + t = t.Add(1) + return Interval{ + NotAfter: &t, + } } +type timeKey [16]byte + +//func (k timeKey) Get() time.Time { +// return time.Unix(int64(binary.BigEndian.Uint64(k[:8])), int64(binary.BigEndian.Uint64(k[8:]))) +//} + func newTimeKey(t time.Time) timeKey { var ret [16]byte binary.BigEndian.PutUint64(ret[:8], uint64(t.Unix())) diff --git a/_draft/v2/timeseq_test.go b/_draft/v2/timeseq_test.go new file mode 100644 index 0000000..7c35039 --- /dev/null +++ b/_draft/v2/timeseq_test.go @@ -0,0 +1,35 @@ +package timeseq + +import ( + "testing" + "time" +) + +func TestInterval_Contain(t *testing.T) { + now := time.Now() + type args struct { + t time.Time + } + tests := []struct { + name string + interval Interval + args args + want bool + }{ + { + name: "regular", + interval: Before(now.Add(time.Hour)), + args: args{ + t: time.Now(), + }, + want: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := tt.interval.Contain(tt.args.t); got != tt.want { + t.Errorf("Contain() = %v, want %v", got, tt.want) + } + }) + } +} From 5957ecf7855ace33798298e77ef73c74235a0741 Mon Sep 17 00:00:00 2001 From: Jason Song Date: Thu, 24 Sep 2020 18:48:10 +0800 Subject: [PATCH 14/19] fix: bug in Interval --- _draft/v2/timeseq.go | 19 +------------------ _draft/v2/timeseq_test.go | 36 ++++++++++++++++++++++++++++++++++-- 2 files changed, 35 insertions(+), 20 deletions(-) diff --git a/_draft/v2/timeseq.go b/_draft/v2/timeseq.go index 1936748..c13bdd2 100644 --- a/_draft/v2/timeseq.go +++ b/_draft/v2/timeseq.go @@ -68,23 +68,6 @@ func (i Interval) Contain(t time.Time) bool { return true } -func (i Interval) Merge(i2 Interval) Interval { - ret := i - if i2.NotBefore != nil { - t := *i2.NotBefore - if ret.NotBefore == nil || ret.NotBefore.Before(t) { - ret.NotBefore = &t - } - } - if i2.NotAfter != nil { - t := *i2.NotAfter - if ret.NotAfter == nil || ret.NotAfter.After(t) { - ret.NotAfter = &t - } - } - return ret -} - func (i Interval) BeforeOrEqual(t time.Time) Interval { return Interval{ NotAfter: &t, @@ -107,7 +90,7 @@ func (i Interval) Before(t time.Time) Interval { func (i Interval) After(t time.Time) Interval { t = t.Add(1) return Interval{ - NotAfter: &t, + NotBefore: &t, } } diff --git a/_draft/v2/timeseq_test.go b/_draft/v2/timeseq_test.go index 7c35039..303e8bc 100644 --- a/_draft/v2/timeseq_test.go +++ b/_draft/v2/timeseq_test.go @@ -18,12 +18,44 @@ func TestInterval_Contain(t *testing.T) { }{ { name: "regular", - interval: Before(now.Add(time.Hour)), + interval: Interval{}.Before(now.Add(time.Hour)).After(now.Add(-time.Hour)), args: args{ - t: time.Now(), + t: now, }, want: true, }, + { + name: "AfterOrEqual", + interval: Interval{}.AfterOrEqual(now), + args: args{ + t: now, + }, + want: true, + }, + { + name: "After", + interval: Interval{}.After(now), + args: args{ + t: now, + }, + want: false, + }, + { + name: "BeforeOrEqual", + interval: Interval{}.BeforeOrEqual(now), + args: args{ + t: now, + }, + want: true, + }, + { + name: "Before", + interval: Interval{}.Before(now), + args: args{ + t: now, + }, + want: false, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { From 0fc8e57aa07423f284f7f0e4c9a2ffdbb4d4183c Mon Sep 17 00:00:00 2001 From: Jason Song Date: Thu, 24 Sep 2020 18:52:30 +0800 Subject: [PATCH 15/19] docs: updat README --- README.md | 52 ++++++---------------------------------------------- 1 file changed, 6 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index 6f9098d..c775f8e 100644 --- a/README.md +++ b/README.md @@ -8,52 +8,12 @@ Time sequence. -## Example +This is v2, work in process. -```go -package main +Switch to [v1](https://github.com/gochore/timeseq/tree/v1). -import ( - "fmt" - "time" +## Install - "github.com/gochore/timeseq" -) - -func main() { - now := time.Now() - seq := timeseq.Int64Sequence{ - { - Time: now, - Value: 0, - }, - { - Time: now.Add(time.Second), - Value: 1, - }, - { - Time: now.Add(-time.Second), - Value: 2, - }, - } - seq = append(seq, timeseq.Int64Item{ - Time: now.Add(-2 * time.Second), - Value: -1, - }) - - // sort by time - seq.Sort() - - // get the first one - fmt.Println(seq.First(nil)) - // get the last one before now - fmt.Println(seq.Last(&now)) - - // get the sub sequence after now - subSeq := seq.Range(&now, nil) - // get the sub sequence's length - fmt.Println(subSeq.Len()) - // get the first one of the sub sequence - fmt.Println(subSeq.First(nil)) -} -``` +```bash +go get github.com/gochore/timeseq/v2 +``` \ No newline at end of file From 9e8318f970e748296a403cf7d19fbcf7897bcfa9 Mon Sep 17 00:00:00 2001 From: Jason Song Date: Thu, 24 Sep 2020 18:56:03 +0800 Subject: [PATCH 16/19] chore: generate --- cmd/generate/gen_x_seq.go.tmpl | 55 ++++++++++++++--------- cmd/generate/gen_x_seq_test.go.tmpl | 51 ++++++++++++++++++++++ gen_float64_seq.go | 55 ++++++++++++++--------- gen_float64_seq_test.go | 51 ++++++++++++++++++++++ gen_int64_seq.go | 55 ++++++++++++++--------- gen_int64_seq_test.go | 51 ++++++++++++++++++++++ gen_int_seq.go | 55 ++++++++++++++--------- gen_int_seq_test.go | 51 ++++++++++++++++++++++ timeseq.go | 62 ++++++++++++++++++++------ timeseq_test.go | 67 +++++++++++++++++++++++++++++ 10 files changed, 460 insertions(+), 93 deletions(-) create mode 100644 timeseq_test.go diff --git a/cmd/generate/gen_x_seq.go.tmpl b/cmd/generate/gen_x_seq.go.tmpl index 7867927..0c21c87 100644 --- a/cmd/generate/gen_x_seq.go.tmpl +++ b/cmd/generate/gen_x_seq.go.tmpl @@ -3,6 +3,7 @@ package timeseq import ( "errors" "sort" + "sync" "time" ) @@ -11,6 +12,10 @@ type {{.Name}} struct { Value {{.Type}} } +func (v {{.Name}}) IsZero() bool { + return v.Value == 0 && v.Time.IsZero() +} + type {{.Name}}s []{{.Name}} func (s {{.Name}}s) Len() int { @@ -25,12 +30,14 @@ func (s {{.Name}}s) Time(i int) time.Time { return s[i].Time } -func (s {{.Name}}s) Slice(i, j int) Slice { +func (s {{.Name}}s) Slice(i, j int) Interface { return s[i:j] } type {{.Name}}Seq struct { - slice {{.Name}}s + slice {{.Name}}s + + indexOnce sync.Once timeIndex map[timeKey][]int valueIndex map[{{.Type}}][]int valueSlice []int @@ -52,26 +59,31 @@ func new{{.Name}}Seq(slice {{.Name}}s) *{{.Name}}Seq { ret := &{{.Name}}Seq{ slice: slice, } - ret.buildIndex() return ret } func (s *{{.Name}}Seq) buildIndex() { - timeIndex := make(map[timeKey][]int, len(s.slice)) - valueIndex := make(map[{{.Type}}][]int, len(s.slice)) - valueSlice := s.valueSlice[:0] - for i, v := range s.slice { - k := newTimeKey(v.Time) - timeIndex[k] = append(timeIndex[k], i) - valueIndex[v.Value] = append(valueIndex[v.Value], i) - valueSlice = append(valueSlice, i) - } - sort.SliceStable(valueSlice, func(i, j int) bool { - return s.slice[valueSlice[i]].Value < s.slice[valueSlice[j]].Value + s.indexOnce.Do(func() { + timeIndex := make(map[timeKey][]int, len(s.slice)) + valueIndex := make(map[{{.Type}}][]int, len(s.slice)) + valueSlice := s.valueSlice[:0] + for i, v := range s.slice { + k := newTimeKey(v.Time) + timeIndex[k] = append(timeIndex[k], i) + valueIndex[v.Value] = append(valueIndex[v.Value], i) + valueSlice = append(valueSlice, i) + } + sort.SliceStable(valueSlice, func(i, j int) bool { + return s.slice[valueSlice[i]].Value < s.slice[valueSlice[j]].Value + }) + s.timeIndex = timeIndex + s.valueIndex = valueIndex + s.valueSlice = valueSlice }) - s.timeIndex = timeIndex - s.valueIndex = valueIndex - s.valueSlice = valueSlice +} + +func (s *{{.Name}}Seq) resetIndex() { + s.indexOnce = sync.Once{} } func (s *{{.Name}}Seq) {{.Name}}s() {{.Name}}s { @@ -88,6 +100,7 @@ func (s *{{.Name}}Seq) Index(i int) {{.Name}} { } func (s *{{.Name}}Seq) Time(t time.Time) {{.Name}}s { + s.buildIndex() index := s.timeIndex[newTimeKey(t)] if len(index) == 0 { return nil @@ -100,6 +113,7 @@ func (s *{{.Name}}Seq) Time(t time.Time) {{.Name}}s { } func (s *{{.Name}}Seq) Value(v {{.Type}}) {{.Name}}s { + s.buildIndex() index := s.valueIndex[v] if len(index) == 0 { return nil @@ -174,6 +188,7 @@ func (s *{{.Name}}Seq) Last() {{.Name}} { } func (s *{{.Name}}Seq) Percentile(pct float64) {{.Name}} { + s.buildIndex() if len(s.slice) == 0 { return {{.Name}}{} } @@ -258,7 +273,7 @@ func (s *{{.Name}}Seq) Merge(fn func(t time.Time, v1, v2 *{{.Type}}) *{{.Type}}, } s.slice = slice1 - s.buildIndex() + s.resetIndex() return nil } @@ -304,7 +319,7 @@ func (s *{{.Name}}Seq) Aggregate(fn func(t time.Time, slice {{.Name}}s) *{{.Type } s.slice = got - s.buildIndex() + s.resetIndex() return nil } @@ -325,7 +340,7 @@ func (s *{{.Name}}Seq) Trim(fn func(i int, v {{.Name}}) bool) error { if updated { s.slice = slice - s.buildIndex() + s.resetIndex() } return nil } diff --git a/cmd/generate/gen_x_seq_test.go.tmpl b/cmd/generate/gen_x_seq_test.go.tmpl index e40002c..8ef609e 100644 --- a/cmd/generate/gen_x_seq_test.go.tmpl +++ b/cmd/generate/gen_x_seq_test.go.tmpl @@ -24,6 +24,43 @@ func Random{{.Name}}s(length int) {{.Name}}s { return ret } +func Test{{.Name}}_IsZero(t *testing.T) { + type fields struct { + Time time.Time + Value {{.Type}} + } + tests := []struct { + name string + fields fields + want bool + }{ + { + name: "zero", + fields: fields{}, + want: true, + }, + { + name: "not zero", + fields: fields{ + Time: time.Now(), + Value: 1, + }, + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + v := {{.Name}}{ + Time: tt.fields.Time, + Value: tt.fields.Value, + } + if got := v.IsZero(); got != tt.want { + t.Errorf("IsZero() = %v, want %v", got, tt.want) + } + }) + } +} + func Test{{.Name}}Seq_{{.Name}}s(t *testing.T) { data := Random{{.Name}}s(100) Sort(data) @@ -623,6 +660,20 @@ func Test{{.Name}}Seq_Merge(t *testing.T) { }, want: data, }, + { + name: "empty slices", + data: data[0:7], + args: args{ + fn: func(t time.Time, v1, v2 *{{.Type}}) *{{.Type}} { + if v1 != nil { + return v1 + } + return v2 + }, + slices: []{{.Name}}s{}, + }, + want: data, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/gen_float64_seq.go b/gen_float64_seq.go index 79f3d30..d892a8a 100644 --- a/gen_float64_seq.go +++ b/gen_float64_seq.go @@ -4,6 +4,7 @@ package timeseq import ( "errors" "sort" + "sync" "time" ) @@ -12,6 +13,10 @@ type Float64 struct { Value float64 } +func (v Float64) IsZero() bool { + return v.Value == 0 && v.Time.IsZero() +} + type Float64s []Float64 func (s Float64s) Len() int { @@ -26,12 +31,14 @@ func (s Float64s) Time(i int) time.Time { return s[i].Time } -func (s Float64s) Slice(i, j int) Slice { +func (s Float64s) Slice(i, j int) Interface { return s[i:j] } type Float64Seq struct { - slice Float64s + slice Float64s + + indexOnce sync.Once timeIndex map[timeKey][]int valueIndex map[float64][]int valueSlice []int @@ -53,26 +60,31 @@ func newFloat64Seq(slice Float64s) *Float64Seq { ret := &Float64Seq{ slice: slice, } - ret.buildIndex() return ret } func (s *Float64Seq) buildIndex() { - timeIndex := make(map[timeKey][]int, len(s.slice)) - valueIndex := make(map[float64][]int, len(s.slice)) - valueSlice := s.valueSlice[:0] - for i, v := range s.slice { - k := newTimeKey(v.Time) - timeIndex[k] = append(timeIndex[k], i) - valueIndex[v.Value] = append(valueIndex[v.Value], i) - valueSlice = append(valueSlice, i) - } - sort.SliceStable(valueSlice, func(i, j int) bool { - return s.slice[valueSlice[i]].Value < s.slice[valueSlice[j]].Value + s.indexOnce.Do(func() { + timeIndex := make(map[timeKey][]int, len(s.slice)) + valueIndex := make(map[float64][]int, len(s.slice)) + valueSlice := s.valueSlice[:0] + for i, v := range s.slice { + k := newTimeKey(v.Time) + timeIndex[k] = append(timeIndex[k], i) + valueIndex[v.Value] = append(valueIndex[v.Value], i) + valueSlice = append(valueSlice, i) + } + sort.SliceStable(valueSlice, func(i, j int) bool { + return s.slice[valueSlice[i]].Value < s.slice[valueSlice[j]].Value + }) + s.timeIndex = timeIndex + s.valueIndex = valueIndex + s.valueSlice = valueSlice }) - s.timeIndex = timeIndex - s.valueIndex = valueIndex - s.valueSlice = valueSlice +} + +func (s *Float64Seq) resetIndex() { + s.indexOnce = sync.Once{} } func (s *Float64Seq) Float64s() Float64s { @@ -89,6 +101,7 @@ func (s *Float64Seq) Index(i int) Float64 { } func (s *Float64Seq) Time(t time.Time) Float64s { + s.buildIndex() index := s.timeIndex[newTimeKey(t)] if len(index) == 0 { return nil @@ -101,6 +114,7 @@ func (s *Float64Seq) Time(t time.Time) Float64s { } func (s *Float64Seq) Value(v float64) Float64s { + s.buildIndex() index := s.valueIndex[v] if len(index) == 0 { return nil @@ -175,6 +189,7 @@ func (s *Float64Seq) Last() Float64 { } func (s *Float64Seq) Percentile(pct float64) Float64 { + s.buildIndex() if len(s.slice) == 0 { return Float64{} } @@ -259,7 +274,7 @@ func (s *Float64Seq) Merge(fn func(t time.Time, v1, v2 *float64) *float64, slice } s.slice = slice1 - s.buildIndex() + s.resetIndex() return nil } @@ -305,7 +320,7 @@ func (s *Float64Seq) Aggregate(fn func(t time.Time, slice Float64s) *float64, du } s.slice = got - s.buildIndex() + s.resetIndex() return nil } @@ -326,7 +341,7 @@ func (s *Float64Seq) Trim(fn func(i int, v Float64) bool) error { if updated { s.slice = slice - s.buildIndex() + s.resetIndex() } return nil } diff --git a/gen_float64_seq_test.go b/gen_float64_seq_test.go index 70113ec..63959e4 100644 --- a/gen_float64_seq_test.go +++ b/gen_float64_seq_test.go @@ -25,6 +25,43 @@ func RandomFloat64s(length int) Float64s { return ret } +func TestFloat64_IsZero(t *testing.T) { + type fields struct { + Time time.Time + Value float64 + } + tests := []struct { + name string + fields fields + want bool + }{ + { + name: "zero", + fields: fields{}, + want: true, + }, + { + name: "not zero", + fields: fields{ + Time: time.Now(), + Value: 1, + }, + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + v := Float64{ + Time: tt.fields.Time, + Value: tt.fields.Value, + } + if got := v.IsZero(); got != tt.want { + t.Errorf("IsZero() = %v, want %v", got, tt.want) + } + }) + } +} + func TestFloat64Seq_Float64s(t *testing.T) { data := RandomFloat64s(100) Sort(data) @@ -624,6 +661,20 @@ func TestFloat64Seq_Merge(t *testing.T) { }, want: data, }, + { + name: "empty slices", + data: data[0:7], + args: args{ + fn: func(t time.Time, v1, v2 *float64) *float64 { + if v1 != nil { + return v1 + } + return v2 + }, + slices: []Float64s{}, + }, + want: data, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/gen_int64_seq.go b/gen_int64_seq.go index ec4e227..4a955bc 100644 --- a/gen_int64_seq.go +++ b/gen_int64_seq.go @@ -4,6 +4,7 @@ package timeseq import ( "errors" "sort" + "sync" "time" ) @@ -12,6 +13,10 @@ type Int64 struct { Value int64 } +func (v Int64) IsZero() bool { + return v.Value == 0 && v.Time.IsZero() +} + type Int64s []Int64 func (s Int64s) Len() int { @@ -26,12 +31,14 @@ func (s Int64s) Time(i int) time.Time { return s[i].Time } -func (s Int64s) Slice(i, j int) Slice { +func (s Int64s) Slice(i, j int) Interface { return s[i:j] } type Int64Seq struct { - slice Int64s + slice Int64s + + indexOnce sync.Once timeIndex map[timeKey][]int valueIndex map[int64][]int valueSlice []int @@ -53,26 +60,31 @@ func newInt64Seq(slice Int64s) *Int64Seq { ret := &Int64Seq{ slice: slice, } - ret.buildIndex() return ret } func (s *Int64Seq) buildIndex() { - timeIndex := make(map[timeKey][]int, len(s.slice)) - valueIndex := make(map[int64][]int, len(s.slice)) - valueSlice := s.valueSlice[:0] - for i, v := range s.slice { - k := newTimeKey(v.Time) - timeIndex[k] = append(timeIndex[k], i) - valueIndex[v.Value] = append(valueIndex[v.Value], i) - valueSlice = append(valueSlice, i) - } - sort.SliceStable(valueSlice, func(i, j int) bool { - return s.slice[valueSlice[i]].Value < s.slice[valueSlice[j]].Value + s.indexOnce.Do(func() { + timeIndex := make(map[timeKey][]int, len(s.slice)) + valueIndex := make(map[int64][]int, len(s.slice)) + valueSlice := s.valueSlice[:0] + for i, v := range s.slice { + k := newTimeKey(v.Time) + timeIndex[k] = append(timeIndex[k], i) + valueIndex[v.Value] = append(valueIndex[v.Value], i) + valueSlice = append(valueSlice, i) + } + sort.SliceStable(valueSlice, func(i, j int) bool { + return s.slice[valueSlice[i]].Value < s.slice[valueSlice[j]].Value + }) + s.timeIndex = timeIndex + s.valueIndex = valueIndex + s.valueSlice = valueSlice }) - s.timeIndex = timeIndex - s.valueIndex = valueIndex - s.valueSlice = valueSlice +} + +func (s *Int64Seq) resetIndex() { + s.indexOnce = sync.Once{} } func (s *Int64Seq) Int64s() Int64s { @@ -89,6 +101,7 @@ func (s *Int64Seq) Index(i int) Int64 { } func (s *Int64Seq) Time(t time.Time) Int64s { + s.buildIndex() index := s.timeIndex[newTimeKey(t)] if len(index) == 0 { return nil @@ -101,6 +114,7 @@ func (s *Int64Seq) Time(t time.Time) Int64s { } func (s *Int64Seq) Value(v int64) Int64s { + s.buildIndex() index := s.valueIndex[v] if len(index) == 0 { return nil @@ -175,6 +189,7 @@ func (s *Int64Seq) Last() Int64 { } func (s *Int64Seq) Percentile(pct float64) Int64 { + s.buildIndex() if len(s.slice) == 0 { return Int64{} } @@ -259,7 +274,7 @@ func (s *Int64Seq) Merge(fn func(t time.Time, v1, v2 *int64) *int64, slices ...I } s.slice = slice1 - s.buildIndex() + s.resetIndex() return nil } @@ -305,7 +320,7 @@ func (s *Int64Seq) Aggregate(fn func(t time.Time, slice Int64s) *int64, duration } s.slice = got - s.buildIndex() + s.resetIndex() return nil } @@ -326,7 +341,7 @@ func (s *Int64Seq) Trim(fn func(i int, v Int64) bool) error { if updated { s.slice = slice - s.buildIndex() + s.resetIndex() } return nil } diff --git a/gen_int64_seq_test.go b/gen_int64_seq_test.go index 165acef..9f9cce4 100644 --- a/gen_int64_seq_test.go +++ b/gen_int64_seq_test.go @@ -25,6 +25,43 @@ func RandomInt64s(length int) Int64s { return ret } +func TestInt64_IsZero(t *testing.T) { + type fields struct { + Time time.Time + Value int64 + } + tests := []struct { + name string + fields fields + want bool + }{ + { + name: "zero", + fields: fields{}, + want: true, + }, + { + name: "not zero", + fields: fields{ + Time: time.Now(), + Value: 1, + }, + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + v := Int64{ + Time: tt.fields.Time, + Value: tt.fields.Value, + } + if got := v.IsZero(); got != tt.want { + t.Errorf("IsZero() = %v, want %v", got, tt.want) + } + }) + } +} + func TestInt64Seq_Int64s(t *testing.T) { data := RandomInt64s(100) Sort(data) @@ -624,6 +661,20 @@ func TestInt64Seq_Merge(t *testing.T) { }, want: data, }, + { + name: "empty slices", + data: data[0:7], + args: args{ + fn: func(t time.Time, v1, v2 *int64) *int64 { + if v1 != nil { + return v1 + } + return v2 + }, + slices: []Int64s{}, + }, + want: data, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/gen_int_seq.go b/gen_int_seq.go index 65dbe54..a201488 100644 --- a/gen_int_seq.go +++ b/gen_int_seq.go @@ -4,6 +4,7 @@ package timeseq import ( "errors" "sort" + "sync" "time" ) @@ -12,6 +13,10 @@ type Int struct { Value int } +func (v Int) IsZero() bool { + return v.Value == 0 && v.Time.IsZero() +} + type Ints []Int func (s Ints) Len() int { @@ -26,12 +31,14 @@ func (s Ints) Time(i int) time.Time { return s[i].Time } -func (s Ints) Slice(i, j int) Slice { +func (s Ints) Slice(i, j int) Interface { return s[i:j] } type IntSeq struct { - slice Ints + slice Ints + + indexOnce sync.Once timeIndex map[timeKey][]int valueIndex map[int][]int valueSlice []int @@ -53,26 +60,31 @@ func newIntSeq(slice Ints) *IntSeq { ret := &IntSeq{ slice: slice, } - ret.buildIndex() return ret } func (s *IntSeq) buildIndex() { - timeIndex := make(map[timeKey][]int, len(s.slice)) - valueIndex := make(map[int][]int, len(s.slice)) - valueSlice := s.valueSlice[:0] - for i, v := range s.slice { - k := newTimeKey(v.Time) - timeIndex[k] = append(timeIndex[k], i) - valueIndex[v.Value] = append(valueIndex[v.Value], i) - valueSlice = append(valueSlice, i) - } - sort.SliceStable(valueSlice, func(i, j int) bool { - return s.slice[valueSlice[i]].Value < s.slice[valueSlice[j]].Value + s.indexOnce.Do(func() { + timeIndex := make(map[timeKey][]int, len(s.slice)) + valueIndex := make(map[int][]int, len(s.slice)) + valueSlice := s.valueSlice[:0] + for i, v := range s.slice { + k := newTimeKey(v.Time) + timeIndex[k] = append(timeIndex[k], i) + valueIndex[v.Value] = append(valueIndex[v.Value], i) + valueSlice = append(valueSlice, i) + } + sort.SliceStable(valueSlice, func(i, j int) bool { + return s.slice[valueSlice[i]].Value < s.slice[valueSlice[j]].Value + }) + s.timeIndex = timeIndex + s.valueIndex = valueIndex + s.valueSlice = valueSlice }) - s.timeIndex = timeIndex - s.valueIndex = valueIndex - s.valueSlice = valueSlice +} + +func (s *IntSeq) resetIndex() { + s.indexOnce = sync.Once{} } func (s *IntSeq) Ints() Ints { @@ -89,6 +101,7 @@ func (s *IntSeq) Index(i int) Int { } func (s *IntSeq) Time(t time.Time) Ints { + s.buildIndex() index := s.timeIndex[newTimeKey(t)] if len(index) == 0 { return nil @@ -101,6 +114,7 @@ func (s *IntSeq) Time(t time.Time) Ints { } func (s *IntSeq) Value(v int) Ints { + s.buildIndex() index := s.valueIndex[v] if len(index) == 0 { return nil @@ -175,6 +189,7 @@ func (s *IntSeq) Last() Int { } func (s *IntSeq) Percentile(pct float64) Int { + s.buildIndex() if len(s.slice) == 0 { return Int{} } @@ -259,7 +274,7 @@ func (s *IntSeq) Merge(fn func(t time.Time, v1, v2 *int) *int, slices ...Ints) e } s.slice = slice1 - s.buildIndex() + s.resetIndex() return nil } @@ -305,7 +320,7 @@ func (s *IntSeq) Aggregate(fn func(t time.Time, slice Ints) *int, duration time. } s.slice = got - s.buildIndex() + s.resetIndex() return nil } @@ -326,7 +341,7 @@ func (s *IntSeq) Trim(fn func(i int, v Int) bool) error { if updated { s.slice = slice - s.buildIndex() + s.resetIndex() } return nil } diff --git a/gen_int_seq_test.go b/gen_int_seq_test.go index 1967faa..6fe0546 100644 --- a/gen_int_seq_test.go +++ b/gen_int_seq_test.go @@ -25,6 +25,43 @@ func RandomInts(length int) Ints { return ret } +func TestInt_IsZero(t *testing.T) { + type fields struct { + Time time.Time + Value int + } + tests := []struct { + name string + fields fields + want bool + }{ + { + name: "zero", + fields: fields{}, + want: true, + }, + { + name: "not zero", + fields: fields{ + Time: time.Now(), + Value: 1, + }, + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + v := Int{ + Time: tt.fields.Time, + Value: tt.fields.Value, + } + if got := v.IsZero(); got != tt.want { + t.Errorf("IsZero() = %v, want %v", got, tt.want) + } + }) + } +} + func TestIntSeq_Ints(t *testing.T) { data := RandomInts(100) Sort(data) @@ -624,6 +661,20 @@ func TestIntSeq_Merge(t *testing.T) { }, want: data, }, + { + name: "empty slices", + data: data[0:7], + args: args{ + fn: func(t time.Time, v1, v2 *int) *int { + if v1 != nil { + return v1 + } + return v2 + }, + slices: []Ints{}, + }, + want: data, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/timeseq.go b/timeseq.go index 9d9915a..c13bdd2 100644 --- a/timeseq.go +++ b/timeseq.go @@ -6,7 +6,7 @@ import ( "time" ) -type Slice interface { +type Interface interface { // return length Len() int // swap items @@ -14,27 +14,27 @@ type Slice interface { // return time of item i Time(i int) time.Time // return Slice[i:j] - Slice(i, j int) Slice + Slice(i, j int) Interface } -type sortableSlice struct { - Slice +type sortable struct { + Interface } -func (s sortableSlice) Less(i, j int) bool { +func (s sortable) Less(i, j int) bool { return s.Time(i).Before(s.Time(j)) } // Sort will sort slice by time -func Sort(slice Slice) { - sort.Stable(sortableSlice{Slice: slice}) +func Sort(slice Interface) { + sort.Stable(sortable{Interface: slice}) } -func IsSorted(slice Slice) bool { - return sort.IsSorted(sortableSlice{Slice: slice}) +func IsSorted(slice Interface) bool { + return sort.IsSorted(sortable{Interface: slice}) } -func Range(slice Slice, interval Interval) Slice { +func Range(slice Interface, interval Interval) Interface { i := 0 if interval.NotBefore != nil { i = sort.Search(slice.Len(), func(i int) bool { @@ -58,12 +58,48 @@ type Interval struct { NotAfter *time.Time } -type timeKey [16]byte +func (i Interval) Contain(t time.Time) bool { + if i.NotAfter != nil && t.After(*i.NotAfter) { + return false + } + if i.NotBefore != nil && t.Before(*i.NotBefore) { + return false + } + return true +} -func (k timeKey) Get() time.Time { - return time.Unix(int64(binary.BigEndian.Uint64(k[:8])), int64(binary.BigEndian.Uint64(k[8:]))) +func (i Interval) BeforeOrEqual(t time.Time) Interval { + return Interval{ + NotAfter: &t, + } } +func (i Interval) AfterOrEqual(t time.Time) Interval { + return Interval{ + NotBefore: &t, + } +} + +func (i Interval) Before(t time.Time) Interval { + t = t.Add(-1) + return Interval{ + NotAfter: &t, + } +} + +func (i Interval) After(t time.Time) Interval { + t = t.Add(1) + return Interval{ + NotBefore: &t, + } +} + +type timeKey [16]byte + +//func (k timeKey) Get() time.Time { +// return time.Unix(int64(binary.BigEndian.Uint64(k[:8])), int64(binary.BigEndian.Uint64(k[8:]))) +//} + func newTimeKey(t time.Time) timeKey { var ret [16]byte binary.BigEndian.PutUint64(ret[:8], uint64(t.Unix())) diff --git a/timeseq_test.go b/timeseq_test.go new file mode 100644 index 0000000..303e8bc --- /dev/null +++ b/timeseq_test.go @@ -0,0 +1,67 @@ +package timeseq + +import ( + "testing" + "time" +) + +func TestInterval_Contain(t *testing.T) { + now := time.Now() + type args struct { + t time.Time + } + tests := []struct { + name string + interval Interval + args args + want bool + }{ + { + name: "regular", + interval: Interval{}.Before(now.Add(time.Hour)).After(now.Add(-time.Hour)), + args: args{ + t: now, + }, + want: true, + }, + { + name: "AfterOrEqual", + interval: Interval{}.AfterOrEqual(now), + args: args{ + t: now, + }, + want: true, + }, + { + name: "After", + interval: Interval{}.After(now), + args: args{ + t: now, + }, + want: false, + }, + { + name: "BeforeOrEqual", + interval: Interval{}.BeforeOrEqual(now), + args: args{ + t: now, + }, + want: true, + }, + { + name: "Before", + interval: Interval{}.Before(now), + args: args{ + t: now, + }, + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := tt.interval.Contain(tt.args.t); got != tt.want { + t.Errorf("Contain() = %v, want %v", got, tt.want) + } + }) + } +} From 086162e04bf969fe6874b38b3f9fbdbc9ce47c7f Mon Sep 17 00:00:00 2001 From: Jason Song Date: Thu, 24 Sep 2020 18:57:21 +0800 Subject: [PATCH 17/19] feat: support uint64 --- cmd/generate/main.go | 5 + gen_uint64_seq.go | 347 +++++++++++++++++ gen_uint64_seq_test.go | 829 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1181 insertions(+) create mode 100644 gen_uint64_seq.go create mode 100644 gen_uint64_seq_test.go diff --git a/cmd/generate/main.go b/cmd/generate/main.go index 507f31f..3a02172 100644 --- a/cmd/generate/main.go +++ b/cmd/generate/main.go @@ -31,6 +31,11 @@ func main() { Type: "int64", Random: "rand.Int63()", }, + { + Name: "Uint64", + Type: "uint64", + Random: "rand.Uint64()", + }, { Name: "Float64", Type: "float64", diff --git a/gen_uint64_seq.go b/gen_uint64_seq.go new file mode 100644 index 0000000..bba2ded --- /dev/null +++ b/gen_uint64_seq.go @@ -0,0 +1,347 @@ +// Code generated by cmd/generate. DO NOT EDIT. +package timeseq + +import ( + "errors" + "sort" + "sync" + "time" +) + +type Uint64 struct { + Time time.Time + Value uint64 +} + +func (v Uint64) IsZero() bool { + return v.Value == 0 && v.Time.IsZero() +} + +type Uint64s []Uint64 + +func (s Uint64s) Len() int { + return len(s) +} + +func (s Uint64s) Swap(i, j int) { + s[i], s[j] = s[j], s[i] +} + +func (s Uint64s) Time(i int) time.Time { + return s[i].Time +} + +func (s Uint64s) Slice(i, j int) Interface { + return s[i:j] +} + +type Uint64Seq struct { + slice Uint64s + + indexOnce sync.Once + timeIndex map[timeKey][]int + valueIndex map[uint64][]int + valueSlice []int +} + +func NewUint64Seq(slice Uint64s) *Uint64Seq { + temp := make(Uint64s, len(slice)) + copy(temp, slice) + slice = temp + + Sort(slice) + sort.SliceStable(slice, func(i, j int) bool { + return slice[i].Time.Before(slice[j].Time) + }) + return newUint64Seq(slice) +} + +func newUint64Seq(slice Uint64s) *Uint64Seq { + ret := &Uint64Seq{ + slice: slice, + } + return ret +} + +func (s *Uint64Seq) buildIndex() { + s.indexOnce.Do(func() { + timeIndex := make(map[timeKey][]int, len(s.slice)) + valueIndex := make(map[uint64][]int, len(s.slice)) + valueSlice := s.valueSlice[:0] + for i, v := range s.slice { + k := newTimeKey(v.Time) + timeIndex[k] = append(timeIndex[k], i) + valueIndex[v.Value] = append(valueIndex[v.Value], i) + valueSlice = append(valueSlice, i) + } + sort.SliceStable(valueSlice, func(i, j int) bool { + return s.slice[valueSlice[i]].Value < s.slice[valueSlice[j]].Value + }) + s.timeIndex = timeIndex + s.valueIndex = valueIndex + s.valueSlice = valueSlice + }) +} + +func (s *Uint64Seq) resetIndex() { + s.indexOnce = sync.Once{} +} + +func (s *Uint64Seq) Uint64s() Uint64s { + slice := make(Uint64s, len(s.slice)) + copy(slice, s.slice) + return slice +} + +func (s *Uint64Seq) Index(i int) Uint64 { + if i < 0 || i >= len(s.slice) { + return Uint64{} + } + return s.slice[i] +} + +func (s *Uint64Seq) Time(t time.Time) Uint64s { + s.buildIndex() + index := s.timeIndex[newTimeKey(t)] + if len(index) == 0 { + return nil + } + ret := make(Uint64s, len(index)) + for i, v := range index { + ret[i] = s.slice[v] + } + return ret +} + +func (s *Uint64Seq) Value(v uint64) Uint64s { + s.buildIndex() + index := s.valueIndex[v] + if len(index) == 0 { + return nil + } + ret := make(Uint64s, len(index)) + for i, v := range index { + ret[i] = s.slice[v] + } + return ret +} + +func (s *Uint64Seq) Visit(fn func(i int, v Uint64) (stop bool)) { + for i, v := range s.slice { + if fn != nil && fn(i, v) { + break + } + } +} + +func (s *Uint64Seq) Sum() uint64 { + var ret uint64 + for _, v := range s.slice { + ret += v.Value + } + return ret +} + +func (s *Uint64Seq) Count() int { + return len(s.slice) +} + +func (s *Uint64Seq) Max() Uint64 { + var max Uint64 + found := false + for _, v := range s.slice { + if !found { + max = v + found = true + } else if v.Value > max.Value { + max = v + } + } + return max +} + +func (s *Uint64Seq) Min() Uint64 { + var min Uint64 + found := false + for _, v := range s.slice { + if !found { + min = v + found = true + } else if v.Value < min.Value { + min = v + } + } + return min +} + +func (s *Uint64Seq) First() Uint64 { + if len(s.slice) == 0 { + return Uint64{} + } + return s.slice[0] +} + +func (s *Uint64Seq) Last() Uint64 { + if len(s.slice) == 0 { + return Uint64{} + } + return s.slice[len(s.slice)-1] +} + +func (s *Uint64Seq) Percentile(pct float64) Uint64 { + s.buildIndex() + if len(s.slice) == 0 { + return Uint64{} + } + if pct > 1 { + pct = 1 + } + if pct < 0 { + pct = 0 + } + i := int(float64(len(s.slice))*pct - 1) + if i < 0 { + i = 0 + } + return s.slice[s.valueSlice[i]] +} + +func (s *Uint64Seq) Range(interval Interval) *Uint64Seq { + slice := Range(s.slice, interval).(Uint64s) + return newUint64Seq(slice) +} + +func (s *Uint64Seq) Merge(fn func(t time.Time, v1, v2 *uint64) *uint64, slices ...Uint64s) error { + if fn == nil { + return errors.New("nil fn") + } + + if len(slices) == 0 { + return nil + } + + slice1 := s.slice + for _, slice2 := range slices { + if !IsSorted(slice2) { + temp := make(Uint64s, len(slice2)) + copy(temp, slice2) + Sort(temp) + slice2 = temp + } + var got Uint64s + for i1, i2 := 0, 0; i1 < len(slice1) || i2 < len(slice2); { + var ( + t time.Time + v *uint64 + ) + switch { + case i1 == len(slice1): + t = slice2[i2].Time + v2 := slice2[i2].Value + v = fn(t, nil, &v2) + i2++ + case i2 == len(slice2): + t = slice1[i1].Time + v1 := slice1[i1].Value + v = fn(t, &v1, nil) + i1++ + case slice1[i1].Time.Equal(slice2[i2].Time): + t = slice1[i1].Time + v1 := slice1[i1].Value + v2 := slice2[i2].Value + v = fn(t, &v1, &v2) + i1++ + i2++ + case slice1[i1].Time.Before(slice2[i2].Time): + t = slice1[i1].Time + v1 := slice1[i1].Value + v = fn(t, &v1, nil) + i1++ + case slice1[i1].Time.After(slice2[i2].Time): + t = slice2[i2].Time + v2 := slice2[i2].Value + v = fn(t, nil, &v2) + i2++ + } + if v != nil { + got = append(got, Uint64{ + Time: t, + Value: *v, + }) + } + } + slice1 = got + } + + s.slice = slice1 + s.resetIndex() + return nil +} + +func (s *Uint64Seq) Aggregate(fn func(t time.Time, slice Uint64s) *uint64, duration time.Duration, begin, end *time.Time) error { + if fn == nil { + return errors.New("nil fn") + } + + if duration <= 0 { + return errors.New("invalid duration") + } + + var bg, ed time.Time + if len(s.slice) > 0 { + bg = s.slice[0].Time.Truncate(duration) + ed = s.slice[len(s.slice)-1].Time + } + if begin != nil { + bg = (*begin).Truncate(duration) + } + if end != nil { + ed = *end + } + + got := Uint64s{} + slice := Uint64s{} + i := 0 + for t := bg; t.Before(ed); t = t.Add(duration) { + slice = slice[:0] + for i < s.slice.Len() && + !s.slice[i].Time.After(t) && + s.slice[i].Time.Before(t.Add(duration)) { + slice = append(slice, s.slice[i]) + i++ + } + v := fn(t, slice) + if v != nil { + got = append(got, Uint64{ + Time: t, + Value: *v, + }) + } + } + + s.slice = got + s.resetIndex() + return nil +} + +func (s *Uint64Seq) Trim(fn func(i int, v Uint64) bool) error { + if fn == nil { + return errors.New("nil fn") + } + + updated := false + slice := make(Uint64s, 0) + for i, v := range s.slice { + if fn(i, v) { + updated = true + } else { + slice = append(slice, v) + } + } + + if updated { + s.slice = slice + s.resetIndex() + } + return nil +} diff --git a/gen_uint64_seq_test.go b/gen_uint64_seq_test.go new file mode 100644 index 0000000..192cb14 --- /dev/null +++ b/gen_uint64_seq_test.go @@ -0,0 +1,829 @@ +// Code generated by cmd/generate. DO NOT EDIT. +package timeseq + +import ( + "fmt" + "math/rand" + "reflect" + "testing" + "time" +) + +func RandomUint64s(length int) Uint64s { + now := time.Now() + ret := make(Uint64s, length) + for i := range ret { + delta := time.Duration(i) * time.Second + if rand.Float64() < 0.5 { + delta = -delta + } + ret[i] = Uint64{ + Time: now.Add(delta), + Value: rand.Uint64(), + } + } + return ret +} + +func TestUint64_IsZero(t *testing.T) { + type fields struct { + Time time.Time + Value uint64 + } + tests := []struct { + name string + fields fields + want bool + }{ + { + name: "zero", + fields: fields{}, + want: true, + }, + { + name: "not zero", + fields: fields{ + Time: time.Now(), + Value: 1, + }, + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + v := Uint64{ + Time: tt.fields.Time, + Value: tt.fields.Value, + } + if got := v.IsZero(); got != tt.want { + t.Errorf("IsZero() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestUint64Seq_Uint64s(t *testing.T) { + data := RandomUint64s(100) + Sort(data) + + tests := []struct { + name string + want Uint64s + }{ + { + name: "regular", + want: data, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewUint64Seq(data) + if got := s.Uint64s(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Uint64s() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestUint64Seq_Index(t *testing.T) { + data := RandomUint64s(100) + Sort(data) + + type args struct { + i int + } + tests := []struct { + name string + args args + want Uint64 + }{ + { + name: "regular", + args: args{ + i: 1, + }, + want: data[1], + }, + { + name: "less than zero", + args: args{ + i: -1, + }, + want: Uint64{}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewUint64Seq(data) + if got := s.Index(tt.args.i); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Index() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestUint64Seq_Time(t *testing.T) { + now := time.Now() + yesterday := now.AddDate(0, 0, -1) + lastMonth := now.AddDate(0, -1, 0) + lastYear := now.AddDate(-1, 0, 0) + + data := RandomUint64s(100) + data[0].Time = lastMonth + data[1].Time = lastMonth + data[2].Time = lastMonth + data[3].Time = yesterday + Sort(data) + + type args struct { + t time.Time + } + tests := []struct { + name string + args args + length int + }{ + { + name: "regular", + args: args{ + t: yesterday, + }, + length: 1, + }, + { + name: "multiple", + args: args{ + t: lastMonth, + }, + length: 3, + }, + { + name: "none", + args: args{ + t: lastYear, + }, + length: 0, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewUint64Seq(data) + if got := s.Time(tt.args.t); len(got) != tt.length { + t.Errorf("Time() = %v, want %v", got, tt.length) + } + }) + } +} + +func TestUint64Seq_Value(t *testing.T) { + data := RandomUint64s(100) + Sort(data) + + value1 := data[0].Value + value2 := data[1].Value + value3 := data[2].Value + + data[0].Value = value1 + data[1].Value = value2 + data[2].Value = value2 + data[3].Value = value2 + + type args struct { + v uint64 + } + tests := []struct { + name string + args args + length int + }{ + { + name: "regular", + args: args{ + v: value1, + }, + length: 1, + }, + { + name: "multiple", + args: args{ + v: value2, + }, + length: 3, + }, + { + name: "none", + args: args{ + v: value3, + }, + length: 0, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewUint64Seq(data) + if got := s.Value(tt.args.v); len(got) != tt.length { + t.Errorf("Value() = %v, want %v", got, tt.length) + } + }) + } +} + +func TestUint64Seq_Visit(t *testing.T) { + data := RandomUint64s(100) + + type args struct { + fn func(i int, v Uint64) (stop bool) + } + tests := []struct { + name string + args args + }{ + { + name: "regular", + args: args{ + fn: func(i int, v Uint64) (stop bool) { + return false + }, + }, + }, + { + name: "stop", + args: args{ + fn: func(i int, v Uint64) (stop bool) { + return i > 10 + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewUint64Seq(data) + s.Visit(tt.args.fn) + }) + } +} + +func TestUint64Seq_Sum(t *testing.T) { + data := RandomUint64s(100) + Sort(data) + var sum uint64 + for _, v := range data { + sum += v.Value + } + tests := []struct { + name string + want uint64 + }{ + { + name: "regular", + want: sum, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewUint64Seq(data) + if got := s.Sum(); got != tt.want { + t.Errorf("Sum() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestUint64Seq_Count(t *testing.T) { + data := RandomUint64s(100) + + tests := []struct { + name string + want int + }{ + { + name: "regular", + want: len(data), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewUint64Seq(data) + if got := s.Count(); got != tt.want { + t.Errorf("Count() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestUint64Seq_Max(t *testing.T) { + data := RandomUint64s(100) + max := data[0] + for _, v := range data { + if v.Value > max.Value { + max = v + } + } + + tests := []struct { + name string + want Uint64 + }{ + { + name: "regular", + want: max, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewUint64Seq(data) + if got := s.Max(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Max() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestUint64Seq_Min(t *testing.T) { + data := RandomUint64s(100) + min := data[0] + for _, v := range data { + if v.Value < min.Value { + min = v + } + } + + tests := []struct { + name string + want Uint64 + }{ + { + name: "regular", + want: min, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewUint64Seq(data) + if got := s.Min(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Min() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestUint64Seq_First(t *testing.T) { + data := RandomUint64s(100) + Sort(data) + + tests := []struct { + name string + data Uint64s + want Uint64 + }{ + { + + name: "regular", + data: data, + want: data[0], + }, + { + name: "emtpy", + data: nil, + want: Uint64{}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewUint64Seq(tt.data) + if got := s.First(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("First() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestUint64Seq_Last(t *testing.T) { + data := RandomUint64s(100) + Sort(data) + tests := []struct { + name string + data Uint64s + want Uint64 + }{ + { + + name: "regular", + data: data, + want: data[len(data)-1], + }, + { + name: "emtpy", + data: nil, + want: Uint64{}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewUint64Seq(tt.data) + if got := s.Last(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Last() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestUint64Seq_Percentile(t *testing.T) { + data := RandomUint64s(100) + Sort(data) + for i := range data { + data[i].Value = uint64(i) + } + + type args struct { + pct float64 + } + tests := []struct { + name string + data Uint64s + args args + want Uint64 + }{ + { + name: "data[0]", + data: data, + args: args{ + pct: 0, + }, + want: data[0], + }, + { + name: "data[49]", + data: data, + args: args{ + pct: 0.5, + }, + want: data[49], + }, + { + name: "0.95", + data: data, + args: args{ + pct: 0.95, + }, + want: data[94], + }, + { + name: "0.955", + data: data, + args: args{ + pct: 0.955, + }, + want: data[94], + }, + { + name: "1", + data: data, + args: args{ + pct: 1, + }, + want: data[99], + }, + { + name: "1.1", + data: data, + args: args{ + pct: 1.1, + }, + want: data[99], + }, + { + name: "-0.1", + data: data, + args: args{ + pct: -0.1, + }, + want: data[0], + }, + { + name: "empty", + data: nil, + args: args{ + pct: 1, + }, + want: Uint64{}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewUint64Seq(tt.data) + if got := s.Percentile(tt.args.pct); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Percentile() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestUint64Seq_Range(t *testing.T) { + data := RandomUint64s(100) + Sort(data) + + type args struct { + interval Interval + } + tests := []struct { + name string + data Uint64s + args args + want Uint64s + }{ + { + name: "regular", + data: data, + args: args{ + interval: Interval{ + NotBefore: &data[10].Time, + NotAfter: &data[89].Time, + }, + }, + want: data[10:90], + }, + { + name: "nil NotBefore", + data: data, + args: args{ + interval: Interval{ + NotAfter: &data[89].Time, + }, + }, + want: data[:90], + }, + { + name: "nil NotAfter", + data: data, + args: args{ + interval: Interval{ + NotBefore: &data[10].Time, + }, + }, + want: data[10:], + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewUint64Seq(data) + if got := s.Range(tt.args.interval).slice; !reflect.DeepEqual(got, tt.want) { + t.Errorf("Range() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestUint64Seq_Merge(t *testing.T) { + data := RandomUint64s(10) + Sort(data) + + type args struct { + fn func(t time.Time, v1, v2 *uint64) *uint64 + slices []Uint64s + } + tests := []struct { + name string + data Uint64s + args args + want Uint64s + wantErr bool + }{ + { + name: "regular", + data: data[0:7], + args: args{ + fn: func(t time.Time, v1, v2 *uint64) *uint64 { + if v1 != nil { + return v1 + } + return v2 + }, + slices: []Uint64s{data[3:10]}, + }, + want: data, + }, + { + name: "reverse", + data: data[3:10], + args: args{ + fn: func(t time.Time, v1, v2 *uint64) *uint64 { + if v1 != nil { + return v1 + } + return v2 + }, + slices: []Uint64s{data[0:7]}, + }, + want: data, + }, + { + name: "nil fn", + data: nil, + args: args{ + fn: nil, + }, + wantErr: true, + }, + { + name: "multiple", + data: nil, + args: args{ + fn: func(t time.Time, v1, v2 *uint64) *uint64 { + if v1 != nil { + return v1 + } + return v2 + }, + slices: []Uint64s{ + data[1:2], + data[0:4], + nil, + data[2:9], + data[9:], + }, + }, + want: data, + }, + { + name: "not sorted", + data: data[0:7], + args: args{ + fn: func(t time.Time, v1, v2 *uint64) *uint64 { + if v1 != nil { + return v1 + } + return v2 + }, + slices: []Uint64s{ + append(Uint64s{data[9]}, data[3:9]...), + }, + }, + want: data, + }, + { + name: "empty slices", + data: data[0:7], + args: args{ + fn: func(t time.Time, v1, v2 *uint64) *uint64 { + if v1 != nil { + return v1 + } + return v2 + }, + slices: []Uint64s{}, + }, + want: data, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewUint64Seq(tt.data) + if err := s.Merge(tt.args.fn, tt.args.slices...); (err != nil) != tt.wantErr { + t.Errorf("Merge() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !tt.wantErr { + if got := s.slice; !reflect.DeepEqual(got, tt.want) { + t.Errorf("Merge() = %v, want %v", got, tt.want) + } + } + }) + } +} + +func TestUint64Seq_Aggregate(t *testing.T) { + data := RandomUint64s(100) + now := time.Now() + begin := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()) + end := begin.Add(24*time.Hour - 1) + + type args struct { + fn func(t time.Time, slice Uint64s) *uint64 + duration time.Duration + begin *time.Time + end *time.Time + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "regular", + args: args{ + fn: func(t time.Time, slice Uint64s) *uint64 { + ret := uint64(t.Hour()) + if len(slice) != 0 { + ret = 0 + } + for _, v := range slice { + ret += v.Value + } + return &ret + }, + duration: time.Hour, + begin: &begin, + end: &end, + }, + wantErr: false, + }, + { + name: "nil fn", + args: args{ + fn: nil, + duration: time.Hour, + begin: &begin, + end: &end, + }, + wantErr: true, + }, + { + name: "zero duration", + args: args{ + fn: func(t time.Time, slice Uint64s) *uint64 { + ret := uint64(t.Hour()) + if len(slice) != 0 { + ret = 0 + } + for _, v := range slice { + ret += v.Value + } + return &ret + }, + duration: 0, + begin: &begin, + end: &end, + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewUint64Seq(data) + if err := s.Aggregate(tt.args.fn, tt.args.duration, tt.args.begin, tt.args.end); (err != nil) != tt.wantErr { + t.Errorf("Aggregate() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !tt.wantErr { + for i, v := range s.slice { + fmt.Println(i, v.Value, v.Time) + } + } + }) + } +} + +func TestUint64Seq_Trim(t *testing.T) { + data := RandomUint64s(10) + Sort(data) + + type args struct { + fn func(i int, v Uint64) bool + } + tests := []struct { + name string + args args + want Uint64s + wantErr bool + }{ + { + name: "regular", + args: args{ + fn: func(i int, v Uint64) bool { + return i >= 5 + }, + }, + want: data[:5], + wantErr: false, + }, + { + name: "nil fn", + args: args{ + fn: nil, + }, + want: data[:5], + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewUint64Seq(data) + if err := s.Trim(tt.args.fn); (err != nil) != tt.wantErr { + t.Errorf("Trim() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !tt.wantErr { + if got := s.slice; !reflect.DeepEqual(got, tt.want) { + t.Errorf("Trim() = %v, want %v", got, tt.want) + for i, v := range got { + fmt.Println(i, v) + } + for i, v := range tt.want { + fmt.Println(i, v) + } + } + } + }) + } +} From 3b879b1a0d31c8c8304d58c56e6d1dc0def036c3 Mon Sep 17 00:00:00 2001 From: Jason Song Date: Thu, 24 Sep 2020 18:58:41 +0800 Subject: [PATCH 18/19] chore: go mod tidy --- go.mod | 2 -- go.sum | 2 -- 2 files changed, 4 deletions(-) diff --git a/go.mod b/go.mod index 11eeeba..4a1d594 100644 --- a/go.mod +++ b/go.mod @@ -1,5 +1,3 @@ module github.com/gochore/timeseq go 1.15 - -require github.com/gochore/pt v1.1.0 diff --git a/go.sum b/go.sum index babe381..e69de29 100644 --- a/go.sum +++ b/go.sum @@ -1,2 +0,0 @@ -github.com/gochore/pt v1.1.0 h1:KZO6HDZRTPtmcpCDM/p0iVA/47I8MyHqS2mqFsjhcPI= -github.com/gochore/pt v1.1.0/go.mod h1:8fd2g+qoAO1QIorsgi9vLJCMudJ5m+nDhY8r1nPP6dg= From 692e1892fca6407beb27c324f7ad935072dc3d52 Mon Sep 17 00:00:00 2001 From: Jason Song Date: Thu, 24 Sep 2020 19:27:51 +0800 Subject: [PATCH 19/19] test: fix cases --- _draft/v1/go.mod | 5 +++++ _draft/v1/go.sum | 2 ++ _draft/v2/int64_seq_test.go | 2 +- cmd/generate/gen_x_seq_test.go.tmpl | 2 +- gen_float64_seq_test.go | 2 +- gen_int64_seq_test.go | 2 +- gen_int_seq_test.go | 2 +- gen_uint64_seq_test.go | 2 +- 8 files changed, 13 insertions(+), 6 deletions(-) create mode 100644 _draft/v1/go.mod create mode 100644 _draft/v1/go.sum diff --git a/_draft/v1/go.mod b/_draft/v1/go.mod new file mode 100644 index 0000000..a5b165c --- /dev/null +++ b/_draft/v1/go.mod @@ -0,0 +1,5 @@ +module github.com/gochore/timeseq/_draft/timeseq + +go 1.15 + +require github.com/gochore/pt v1.1.2 diff --git a/_draft/v1/go.sum b/_draft/v1/go.sum new file mode 100644 index 0000000..414856e --- /dev/null +++ b/_draft/v1/go.sum @@ -0,0 +1,2 @@ +github.com/gochore/pt v1.1.2 h1:3qS64f1ZrFgp28dperUHfo7U22gL/QeGWsaxQ0veIBE= +github.com/gochore/pt v1.1.2/go.mod h1:8fd2g+qoAO1QIorsgi9vLJCMudJ5m+nDhY8r1nPP6dg= diff --git a/_draft/v2/int64_seq_test.go b/_draft/v2/int64_seq_test.go index 33e9944..4a71100 100644 --- a/_draft/v2/int64_seq_test.go +++ b/_draft/v2/int64_seq_test.go @@ -672,7 +672,7 @@ func TestInt64Seq_Merge(t *testing.T) { }, slices: []Int64s{}, }, - want: data, + want: data[0:7], }, } for _, tt := range tests { diff --git a/cmd/generate/gen_x_seq_test.go.tmpl b/cmd/generate/gen_x_seq_test.go.tmpl index 8ef609e..82e390f 100644 --- a/cmd/generate/gen_x_seq_test.go.tmpl +++ b/cmd/generate/gen_x_seq_test.go.tmpl @@ -672,7 +672,7 @@ func Test{{.Name}}Seq_Merge(t *testing.T) { }, slices: []{{.Name}}s{}, }, - want: data, + want: data[0:7], }, } for _, tt := range tests { diff --git a/gen_float64_seq_test.go b/gen_float64_seq_test.go index 63959e4..ef62aa9 100644 --- a/gen_float64_seq_test.go +++ b/gen_float64_seq_test.go @@ -673,7 +673,7 @@ func TestFloat64Seq_Merge(t *testing.T) { }, slices: []Float64s{}, }, - want: data, + want: data[0:7], }, } for _, tt := range tests { diff --git a/gen_int64_seq_test.go b/gen_int64_seq_test.go index 9f9cce4..fb9bed7 100644 --- a/gen_int64_seq_test.go +++ b/gen_int64_seq_test.go @@ -673,7 +673,7 @@ func TestInt64Seq_Merge(t *testing.T) { }, slices: []Int64s{}, }, - want: data, + want: data[0:7], }, } for _, tt := range tests { diff --git a/gen_int_seq_test.go b/gen_int_seq_test.go index 6fe0546..b330615 100644 --- a/gen_int_seq_test.go +++ b/gen_int_seq_test.go @@ -673,7 +673,7 @@ func TestIntSeq_Merge(t *testing.T) { }, slices: []Ints{}, }, - want: data, + want: data[0:7], }, } for _, tt := range tests { diff --git a/gen_uint64_seq_test.go b/gen_uint64_seq_test.go index 192cb14..744c370 100644 --- a/gen_uint64_seq_test.go +++ b/gen_uint64_seq_test.go @@ -673,7 +673,7 @@ func TestUint64Seq_Merge(t *testing.T) { }, slices: []Uint64s{}, }, - want: data, + want: data[0:7], }, } for _, tt := range tests {