github.com/Aoi-hosizora/ahlib@v1.5.1-0.20230404072829-241b93cf91c7/xslice/xslice_internal.go (about)

     1  package xslice
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  )
     7  
     8  // ==========
     9  // innerSlice
    10  // ==========
    11  
    12  // innerSlice represents an inner slice interface, implemented by interfaceItemSlice and interfaceWrappedSlice.
    13  type innerSlice interface {
    14  	// getter
    15  	actual() interface{}
    16  	length() int
    17  	capacity() int
    18  	get(index int) interface{}
    19  	slice(index1, index2 int) innerSlice
    20  	// setter
    21  	set(index int, item interface{})
    22  	insert(index int, items innerSlice)
    23  	remove(index int)
    24  	append(item interface{})
    25  }
    26  
    27  const (
    28  	panicIndexOutOfRange   = "xslice: index out of range"
    29  	panicInvalidInnerSlice = "xslice: innerSlice must be '%s' type (internal)"
    30  	panicInvalidItemType   = "xslice: cannot use item type '%s' to slice type '%s'"
    31  )
    32  
    33  // =========================
    34  // innerSlice: []interface{}
    35  // =========================
    36  
    37  // interfaceItemSlice represents a []interface{} slice.
    38  type interfaceItemSlice struct {
    39  	origin []interface{}
    40  }
    41  
    42  var _ innerSlice = (*interfaceItemSlice)(nil)
    43  
    44  func (i *interfaceItemSlice) actual() interface{} {
    45  	return i.origin
    46  }
    47  
    48  func (i *interfaceItemSlice) length() int {
    49  	return len(i.origin)
    50  }
    51  
    52  func (i *interfaceItemSlice) capacity() int {
    53  	return cap(i.origin)
    54  }
    55  
    56  func (i *interfaceItemSlice) get(index int) interface{} {
    57  	if index < 0 || index >= i.length() {
    58  		panic(panicIndexOutOfRange)
    59  	}
    60  	return i.origin[index]
    61  }
    62  
    63  func (i *interfaceItemSlice) slice(index1, index2 int) innerSlice {
    64  	if index1 < 0 || index2 < index1 || index2 > i.capacity() {
    65  		panic(panicIndexOutOfRange)
    66  	}
    67  	return &interfaceItemSlice{origin: i.origin[index1:index2]}
    68  }
    69  
    70  func (i *interfaceItemSlice) set(index int, item interface{}) {
    71  	if index < 0 || index >= i.length() {
    72  		panic(panicIndexOutOfRange)
    73  	}
    74  	i.origin[index] = item
    75  }
    76  
    77  func (i *interfaceItemSlice) insert(index int, items innerSlice) {
    78  	ii, ok := items.(*interfaceItemSlice)
    79  	if !ok {
    80  		panic(fmt.Sprintf(panicInvalidInnerSlice, reflect.TypeOf(i).String()))
    81  	}
    82  	if i.length() == 0 || index >= i.length() {
    83  		i.origin = append(i.origin, ii.origin...)
    84  		return
    85  	}
    86  	if index <= 0 {
    87  		index = 0
    88  	}
    89  	// i.origin = append(i.origin[:index], append(ii.origin, i.origin[index:]...)...)
    90  	expanded := append(i.origin, ii.origin...)
    91  	shifted := append(expanded[:index+len(ii.origin)], i.origin[index:]...)
    92  	copy(shifted[index:], ii.origin)
    93  	i.origin = shifted
    94  }
    95  
    96  func (i *interfaceItemSlice) remove(index int) {
    97  	if index < 0 || index >= i.length() {
    98  		panic(panicIndexOutOfRange)
    99  	}
   100  	if index == i.length()-1 {
   101  		i.origin = i.origin[:index]
   102  	} else {
   103  		i.origin = append(i.origin[:index], i.origin[index+1:]...)
   104  	}
   105  }
   106  
   107  func (i *interfaceItemSlice) append(item interface{}) {
   108  	i.origin = append(i.origin, item)
   109  }
   110  
   111  // ===============
   112  // innerSlice: []T
   113  // ===============
   114  
   115  // interfaceWrappedSlice represents a []T slice.
   116  type interfaceWrappedSlice struct {
   117  	val reflect.Value
   118  	typ reflect.Type
   119  }
   120  
   121  var _ innerSlice = (*interfaceWrappedSlice)(nil)
   122  
   123  func (i *interfaceWrappedSlice) actual() interface{} {
   124  	return i.val.Interface()
   125  }
   126  
   127  func (i *interfaceWrappedSlice) length() int {
   128  	return i.val.Len()
   129  }
   130  
   131  func (i *interfaceWrappedSlice) capacity() int {
   132  	return i.val.Cap()
   133  }
   134  
   135  func (i *interfaceWrappedSlice) get(index int) interface{} {
   136  	if index < 0 || index >= i.length() {
   137  		panic(panicIndexOutOfRange)
   138  	}
   139  	return i.val.Index(index).Interface()
   140  }
   141  
   142  func (i *interfaceWrappedSlice) slice(index1, index2 int) innerSlice {
   143  	if index1 < 0 || index2 < index1 || index2 > i.capacity() {
   144  		panic(panicIndexOutOfRange)
   145  	}
   146  	return &interfaceWrappedSlice{typ: i.typ, val: i.val.Slice(index1, index2)}
   147  }
   148  
   149  func (i *interfaceWrappedSlice) set(index int, item interface{}) {
   150  	if index < 0 || index >= i.length() {
   151  		panic(panicIndexOutOfRange)
   152  	}
   153  	i.val.Index(index).Set(i.checkInterfaceItem(item))
   154  }
   155  
   156  func (i *interfaceWrappedSlice) insert(index int, items innerSlice) {
   157  	ii, ok := items.(*interfaceWrappedSlice)
   158  	if !ok {
   159  		panic(fmt.Sprintf(panicInvalidInnerSlice, reflect.TypeOf(i).String()))
   160  	}
   161  	if i.length() == 0 || index >= i.length() {
   162  		i.val = reflect.AppendSlice(i.val, ii.val)
   163  		return
   164  	}
   165  	if index <= 0 {
   166  		index = 0
   167  	}
   168  	expanded := reflect.AppendSlice(i.val, ii.val)
   169  	shifted := reflect.AppendSlice(expanded.Slice(0, index+ii.length()), i.val.Slice(index, i.length()))
   170  	reflect.Copy(shifted.Slice(index, shifted.Len()), ii.val)
   171  	i.val = shifted
   172  	// i.val = reflect.AppendSlice(i.val.Slice(0, index), reflect.AppendSlice(ii.val, i.val.Slice(index, i.length())))
   173  }
   174  
   175  func (i *interfaceWrappedSlice) remove(index int) {
   176  	if index < 0 || index >= i.length() {
   177  		panic(panicIndexOutOfRange)
   178  	}
   179  	if index == i.length()-1 {
   180  		i.val = i.val.Slice(0, index)
   181  	} else {
   182  		l, r := i.val.Slice(0, index), i.val.Slice(index+1, i.length())
   183  		i.val = reflect.AppendSlice(l, r)
   184  	}
   185  }
   186  
   187  func (i *interfaceWrappedSlice) append(item interface{}) {
   188  	i.val = reflect.Append(i.val, i.checkInterfaceItem(item))
   189  }
   190  
   191  func (i *interfaceWrappedSlice) checkInterfaceItem(item interface{}) reflect.Value {
   192  	itemVal := reflect.ValueOf(item)
   193  	if !itemVal.IsValid() {
   194  		itemVal = reflect.Zero(i.typ.Elem())
   195  	}
   196  	if itemTyp := itemVal.Type(); itemTyp != i.typ.Elem() {
   197  		panic(fmt.Sprintf(panicInvalidItemType, itemTyp.String(), i.typ.String()))
   198  	}
   199  	return itemVal
   200  }
   201  
   202  // ==========
   203  // checkParam
   204  // ==========
   205  
   206  const (
   207  	panicNilSliceInterface      = "xslice: nil slice interface"
   208  	panicNonSliceInterface      = "xslice: non-slice interface, got '%s'"
   209  	panicDifferentSlicesType    = "xslice: different types of two slices, got '%s' and '%s'"
   210  	panicDifferentSliceElemType = "xslice: different types of slice and element, got '%s' and '%s'"
   211  )
   212  
   213  // checkInterfaceSliceParam checks []interface{} parameter and returns innerSlice.
   214  func checkInterfaceSliceParam(slice []interface{}) innerSlice {
   215  	if slice == nil {
   216  		slice = make([]interface{}, 0, 0)
   217  	}
   218  	return &interfaceItemSlice{origin: slice}
   219  }
   220  
   221  // checkSliceInterfaceParam checks []T from interface{} parameter and returns innerSlice.
   222  func checkSliceInterfaceParam(slice interface{}) innerSlice {
   223  	if slice == nil {
   224  		panic(panicNilSliceInterface)
   225  	}
   226  	val := reflect.ValueOf(slice)
   227  	typ := val.Type()
   228  	if typ.Kind() != reflect.Slice {
   229  		panic(fmt.Sprintf(panicNonSliceInterface, typ.String()))
   230  	}
   231  	if val.IsNil() {
   232  		val = reflect.MakeSlice(typ, 0, 0)
   233  	}
   234  
   235  	return &interfaceWrappedSlice{val: val, typ: typ}
   236  }
   237  
   238  // checkTwoSliceInterfaceParam checks two []T from interface{} parameter and returns two innerSlice.
   239  func checkTwoSliceInterfaceParam(slice1, slice2 interface{}) (innerSlice, innerSlice) {
   240  	i1 := checkSliceInterfaceParam(slice1).(*interfaceWrappedSlice)
   241  	i2 := checkSliceInterfaceParam(slice2).(*interfaceWrappedSlice)
   242  	if i1.typ != i2.typ {
   243  		panic(fmt.Sprintf(panicDifferentSlicesType, i1.typ.String(), i2.typ.String()))
   244  	}
   245  	return i1, i2
   246  }
   247  
   248  // checkSliceInterfaceAndElemParam checks []T from interface{} parameter with element and returns innerSlice with element value.
   249  func checkSliceInterfaceAndElemParam(slice, value interface{}) (innerSlice, interface{}) {
   250  	i := checkSliceInterfaceParam(slice).(*interfaceWrappedSlice)
   251  	valVal := reflect.ValueOf(value)
   252  	if !valVal.IsValid() {
   253  		valVal = reflect.Zero(i.typ.Elem())
   254  	}
   255  	if valTyp := valVal.Type(); valTyp != i.typ.Elem() {
   256  		panic(fmt.Sprintf(panicDifferentSliceElemType, i.typ.String(), valTyp.String()))
   257  	}
   258  	return i, valVal.Interface()
   259  }
   260  
   261  // ======================
   262  // cloneSlice & makeSlice
   263  // ======================
   264  
   265  // cloneInterfaceSlice clones a []interface{} slice.
   266  func cloneInterfaceSlice(slice []interface{}) []interface{} {
   267  	newSlice := make([]interface{}, len(slice), cap(slice))
   268  	for idx, item := range slice {
   269  		newSlice[idx] = item
   270  	}
   271  	return newSlice
   272  }
   273  
   274  // cloneSliceInterface clones a []T slice.
   275  func cloneSliceInterface(slice interface{}) interface{} {
   276  	if slice == nil {
   277  		panic(panicNilSliceInterface)
   278  	}
   279  	val := reflect.ValueOf(slice)
   280  	typ := val.Type()
   281  	if typ.Kind() != reflect.Slice {
   282  		panic(fmt.Sprintf(panicNonSliceInterface, typ.String()))
   283  	}
   284  
   285  	newSliceVal := reflect.MakeSlice(typ, val.Len(), val.Cap())
   286  	for idx := 0; idx < val.Len(); idx++ {
   287  		newSliceVal.Index(idx).Set(val.Index(idx))
   288  	}
   289  	return newSliceVal.Interface()
   290  }
   291  
   292  // cloneSliceInterface clones a []T slice from a []interface{} slice, using given fromSlice type.
   293  func cloneSliceInterfaceFromInterfaceSlice(slice []interface{}, fromSlice interface{}) interface{} {
   294  	if fromSlice == nil {
   295  		panic(panicNilSliceInterface)
   296  	}
   297  	sliceVal := reflect.ValueOf(fromSlice)
   298  	sliceTyp := sliceVal.Type()
   299  	if sliceTyp.Kind() != reflect.Slice {
   300  		panic(fmt.Sprintf(panicNonSliceInterface, sliceTyp.String()))
   301  	}
   302  	sliceElemTyp := sliceTyp.Elem()
   303  
   304  	newSliceVal := reflect.MakeSlice(sliceTyp, len(slice), cap(slice))
   305  	for idx, item := range slice {
   306  		itemVal := reflect.ValueOf(item)
   307  		if !itemVal.IsValid() {
   308  			itemVal = reflect.Zero(sliceElemTyp)
   309  		}
   310  		if !(sliceElemTyp.Kind() == reflect.Interface && sliceElemTyp.NumMethod() == 0) { // fromSlice is not []interface{}
   311  			if itemTyp := itemVal.Type(); itemTyp != sliceElemTyp {
   312  				panic(fmt.Sprintf(panicDifferentSliceElemType, sliceTyp.String(), itemTyp.String()))
   313  			}
   314  		}
   315  		newSliceVal.Index(idx).Set(itemVal)
   316  	}
   317  	return newSliceVal.Interface()
   318  }
   319  
   320  const (
   321  	panicNilTypeForCreation = "xslice: nil slice or item type for creation (internal)"
   322  )
   323  
   324  // makeSameTypeInnerSlice creates a new innerSlice by given innerSlice type.
   325  func makeSameTypeInnerSlice(sliceType innerSlice, length, capacity int) innerSlice {
   326  	if length < 0 {
   327  		length = 0
   328  	}
   329  	if capacity < length {
   330  		capacity = length
   331  	}
   332  
   333  	if sliceType == nil {
   334  		panic(panicNilTypeForCreation)
   335  	}
   336  	if slice, ok := sliceType.(*interfaceWrappedSlice); ok {
   337  		newSlice := reflect.MakeSlice(slice.typ, length, capacity).Interface()
   338  		return checkSliceInterfaceParam(newSlice)
   339  	}
   340  	newSlice := make([]interface{}, length, capacity)
   341  	return checkInterfaceSliceParam(newSlice)
   342  }
   343  
   344  // makeItemTypeInnerSlice creates a new innerSlice by given item type.
   345  func makeItemTypeInnerSlice(itemType interface{}, length, capacity int, g bool) innerSlice {
   346  	if length < 0 {
   347  		length = 0
   348  	}
   349  	if capacity < length {
   350  		capacity = length
   351  	}
   352  
   353  	if g {
   354  		if itemType == nil {
   355  			panic(panicNilTypeForCreation)
   356  		}
   357  		newSlice := reflect.MakeSlice(reflect.SliceOf(reflect.TypeOf(itemType)), length, capacity).Interface()
   358  		return checkSliceInterfaceParam(newSlice)
   359  	}
   360  	newSlice := make([]interface{}, length, capacity)
   361  	return checkInterfaceSliceParam(newSlice)
   362  }
   363  
   364  // cloneInnerSliceItems clones an innerSlice slice.
   365  func cloneInnerSliceItems(slice innerSlice, extraCap int) innerSlice {
   366  	if slice == nil {
   367  		panic(panicNilTypeForCreation)
   368  	}
   369  	if extraCap < 0 {
   370  		extraCap = 0
   371  	}
   372  	newSlice := makeSameTypeInnerSlice(slice, slice.length(), slice.capacity()+extraCap)
   373  	for idx := 0; idx < slice.length(); idx++ {
   374  		newSlice.set(idx, slice.get(idx))
   375  	}
   376  	return newSlice
   377  }
   378  
   379  // =============
   380  // sortableSlice
   381  // =============
   382  
   383  // sortableSlice wraps innerSlice and implements sort.Interface.
   384  type sortableSlice struct {
   385  	slice innerSlice
   386  	less  func(i, j interface{}) bool // Note: this field is different from sort.Slice's less parameter
   387  }
   388  
   389  func (s sortableSlice) Len() int {
   390  	return s.slice.length()
   391  }
   392  
   393  func (s sortableSlice) Swap(i, j int) {
   394  	itemI, itemJ := s.slice.get(i), s.slice.get(j)
   395  	s.slice.set(i, itemJ)
   396  	s.slice.set(j, itemI)
   397  }
   398  
   399  func (s sortableSlice) Less(i, j int) bool {
   400  	return s.less(s.slice.get(i), s.slice.get(j))
   401  }