]> Cypherpunks.ru repositories - gostls13.git/commitdiff
reflect,runtime: add Value.Clear
authorCuong Manh Le <cuong.manhle.vn@gmail.com>
Thu, 15 Dec 2022 11:14:13 +0000 (18:14 +0700)
committerCuong Manh Le <cuong.manhle.vn@gmail.com>
Mon, 30 Jan 2023 16:00:58 +0000 (16:00 +0000)
Fixes #55002

Change-Id: I7d0f14cc54f67f2769b51d2efafc4ae3714f0e3d
Reviewed-on: https://go-review.googlesource.com/c/go/+/457895
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-by: Ian Lance Taylor <iant@google.com>
Auto-Submit: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Reviewed-by: Keith Randall <khr@google.com>
Run-TryBot: Cuong Manh Le <cuong.manhle.vn@gmail.com>
TryBot-Result: Gopher Robot <gobot@golang.org>

api/next/55002.txt [new file with mode: 0644]
src/reflect/all_test.go
src/reflect/value.go
src/runtime/map.go
src/runtime/mbarrier.go

diff --git a/api/next/55002.txt b/api/next/55002.txt
new file mode 100644 (file)
index 0000000..cfc4058
--- /dev/null
@@ -0,0 +1 @@
+pkg reflect, method (Value) Clear() #55002
index e9c0935b9e067b1d457f145322f900fdbafc5aa8..c257bec1e589fbecf1e92bcaccd56edc3fa65980 100644 (file)
@@ -8363,3 +8363,48 @@ func TestInitFuncTypes(t *testing.T) {
        }
        wg.Wait()
 }
+
+func TestClear(t *testing.T) {
+       m := make(map[string]any, len(valueTests))
+       for _, tt := range valueTests {
+               m[tt.s] = tt.i
+       }
+       mapTestFn := func(v Value) bool { v.Clear(); return v.Len() == 0 }
+
+       s := make([]*pair, len(valueTests))
+       for i := range s {
+               s[i] = &valueTests[i]
+       }
+       sliceTestFn := func(v Value) bool {
+               v.Clear()
+               for i := 0; i < v.Len(); i++ {
+                       if !v.Index(i).IsZero() {
+                               return false
+                       }
+               }
+               return true
+       }
+
+       panicTestFn := func(v Value) bool { shouldPanic("reflect.Value.Clear", func() { v.Clear() }); return true }
+
+       tests := []struct {
+               name     string
+               value    Value
+               testFunc func(v Value) bool
+       }{
+               {"map", ValueOf(m), mapTestFn},
+               {"slice no pointer", ValueOf([]int{1, 2, 3, 4, 5}), sliceTestFn},
+               {"slice has pointer", ValueOf(s), sliceTestFn},
+               {"non-map/slice", ValueOf(1), panicTestFn},
+       }
+
+       for _, tc := range tests {
+               tc := tc
+               t.Run(tc.name, func(t *testing.T) {
+                       t.Parallel()
+                       if !tc.testFunc(tc.value) {
+                               t.Errorf("unexpected result for value.Clear(): %value", tc.value)
+                       }
+               })
+       }
+}
index 42bb5ea527fdd4eedb77eccdc56c6bd0e6139e4a..5feca614341d1e0b747b837c81baa92edc0200f9 100644 (file)
@@ -2827,6 +2827,22 @@ func (v Value) extendSlice(n int) Value {
        return v
 }
 
+// Clear clears the contents of a map or zeros the contents of a slice.
+//
+// It panics if v's Kind is not Map or Slice.
+func (v Value) Clear() {
+       switch v.Kind() {
+       case Slice:
+               sh := *(*unsafeheader.Slice)(v.ptr)
+               st := (*sliceType)(unsafe.Pointer(v.typ))
+               typedarrayclear(st.elem, sh.Data, sh.Len)
+       case Map:
+               mapclear(v.typ, v.pointer())
+       default:
+               panic(&ValueError{"reflect.Value.Clear", v.Kind()})
+       }
+}
+
 // Append appends the values x to a slice s and returns the resulting slice.
 // As in Go, each x's value must be assignable to the slice's element type.
 func Append(s Value, x ...Value) Value {
@@ -3774,6 +3790,8 @@ func mapiternext(it *hiter)
 //go:noescape
 func maplen(m unsafe.Pointer) int
 
+func mapclear(t *rtype, m unsafe.Pointer)
+
 // call calls fn with "stackArgsSize" bytes of stack arguments laid out
 // at stackArgs and register arguments laid out in regArgs. frameSize is
 // the total amount of stack space that will be reserved by call, so this
@@ -3837,6 +3855,12 @@ func typedmemclrpartial(t *rtype, ptr unsafe.Pointer, off, size uintptr)
 //go:noescape
 func typedslicecopy(elemType *rtype, dst, src unsafeheader.Slice) int
 
+// typedarrayclear zeroes the value at ptr of an array of elemType,
+// only clears len elem.
+//
+//go:noescape
+func typedarrayclear(elemType *rtype, ptr unsafe.Pointer, len int)
+
 //go:noescape
 func typehash(t *rtype, p unsafe.Pointer, h uintptr) uintptr
 
index 6179c1e3710529448bc41ad0d3e37a326eee6257..3f5817a577bb2de403f1cca0144bfb2a16dae779 100644 (file)
@@ -1403,6 +1403,11 @@ func reflect_maplen(h *hmap) int {
        return h.count
 }
 
+//go:linkname reflect_mapclear reflect.mapclear
+func reflect_mapclear(t *maptype, h *hmap) {
+       mapclear(t, h)
+}
+
 //go:linkname reflectlite_maplen internal/reflectlite.maplen
 func reflectlite_maplen(h *hmap) int {
        if h == nil {
index 46ef42f74dd5d34606b369bdc6dfea808d887652..dbcd4db8684b51ef79a195f4358663b1bb2c35aa 100644 (file)
@@ -334,6 +334,15 @@ func reflect_typedmemclrpartial(typ *_type, ptr unsafe.Pointer, off, size uintpt
        memclrNoHeapPointers(ptr, size)
 }
 
+//go:linkname reflect_typedarrayclear reflect.typedarrayclear
+func reflect_typedarrayclear(typ *_type, ptr unsafe.Pointer, len int) {
+       size := typ.size * uintptr(len)
+       if writeBarrier.needed && typ.ptrdata != 0 {
+               bulkBarrierPreWrite(uintptr(ptr), 0, size)
+       }
+       memclrNoHeapPointers(ptr, size)
+}
+
 // memclrHasPointers clears n bytes of typed memory starting at ptr.
 // The caller must ensure that the type of the object at ptr has
 // pointers, usually by checking typ.ptrdata. However, ptr