123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209 |
- /*
- Copyright 2019 The Kubernetes Authors.
- Licensed 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 value
- import (
- "reflect"
- )
- type mapReflect struct {
- valueReflect
- }
- func (r mapReflect) Length() int {
- val := r.Value
- return val.Len()
- }
- func (r mapReflect) Empty() bool {
- val := r.Value
- return val.Len() == 0
- }
- func (r mapReflect) Get(key string) (Value, bool) {
- return r.GetUsing(HeapAllocator, key)
- }
- func (r mapReflect) GetUsing(a Allocator, key string) (Value, bool) {
- k, v, ok := r.get(key)
- if !ok {
- return nil, false
- }
- return a.allocValueReflect().mustReuse(v, nil, &r.Value, &k), true
- }
- func (r mapReflect) get(k string) (key, value reflect.Value, ok bool) {
- mapKey := r.toMapKey(k)
- val := r.Value.MapIndex(mapKey)
- return mapKey, val, val.IsValid() && val != reflect.Value{}
- }
- func (r mapReflect) Has(key string) bool {
- var val reflect.Value
- val = r.Value.MapIndex(r.toMapKey(key))
- if !val.IsValid() {
- return false
- }
- return val != reflect.Value{}
- }
- func (r mapReflect) Set(key string, val Value) {
- r.Value.SetMapIndex(r.toMapKey(key), reflect.ValueOf(val.Unstructured()))
- }
- func (r mapReflect) Delete(key string) {
- val := r.Value
- val.SetMapIndex(r.toMapKey(key), reflect.Value{})
- }
- // TODO: Do we need to support types that implement json.Marshaler and are used as string keys?
- func (r mapReflect) toMapKey(key string) reflect.Value {
- val := r.Value
- return reflect.ValueOf(key).Convert(val.Type().Key())
- }
- func (r mapReflect) Iterate(fn func(string, Value) bool) bool {
- return r.IterateUsing(HeapAllocator, fn)
- }
- func (r mapReflect) IterateUsing(a Allocator, fn func(string, Value) bool) bool {
- if r.Value.Len() == 0 {
- return true
- }
- v := a.allocValueReflect()
- defer a.Free(v)
- return eachMapEntry(r.Value, func(e *TypeReflectCacheEntry, key reflect.Value, value reflect.Value) bool {
- return fn(key.String(), v.mustReuse(value, e, &r.Value, &key))
- })
- }
- func eachMapEntry(val reflect.Value, fn func(*TypeReflectCacheEntry, reflect.Value, reflect.Value) bool) bool {
- iter := val.MapRange()
- entry := TypeReflectEntryOf(val.Type().Elem())
- for iter.Next() {
- next := iter.Value()
- if !next.IsValid() {
- continue
- }
- if !fn(entry, iter.Key(), next) {
- return false
- }
- }
- return true
- }
- func (r mapReflect) Unstructured() interface{} {
- result := make(map[string]interface{}, r.Length())
- r.Iterate(func(s string, value Value) bool {
- result[s] = value.Unstructured()
- return true
- })
- return result
- }
- func (r mapReflect) Equals(m Map) bool {
- return r.EqualsUsing(HeapAllocator, m)
- }
- func (r mapReflect) EqualsUsing(a Allocator, m Map) bool {
- lhsLength := r.Length()
- rhsLength := m.Length()
- if lhsLength != rhsLength {
- return false
- }
- if lhsLength == 0 {
- return true
- }
- vr := a.allocValueReflect()
- defer a.Free(vr)
- entry := TypeReflectEntryOf(r.Value.Type().Elem())
- return m.Iterate(func(key string, value Value) bool {
- _, lhsVal, ok := r.get(key)
- if !ok {
- return false
- }
- return Equals(vr.mustReuse(lhsVal, entry, nil, nil), value)
- })
- }
- func (r mapReflect) Zip(other Map, order MapTraverseOrder, fn func(key string, lhs, rhs Value) bool) bool {
- return r.ZipUsing(HeapAllocator, other, order, fn)
- }
- func (r mapReflect) ZipUsing(a Allocator, other Map, order MapTraverseOrder, fn func(key string, lhs, rhs Value) bool) bool {
- if otherMapReflect, ok := other.(*mapReflect); ok && order == Unordered {
- return r.unorderedReflectZip(a, otherMapReflect, fn)
- }
- return defaultMapZip(a, &r, other, order, fn)
- }
- // unorderedReflectZip provides an optimized unordered zip for mapReflect types.
- func (r mapReflect) unorderedReflectZip(a Allocator, other *mapReflect, fn func(key string, lhs, rhs Value) bool) bool {
- if r.Empty() && (other == nil || other.Empty()) {
- return true
- }
- lhs := r.Value
- lhsEntry := TypeReflectEntryOf(lhs.Type().Elem())
- // map lookup via reflection is expensive enough that it is better to keep track of visited keys
- visited := map[string]struct{}{}
- vlhs, vrhs := a.allocValueReflect(), a.allocValueReflect()
- defer a.Free(vlhs)
- defer a.Free(vrhs)
- if other != nil {
- rhs := other.Value
- rhsEntry := TypeReflectEntryOf(rhs.Type().Elem())
- iter := rhs.MapRange()
- for iter.Next() {
- key := iter.Key()
- keyString := key.String()
- next := iter.Value()
- if !next.IsValid() {
- continue
- }
- rhsVal := vrhs.mustReuse(next, rhsEntry, &rhs, &key)
- visited[keyString] = struct{}{}
- var lhsVal Value
- if _, v, ok := r.get(keyString); ok {
- lhsVal = vlhs.mustReuse(v, lhsEntry, &lhs, &key)
- }
- if !fn(keyString, lhsVal, rhsVal) {
- return false
- }
- }
- }
- iter := lhs.MapRange()
- for iter.Next() {
- key := iter.Key()
- if _, ok := visited[key.String()]; ok {
- continue
- }
- next := iter.Value()
- if !next.IsValid() {
- continue
- }
- if !fn(key.String(), vlhs.mustReuse(next, lhsEntry, &lhs, &key), nil) {
- return false
- }
- }
- return true
- }
|