diff options
Diffstat (limited to 'src/internal/runtime/maps/map.go')
| -rw-r--r-- | src/internal/runtime/maps/map.go | 37 |
1 files changed, 37 insertions, 0 deletions
diff --git a/src/internal/runtime/maps/map.go b/src/internal/runtime/maps/map.go index 62463351c7..b4db522978 100644 --- a/src/internal/runtime/maps/map.go +++ b/src/internal/runtime/maps/map.go @@ -770,3 +770,40 @@ func (m *Map) clearSmall(typ *abi.SwissMapType) { 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 +} |
