Source file
src/unique/clone.go
1
2
3
4
5 package unique
6
7 import (
8 "internal/abi"
9 "internal/stringslite"
10 "unsafe"
11 )
12
13
14
15
16
17
18
19
20
21 func clone[T comparable](value T, seq *cloneSeq) T {
22 for _, offset := range seq.stringOffsets {
23 ps := (*string)(unsafe.Pointer(uintptr(unsafe.Pointer(&value)) + offset))
24 *ps = stringslite.Clone(*ps)
25 }
26 return value
27 }
28
29
30 var singleStringClone = cloneSeq{stringOffsets: []uintptr{0}}
31
32
33 type cloneSeq struct {
34 stringOffsets []uintptr
35 }
36
37
38 func makeCloneSeq(typ *abi.Type) cloneSeq {
39 if typ == nil {
40 return cloneSeq{}
41 }
42 if typ.Kind() == abi.String {
43 return singleStringClone
44 }
45 var seq cloneSeq
46 switch typ.Kind() {
47 case abi.Struct:
48 buildStructCloneSeq(typ, &seq, 0)
49 case abi.Array:
50 buildArrayCloneSeq(typ, &seq, 0)
51 }
52 return seq
53 }
54
55
56 func buildStructCloneSeq(typ *abi.Type, seq *cloneSeq, baseOffset uintptr) {
57 styp := typ.StructType()
58 for i := range styp.Fields {
59 f := &styp.Fields[i]
60 switch f.Typ.Kind() {
61 case abi.String:
62 seq.stringOffsets = append(seq.stringOffsets, baseOffset+f.Offset)
63 case abi.Struct:
64 buildStructCloneSeq(f.Typ, seq, baseOffset+f.Offset)
65 case abi.Array:
66 buildArrayCloneSeq(f.Typ, seq, baseOffset+f.Offset)
67 }
68 }
69 }
70
71
72 func buildArrayCloneSeq(typ *abi.Type, seq *cloneSeq, baseOffset uintptr) {
73 atyp := typ.ArrayType()
74 etyp := atyp.Elem
75 offset := baseOffset
76 for range atyp.Len {
77 switch etyp.Kind() {
78 case abi.String:
79 seq.stringOffsets = append(seq.stringOffsets, offset)
80 case abi.Struct:
81 buildStructCloneSeq(etyp, seq, offset)
82 case abi.Array:
83 buildArrayCloneSeq(etyp, seq, offset)
84 }
85 offset += etyp.Size()
86 align := uintptr(etyp.FieldAlign())
87 offset = (offset + align - 1) &^ (align - 1)
88 }
89 }
90
View as plain text