-
Notifications
You must be signed in to change notification settings - Fork 12
/
pcopy.go
587 lines (494 loc) · 14.1 KB
/
pcopy.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
// Copyright [2020-2023] [guonaihong]
package pcopy
import (
"errors"
"fmt"
"reflect"
"time"
"unsafe"
)
// 不支持的类型
var ErrUnsupportedType = errors.New("Unsupported type")
// 不支持nil类型
var ErrUnsupportedNil = errors.New("Unsupported nil type")
// dst 和 src必须是指针类型
var ErrNotPointer = errors.New("dst and src must be pointer")
// 不能获取指针地址
var ErrNotAddr = errors.New("dst or src type can not get address")
var zeroUintptr unsafe.Pointer
// pcopy结构体
type pcopy struct {
options
}
func Copy[T any, U any](dst *T, src *U, opts ...Option) error {
if dst == nil || src == nil {
return ErrUnsupportedNil
}
var opt options
for _, o := range opts {
o(&opt)
}
var dstI interface{} = dst
var srcI interface{} = src
return pcopyInner(dstI, srcI, opt)
}
func pcopyInner(dst, src interface{}, opt options) error {
if dst == nil || src == nil {
return ErrUnsupportedNil
}
dstValue := reflect.ValueOf(dst)
srcValue := reflect.ValueOf(src)
// 开启预热逻辑
dstAddr := zeroUintptr
srcAddr := zeroUintptr
// 预热逻辑和预热cache逻辑都要走
var of offsetAndFunc
var all *allFieldFunc
if opt.preheat || opt.usePreheat {
if dstValue.Kind() != reflect.Ptr || srcValue.Kind() != reflect.Ptr {
return ErrNotPointer
}
if !dstValue.Elem().CanAddr() {
return fmt.Errorf("dst %w", ErrNotAddr)
}
if !srcValue.Elem().CanAddr() {
return fmt.Errorf("src %w", ErrNotAddr)
}
dstAddr = unsafe.Pointer(dstValue.Elem().UnsafeAddr())
srcAddr = unsafe.Pointer(srcValue.Elem().UnsafeAddr())
dstValue = dstValue.Elem()
srcValue = srcValue.Elem()
// 从cache load出类型直接执行
exist, err := getFromCacheSetAndRun(dstSrcType{dst: dstValue.Type(), src: srcValue.Type()}, dstAddr, srcAddr, opt)
if exist || err != nil {
return err
}
of.srcType = srcValue.Type()
of.dstType = dstValue.Type()
if opt.preheat {
all = newAllFieldFunc()
// 如果顶层对象是结构体,肯定会有预热结构
// 但是是其它类型可能没有预热结构, 所以这里要判断一下
if dstValue.Type().Kind() != reflect.Struct && srcValue.Type().Kind() != reflect.Struct {
defer saveToCache(dstSrcType{
dst: dstValue.Type(),
src: srcValue.Type(),
},
all)
}
}
// 按道理已经预热过的类型, 不会走到这里
// 但这里有个特殊情况,比如多级不对称指针。为了支持这种情况,就不报错了
// if opt.usePreheat {
// return errors.New("usePreheat must be used with preheat")
// }
}
d := pcopy{
options: opt,
}
return d.pcopy(dstValue, srcValue, dstAddr, srcAddr, of, all)
}
// // 需要的tag name
// func haveTagName(curTabName string) bool {
// return len(curTabName) > 0
// }
// 判断是array或slice类型
func isArraySlice(v reflect.Value) bool {
switch v.Kind() {
case reflect.Array, reflect.Slice:
return true
}
return false
}
// 拷贝slice array
func (d *pcopy) cpySliceArray(dst, src reflect.Value, dstBase, srcBase unsafe.Pointer, of offsetAndFunc, all *allFieldFunc) error {
// dst只能是slice和array类型
if !isArraySlice(dst) {
return nil
}
// 保存类型缓存
l := src.Len()
if dst.Len() > 0 && dst.Len() < src.Len() {
l = dst.Len()
}
// 被拷贝dst类型是slice, 长度是0, src的长度有值
if dst.Kind() == reflect.Slice && dst.Len() == 0 && src.Len() > 0 {
dstElemType := dst.Type().Elem()
newDst := reflect.MakeSlice(reflect.SliceOf(dstElemType), l, l)
dst.Set(newDst)
}
if d.preheat {
of.srcType = src.Type()
of.dstType = dst.Type()
// 如果是基础类型的slice, []int []string 这种
if isBaseType(dst.Type().Elem().Kind()) && isBaseType(src.Type().Elem().Kind()) {
of.unsafeSet = getSetBaseSliceFunc(dst.Type().Elem().Kind())
all.append(of)
of.createFlag = baseSliceTypeSet
return nil
}
// 如果任一类型是基础类型的指针类型, *[]int *[]string 这种,和基础类型的slice的组合
var k reflect.Kind
if isBaseSliceOrBaseSlicePtr(dst.Type(), &k) && isBaseSliceOrBaseSlicePtr(src.Type(), &k) {
of.reflectSet = getSetSliceElemIsBaseTypeOrPtrFunc(k, false)
of.createFlag = baseMapTypeSet
all.append(of)
return nil
}
// 处理复合类型的slice
of.reflectSet = getSetCompositeFunc(dst.Type().Kind())
all.append(of)
dstElemType := dst.Type().Elem()
srcElemType := src.Type().Elem()
exits := hasSetFromCache(dstSrcType{dst: dstElemType, src: srcElemType})
// 已经存在穿上类型的转换表,直接返回
if exits {
return nil
}
// 元素不存在转换表,需要创建
return pcopyInner(reflect.New(dstElemType).Interface(), reflect.New(srcElemType).Interface(), d.options)
}
for i := 0; i < l; i++ {
if err := d.pcopy(dst.Index(i), src.Index(i), dstBase, srcBase, of, all); err != nil {
return err
}
}
return nil
}
// 拷贝map
func (d *pcopy) cpyMap(dst, src reflect.Value, dstBase, srcBase unsafe.Pointer, of offsetAndFunc, all *allFieldFunc) error {
if dst.Kind() == reflect.Ptr {
return d.cpyPtr(dst, src, dstBase, srcBase, of, all)
}
if dst.Kind() != src.Kind() {
return nil
}
if !dst.CanSet() {
return nil
}
// 检查value的类型
if dst.Type().Elem().Kind() != src.Type().Elem().Kind() {
return nil
}
// 检查key的类型
if dst.Type().Key().Kind() != src.Type().Key().Kind() {
return nil
}
if dst.IsNil() {
newMap := reflect.MakeMap(src.Type())
dst.Set(newMap)
}
if d.preheat {
// 如果是基础类型的slice
of.srcType = src.Type()
of.dstType = dst.Type()
if isBaseType(dst.Type().Elem().Kind()) && isBaseType(src.Type().Elem().Kind()) {
of.unsafeSet = getSetBaseMapFunc(src.Type().Key().Kind(), src.Type().Elem().Kind(), true)
of.createFlag = baseMapTypeSet
all.append(of)
return nil
}
of.reflectSet = getSetCompositeFunc(dst.Type().Kind())
all.append(of)
dstElemType := dst.Type().Elem()
srcElemType := src.Type().Elem()
exits := hasSetFromCache(dstSrcType{dst: dstElemType, src: srcElemType})
// 已经存在穿上类型的转换表,直接返回
if exits {
return nil
}
// 元素不存在转换表,需要创建
return pcopyInner(reflect.New(dstElemType).Interface(), reflect.New(srcElemType).Interface(), d.options)
}
iter := src.MapRange()
for iter.Next() {
k := iter.Key()
v := iter.Value()
newVal := reflect.New(v.Type()).Elem()
if err := d.pcopy(newVal, v, zeroUintptr, zeroUintptr, of, all); err != nil {
return err
}
dst.SetMapIndex(k, newVal)
}
return nil
}
// 拷贝函数
func (d *pcopy) cpyFunc(dst, src reflect.Value) error {
if dst.Kind() != src.Kind() {
return nil
}
dst.Set(src)
return nil
}
// 拷贝结构体
func (d *pcopy) cpyStruct(dst, src reflect.Value, dstBase, srcBase unsafe.Pointer, of offsetAndFunc, all *allFieldFunc) error {
if dst.Kind() != src.Kind() {
return nil
}
if dst.CanSet() {
if _, ok := src.Interface().(time.Time); ok {
if d.preheat {
of.srcType = src.Type()
of.dstType = dst.Type()
of.unsafeSet = setTime
of.createFlag = baseTypeSet
all.append(of)
return nil
}
dst.Set(src)
}
}
if d.usePreheat {
// 从cache load出类型直接执行
exist, err := getFromCacheSetAndRun(dstSrcType{dst: dst.Type(), src: src.Type()}, dstBase, srcBase, d.options)
if exist || err != nil {
return nil
}
}
typ := src.Type()
for i, n := 0, src.NumField(); i < n; i++ {
sf := typ.Field(i)
if sf.PkgPath != "" && !sf.Anonymous {
continue
}
// 使用src的字段名在dst里面取出reflect.Value值
dstValue := dst.FieldByName(sf.Name)
// dst没有src里面所有的字段,跳过
if !dstValue.IsValid() {
continue
}
// 检查结构体里面的字段是否有循环引用
sField := src.Field(i)
if d.preheat {
// 更新这个类型的offset
of.dstOffset = sub(dstValue.UnsafeAddr(), uintptr(dstBase))
of.srcOffset = sub(sField.UnsafeAddr(), uintptr(srcBase))
}
if err := d.pcopy(dstValue, sField, dstBase, srcBase, of, all); err != nil {
return err
}
}
return nil
}
// 拷贝interface{}
func (d *pcopy) cpyInterface(dst, src reflect.Value, of offsetAndFunc, all *allFieldFunc) error {
if dst.Kind() != src.Kind() {
return nil
}
src = src.Elem()
newDst := reflect.New(src.Type()).Elem()
newDstAddr := zeroUintptr
newSrcAddr := zeroUintptr
if d.usePreheat {
newDstAddr = unsafe.Pointer(newDst.UnsafeAddr())
newSrcAddr = unsafe.Pointer(src.UnsafeAddr())
}
if err := d.pcopy(newDst, src, newDstAddr, newSrcAddr, of, all); err != nil {
return err
}
dst.Set(newDst)
return nil
}
func (d *pcopy) preheatPtr(dst, src reflect.Value, of offsetAndFunc, all *allFieldFunc) error {
bkDst := dst
bkSrc := src
for {
if dst.Kind() == reflect.Ptr && dst.IsNil() {
// dst.CanSet必须放到dst.IsNil判断里面
// 不然会影响到struct或者map类型的指针
if !dst.CanSet() {
return nil
}
p := reflect.New(dst.Type().Elem())
dst.Set(p)
}
if src.Kind() == reflect.Ptr && src.IsNil() {
// dst.CanSet必须放到dst.IsNil判断里面
// 不然会影响到struct或者map类型的指针
if !src.CanSet() {
return nil
}
p := reflect.New(src.Type().Elem())
src.Set(p)
}
if src.Kind() == reflect.Ptr {
src = src.Elem()
}
if dst.Kind() == reflect.Ptr {
dst = dst.Elem()
}
if src.Kind() != reflect.Ptr && dst.Kind() != reflect.Ptr {
break
}
}
if src.Kind() != dst.Kind() {
return nil
}
if isBaseType(src.Kind()) {
of.unsafeSet = getSetBaseFunc(src.Kind())
} else if src.Kind() == reflect.Slice && isBaseType(src.Type().Elem().Kind()) {
of.unsafeSet = getSetBaseSliceFunc(src.Type().Elem().Kind())
} else if src.Kind() == reflect.Map {
of.unsafeSet = getSetBaseMapFunc(src.Type().Key().Kind(), src.Type().Elem().Kind(), false)
}
of.dstType = bkDst.Type()
of.srcType = bkSrc.Type()
of.reflectSet = getSetCompositeFunc(reflect.Ptr)
all.append(of)
if src.Kind() == reflect.Struct {
// 预热下这个结构体
exits := hasSetFromCache(dstSrcType{dst: dst.Type(), src: src.Type()})
if exits {
return nil
}
return pcopyInner(dst.Addr().Interface(), src.Addr().Interface(), d.options)
}
return nil
}
// 拷贝指针
func (d *pcopy) cpyPtr(dst, src reflect.Value, dstBase, srcBase unsafe.Pointer, of offsetAndFunc, all *allFieldFunc) error {
// 解引用之后的类型如果不一样,直接返回
if d.preheat {
return d.preheatPtr(dst, src, of, all)
}
if dst.Kind() == reflect.Ptr && dst.IsNil() {
// dst.CanSet必须放到dst.IsNil判断里面
// 不然会影响到struct或者map类型的指针
if !dst.CanSet() {
return nil
}
p := reflect.New(dst.Type().Elem())
dst.Set(p)
}
if src.Kind() == reflect.Ptr {
src = src.Elem()
srcBase = unsafe.Pointer(src.UnsafeAddr())
}
if dst.Kind() == reflect.Ptr {
dst = dst.Elem()
dstBase = unsafe.Pointer(dst.UnsafeAddr())
}
return d.pcopy(dst, src, dstBase, srcBase, of, all)
}
// 其他类型
func (d *pcopy) cpyDefault(dst, src reflect.Value, dstBase, srcBase unsafe.Pointer, of offsetAndFunc, all *allFieldFunc) error {
if dst.Kind() != src.Kind() {
// 如果是尺寸相等但类型不同的数字类型,可以进行转换
if !(isInt64(dst.Kind()) && isInt64(src.Kind()) ||
isInt32(dst.Kind()) && isInt32(src.Kind()) ||
isInt16(dst.Kind()) && isInt16(src.Kind()) ||
isInt8(dst.Kind()) && isInt8(src.Kind())) {
return nil
}
}
if d.preheat {
of.srcType = src.Type()
of.dstType = dst.Type()
of.unsafeSet = getSetBaseFunc(src.Kind())
of.createFlag = baseTypeSet
all.append(of)
return nil
}
switch src.Kind() {
case
reflect.Int,
reflect.Int8,
reflect.Int16,
reflect.Int32,
reflect.Int64:
switch dst.Kind() {
case
reflect.Uint,
reflect.Uint8,
reflect.Uint16,
reflect.Uint32,
reflect.Uint64:
dst.SetUint(uint64(src.Int()))
default:
dst.SetInt(src.Int())
}
return nil
case
reflect.Uint,
reflect.Uint8,
reflect.Uint16,
reflect.Uint32,
reflect.Uint64:
switch dst.Kind() {
case
reflect.Int,
reflect.Int8,
reflect.Int16,
reflect.Int32,
reflect.Int64:
dst.SetInt(int64(src.Uint()))
default:
dst.SetUint(src.Uint())
}
return nil
case reflect.String:
dst.SetString(src.String())
return nil
case reflect.Bool:
dst.SetBool(src.Bool())
return nil
case reflect.Float32, reflect.Float64:
dst.SetFloat(src.Float())
return nil
}
// 如果这里是枚举类型(type newType oldType),哪怕底层的数据类型(oldType)一样,set也会报错, 所以在前面加个前置判断保护下
dst.Set(src)
return nil
}
func (d *pcopy) pcopy(dst, src reflect.Value, dstBase, srcBase unsafe.Pointer, of offsetAndFunc, all *allFieldFunc) error {
// 预热的时候一定要绕开这个判断, 不管src有值没值都要继续往下走
// 寻找和dst匹配的字段
if !(d.preheat || d.usePreheat) {
if src.IsZero() {
return nil
}
}
if dst.Kind() == reflect.Ptr {
return d.cpyPtr(dst, src, dstBase, srcBase, of, all)
}
switch src.Kind() {
case reflect.Slice, reflect.Array:
return d.cpySliceArray(dst, src, dstBase, srcBase, of, all)
case reflect.Map:
return d.cpyMap(dst, src, dstBase, srcBase, of, all)
case reflect.Func:
return d.cpyFunc(dst, src)
case reflect.Struct:
// 保存类型缓存
if d.preheat {
all = addNextComposite(all, of)
defer saveToCache(dstSrcType{dst.Type(), src.Type()}, all)
}
return d.cpyStruct(dst, src, dstBase, srcBase, of, all)
case reflect.Interface:
if d.preheat {
of.srcType = src.Type()
of.dstType = dst.Type()
of.reflectSet = getSetCompositeFunc(src.Kind())
all.append(of)
// interface是可变类型。cache加速是把类型关系固化,所以这里只需要知道这个offset是interface就行
// 后需要的类型是可变的,就没有必要分析现在interface存放的类型
return nil
}
return d.cpyInterface(dst, src, of, all)
case reflect.Ptr:
return d.cpyPtr(dst, src, dstBase, srcBase, of, all)
default:
return d.cpyDefault(dst, src, dstBase, srcBase, of, all)
}
}
func addNextComposite(all *allFieldFunc, of offsetAndFunc) (newAll *allFieldFunc) {
of.nextComposite = newAllFieldFunc()
of.createFlag = sliceTypeSet
all.append(of)
// 重置all
of.createFlag = debugTypeSet
newAll = of.nextComposite
of.nextComposite = nil
return
}