github.com/RomiChan/protobuf@v0.1.1-0.20230204044148-2ed269a2e54d/proto/slice.go (about) 1 package proto 2 3 import ( 4 "reflect" 5 "sync" 6 "unsafe" 7 8 . "github.com/RomiChan/protobuf/internal/runtime_reflect" 9 ) 10 11 var sliceMap sync.Map // map[*codec]*codec for slice 12 13 func sliceCodecOf(t reflect.Type, c *codec, w *walker) *codec { 14 if loaded, ok := sliceMap.Load(c); ok { 15 return loaded.(*codec) 16 } 17 if w.codecs[t] != nil { 18 return w.codecs[t] 19 } 20 s := new(codec) 21 w.codecs[t] = s 22 23 s.size = sliceSizeFuncOf(t, c) 24 s.encode = sliceEncodeFuncOf(t, c) 25 s.decode = sliceDecodeFuncOf(t, c) 26 27 actualCodec, _ := sliceMap.LoadOrStore(c, s) 28 return actualCodec.(*codec) 29 } 30 31 func sliceSizeFuncOf(t reflect.Type, c *codec) sizeFunc { 32 elemSize := alignedSize(t.Elem()) 33 return func(p unsafe.Pointer, sf *structField) int { 34 n := 0 35 if v := (*Slice)(p); v != nil { 36 for i := 0; i < v.Len(); i++ { 37 elem := v.Index(i, elemSize) 38 n += c.size(elem, sf) 39 } 40 } 41 return n 42 } 43 } 44 45 func sliceEncodeFuncOf(t reflect.Type, c *codec) encodeFunc { 46 elemSize := alignedSize(t.Elem()) 47 return func(b []byte, p unsafe.Pointer, sf *structField) []byte { 48 if s := (*Slice)(p); s != nil { 49 for i := 0; i < s.Len(); i++ { 50 elem := s.Index(i, elemSize) 51 b = c.encode(b, elem, sf) 52 } 53 } 54 return b 55 } 56 } 57 58 func sliceDecodeFuncOf(t reflect.Type, c *codec) decodeFunc { 59 elemType := t.Elem() 60 elemSize := alignedSize(elemType) 61 return func(b []byte, p unsafe.Pointer) (int, error) { 62 s := (*Slice)(p) 63 i := s.Len() 64 65 if i == s.Cap() { 66 *s = growSlice(elemType, s) 67 } 68 69 n, err := c.decode(b, s.Index(i, elemSize)) 70 if err == nil { 71 s.SetLen(i + 1) 72 } 73 return n, err 74 } 75 } 76 77 func alignedSize(t reflect.Type) uintptr { 78 a := t.Align() 79 s := t.Size() 80 return align(uintptr(a), s) 81 } 82 83 func align(align, size uintptr) uintptr { 84 if align != 0 && (size%align) != 0 { 85 size = ((size / align) + 1) * align 86 } 87 return size 88 } 89 90 func growSlice(t reflect.Type, s *Slice) Slice { 91 cap := 2 * s.Cap() 92 if cap == 0 { 93 cap = 10 94 } 95 p := pointer(t) 96 d := MakeSlice(p, s.Len(), cap) 97 CopySlice(p, d, *s) 98 return d 99 }