feat: add container group (#1452)

* add container group
pull/1456/head
Tony Chen 3 years ago committed by GitHub
parent 378d1ee3c7
commit 009cf68312
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 42
      container/group/example_test.go
  2. 64
      container/group/group.go
  3. 65
      container/group/group_test.go

@ -0,0 +1,42 @@
package group
import "fmt"
type Counter struct {
Value int
}
func (c *Counter) Incr() {
c.Value++
}
func ExampleGroup_Get() {
group := NewGroup(func() interface{} {
fmt.Println("Only Once")
return &Counter{}
})
// Create a new Counter
group.Get("pass").(*Counter).Incr()
// Get the created Counter again.
group.Get("pass").(*Counter).Incr()
// Output:
// Only Once
}
func ExampleGroup_Reset() {
group := NewGroup(func() interface{} {
return &Counter{}
})
// Reset the new function and clear all created objects.
group.Reset(func() interface{} {
fmt.Println("reset")
return &Counter{}
})
// Create a new Counter
group.Get("pass").(*Counter).Incr()
// Output:reset
}

@ -0,0 +1,64 @@
// Package group provides a sample lazy load container.
// The group only creating a new object not until the object is needed by user.
// And it will cache all the objects to reduce the creation of object.
package group
import "sync"
// Group is a lazy load container.
type Group struct {
new func() interface{}
vals map[string]interface{}
sync.RWMutex
}
// NewGroup news a group container.
func NewGroup(new func() interface{}) *Group {
if new == nil {
panic("container.group: can't assign a nil to the new function")
}
return &Group{
new: new,
vals: make(map[string]interface{}),
}
}
// Get gets the object by the given key.
func (g *Group) Get(key string) interface{} {
g.RLock()
v, ok := g.vals[key]
if ok {
g.RUnlock()
return v
}
g.RUnlock()
// slowpath for group don`t have specified key value
g.Lock()
defer g.Unlock()
v, ok = g.vals[key]
if ok {
return v
}
v = g.new()
g.vals[key] = v
return v
}
// Reset resets the new function and deletes all existing objects.
func (g *Group) Reset(new func() interface{}) {
if new == nil {
panic("container.group: can't assign a nil to the new function")
}
g.Lock()
g.new = new
g.Unlock()
g.Clear()
}
// Clear deletes all objects.
func (g *Group) Clear() {
g.Lock()
g.vals = make(map[string]interface{})
g.Unlock()
}

@ -0,0 +1,65 @@
package group
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestGroupGet(t *testing.T) {
count := 0
g := NewGroup(func() interface{} {
count++
return count
})
v := g.Get("key_0")
assert.Equal(t, 1, v.(int))
v = g.Get("key_1")
assert.Equal(t, 2, v.(int))
v = g.Get("key_0")
assert.Equal(t, 1, v.(int))
assert.Equal(t, 2, count)
}
func TestGroupReset(t *testing.T) {
g := NewGroup(func() interface{} {
return 1
})
g.Get("key")
call := false
g.Reset(func() interface{} {
call = true
return 1
})
length := 0
for range g.vals {
length++
}
assert.Equal(t, 0, length)
g.Get("key")
assert.Equal(t, true, call)
}
func TestGroupClear(t *testing.T) {
g := NewGroup(func() interface{} {
return 1
})
g.Get("key")
length := 0
for range g.vals {
length++
}
assert.Equal(t, 1, length)
g.Clear()
length = 0
for range g.vals {
length++
}
assert.Equal(t, 0, length)
}
Loading…
Cancel
Save