counter.go 1.1 KB
package counter

import (
	"sync"
)

// Counter is a counter interface.
type Counter interface {
	Add(int64)
	Reset()
	Value() int64
}

// Group is a counter group.
type Group struct {
	mu   sync.RWMutex
	vecs map[string]Counter

	// New optionally specifies a function to generate a counter.
	// It may not be changed concurrently with calls to other functions.
	New func() Counter
}

// Add add a counter by a specified key, if counter not exists then make a new one and return new value.
func (g *Group) Add(key string, value int64) {
	g.mu.RLock()
	vec, ok := g.vecs[key]
	g.mu.RUnlock()
	if !ok {
		vec = g.New()
		g.mu.Lock()
		if g.vecs == nil {
			g.vecs = make(map[string]Counter)
		}
		if _, ok = g.vecs[key]; !ok {
			g.vecs[key] = vec
		}
		g.mu.Unlock()
	}
	vec.Add(value)
}

// Value get a counter value by key.
func (g *Group) Value(key string) int64 {
	g.mu.RLock()
	vec, ok := g.vecs[key]
	g.mu.RUnlock()
	if ok {
		return vec.Value()
	}
	return 0
}

// Reset reset a counter by key.
func (g *Group) Reset(key string) {
	g.mu.RLock()
	vec, ok := g.vecs[key]
	g.mu.RUnlock()
	if ok {
		vec.Reset()
	}
}