diff --git a/cache_test.go b/cache_test.go index c1a4d80..904a2df 100644 --- a/cache_test.go +++ b/cache_test.go @@ -198,21 +198,22 @@ func TestFlush(t *testing.T) { } func TestOnEvicted(t *testing.T) { - tc := New_tpl(Attr_tpl{ + works := false + var tc *Cache_tpl + tc = New_tpl(Attr_tpl{ DefaultExpiration: DefaultExpiration, DefaultCleanupInterval: 0, + OnEvicted: func(k string, v ValueType_tpl) { + if k == "foo" && v == 3 { + works = true + } + tc.Set("bar", 4, DefaultExpiration) + }, }) tc.Set("foo", 3, DefaultExpiration) - if tc.onEvicted != nil { - t.Fatal("tc.onEvicted is not nil") + if tc.onEvicted == nil { + t.Fatal("tc.onEvicted is nil") } - works := false - tc.OnEvicted(func(k string, v ValueType_tpl) { - if k == "foo" && v == 3 { - works = true - } - tc.Set("bar", 4, DefaultExpiration) - }) tc.Delete("foo") x, _ := tc.Get("bar") if !works { diff --git a/cachemap/cache.tmpl b/cachemap/cache.tmpl index 26dc373..351c3c0 100644 --- a/cachemap/cache.tmpl +++ b/cachemap/cache.tmpl @@ -182,8 +182,7 @@ func (c *cache) delete(k string) ({{.ValueType}}, bool) { delete(c.items, k) return v.Object, true } - //TODO: zeroValue - return 0, false + return {{ .ZeroValue }}, false } func (c *cache) deleteFast(k string) { diff --git a/cachemap/main.go b/cachemap/main.go index 3c2dd4e..e7f480d 100644 --- a/cachemap/main.go +++ b/cachemap/main.go @@ -3,6 +3,7 @@ package main import ( "flag" "fmt" + "go/ast" "go/parser" "go/token" "os" @@ -25,6 +26,61 @@ func packageDir() string { return path.Dir(filename) } +// find value of ident 'grammar' in GenDecl. +func findInGenDecl(genDecl *ast.GenDecl, grammarName string) string { + for _, spec := range genDecl.Specs { + valueSpec, ok := spec.(*ast.TypeSpec) + if ok { + // type ident + ident, ok := valueSpec.Type.(*ast.Ident) + if ok { + return ident.Name + } + } + } + return "" +} + +func findInDecl(decl ast.Decl, grammarName string) string { + genDecl, ok := decl.(*ast.GenDecl) + if ok { + g := findInGenDecl(genDecl, grammarName) + if g != "" { + return g + } + } + return "" +} + +// zeroValue returns literal zero value. +func zeroValue(s string) string { + // TODO: support func type. + switch s { + case "string": + return "\"\"" + case "int", "uint", "int64", "uint64", "uint32", "int32", "int16", + "uint16", "int8", "uint8", "byte", "rune", "float64", "float32", + "complex64", "complex32", "uintptr": + return "0" + case "slice": + return "nil" + default: + if s[0] == '*' { // Pointer + return "nil" + } + return s + "{}" + } +} + +// TODO: support more builtin types +func builtin(s string) bool { + switch s { + case "string": + return true + } + return false +} + func main() { keyType := flag.String("k", "", "key type") valueType := flag.String("v", "", "value type") @@ -40,10 +96,23 @@ func main() { if err != nil { fatal(err) } - var packageName string - for name := range pkgs { + packageName := "main" + typeName := "" + for name, pkg := range pkgs { packageName = name + for _, f := range pkg.Files { + for _, decl := range f.Decls { + typeName = findInDecl(decl, *valueType) + } + } } + if typeName == "" && !builtin(*valueType) { + fatal(fmt.Errorf("found no definition of %s in files\n", *valueType)) + } + if typeName == "" { + typeName = *valueType + } + zeroTypeValue := zeroValue(typeName) f, err := os.OpenFile(fmt.Sprintf("%s2%s_cachemap.go", *keyType, *valueType), os.O_TRUNC|os.O_WRONLY|os.O_CREATE, 0644) if err != nil { fatal(err) @@ -59,6 +128,7 @@ func main() { "ValueType": *valueType, "PackageName": packageName, "Cache": fmt.Sprintf("String2%sCache", *valueType), + "ZeroValue": zeroTypeValue, }, ) if err != nil {