func combineIndexable(left Indexable, right interface{}, f func(interface{}, interface{}) interface{}) (result interface{}) { switch right := right.(type) { case Indexable: makeSlice := func(length int) (r Indexable) { raw.CatchAll(func() { r = Reallocate(left, length, length).(Indexable) }) return } var s Indexable switch l, r := left.Len(), right.Len(); { case l == r: if s := makeSlice(l); result != nil { for i := 0; i < l; i++ { s.Set(i, f(left.At(i), right.At(i))) } } case l > r: if s := makeSlice(l); result != nil { for i := 0; i < r; i++ { s.Set(i, f(left.At(i), right.At(i))) } blank := reflect.Zero(reflect.ValueOf(left).Type().Elem()).Interface() for i := r; i < l; i++ { s.Set(i, f(left.At(i), blank)) } } case l < r: if s := makeSlice(r); result != nil { for i := 0; i < l; i++ { s.Set(i, f(left.At(i), right.At(i))) } blank := reflect.Zero(reflect.ValueOf(left).Type().Elem()).Interface() for i := l; i < r; i++ { s.Set(i, f(blank, right.At(i))) } } } result = s default: switch right := reflect.ValueOf(right); right.Kind() { case reflect.Slice: makeSlice := func(length int) (r reflect.Value) { raw.CatchAll(func() { Reallocate(left, length, length) r = reflect.ValueOf(left) }) return } var s reflect.Value CombineAndSet := func(i int, l interface{}, r reflect.Value) { s.Index(i).Set(reflect.ValueOf(f(l, r.Interface()))) } switch l, r := left.Len(), right.Len(); { case l == r: if s = makeSlice(l); s.IsValid() { for i := 0; i < l; i++ { CombineAndSet(i, left.At(i), right.Index(i)) } } case l > r: if s = makeSlice(l); s.IsValid() { for i := 0; i < r; i++ { CombineAndSet(i, left.At(i), right.Index(i)) } for i := r; i < l; i++ { CombineAndSet(i, left.At(i), reflect.Value{}) } } case l < r: if s = makeSlice(r); s.IsValid() { for i := 0; i < l; i++ { CombineAndSet(i, left.At(i), right.Index(i)) } for i := l; i < r; i++ { CombineAndSet(i, nil, right.Index(i)) } } } result = s.Interface() case reflect.Map: m := reflect.MakeMap(right.Type()) CombineAndSet := func(i, l interface{}, r reflect.Value) { m.SetMapIndex(reflect.ValueOf(i), reflect.ValueOf(f(l, r.Interface()))) } for i := left.Len() - 1; i > 0; i-- { CombineAndSet(i, left.At(i), right.MapIndex(reflect.ValueOf(i))) } for _, k := range right.MapKeys() { i := int(k.Int()) if left.At(i) == nil { CombineAndSet(i, left.At(i), right.MapIndex(k)) } } result = m.Interface() } } return }
func combineValue(Left, Right interface{}, f func(interface{}, interface{}) interface{}) (result interface{}) { left := reflect.ValueOf(Left) blank := reflect.Zero(left.Type().Elem()) switch left.Kind() { case reflect.Slice: switch right := Right.(type) { case Indexable: makeSlice := func(length int) (r reflect.Value) { raw.CatchAll(func() { Reallocate(left, length, length) r = reflect.ValueOf(left) }) return } var s reflect.Value CombineAndSet := func(i int, l reflect.Value, r interface{}) { s.Index(i).Set(reflect.ValueOf(f(l.Interface(), r))) } switch l, r := left.Len(), right.Len(); { case l == r: if s = makeSlice(l); s.IsValid() { for i := 0; i < l; i++ { CombineAndSet(i, left.Index(i), right.At(i)) } } case l > r: if s = makeSlice(l); s.IsValid() { for i := 0; i < r; i++ { CombineAndSet(i, left.Index(i), right.At(i)) } for i := r; i < l; i++ { CombineAndSet(i, left.Index(i), blank) } } case l < r: if s = makeSlice(r); s.IsValid() { for i := 0; i < l; i++ { CombineAndSet(i, left.Index(i), right.At(i)) } for i := l; i < r; i++ { CombineAndSet(i, blank, right.At(i)) } } } result = s.Interface() default: switch right := reflect.ValueOf(right); right.Kind() { case reflect.Slice: makeSlice := func(length int) reflect.Value { return reflect.MakeSlice(left.Type(), length, length) } var s reflect.Value CombineAndSet := func(i int, l, r reflect.Value) { s.Index(i).Set(reflect.ValueOf(f(l.Interface(), r.Interface()))) } switch l, r := left.Len(), right.Len(); { case l == r: if s = makeSlice(l); s.IsValid() { for i := 0; i < l; i++ { CombineAndSet(i, left.Index(i), right.Index(i)) } } case l > r: if s = makeSlice(l); s.IsValid() { for i := 0; i < r; i++ { CombineAndSet(i, left.Index(i), right.Index(i)) } for i := r; i < l; i++ { CombineAndSet(i, left.Index(i), blank) } } case l < r: if s = makeSlice(r); s.IsValid() { for i := 0; i < l; i++ { CombineAndSet(i, left.Index(i), right.Index(i)) } for i := l; i < r; i++ { CombineAndSet(i, blank, right.Index(i)) } } } result = s.Interface() case reflect.Map: if map_type := right.Type(); map_type.Key().Kind() == reflect.Int { n := reflect.MakeMap(map_type) for i := 0; i < left.Len(); i++ { n.SetMapIndex(reflect.ValueOf(i), left.Index(i)) } result = combineValue(n.Interface(), Right, f) } } } case reflect.Map: switch right := Right.(type) { /* case Map: m := reflect.MakeMap(left.Type()) CombineAndSet := func(k interface{}, l reflect.Value, r interface{}) { m.SetMapIndex(reflect.ValueOf(k), reflect.ValueOf(f(l.Interface(), r))) } right.EachWithKey(func(k, r interface{}) { if l := left.MapIndex(reflect.ValueOf(k)); l.IsValid() { CombineAndSet(k, l, r) } }) */ case Indexable: m := reflect.MakeMap(left.Type()) CombineAndSet := func(i int, l reflect.Value, r interface{}) { m.SetMapIndex(reflect.ValueOf(i), reflect.ValueOf(f(l.Interface(), r))) } for i := left.Len() - 1; i > 0; i-- { CombineAndSet(i, left.MapIndex(reflect.ValueOf(i)), right.At(i)) } for i := right.Len() - 1; i > 0; i-- { k := reflect.ValueOf(i) if !m.MapIndex(k).IsValid() { CombineAndSet(i, left.MapIndex(k), right.At(i)) } } result = m.Interface() default: switch right := reflect.ValueOf(right); right.Kind() { case reflect.Map: m := reflect.MakeMap(left.Type()) CombineAndSet := func(k reflect.Value) { lv := left.MapIndex(k) rv := right.MapIndex(k) var x interface{} if lv.IsValid() { if rv.IsValid() { x = f(lv.Interface(), rv.Interface()) } else { x = f(lv.Interface(), blank.Interface()) } } else { x = f(blank.Interface(), rv.Interface()) } m.SetMapIndex(k, reflect.ValueOf(x)) } for _, k := range left.MapKeys() { CombineAndSet(k) } for _, k := range right.MapKeys() { CombineAndSet(k) } result = m.Interface() case reflect.Slice: if map_type := left.Type(); map_type.Key().Kind() == reflect.Int { n := reflect.MakeMap(map_type) for i := 0; i < right.Len(); i++ { n.SetMapIndex(reflect.ValueOf(i), right.Index(i)) } result = combineValue(Left, n.Interface(), f) } } } } return }