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 }