]> Sergey Matveev's repositories - btrtrc.git/commitdiff
bencode: Cache struct fields
authorMatt Joiner <anacrolix@gmail.com>
Mon, 23 Jul 2018 00:50:58 +0000 (10:50 +1000)
committerMatt Joiner <anacrolix@gmail.com>
Mon, 23 Jul 2018 00:50:58 +0000 (10:50 +1000)
bencode/decode.go

index ab77ab49a229c0eb41e0f8a58543996ac8070863..4e9e197ae42b7a00f4e096f5c515190faf83f8e0 100644 (file)
@@ -9,7 +9,7 @@ import (
        "reflect"
        "runtime"
        "strconv"
-       "strings"
+       "sync"
        "unsafe"
 )
 
@@ -243,9 +243,14 @@ func getDictField(dict reflect.Value, key string) dictField {
        }
 }
 
-func getStructFieldForKey(struct_ reflect.Type, key string) (f reflect.StructField, ok bool) {
+var (
+       structFieldsMu sync.Mutex
+       structFields   = map[reflect.Type]map[string]reflect.StructField{}
+)
+
+func parseStructFields(struct_ reflect.Type, each func(string, reflect.StructField)) {
        for i, n := 0, struct_.NumField(); i < n; i++ {
-               f = struct_.Field(i)
+               f := struct_.Field(i)
                tag := f.Tag.Get("bencode")
                if tag == "-" {
                        continue
@@ -253,22 +258,29 @@ func getStructFieldForKey(struct_ reflect.Type, key string) (f reflect.StructFie
                if f.Anonymous {
                        continue
                }
-
-               if parseTag(tag).Key() == key {
-                       ok = true
-                       break
+               if key := parseTag(tag).Key(); key != "" {
+                       each(key, f)
+               } else {
+                       each(f.Name, f)
                }
+       }
+}
 
-               if f.Name == key {
-                       ok = true
-                       break
-               }
+func saveStructFields(struct_ reflect.Type) {
+       m := make(map[string]reflect.StructField)
+       parseStructFields(struct_, func(key string, sf reflect.StructField) {
+               m[key] = sf
+       })
+       structFields[struct_] = m
+}
 
-               if strings.EqualFold(f.Name, key) {
-                       ok = true
-                       break
-               }
+func getStructFieldForKey(struct_ reflect.Type, key string) (f reflect.StructField, ok bool) {
+       structFieldsMu.Lock()
+       if _, ok := structFields[struct_]; !ok {
+               saveStructFields(struct_)
        }
+       f, ok = structFields[struct_][key]
+       structFieldsMu.Unlock()
        return
 }
 
@@ -488,7 +500,7 @@ func (d *Decoder) parseValue(v reflect.Value) (bool, error) {
                if b >= '0' && b <= '9' {
                        // It's a string.
                        d.buf.Reset()
-                       // Write the  first digit of the length to the buffer.
+                       // Write the first digit of the length to the buffer.
                        d.buf.WriteByte(b)
                        return true, d.parseString(v)
                }