aboutsummaryrefslogtreecommitdiff
path: root/src/internal/runtime/maps/map.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/internal/runtime/maps/map.go')
-rw-r--r--src/internal/runtime/maps/map.go37
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
+}