github.com/goki/ki@v1.1.11/kit/slices.go (about)

     1  // Copyright (c) 2018, The GoKi Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package kit
     6  
     7  import (
     8  	"fmt"
     9  	"log"
    10  	"reflect"
    11  	"sort"
    12  	"strings"
    13  	"time"
    14  
    15  	"github.com/goki/ki/floats"
    16  	"github.com/goki/ki/ints"
    17  )
    18  
    19  // This file contains helpful functions for dealing with slices, in the reflect
    20  // system
    21  
    22  // SliceElType returns the type of the elements for the given slice (which can be
    23  // a pointer to a slice or a direct slice) -- just Elem() of slice type, but using
    24  // this function makes it more explicit what is going on.  And it uses
    25  // OnePtrUnderlyingValue to get past any interface wrapping.
    26  func SliceElType(sl interface{}) reflect.Type {
    27  	return NonPtrValue(OnePtrUnderlyingValue(reflect.ValueOf(sl))).Type().Elem()
    28  }
    29  
    30  // SliceNewAt inserts a new blank element at given index in the slice -- -1
    31  // means the end
    32  func SliceNewAt(sl interface{}, idx int) {
    33  	sltyp := SliceElType(sl)
    34  	slptr := sltyp.Kind() == reflect.Ptr
    35  
    36  	svl := reflect.ValueOf(sl)
    37  	svnp := NonPtrValue(svl)
    38  
    39  	nval := reflect.New(NonPtrType(sltyp)) // make the concrete el
    40  	if !slptr {
    41  		nval = nval.Elem() // use concrete value
    42  	}
    43  	sz := svnp.Len()
    44  	svnp = reflect.Append(svnp, nval)
    45  	if idx >= 0 && idx < sz {
    46  		reflect.Copy(svnp.Slice(idx+1, sz+1), svnp.Slice(idx, sz))
    47  		svnp.Index(idx).Set(nval)
    48  	}
    49  	svl.Elem().Set(svnp)
    50  }
    51  
    52  // SliceDeleteAt deletes element at given index from slice
    53  func SliceDeleteAt(sl interface{}, idx int) {
    54  	svl := reflect.ValueOf(sl)
    55  	svnp := NonPtrValue(svl)
    56  	svtyp := svnp.Type()
    57  	nval := reflect.New(svtyp.Elem())
    58  	sz := svnp.Len()
    59  	reflect.Copy(svnp.Slice(idx, sz-1), svnp.Slice(idx+1, sz))
    60  	svnp.Index(sz - 1).Set(nval.Elem())
    61  	svl.Elem().Set(svnp.Slice(0, sz-1))
    62  }
    63  
    64  // SliceSort sorts a slice of basic values (see StructSliceSort for sorting a
    65  // slice-of-struct using a specific field), trying floats.Floater Float(),
    66  // ints.Inter Int(), interfaces first, and then falling back on reflect.Kind
    67  // float, int, string conversions (first fmt.Stringer String()) and supporting
    68  // time.Time directly as well.
    69  func SliceSort(sl interface{}, ascending bool) error {
    70  	sv := reflect.ValueOf(sl)
    71  	svnp := NonPtrValue(sv)
    72  	if svnp.Len() == 0 {
    73  		return nil
    74  	}
    75  	eltyp := SliceElType(sl)
    76  	elnptyp := NonPtrType(eltyp)
    77  	vk := elnptyp.Kind()
    78  	elval := OnePtrValue(svnp.Index(0))
    79  	elif := elval.Interface()
    80  
    81  	switch elif.(type) {
    82  	case floats.Floater:
    83  		sort.Slice(svnp.Interface(), func(i, j int) bool {
    84  			iv := NonPtrValue(svnp.Index(i)).Interface().(floats.Floater).Float()
    85  			jv := NonPtrValue(svnp.Index(j)).Interface().(floats.Floater).Float()
    86  			if ascending {
    87  				return iv < jv
    88  			}
    89  			return iv > jv
    90  		})
    91  		return nil
    92  	case ints.Inter:
    93  		sort.Slice(svnp.Interface(), func(i, j int) bool {
    94  			iv := NonPtrValue(svnp.Index(i)).Interface().(ints.Inter).Int()
    95  			jv := NonPtrValue(svnp.Index(j)).Interface().(ints.Inter).Int()
    96  			if ascending {
    97  				return iv < jv
    98  			}
    99  			return iv > jv
   100  		})
   101  		return nil
   102  	}
   103  
   104  	// try all the numeric types first!
   105  
   106  	switch {
   107  	case vk >= reflect.Int && vk <= reflect.Int64:
   108  		sort.Slice(svnp.Interface(), func(i, j int) bool {
   109  			iv := NonPtrValue(svnp.Index(i)).Int()
   110  			jv := NonPtrValue(svnp.Index(j)).Int()
   111  			if ascending {
   112  				return iv < jv
   113  			}
   114  			return iv > jv
   115  		})
   116  		return nil
   117  	case vk >= reflect.Uint && vk <= reflect.Uint64:
   118  		sort.Slice(svnp.Interface(), func(i, j int) bool {
   119  			iv := NonPtrValue(svnp.Index(i)).Uint()
   120  			jv := NonPtrValue(svnp.Index(j)).Uint()
   121  			if ascending {
   122  				return iv < jv
   123  			}
   124  			return iv > jv
   125  		})
   126  		return nil
   127  	case vk >= reflect.Float32 && vk <= reflect.Float64:
   128  		sort.Slice(svnp.Interface(), func(i, j int) bool {
   129  			iv := NonPtrValue(svnp.Index(i)).Float()
   130  			jv := NonPtrValue(svnp.Index(j)).Float()
   131  			if ascending {
   132  				return iv < jv
   133  			}
   134  			return iv > jv
   135  		})
   136  		return nil
   137  	case vk == reflect.Struct && ShortTypeName(elnptyp) == "time.Time":
   138  		sort.Slice(svnp.Interface(), func(i, j int) bool {
   139  			iv := NonPtrValue(svnp.Index(i)).Interface().(time.Time)
   140  			jv := NonPtrValue(svnp.Index(j)).Interface().(time.Time)
   141  			if ascending {
   142  				return iv.Before(jv)
   143  			}
   144  			return jv.Before(iv)
   145  		})
   146  	}
   147  
   148  	// this stringer case will likely pick up most of the rest
   149  	switch elif.(type) {
   150  	case fmt.Stringer:
   151  		sort.Slice(svnp.Interface(), func(i, j int) bool {
   152  			iv := NonPtrValue(svnp.Index(i)).Interface().(fmt.Stringer).String()
   153  			jv := NonPtrValue(svnp.Index(j)).Interface().(fmt.Stringer).String()
   154  			if ascending {
   155  				return iv < jv
   156  			}
   157  			return iv > jv
   158  		})
   159  		return nil
   160  	}
   161  
   162  	// last resort!
   163  	switch {
   164  	case vk == reflect.String:
   165  		sort.Slice(svnp.Interface(), func(i, j int) bool {
   166  			iv := NonPtrValue(svnp.Index(i)).String()
   167  			jv := NonPtrValue(svnp.Index(j)).String()
   168  			if ascending {
   169  				return strings.ToLower(iv) < strings.ToLower(jv)
   170  			}
   171  			return strings.ToLower(iv) > strings.ToLower(jv)
   172  		})
   173  		return nil
   174  	}
   175  
   176  	err := fmt.Errorf("SortSlice: unable to sort elements of type: %v", eltyp.String())
   177  	log.Println(err)
   178  	return err
   179  }
   180  
   181  // StructSliceSort sorts a slice of a struct according to the given field
   182  // indexes and sort direction, trying floats.Floater Float(), ints.Inter Int(),
   183  // interfaces first, and then falling back on reflect.Kind float, int, string
   184  // conversions (first fmt.Stringer String()) and supporting time.Time directly
   185  // as well.  There is no direct method for checking the field indexes so those
   186  // are assumed to be accurate -- will panic if not!
   187  func StructSliceSort(struSlice interface{}, fldIdx []int, ascending bool) error {
   188  	sv := reflect.ValueOf(struSlice)
   189  	svnp := NonPtrValue(sv)
   190  	if svnp.Len() == 0 {
   191  		return nil
   192  	}
   193  	struTyp := SliceElType(struSlice)
   194  	struNpTyp := NonPtrType(struTyp)
   195  	fld := struNpTyp.FieldByIndex(fldIdx) // not easy to check.
   196  	vk := fld.Type.Kind()
   197  	struVal := OnePtrValue(svnp.Index(0))
   198  	fldVal := struVal.Elem().FieldByIndex(fldIdx)
   199  	fldIf := fldVal.Interface()
   200  
   201  	switch fldIf.(type) {
   202  	case floats.Floater:
   203  		sort.Slice(svnp.Interface(), func(i, j int) bool {
   204  			ival := OnePtrValue(svnp.Index(i))
   205  			iv := ival.Elem().FieldByIndex(fldIdx).Interface().(floats.Floater).Float()
   206  			jval := OnePtrValue(svnp.Index(j))
   207  			jv := jval.Elem().FieldByIndex(fldIdx).Interface().(floats.Floater).Float()
   208  			if ascending {
   209  				return iv < jv
   210  			}
   211  			return iv > jv
   212  		})
   213  		return nil
   214  	case ints.Inter:
   215  		sort.Slice(svnp.Interface(), func(i, j int) bool {
   216  			ival := OnePtrValue(svnp.Index(i))
   217  			iv := ival.Elem().FieldByIndex(fldIdx).Interface().(ints.Inter).Int()
   218  			jval := OnePtrValue(svnp.Index(j))
   219  			jv := jval.Elem().FieldByIndex(fldIdx).Interface().(ints.Inter).Int()
   220  			if ascending {
   221  				return iv < jv
   222  			}
   223  			return iv > jv
   224  		})
   225  		return nil
   226  	}
   227  
   228  	// try all the numeric types first!
   229  
   230  	switch {
   231  	case vk >= reflect.Int && vk <= reflect.Int64:
   232  		sort.Slice(svnp.Interface(), func(i, j int) bool {
   233  			ival := OnePtrValue(svnp.Index(i))
   234  			iv := ival.Elem().FieldByIndex(fldIdx).Int()
   235  			jval := OnePtrValue(svnp.Index(j))
   236  			jv := jval.Elem().FieldByIndex(fldIdx).Int()
   237  			if ascending {
   238  				return iv < jv
   239  			}
   240  			return iv > jv
   241  		})
   242  		return nil
   243  	case vk >= reflect.Uint && vk <= reflect.Uint64:
   244  		sort.Slice(svnp.Interface(), func(i, j int) bool {
   245  			ival := OnePtrValue(svnp.Index(i))
   246  			iv := ival.Elem().FieldByIndex(fldIdx).Uint()
   247  			jval := OnePtrValue(svnp.Index(j))
   248  			jv := jval.Elem().FieldByIndex(fldIdx).Uint()
   249  			if ascending {
   250  				return iv < jv
   251  			}
   252  			return iv > jv
   253  		})
   254  		return nil
   255  	case vk >= reflect.Float32 && vk <= reflect.Float64:
   256  		sort.Slice(svnp.Interface(), func(i, j int) bool {
   257  			ival := OnePtrValue(svnp.Index(i))
   258  			iv := ival.Elem().FieldByIndex(fldIdx).Float()
   259  			jval := OnePtrValue(svnp.Index(j))
   260  			jv := jval.Elem().FieldByIndex(fldIdx).Float()
   261  			if ascending {
   262  				return iv < jv
   263  			}
   264  			return iv > jv
   265  		})
   266  		return nil
   267  	case vk == reflect.Struct && ShortTypeName(fld.Type) == "time.Time":
   268  		sort.Slice(svnp.Interface(), func(i, j int) bool {
   269  			ival := OnePtrValue(svnp.Index(i))
   270  			iv := ival.Elem().FieldByIndex(fldIdx).Interface().(time.Time)
   271  			jval := OnePtrValue(svnp.Index(j))
   272  			jv := jval.Elem().FieldByIndex(fldIdx).Interface().(time.Time)
   273  			if ascending {
   274  				return iv.Before(jv)
   275  			}
   276  			return jv.Before(iv)
   277  		})
   278  	}
   279  
   280  	// this stringer case will likely pick up most of the rest
   281  	switch fldIf.(type) {
   282  	case fmt.Stringer:
   283  		sort.Slice(svnp.Interface(), func(i, j int) bool {
   284  			ival := OnePtrValue(svnp.Index(i))
   285  			iv := ival.Elem().FieldByIndex(fldIdx).Interface().(fmt.Stringer).String()
   286  			jval := OnePtrValue(svnp.Index(j))
   287  			jv := jval.Elem().FieldByIndex(fldIdx).Interface().(fmt.Stringer).String()
   288  			if ascending {
   289  				return iv < jv
   290  			}
   291  			return iv > jv
   292  		})
   293  		return nil
   294  	}
   295  
   296  	// last resort!
   297  	switch {
   298  	case vk == reflect.String:
   299  		sort.Slice(svnp.Interface(), func(i, j int) bool {
   300  			ival := OnePtrValue(svnp.Index(i))
   301  			iv := ival.Elem().FieldByIndex(fldIdx).String()
   302  			jval := OnePtrValue(svnp.Index(j))
   303  			jv := jval.Elem().FieldByIndex(fldIdx).String()
   304  			if ascending {
   305  				return strings.ToLower(iv) < strings.ToLower(jv)
   306  			}
   307  			return strings.ToLower(iv) > strings.ToLower(jv)
   308  		})
   309  		return nil
   310  	}
   311  
   312  	err := fmt.Errorf("SortStructSlice: unable to sort on field of type: %v\n", fld.Type.String())
   313  	log.Println(err)
   314  	return err
   315  }
   316  
   317  // ValueSliceSort sorts a slice of reflect.Values using basic types where possible
   318  func ValueSliceSort(sl []reflect.Value, ascending bool) error {
   319  	if len(sl) == 0 {
   320  		return nil
   321  	}
   322  	felval := sl[0] // reflect.Value
   323  	eltyp := felval.Type()
   324  	elnptyp := NonPtrType(eltyp)
   325  	vk := elnptyp.Kind()
   326  	elval := OnePtrValue(felval)
   327  	elif := elval.Interface()
   328  
   329  	switch elif.(type) {
   330  	case floats.Floater:
   331  		sort.Slice(sl, func(i, j int) bool {
   332  			iv := NonPtrValue(sl[i]).Interface().(floats.Floater).Float()
   333  			jv := NonPtrValue(sl[j]).Interface().(floats.Floater).Float()
   334  			if ascending {
   335  				return iv < jv
   336  			}
   337  			return iv > jv
   338  		})
   339  		return nil
   340  	case ints.Inter:
   341  		sort.Slice(sl, func(i, j int) bool {
   342  			iv := NonPtrValue(sl[i]).Interface().(ints.Inter).Int()
   343  			jv := NonPtrValue(sl[j]).Interface().(ints.Inter).Int()
   344  			if ascending {
   345  				return iv < jv
   346  			}
   347  			return iv > jv
   348  		})
   349  		return nil
   350  	}
   351  
   352  	// try all the numeric types first!
   353  
   354  	switch {
   355  	case vk >= reflect.Int && vk <= reflect.Int64:
   356  		sort.Slice(sl, func(i, j int) bool {
   357  			iv := NonPtrValue(sl[i]).Int()
   358  			jv := NonPtrValue(sl[j]).Int()
   359  			if ascending {
   360  				return iv < jv
   361  			}
   362  			return iv > jv
   363  		})
   364  		return nil
   365  	case vk >= reflect.Uint && vk <= reflect.Uint64:
   366  		sort.Slice(sl, func(i, j int) bool {
   367  			iv := NonPtrValue(sl[i]).Uint()
   368  			jv := NonPtrValue(sl[j]).Uint()
   369  			if ascending {
   370  				return iv < jv
   371  			}
   372  			return iv > jv
   373  		})
   374  		return nil
   375  	case vk >= reflect.Float32 && vk <= reflect.Float64:
   376  		sort.Slice(sl, func(i, j int) bool {
   377  			iv := NonPtrValue(sl[i]).Float()
   378  			jv := NonPtrValue(sl[j]).Float()
   379  			if ascending {
   380  				return iv < jv
   381  			}
   382  			return iv > jv
   383  		})
   384  		return nil
   385  	case vk == reflect.Struct && ShortTypeName(elnptyp) == "time.Time":
   386  		sort.Slice(sl, func(i, j int) bool {
   387  			iv := NonPtrValue(sl[i]).Interface().(time.Time)
   388  			jv := NonPtrValue(sl[j]).Interface().(time.Time)
   389  			if ascending {
   390  				return iv.Before(jv)
   391  			}
   392  			return jv.Before(iv)
   393  		})
   394  	}
   395  
   396  	// this stringer case will likely pick up most of the rest
   397  	switch elif.(type) {
   398  	case fmt.Stringer:
   399  		sort.Slice(sl, func(i, j int) bool {
   400  			iv := NonPtrValue(sl[i]).Interface().(fmt.Stringer).String()
   401  			jv := NonPtrValue(sl[j]).Interface().(fmt.Stringer).String()
   402  			if ascending {
   403  				return iv < jv
   404  			}
   405  			return iv > jv
   406  		})
   407  		return nil
   408  	}
   409  
   410  	// last resort!
   411  	switch {
   412  	case vk == reflect.String:
   413  		sort.Slice(sl, func(i, j int) bool {
   414  			iv := NonPtrValue(sl[i]).String()
   415  			jv := NonPtrValue(sl[j]).String()
   416  			if ascending {
   417  				return strings.ToLower(iv) < strings.ToLower(jv)
   418  			}
   419  			return strings.ToLower(iv) > strings.ToLower(jv)
   420  		})
   421  		return nil
   422  	}
   423  
   424  	err := fmt.Errorf("ValueSliceSort: unable to sort elements of type: %v", eltyp.String())
   425  	log.Println(err)
   426  	return err
   427  }