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  }