diff --git a/stats.go b/stats.go index ae598c2..4ced007 100644 --- a/stats.go +++ b/stats.go @@ -66,6 +66,37 @@ func (t *Sampdo) Append(point ...float64) error { return nil } +// Count returns the number of points currently stored in the Sampdo instance. +func (t *Sampdo) Count() int { + if t == nil { + return 0 + } + return len(t.points) +} + +// CopyTo copies all points from the current Sampdo instance to the provided destination slice. +func (t *Sampdo) CopyTo(dst *[]float64) error { + if t == nil { + return fmt.Errorf("source is nil") + } + if dst == nil || *dst == nil { + return fmt.Errorf("destination slice is nil") + } + *dst = append(*dst, t.points...) + return nil +} + +// AppendTo appends all points from the current Sampdo instance to the destination Sampdo instance. +func (t *Sampdo) AppendTo(dst *Sampdo) error { + if t == nil { + return fmt.Errorf("source is nil") + } + if dst == nil { + return fmt.Errorf("destination is nil") + } + return dst.Append(t.points...) +} + func (t *Sampdo) Sorted() (*Sorted, error) { if t == nil { return nil, fmt.Errorf("sorted is nil") diff --git a/stats_test.go b/stats_test.go index bd9022e..be4eec7 100644 --- a/stats_test.go +++ b/stats_test.go @@ -219,3 +219,94 @@ func TestSampdoFrozenAppend(t *testing.T) { require.NoError(t, err) require.Equal(t, []float64{0.5, 1.0, 2.0, 3.0}, sorted2.points) } + +func TestSampdoCount(t *testing.T) { + t.Run("empty", func(t *testing.T) { + s := New() + require.Equal(t, 0, s.Count()) + }) + + t.Run("after append", func(t *testing.T) { + s := New() + require.NoError(t, s.Append(1.0, 2.0, 3.0)) + require.Equal(t, 3, s.Count()) + }) + + t.Run("after sorted", func(t *testing.T) { + s := New() + require.NoError(t, s.Append(1.0, 2.0, 3.0)) + sorted, err := s.Sorted() + require.NoError(t, err) + require.Equal(t, 3, sorted.Count()) + }) +} + +func TestSampdoCopyTo(t *testing.T) { + t.Run("copies points", func(t *testing.T) { + s := New() + require.NoError(t, s.Append(1.0, 2.0, 3.0)) + dst := make([]float64, 0, 3) + err := s.CopyTo(&dst) + require.NoError(t, err) + require.Equal(t, []float64{1.0, 2.0, 3.0}, dst) + }) + + t.Run("appends to existing slice", func(t *testing.T) { + s := New() + require.NoError(t, s.Append(4.0, 5.0)) + dst := []float64{1.0, 2.0, 3.0} + err := s.CopyTo(&dst) + require.NoError(t, err) + require.Equal(t, []float64{1.0, 2.0, 3.0, 4.0, 5.0}, dst) + }) + + t.Run("nil destination", func(t *testing.T) { + s := New() + require.NoError(t, s.Append(1.0)) + err := s.CopyTo(nil) + require.Error(t, err) + }) + + t.Run("nil underlying slice", func(t *testing.T) { + s := New() + require.NoError(t, s.Append(1.0)) + var dst []float64 + err := s.CopyTo(&dst) + require.Error(t, err) + }) +} + +func TestSampdoAppendTo(t *testing.T) { + t.Run("appends points", func(t *testing.T) { + s := New() + require.NoError(t, s.Append(1.0, 2.0, 3.0)) + dst := New() + require.NoError(t, s.AppendTo(dst)) + require.Equal(t, []float64{1.0, 2.0, 3.0}, dst.points) + }) + + t.Run("appends to existing points", func(t *testing.T) { + s := New() + require.NoError(t, s.Append(4.0, 5.0)) + dst := New() + require.NoError(t, dst.Append(1.0, 2.0, 3.0)) + require.NoError(t, s.AppendTo(dst)) + require.Equal(t, []float64{1.0, 2.0, 3.0, 4.0, 5.0}, dst.points) + require.Equal(t, 15.0, dst.sum) + }) + + t.Run("nil destination", func(t *testing.T) { + s := New() + require.NoError(t, s.Append(1.0)) + err := s.AppendTo(nil) + require.Error(t, err) + }) + + t.Run("preserves sum", func(t *testing.T) { + s := New() + require.NoError(t, s.Append(1.0, 2.0, 3.0)) + dst := New() + require.NoError(t, s.AppendTo(dst)) + require.Equal(t, 6.0, dst.sum) + }) +}