Skip to content

Commit

Permalink
improve performance for slice functions
Browse files Browse the repository at this point in the history
  • Loading branch information
shockerli committed Sep 27, 2022
1 parent 3065c7f commit 6f63f08
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 56 deletions.
140 changes: 85 additions & 55 deletions slice.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,26 +28,35 @@ func SliceE(val interface{}) (sl []interface{}, err error) {

switch rv.Kind() {
case reflect.String:
for _, vvv := range rv.String() {
sl = append(sl, vvv)
var length = rv.Len()
if length > 0 {
sl = make([]interface{}, length)
for j, vvv := range rv.String() {
sl[j] = vvv
}
}
return
case reflect.Slice, reflect.Array:
for j := 0; j < rv.Len(); j++ {
sl = append(sl, rv.Index(j).Interface())
var length = rv.Len()
if length > 0 {
sl = make([]interface{}, length)
for j := 0; j < length; j++ {
sl[j] = rv.Index(j).Interface()
}
}
return
case reflect.Map:
for _, key := range sortedMapKeys(rv) {
sl = append(sl, rv.MapIndex(key).Interface())
var length = rv.Len()
if length > 0 {
sl = make([]interface{}, length)
for j, key := range sortedMapKeys(rv) {
sl[j] = rv.MapIndex(key).Interface()
}
}
return
case reflect.Struct:
sl = deepStructValues(rv)
return
default:
err = newErr(val, "slice")
}

return sl, newErr(val, "slice")
return
}

// SliceInt convert an interface to a []int type, with default value
Expand All @@ -70,13 +79,16 @@ func SliceIntE(val interface{}) (sl []int, err error) {
return
}

var vv int
for _, v := range list {
vv, err = IntE(v)
if err != nil {
return
if len(list) > 0 {
var vv int
sl = make([]int, len(list))
for j, v := range list {
vv, err = IntE(v)
if err != nil {
return
}
sl[j] = vv
}
sl = append(sl, vv)
}

return
Expand All @@ -102,13 +114,16 @@ func SliceInt64E(val interface{}) (sl []int64, err error) {
return
}

var vv int64
for _, v := range list {
vv, err = Int64E(v)
if err != nil {
return
if len(list) > 0 {
var vv int64
sl = make([]int64, len(list))
for j, v := range list {
vv, err = Int64E(v)
if err != nil {
return
}
sl[j] = vv
}
sl = append(sl, vv)
}

return
Expand All @@ -134,13 +149,16 @@ func SliceFloat64E(val interface{}) (sl []float64, err error) {
return
}

var vv float64
for _, v := range list {
vv, err = Float64E(v)
if err != nil {
return
if len(list) > 0 {
var vv float64
sl = make([]float64, len(list))
for j, v := range list {
vv, err = Float64E(v)
if err != nil {
return
}
sl[j] = vv
}
sl = append(sl, vv)
}

return
Expand All @@ -166,13 +184,16 @@ func SliceStringE(val interface{}) (sl []string, err error) {
return
}

var vv string
for _, v := range list {
vv, err = StringE(v)
if err != nil {
return
if len(list) > 0 {
var vv string
sl = make([]string, len(list))
for j, v := range list {
vv, err = StringE(v)
if err != nil {
return
}
sl[j] = vv
}
sl = append(sl, vv)
}

return
Expand All @@ -188,27 +209,28 @@ func ColumnsE(val interface{}, field interface{}) (sl []interface{}, err error)

switch rv.Kind() {
case reflect.Slice, reflect.Array:
var vv interface{}
for j := 0; j < rv.Len(); j++ {
vv, e := FieldE(rv.Index(j).Interface(), field)
if e == nil {
sl = append(sl, vv)
vv, err = FieldE(rv.Index(j).Interface(), field)
if err != nil {
return nil, fmt.Errorf("unsupported type: %s", rv.Type().String())
}
sl = append(sl, vv)
}
case reflect.Map:
var vv interface{}
for _, key := range sortedMapKeys(rv) {
vv, e := FieldE(rv.MapIndex(key).Interface(), field)
if e == nil {
sl = append(sl, vv)
vv, err = FieldE(rv.MapIndex(key).Interface(), field)
if err != nil {
return nil, fmt.Errorf("unsupported type: %s", rv.Type().String())
}
sl = append(sl, vv)
}
default:
return nil, fmt.Errorf("unsupported type: %s", rv.Type().String())
}

// non valid field value, means error
if len(sl) > 0 {
return
}

return nil, fmt.Errorf("unsupported type: %s", rv.Type().Name())
return
}

// KeysE return the keys of map, sorted by asc; or fields of struct
Expand All @@ -221,16 +243,24 @@ func KeysE(val interface{}) (sl []interface{}, err error) {

switch rv.Kind() {
case reflect.Map:
for _, key := range sortedMapKeys(rv) {
sl = append(sl, key.Interface())
var length = rv.Len()
if length > 0 {
sl = make([]interface{}, length)
for j, key := range sortedMapKeys(rv) {
sl[j] = key.Interface()
}
}
return
case reflect.Struct:
for _, v := range deepStructFields(rv.Type()) {
sl = append(sl, v)
fs := deepStructFields(rv.Type())
if len(fs) > 0 {
sl = make([]interface{}, len(fs))
for j, v := range fs {
sl[j] = v
}
}
return
default:
err = fmt.Errorf("unsupported type: %s", rv.Type().Name())
}

return nil, fmt.Errorf("unsupported type: %s", rv.Type().Name())
return
}
6 changes: 5 additions & 1 deletion slice_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -484,9 +484,10 @@ func TestColumnsE(t *testing.T) {
tests := []struct {
input interface{}
field interface{}
expect interface{}
expect []interface{}
isErr bool
}{
{[]interface{}{}, "empty", nil, false},
{[]interface{}{TestStructE{D1: 1, DD: &TestStructD{D1: 2}}}, "D1", []interface{}{1}, false},
{[]TestStructE{{D1: 1}, {D1: 2}}, "D1", []interface{}{1, 2}, false},
{[]TestStructE{{DD: &TestStructD{}}, {D1: 2}}, "DD", []interface{}{&TestStructD{}, (*TestStructD)(nil)}, false},
Expand All @@ -496,6 +497,7 @@ func TestColumnsE(t *testing.T) {
{map[int]TestStructD{1: {11}, 2: {22}}, "D1", []interface{}{11, 22}, false},

// errors
{[]int{1, 2, 3}, 888, nil, true},
{TestStructE{D1: 1, DD: &TestStructD{D1: 2}}, "", nil, true},
{TestStructE{D1: 1, DD: &TestStructD{D1: 2}}, "Age", nil, true},
{int(123), "Name", nil, true},
Expand Down Expand Up @@ -537,13 +539,15 @@ func TestKeysE(t *testing.T) {
isErr bool
}{
// map
{map[string]int{}, nil, false},
{map[int]map[string]interface{}{1: {"1": 111, "DDD": 12.3}, -2: {"2": 222, "DDD": "321"}, 3: {"DDD": nil}}, []interface{}{-2, 1, 3}, false},
{map[string]interface{}{"A": 1, "2": 2}, []interface{}{"2", "A"}, false},
{map[float64]float64{0.1: -0.1, -1.2: 1.2}, []interface{}{-1.2, 0.1}, false},
{map[float64]TestStructD{-1: {11}, 2: {22}}, []interface{}{float64(-1), float64(2)}, false},
{map[interface{}]interface{}{1: 1, 2.2: 2.22, "A": "A"}, []interface{}{1, 2.2, "A"}, false},

// struct
{struct{}{}, nil, false},
{TestStructA{}, []interface{}{"A1", "C1", "B1", "A2", "DD"}, false},
{&TestStructB{}, []interface{}{"C1", "B1"}, false},
{struct {
Expand Down

1 comment on commit 6f63f08

@vercel
Copy link

@vercel vercel bot commented on 6f63f08 Sep 27, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.