data: unsafe.Pointer(uintptr(g.data) + offset),
}
}
+
+func cloneGroup(typ *abi.SwissMapType, newGroup, oldGroup groupReference) {
+ typedmemmove(typ.Group, newGroup.data, oldGroup.data)
+ if typ.IndirectKey() {
+ // Deep copy keys if indirect.
+ for i := uintptr(0); i < abi.SwissMapGroupSlots; i++ {
+ oldKey := *(*unsafe.Pointer)(oldGroup.key(typ, i))
+ if oldKey == nil {
+ continue
+ }
+ newKey := newobject(typ.Key)
+ typedmemmove(typ.Key, newKey, oldKey)
+ *(*unsafe.Pointer)(newGroup.key(typ, i)) = newKey
+ }
+ }
+ if typ.IndirectElem() {
+ // Deep copy elems if indirect.
+ for i := uintptr(0); i < abi.SwissMapGroupSlots; i++ {
+ oldElem := *(*unsafe.Pointer)(oldGroup.elem(typ, i))
+ if oldElem == nil {
+ continue
+ }
+ newElem := newobject(typ.Elem)
+ typedmemmove(typ.Elem, newElem, oldElem)
+ *(*unsafe.Pointer)(newGroup.elem(typ, i)) = newElem
+ }
+ }
+
+}
m.used = 0
m.clearSeq++
}
+
+func (m *Map) Clone(typ *abi.SwissMapType) *Map {
+ // Note: this should never be called with a nil map.
+ if m.writing != 0 {
+ fatal("concurrent map clone and map write")
+ }
+
+ // Shallow copy the Map structure.
+ m2 := new(Map)
+ *m2 = *m
+ m = m2
+
+ // We need to just deep copy the dirPtr field.
+ if m.dirPtr == nil {
+ // delayed group allocation, nothing to do.
+ } else if m.dirLen == 0 {
+ // Clone one group.
+ oldGroup := groupReference{data: m.dirPtr}
+ newGroup := groupReference{data: newGroups(typ, 1).data}
+ cloneGroup(typ, newGroup, oldGroup)
+ m.dirPtr = newGroup.data
+ } else {
+ // Clone each (different) table.
+ oldDir := unsafe.Slice((**table)(m.dirPtr), m.dirLen)
+ newDir := make([]*table, m.dirLen)
+ for i, t := range oldDir {
+ if i > 0 && t == oldDir[i-1] {
+ newDir[i] = newDir[i-1]
+ continue
+ }
+ newDir[i] = t.clone(typ)
+ }
+ m.dirPtr = unsafe.Pointer(&newDir[0])
+ }
+
+ return m
+}
s.offset = (s.offset + s.index) & s.mask
return s
}
+
+func (t *table) clone(typ *abi.SwissMapType) *table {
+ // Shallow copy the table structure.
+ t2 := new(table)
+ *t2 = *t
+ t = t2
+
+ // We need to just deep copy the groups.data field.
+ oldGroups := t.groups
+ newGroups := newGroups(typ, oldGroups.lengthMask+1)
+ for i := uint64(0); i <= oldGroups.lengthMask; i++ {
+ oldGroup := oldGroups.group(typ, i)
+ newGroup := newGroups.group(typ, i)
+ cloneGroup(typ, newGroup, oldGroup)
+ }
+ t.groups = newGroups
+
+ return t
+}
//go:linkname mapclone maps.clone
func mapclone(m any) any {
e := efaceOf(&m)
- e.data = unsafe.Pointer(mapclone2((*abi.SwissMapType)(unsafe.Pointer(e._type)), (*maps.Map)(e.data)))
+ typ := (*abi.SwissMapType)(unsafe.Pointer(e._type))
+ map_ := (*maps.Map)(e.data)
+ map_ = map_.Clone(typ)
+ e.data = (unsafe.Pointer)(map_)
return m
}
-func mapclone2(t *abi.SwissMapType, src *maps.Map) *maps.Map {
- dst := makemap(t, int(src.Used()), nil)
-
- var iter maps.Iter
- iter.Init(t, src)
- for iter.Next(); iter.Key() != nil; iter.Next() {
- dst.Put(t, iter.Key(), iter.Elem())
- }
-
- return dst
-}
-
// keys for implementing maps.keys
//
//go:linkname keys maps.keys