Refactor gauge and registry to accommodate cumulative. (#1089)

* Refactor gauge and registry to accomodate cummulative.
- use common baseMetric type to manage gauge and cumulative.

* fix copyright and renamed couple of func.
diff --git a/metric/common.go b/metric/common.go
new file mode 100644
index 0000000..3dcaf19
--- /dev/null
+++ b/metric/common.go
@@ -0,0 +1,126 @@
+// Copyright 2019, OpenCensus Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package metric
+
+import (
+	"sync"
+	"time"
+
+	"go.opencensus.io/internal/tagencoding"
+	"go.opencensus.io/metric/metricdata"
+)
+
+// baseMetric is common representation for gauge and cumulative metrics.
+//
+// baseMetric maintains a value for each combination of of label values passed to
+// Set, Add, or Inc method.
+//
+// baseMetric should not be used directly, use metric specific type such as
+// Float64Gauge or Int64Gauge.
+type baseMetric struct {
+	vals   sync.Map
+	desc   metricdata.Descriptor
+	start  time.Time
+	keys   []string
+	bmType baseMetricType
+}
+
+type baseMetricType int
+
+const (
+	gaugeInt64 baseMetricType = iota
+	gaugeFloat64
+	derivedGaugeInt64
+	derivedGaugeFloat64
+	cumulativeInt64
+	cumulativeFloat64
+	derivedCumulativeInt64
+	derivedCumulativeFloat64
+)
+
+type baseEntry interface {
+	read(t time.Time) metricdata.Point
+}
+
+// Read returns the current values of the baseMetric as a metric for export.
+func (bm *baseMetric) read() *metricdata.Metric {
+	now := time.Now()
+	m := &metricdata.Metric{
+		Descriptor: bm.desc,
+	}
+	bm.vals.Range(func(k, v interface{}) bool {
+		entry := v.(baseEntry)
+		key := k.(string)
+		labelVals := bm.decodeLabelVals(key)
+		m.TimeSeries = append(m.TimeSeries, &metricdata.TimeSeries{
+			StartTime:   now, // Gauge value is instantaneous.
+			LabelValues: labelVals,
+			Points: []metricdata.Point{
+				entry.read(now),
+			},
+		})
+		return true
+	})
+	return m
+}
+
+func (bm *baseMetric) encodeLabelVals(labelVals []metricdata.LabelValue) string {
+	vb := &tagencoding.Values{}
+	for _, v := range labelVals {
+		b := make([]byte, 1, len(v.Value)+1)
+		if v.Present {
+			b[0] = 1
+			b = append(b, []byte(v.Value)...)
+		}
+		vb.WriteValue(b)
+	}
+	return string(vb.Bytes())
+}
+
+func (bm *baseMetric) decodeLabelVals(s string) []metricdata.LabelValue {
+	vals := make([]metricdata.LabelValue, 0, len(bm.keys))
+	vb := &tagencoding.Values{Buffer: []byte(s)}
+	for range bm.keys {
+		v := vb.ReadValue()
+		if v[0] == 0 {
+			vals = append(vals, metricdata.LabelValue{})
+		} else {
+			vals = append(vals, metricdata.NewLabelValue(string(v[1:])))
+		}
+	}
+	return vals
+}
+
+func (bm *baseMetric) entryForValues(labelVals []metricdata.LabelValue, newEntry func() baseEntry) (interface{}, error) {
+	if len(labelVals) != len(bm.keys) {
+		return nil, errKeyValueMismatch
+	}
+	mapKey := bm.encodeLabelVals(labelVals)
+	if entry, ok := bm.vals.Load(mapKey); ok {
+		return entry, nil
+	}
+	entry, _ := bm.vals.LoadOrStore(mapKey, newEntry())
+	return entry, nil
+}
+
+func (bm *baseMetric) upsertEntry(labelVals []metricdata.LabelValue, newEntry func() baseEntry) error {
+	if len(labelVals) != len(bm.keys) {
+		return errKeyValueMismatch
+	}
+	mapKey := bm.encodeLabelVals(labelVals)
+	bm.vals.Delete(mapKey)
+	bm.vals.Store(mapKey, newEntry())
+	return nil
+}
diff --git a/metric/doc.go b/metric/doc.go
index 485ee8f..4b69f9a 100644
--- a/metric/doc.go
+++ b/metric/doc.go
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// Package metric support for gauge metrics.
+// Package metric support for gauge and cumulative metrics.
 //
 // This is an EXPERIMENTAL package, and may change in arbitrary ways without
 // notice.
diff --git a/metric/error_const.go b/metric/error_const.go
index c2bdf2b..da15894 100644
--- a/metric/error_const.go
+++ b/metric/error_const.go
@@ -17,7 +17,7 @@
 import "errors"
 
 var (
-	errInvalidParam            = errors.New("invalid parameter")
-	errGaugeExistsWithDiffType = errors.New("gauge with same name exists with a different type")
-	errKeyValueMismatch        = errors.New("must supply the same number of label values as keys used to construct this gauge")
+	errInvalidParam             = errors.New("invalid parameter")
+	errMetricExistsWithDiffType = errors.New("metric with same name exists with a different type")
+	errKeyValueMismatch         = errors.New("must supply the same number of label values as keys used to construct this metric")
 )
diff --git a/metric/gauge.go b/metric/gauge.go
index 0f5dcba..d810484 100644
--- a/metric/gauge.go
+++ b/metric/gauge.go
@@ -16,110 +16,18 @@
 
 import (
 	"math"
-	"sync"
 	"sync/atomic"
 	"time"
 
-	"go.opencensus.io/internal/tagencoding"
 	"go.opencensus.io/metric/metricdata"
 )
 
-// gauge represents a quantity that can go up an down, for example queue depth
-// or number of outstanding requests.
-//
-// gauge maintains a value for each combination of of label values passed to
-// the Set or Add methods.
-//
-// gauge should not be used directly, use Float64Gauge or Int64Gauge.
-type gauge struct {
-	vals  sync.Map
-	desc  metricdata.Descriptor
-	start time.Time
-	keys  []string
-	gType gaugeType
-}
-
-type gaugeEntry interface {
-	read(t time.Time) metricdata.Point
-}
-
-// Read returns the current values of the gauge as a metric for export.
-func (g *gauge) read() *metricdata.Metric {
-	now := time.Now()
-	m := &metricdata.Metric{
-		Descriptor: g.desc,
-	}
-	g.vals.Range(func(k, v interface{}) bool {
-		entry := v.(gaugeEntry)
-		key := k.(string)
-		labelVals := g.labelValues(key)
-		m.TimeSeries = append(m.TimeSeries, &metricdata.TimeSeries{
-			StartTime:   now, // Gauge value is instantaneous.
-			LabelValues: labelVals,
-			Points: []metricdata.Point{
-				entry.read(now),
-			},
-		})
-		return true
-	})
-	return m
-}
-
-func (g *gauge) mapKey(labelVals []metricdata.LabelValue) string {
-	vb := &tagencoding.Values{}
-	for _, v := range labelVals {
-		b := make([]byte, 1, len(v.Value)+1)
-		if v.Present {
-			b[0] = 1
-			b = append(b, []byte(v.Value)...)
-		}
-		vb.WriteValue(b)
-	}
-	return string(vb.Bytes())
-}
-
-func (g *gauge) labelValues(s string) []metricdata.LabelValue {
-	vals := make([]metricdata.LabelValue, 0, len(g.keys))
-	vb := &tagencoding.Values{Buffer: []byte(s)}
-	for range g.keys {
-		v := vb.ReadValue()
-		if v[0] == 0 {
-			vals = append(vals, metricdata.LabelValue{})
-		} else {
-			vals = append(vals, metricdata.NewLabelValue(string(v[1:])))
-		}
-	}
-	return vals
-}
-
-func (g *gauge) entryForValues(labelVals []metricdata.LabelValue, newEntry func() gaugeEntry) (interface{}, error) {
-	if len(labelVals) != len(g.keys) {
-		return nil, errKeyValueMismatch
-	}
-	mapKey := g.mapKey(labelVals)
-	if entry, ok := g.vals.Load(mapKey); ok {
-		return entry, nil
-	}
-	entry, _ := g.vals.LoadOrStore(mapKey, newEntry())
-	return entry, nil
-}
-
-func (g *gauge) upsertEntry(labelVals []metricdata.LabelValue, newEntry func() gaugeEntry) error {
-	if len(labelVals) != len(g.keys) {
-		return errKeyValueMismatch
-	}
-	mapKey := g.mapKey(labelVals)
-	g.vals.Delete(mapKey)
-	g.vals.Store(mapKey, newEntry())
-	return nil
-}
-
 // Float64Gauge represents a float64 value that can go up and down.
 //
 // Float64Gauge maintains a float64 value for each combination of of label values
 // passed to the Set or Add methods.
 type Float64Gauge struct {
-	g gauge
+	bm baseMetric
 }
 
 // Float64Entry represents a single value of the gauge corresponding to a set
@@ -142,7 +50,7 @@
 // The number of label values supplied must be exactly the same as the number
 // of keys supplied when this gauge was created.
 func (g *Float64Gauge) GetEntry(labelVals ...metricdata.LabelValue) (*Float64Entry, error) {
-	entry, err := g.g.entryForValues(labelVals, func() gaugeEntry {
+	entry, err := g.bm.entryForValues(labelVals, func() baseEntry {
 		return &Float64Entry{}
 	})
 	if err != nil {
@@ -171,7 +79,7 @@
 // Int64Gauge maintains an int64 value for each combination of label values passed to the
 // Set or Add methods.
 type Int64Gauge struct {
-	g gauge
+	bm baseMetric
 }
 
 // Int64GaugeEntry represents a single value of the gauge corresponding to a set
@@ -194,7 +102,7 @@
 // The number of label values supplied must be exactly the same as the number
 // of keys supplied when this gauge was created.
 func (g *Int64Gauge) GetEntry(labelVals ...metricdata.LabelValue) (*Int64GaugeEntry, error) {
-	entry, err := g.g.entryForValues(labelVals, func() gaugeEntry {
+	entry, err := g.bm.entryForValues(labelVals, func() baseEntry {
 		return &Int64GaugeEntry{}
 	})
 	if err != nil {
@@ -219,7 +127,7 @@
 // These objects implement Int64DerivedGaugeInterface to read instantaneous value
 // representing the object.
 type Int64DerivedGauge struct {
-	g gauge
+	bm baseMetric
 }
 
 type int64DerivedGaugeEntry struct {
@@ -241,7 +149,7 @@
 	if fn == nil {
 		return errInvalidParam
 	}
-	return g.g.upsertEntry(labelVals, func() gaugeEntry {
+	return g.bm.upsertEntry(labelVals, func() baseEntry {
 		return &int64DerivedGaugeEntry{fn}
 	})
 }
@@ -252,7 +160,7 @@
 // These objects implement Float64DerivedGaugeInterface to read instantaneous value
 // representing the object.
 type Float64DerivedGauge struct {
-	g gauge
+	bm baseMetric
 }
 
 type float64DerivedGaugeEntry struct {
@@ -274,7 +182,7 @@
 	if fn == nil {
 		return errInvalidParam
 	}
-	return g.g.upsertEntry(labelVals, func() gaugeEntry {
+	return g.bm.upsertEntry(labelVals, func() baseEntry {
 		return &float64DerivedGaugeEntry{fn}
 	})
 }
diff --git a/metric/gauge_test.go b/metric/gauge_test.go
index 8ed358b..b8c41d1 100644
--- a/metric/gauge_test.go
+++ b/metric/gauge_test.go
@@ -86,13 +86,13 @@
 	r := NewRegistry()
 
 	gf, _ := r.AddFloat64Gauge("float64_gauge")
-	compareType(gf.g.desc.Type, metricdata.TypeGaugeFloat64, t)
+	compareType(gf.bm.desc.Type, metricdata.TypeGaugeFloat64, t)
 	gi, _ := r.AddInt64Gauge("int64_gauge")
-	compareType(gi.g.desc.Type, metricdata.TypeGaugeInt64, t)
+	compareType(gi.bm.desc.Type, metricdata.TypeGaugeInt64, t)
 	dgf, _ := r.AddFloat64DerivedGauge("derived_float64_gauge")
-	compareType(dgf.g.desc.Type, metricdata.TypeGaugeFloat64, t)
+	compareType(dgf.bm.desc.Type, metricdata.TypeGaugeFloat64, t)
 	dgi, _ := r.AddInt64DerivedGauge("derived_int64_gauge")
-	compareType(dgi.g.desc.Type, metricdata.TypeGaugeInt64, t)
+	compareType(dgi.bm.desc.Type, metricdata.TypeGaugeInt64, t)
 }
 
 func compareType(got, want metricdata.Type, t *testing.T) {
@@ -110,7 +110,7 @@
 		Description: "test",
 		Type:        metricdata.TypeGaugeFloat64,
 	}
-	got := gf.g.desc
+	got := gf.bm.desc
 	if !cmp.Equal(got, want) {
 		t.Errorf("metric option description: got %v, want %v\n", got, want)
 	}
@@ -125,7 +125,7 @@
 		Unit: metricdata.UnitMilliseconds,
 		Type: metricdata.TypeGaugeFloat64,
 	}
-	got := gf.g.desc
+	got := gf.bm.desc
 	if !cmp.Equal(got, want) {
 		t.Errorf("metric descriptor: got %v, want %v\n", got, want)
 	}
@@ -140,7 +140,7 @@
 		LabelKeys: []string{"k1", "k3"},
 		Type:      metricdata.TypeGaugeFloat64,
 	}
-	got := gf.g.desc
+	got := gf.bm.desc
 	if !cmp.Equal(got, want) {
 		t.Errorf("metric descriptor: got %v, want %v\n", got, want)
 	}
@@ -154,7 +154,7 @@
 		Name: name,
 		Type: metricdata.TypeGaugeFloat64,
 	}
-	got := gf.g.desc
+	got := gf.bm.desc
 	if !cmp.Equal(got, want) {
 		t.Errorf("metric descriptor: got %v, want %v\n", got, want)
 	}
@@ -227,15 +227,15 @@
 	r.AddInt64Gauge("g")
 	_, gotErr := r.AddFloat64Gauge("g")
 	if gotErr == nil {
-		t.Errorf("got: nil, want error: %v", errGaugeExistsWithDiffType)
+		t.Errorf("got: nil, want error: %v", errMetricExistsWithDiffType)
 	}
 	_, gotErr = r.AddInt64DerivedGauge("g")
 	if gotErr == nil {
-		t.Errorf("got: nil, want error: %v", errGaugeExistsWithDiffType)
+		t.Errorf("got: nil, want error: %v", errMetricExistsWithDiffType)
 	}
 	_, gotErr = r.AddFloat64DerivedGauge("g")
 	if gotErr == nil {
-		t.Errorf("got: nil, want error: %v", errGaugeExistsWithDiffType)
+		t.Errorf("got: nil, want error: %v", errMetricExistsWithDiffType)
 	}
 }
 
@@ -262,11 +262,11 @@
 	}
 	for i, tc := range cases {
 		t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
-			g := &gauge{
+			g := &baseMetric{
 				keys: make([]string, len(tc)),
 			}
-			mk := g.mapKey(tc)
-			vals := g.labelValues(mk)
+			mk := g.encodeLabelVals(tc)
+			vals := g.decodeLabelVals(mk)
 			if diff := cmp.Diff(vals, tc); diff != "" {
 				t.Errorf("values differ after serialization -got +want: %s", diff)
 			}
diff --git a/metric/registry.go b/metric/registry.go
index 80df542..6b1ff32 100644
--- a/metric/registry.go
+++ b/metric/registry.go
@@ -21,22 +21,13 @@
 	"go.opencensus.io/metric/metricdata"
 )
 
-// Registry creates and manages a set of gauges.
-// External synchronization is required if you want to add gauges to the same
+// Registry creates and manages a set of gauges and cumulative.
+// External synchronization is required if you want to add gauges and cumulative to the same
 // registry from multiple goroutines.
 type Registry struct {
-	gauges sync.Map
+	baseMetrics sync.Map
 }
 
-type gaugeType int
-
-const (
-	gaugeInt64 gaugeType = iota
-	gaugeFloat64
-	derivedGaugeInt64
-	derivedGaugeFloat64
-)
-
 //TODO: [rghetia] add constant labels.
 type metricOptions struct {
 	unit      metricdata.Unit
@@ -76,11 +67,11 @@
 // AddFloat64Gauge creates and adds a new float64-valued gauge to this registry.
 func (r *Registry) AddFloat64Gauge(name string, mos ...Options) (*Float64Gauge, error) {
 	f := &Float64Gauge{
-		g: gauge{
-			gType: gaugeFloat64,
+		bm: baseMetric{
+			bmType: gaugeFloat64,
 		},
 	}
-	_, err := r.initGauge(&f.g, name, mos...)
+	_, err := r.initBaseMetric(&f.bm, name, mos...)
 	if err != nil {
 		return nil, err
 	}
@@ -90,11 +81,11 @@
 // AddInt64Gauge creates and adds a new int64-valued gauge to this registry.
 func (r *Registry) AddInt64Gauge(name string, mos ...Options) (*Int64Gauge, error) {
 	i := &Int64Gauge{
-		g: gauge{
-			gType: gaugeInt64,
+		bm: baseMetric{
+			bmType: gaugeInt64,
 		},
 	}
-	_, err := r.initGauge(&i.g, name, mos...)
+	_, err := r.initBaseMetric(&i.bm, name, mos...)
 	if err != nil {
 		return nil, err
 	}
@@ -106,11 +97,11 @@
 // provides its value by implementing func() int64.
 func (r *Registry) AddInt64DerivedGauge(name string, mos ...Options) (*Int64DerivedGauge, error) {
 	i := &Int64DerivedGauge{
-		g: gauge{
-			gType: derivedGaugeInt64,
+		bm: baseMetric{
+			bmType: derivedGaugeInt64,
 		},
 	}
-	_, err := r.initGauge(&i.g, name, mos...)
+	_, err := r.initBaseMetric(&i.bm, name, mos...)
 	if err != nil {
 		return nil, err
 	}
@@ -122,19 +113,19 @@
 // provides its value by implementing func() float64.
 func (r *Registry) AddFloat64DerivedGauge(name string, mos ...Options) (*Float64DerivedGauge, error) {
 	f := &Float64DerivedGauge{
-		g: gauge{
-			gType: derivedGaugeFloat64,
+		bm: baseMetric{
+			bmType: derivedGaugeFloat64,
 		},
 	}
-	_, err := r.initGauge(&f.g, name, mos...)
+	_, err := r.initBaseMetric(&f.bm, name, mos...)
 	if err != nil {
 		return nil, err
 	}
 	return f, nil
 }
 
-func gTypeToMetricType(g *gauge) metricdata.Type {
-	switch g.gType {
+func bmTypeToMetricType(bm *baseMetric) metricdata.Type {
+	switch bm.bmType {
 	case derivedGaugeFloat64:
 		return metricdata.TypeGaugeFloat64
 	case derivedGaugeInt64:
@@ -144,7 +135,7 @@
 	case gaugeInt64:
 		return metricdata.TypeGaugeInt64
 	default:
-		panic("unsupported gauge type")
+		panic("unsupported metric type")
 	}
 }
 
@@ -156,34 +147,34 @@
 	return o
 }
 
-func (r *Registry) initGauge(g *gauge, name string, mos ...Options) (*gauge, error) {
-	val, ok := r.gauges.Load(name)
+func (r *Registry) initBaseMetric(bm *baseMetric, name string, mos ...Options) (*baseMetric, error) {
+	val, ok := r.baseMetrics.Load(name)
 	if ok {
-		existing := val.(*gauge)
-		if existing.gType != g.gType {
-			return nil, errGaugeExistsWithDiffType
+		existing := val.(*baseMetric)
+		if existing.bmType != bm.bmType {
+			return nil, errMetricExistsWithDiffType
 		}
 	}
-	g.start = time.Now()
+	bm.start = time.Now()
 	o := createMetricOption(mos...)
-	g.keys = o.labelkeys
-	g.desc = metricdata.Descriptor{
+	bm.keys = o.labelkeys
+	bm.desc = metricdata.Descriptor{
 		Name:        name,
 		Description: o.desc,
 		Unit:        o.unit,
 		LabelKeys:   o.labelkeys,
-		Type:        gTypeToMetricType(g),
+		Type:        bmTypeToMetricType(bm),
 	}
-	r.gauges.Store(name, g)
-	return g, nil
+	r.baseMetrics.Store(name, bm)
+	return bm, nil
 }
 
 // Read reads all gauges in this registry and returns their values as metrics.
 func (r *Registry) Read() []*metricdata.Metric {
 	ms := []*metricdata.Metric{}
-	r.gauges.Range(func(k, v interface{}) bool {
-		g := v.(*gauge)
-		ms = append(ms, g.read())
+	r.baseMetrics.Range(func(k, v interface{}) bool {
+		bm := v.(*baseMetric)
+		ms = append(ms, bm.read())
 		return true
 	})
 	return ms