@@ -1423,3 +1423,151 @@ var zeroVal [maxZero]byte
1423
1423
// map init function to this symbol. Defined in assembly so as to avoid
1424
1424
// complications with instrumentation (coverage, etc).
1425
1425
func mapinitnoop ()
1426
+
1427
+ // mapclone for implementing maps.Clone
1428
+ //
1429
+ //go:linkname mapclone maps.clone
1430
+ func mapclone (m any ) any {
1431
+ e := efaceOf (& m )
1432
+ e .data = unsafe .Pointer (mapclone2 ((* maptype )(unsafe .Pointer (e ._type )), (* hmap )(e .data )))
1433
+ return m
1434
+ }
1435
+
1436
+ // moveToBmap moves a bucket from src to dst. It returns the destination bucket or new destination bucket if it overflows
1437
+ // and the pos that the next key/value will be written, if pos == bucketCnt means needs to written in overflow bucket.
1438
+ func moveToBmap (t * maptype , h * hmap , dst * bmap , pos int , src * bmap ) (* bmap , int ) {
1439
+ for i := 0 ; i < bucketCnt ; i ++ {
1440
+ if isEmpty (src .tophash [i ]) {
1441
+ continue
1442
+ }
1443
+
1444
+ for ; pos < bucketCnt ; pos ++ {
1445
+ if isEmpty (dst .tophash [pos ]) {
1446
+ break
1447
+ }
1448
+ }
1449
+
1450
+ if pos == bucketCnt {
1451
+ dst = h .newoverflow (t , dst )
1452
+ pos = 0
1453
+ }
1454
+
1455
+ srcK := add (unsafe .Pointer (src ), dataOffset + uintptr (i )* uintptr (t .keysize ))
1456
+ srcEle := add (unsafe .Pointer (src ), dataOffset + bucketCnt * uintptr (t .keysize )+ uintptr (i )* uintptr (t .elemsize ))
1457
+ dstK := add (unsafe .Pointer (dst ), dataOffset + uintptr (pos )* uintptr (t .keysize ))
1458
+ dstEle := add (unsafe .Pointer (dst ), dataOffset + bucketCnt * uintptr (t .keysize )+ uintptr (pos )* uintptr (t .elemsize ))
1459
+
1460
+ dst .tophash [pos ] = src .tophash [i ]
1461
+ if t .indirectkey () {
1462
+ * (* unsafe .Pointer )(dstK ) = * (* unsafe .Pointer )(srcK )
1463
+ } else {
1464
+ typedmemmove (t .key , dstK , srcK )
1465
+ }
1466
+ if t .indirectelem () {
1467
+ * (* unsafe .Pointer )(dstEle ) = * (* unsafe .Pointer )(srcEle )
1468
+ } else {
1469
+ typedmemmove (t .elem , dstEle , srcEle )
1470
+ }
1471
+ pos ++
1472
+ h .count ++
1473
+ }
1474
+ return dst , pos
1475
+ }
1476
+
1477
+ func mapclone2 (t * maptype , src * hmap ) * hmap {
1478
+ dst := makemap (t , src .count , nil )
1479
+ dst .hash0 = src .hash0
1480
+ dst .nevacuate = 0
1481
+ //flags do not need to be copied here, just like a new map has no flags.
1482
+
1483
+ if src .count == 0 {
1484
+ return dst
1485
+ }
1486
+
1487
+ if src .flags & hashWriting != 0 {
1488
+ fatal ("concurrent map clone and map write" )
1489
+ }
1490
+
1491
+ if src .B == 0 {
1492
+ dst .buckets = newobject (t .bucket )
1493
+ dst .count = src .count
1494
+ typedmemmove (t .bucket , dst .buckets , src .buckets )
1495
+ return dst
1496
+ }
1497
+
1498
+ //src.B != 0
1499
+ if dst .B == 0 {
1500
+ dst .buckets = newobject (t .bucket )
1501
+ }
1502
+ dstArraySize := int (bucketShift (dst .B ))
1503
+ srcArraySize := int (bucketShift (src .B ))
1504
+ for i := 0 ; i < dstArraySize ; i ++ {
1505
+ dstBmap := (* bmap )(add (dst .buckets , uintptr (i * int (t .bucketsize ))))
1506
+ pos := 0
1507
+ for j := 0 ; j < srcArraySize ; j += dstArraySize {
1508
+ srcBmap := (* bmap )(add (src .buckets , uintptr ((i + j )* int (t .bucketsize ))))
1509
+ for srcBmap != nil {
1510
+ dstBmap , pos = moveToBmap (t , dst , dstBmap , pos , srcBmap )
1511
+ srcBmap = srcBmap .overflow (t )
1512
+ }
1513
+ }
1514
+ }
1515
+
1516
+ if src .oldbuckets == nil {
1517
+ return dst
1518
+ }
1519
+
1520
+ oldB := src .B
1521
+ srcOldbuckets := src .oldbuckets
1522
+ if ! src .sameSizeGrow () {
1523
+ oldB --
1524
+ }
1525
+ oldSrcArraySize := int (bucketShift (oldB ))
1526
+
1527
+ for i := 0 ; i < oldSrcArraySize ; i ++ {
1528
+ srcBmap := (* bmap )(add (srcOldbuckets , uintptr (i * int (t .bucketsize ))))
1529
+ if evacuated (srcBmap ) {
1530
+ continue
1531
+ }
1532
+
1533
+ if oldB >= dst .B { // main bucket bits in dst is less than oldB bits in src
1534
+ dstBmap := (* bmap )(add (dst .buckets , uintptr (i )& bucketMask (dst .B )))
1535
+ for dstBmap .overflow (t ) != nil {
1536
+ dstBmap = dstBmap .overflow (t )
1537
+ }
1538
+ pos := 0
1539
+ for srcBmap != nil {
1540
+ dstBmap , pos = moveToBmap (t , dst , dstBmap , pos , srcBmap )
1541
+ srcBmap = srcBmap .overflow (t )
1542
+ }
1543
+ continue
1544
+ }
1545
+
1546
+ for srcBmap != nil {
1547
+ // move from oldBlucket to new bucket
1548
+ for i := uintptr (0 ); i < bucketCnt ; i ++ {
1549
+ if isEmpty (srcBmap .tophash [i ]) {
1550
+ continue
1551
+ }
1552
+
1553
+ if src .flags & hashWriting != 0 {
1554
+ fatal ("concurrent map clone and map write" )
1555
+ }
1556
+
1557
+ srcK := add (unsafe .Pointer (srcBmap ), dataOffset + i * uintptr (t .keysize ))
1558
+ if t .indirectkey () {
1559
+ srcK = * ((* unsafe .Pointer )(srcK ))
1560
+ }
1561
+
1562
+ srcEle := add (unsafe .Pointer (srcBmap ), dataOffset + bucketCnt * uintptr (t .keysize )+ i * uintptr (t .elemsize ))
1563
+ if t .indirectelem () {
1564
+ srcEle = * ((* unsafe .Pointer )(srcEle ))
1565
+ }
1566
+ dstEle := mapassign (t , dst , srcK )
1567
+ typedmemmove (t .elem , dstEle , srcEle )
1568
+ }
1569
+ srcBmap = srcBmap .overflow (t )
1570
+ }
1571
+ }
1572
+ return dst
1573
+ }
0 commit comments