forked from apache/beam
-
Notifications
You must be signed in to change notification settings - Fork 0
/
util.go
92 lines (79 loc) · 2.47 KB
/
util.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
// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package reflectx
import (
"fmt"
"reflect"
)
// ShallowClone creates a shallow copy of the given value. Most
// useful for slices and maps.
func ShallowClone(v interface{}) interface{} {
if v == nil {
return nil
}
val := reflect.ValueOf(v)
t := val.Type()
switch t.Kind() {
case reflect.Slice:
if val.IsNil() {
return reflect.Zero(t).Interface() // don't allocate for zero values
}
size := val.Len()
ret := reflect.MakeSlice(t, size, size)
for i := 0; i < size; i++ {
ret.Index(i).Set(val.Index(i))
}
return ret.Interface()
case reflect.Map:
if val.IsNil() {
return reflect.Zero(t).Interface() // don't allocate for zero values
}
ret := reflect.MakeMapWithSize(t, val.Len())
keys := val.MapKeys()
for _, key := range keys {
ret.SetMapIndex(key, val.MapIndex(key))
}
return ret.Interface()
case reflect.Array, reflect.Chan, reflect.Interface, reflect.Func, reflect.Invalid:
panic(fmt.Sprintf("unsupported type for clone: %v", t))
default:
return v
}
}
// UpdateMap merges two maps of type map[K]*V, with the second overwriting values
// into the first (and mutating it). If the overwriting value is nil, the key is
// deleted.
func UpdateMap(base, updates interface{}) {
if updates == nil {
return // ok: nop
}
if base == nil {
panic("base map cannot be nil")
}
m := reflect.ValueOf(base)
o := reflect.ValueOf(updates)
if o.Type().Kind() != reflect.Map || m.Type() != o.Type() {
panic(fmt.Sprintf("invalid types for map update: %v != %v", m.Type(), o.Type()))
}
keys := o.MapKeys()
for _, key := range keys {
val := o.MapIndex(key)
if val.IsNil() {
m.SetMapIndex(key, reflect.Value{}) // delete
} else {
m.SetMapIndex(key, val)
}
}
}