github.com/jxskiss/gopkg@v0.17.3/easy/slice.go (about) 1 package easy 2 3 import ( 4 "fmt" 5 "reflect" 6 "strconv" 7 "strings" 8 "unsafe" 9 10 "github.com/jxskiss/gopkg/internal/unsafeheader" 11 "github.com/jxskiss/gopkg/reflectx" 12 ) 13 14 const ( 15 maxInsertGrowth = 1024 16 ) 17 18 //nolint:unused 19 const ( 20 errNotSliceType = "not slice type" 21 errNotSliceOfInt = "not a slice of integers" 22 errElemTypeNotMatchSlice = "elem type does not match slice" 23 errElemNotStructOrPointer = "elem is not struct or pointer to struct" 24 errStructFieldNotProvided = "struct field is not provided" 25 errStructFieldNotExists = "struct field not exists" 26 errStructFieldIsNotInt = "struct field is not integer or pointer" 27 errStructFieldIsNotStr = "struct field is not string or pointer" 28 ) 29 30 func panicNilParams(where string, params ...interface{}) { 31 for i := 0; i < len(params); i += 2 { 32 arg := params[i].(string) 33 val := params[i+1] 34 if val == nil { 35 panic(fmt.Sprintf("%s: param %s is nil interface", where, arg)) 36 } 37 } 38 } 39 40 func assertSliceOfIntegers(where string, sliceTyp reflect.Type) { 41 if sliceTyp.Kind() != reflect.Slice || !reflectx.IsIntType(sliceTyp.Elem().Kind()) { 42 panic(where + ":" + errNotSliceOfInt) 43 } 44 } 45 46 func assertSliceAndElemType(where string, sliceVal reflect.Value, elemTyp reflect.Type) (reflect.Value, bool) { 47 if sliceVal.Kind() != reflect.Slice { 48 panic(where + ": " + errNotSliceType) 49 } 50 intTypeNotMatch := false 51 sliceTyp := sliceVal.Type() 52 if elemTyp != sliceTyp.Elem() { 53 // int-family 54 if reflectx.IsIntType(sliceTyp.Elem().Kind()) && 55 reflectx.IsIntType(elemTyp.Kind()) { 56 intTypeNotMatch = true 57 } else { 58 panic(where + ": " + errElemTypeNotMatchSlice) 59 } 60 } 61 return sliceVal, intTypeNotMatch 62 } 63 64 func assertSliceElemStructAndField(where string, sliceTyp reflect.Type, field string) reflect.StructField { 65 if field == "" { 66 panic(where + ": " + errStructFieldNotProvided) 67 } 68 if sliceTyp.Kind() != reflect.Slice { 69 panic(where + ": " + errNotSliceType) 70 } 71 elemTyp := sliceTyp.Elem() 72 elemIsPtr := elemTyp.Kind() == reflect.Ptr 73 if !(elemTyp.Kind() == reflect.Struct || 74 (elemIsPtr && elemTyp.Elem().Kind() == reflect.Struct)) { 75 panic(where + ": " + errElemNotStructOrPointer) 76 } 77 var fieldInfo reflect.StructField 78 var ok bool 79 if elemIsPtr { 80 fieldInfo, ok = elemTyp.Elem().FieldByName(field) 81 } else { 82 fieldInfo, ok = elemTyp.FieldByName(field) 83 } 84 if !ok { 85 panic(where + ": " + errStructFieldNotExists) 86 } 87 return fieldInfo 88 } 89 90 // InSlice is reserved for a generic implementation. 91 92 // InSliceFunc iterates the given slice, it calls predicate(i) for i in range [0, n) 93 // where n is the length of the slice. 94 // When predicate(i) returns true, it stops and returns true. 95 // 96 // The parameter predicate must be not nil, otherwise it panics. 97 func InSliceFunc(slice interface{}, predicate func(i int) bool) bool { 98 if slice == nil { 99 return false 100 } 101 sliceTyp := reflect.TypeOf(slice) 102 if sliceTyp.Kind() != reflect.Slice { 103 panic("InSliceFunc: " + errNotSliceType) 104 } 105 _, header := reflectx.UnpackSlice(slice) 106 for i := 0; i < header.Len; i++ { 107 if predicate(i) { 108 return true 109 } 110 } 111 return false 112 } 113 114 // InInt32s tells whether the int32 value elem is in the slice. 115 func InInt32s(slice []int32, elem int32) bool { 116 for _, x := range slice { 117 if x == elem { 118 return true 119 } 120 } 121 return false 122 } 123 124 // InInt64s tells whether the int64 value elem is in the slice. 125 func InInt64s(slice []int64, elem int64) bool { 126 for _, x := range slice { 127 if x == elem { 128 return true 129 } 130 } 131 return false 132 } 133 134 // InStrings tells whether the string value elem is in the slice. 135 func InStrings(slice []string, elem string) bool { 136 for _, x := range slice { 137 if elem == x { 138 return true 139 } 140 } 141 return false 142 } 143 144 // Index is reserved for a generic implementation. 145 146 // IndexFunc iterates the given slice, it calls predicate(i) for i in 147 // range [0, n) where n is the length of the slice. 148 // When predicate(i) returns true, it stops and returns the index i. 149 // 150 // The parameter predicate must not be nil, otherwise it panics. 151 func IndexFunc(slice interface{}, predicate func(i int) bool) int { 152 if slice == nil { 153 return -1 154 } 155 sliceTyp := reflect.TypeOf(slice) 156 if sliceTyp.Kind() != reflect.Slice { 157 panic("IndexFunc: " + errNotSliceType) 158 } 159 _, header := reflectx.UnpackSlice(slice) 160 for i := 0; i < header.Len; i++ { 161 if predicate(i) { 162 return i 163 } 164 } 165 return -1 166 } 167 168 // IndexInt32s returns the index of the first instance of elem slice, 169 // or -1 if elem is not present in slice. 170 func IndexInt32s(slice []int32, elem int32) int { 171 for i := 0; i < len(slice); i++ { 172 if elem == slice[i] { 173 return i 174 } 175 } 176 return -1 177 } 178 179 // IndexInt64s returns the index of the first instance of elem in slice, 180 // or -1 if elem is not present in slice. 181 func IndexInt64s(slice []int64, elem int64) int { 182 for i := 0; i < len(slice); i++ { 183 if elem == slice[i] { 184 return i 185 } 186 } 187 return -1 188 } 189 190 // IndexStrings returns the index of the first instance of elem in slice, 191 // or -1 if elem is not present in slice. 192 func IndexStrings(slice []string, elem string) int { 193 for i := 0; i < len(slice); i++ { 194 if elem == slice[i] { 195 return i 196 } 197 } 198 return -1 199 } 200 201 // LastIndex is reserved for a generic implementation. 202 203 // LastIndexFunc iterates the given slice, it calls predicate(i) for i in 204 // range [0, n) in descending order, where n is the length of the slice. 205 // When predicate(i) returns true, it stops and returns the index i. 206 // 207 // The parameter predicate must not be nil, otherwise it panics. 208 func LastIndexFunc(slice interface{}, predicate func(i int) bool) int { 209 if slice == nil { 210 return -1 211 } 212 sliceTyp := reflect.TypeOf(slice) 213 if sliceTyp.Kind() != reflect.Slice { 214 panic("LastIndexFunc: " + errNotSliceType) 215 } 216 _, header := reflectx.UnpackSlice(slice) 217 for i := header.Len - 1; i >= 0; i-- { 218 if predicate(i) { 219 return i 220 } 221 } 222 return -1 223 } 224 225 // LastIndexInt32s returns the index of the last instance of elem in slice, 226 // or -1 if elem is not present in slice. 227 func LastIndexInt32s(slice []int32, elem int32) int { 228 for i := len(slice) - 1; i >= 0; i-- { 229 if elem == slice[i] { 230 return i 231 } 232 } 233 return -1 234 } 235 236 // LastIndexInt64s returns the index of the last instance of elem in slice, 237 // or -1 if elem is not present in slice. 238 func LastIndexInt64s(slice []int64, elem int64) int { 239 for i := len(slice) - 1; i >= 0; i-- { 240 if elem == slice[i] { 241 return i 242 } 243 } 244 return -1 245 } 246 247 // LastIndexStrings returns the index of the last instance of elem in slice, 248 // or -1 if elem is not present in slice. 249 func LastIndexStrings(slice []string, elem string) int { 250 for i := len(slice) - 1; i >= 0; i-- { 251 if elem == slice[i] { 252 return i 253 } 254 } 255 return -1 256 } 257 258 // InsertSlice is reserved for a generic implementation. 259 260 // InsertInt32s inserts the given int32 elem into the slice at index position. 261 // If index is equal or greater than the length of slice, the elem will be 262 // appended to the end of the slice. In case the slice is full of it's 263 // capacity, a new slice will be created and returned. 264 func InsertInt32s(slice []int32, index int, elem int32) (out []int32) { 265 if index >= len(slice) { 266 return append(slice, elem) 267 } 268 oldLen := len(slice) 269 if len(slice) == cap(slice) { 270 // capacity not enough, grow the slice 271 newCap := oldLen + min(max(1, oldLen), maxInsertGrowth) 272 out = make([]int32, oldLen+1, newCap) 273 copy(out, slice[:index]) 274 } else { 275 out = slice[:oldLen+1] 276 } 277 copy(out[index+1:], slice[index:]) 278 out[index] = elem 279 return 280 } 281 282 // InsertInt64s inserts the given int64 elem into the slice at index position. 283 // If index is equal or greater than the length of slice, the elem will be 284 // appended to the end of the slice. In case the slice is full of it's 285 // capacity, a new slice will be created and returned. 286 func InsertInt64s(slice []int64, index int, elem int64) (out []int64) { 287 if index >= len(slice) { 288 return append(slice, elem) 289 } 290 oldLen := len(slice) 291 if len(slice) == cap(slice) { 292 // capacity not enough, grow the slice 293 newCap := oldLen + min(max(1, oldLen), maxInsertGrowth) 294 out = make([]int64, oldLen+1, newCap) 295 copy(out, slice[:index]) 296 } else { 297 out = slice[:oldLen+1] 298 } 299 copy(out[index+1:], slice[index:]) 300 out[index] = elem 301 return 302 } 303 304 // InsertStrings inserts the given string elem into the slice at index position. 305 // If index is equal or greater than the length of slice, the elem will be 306 // appended to the end of the slice. In case the slice is full of it's 307 // capacity, a new slice will be created and returned. 308 func InsertStrings(slice []string, index int, elem string) (out []string) { 309 if index >= len(slice) { 310 return append(slice, elem) 311 } 312 oldLen := len(slice) 313 if len(slice) == cap(slice) { 314 // capacity not enough, grow the slice 315 newCap := oldLen + min(max(1, oldLen), maxInsertGrowth) 316 out = make([]string, oldLen+1, newCap) 317 copy(out, slice[:index]) 318 } else { 319 out = slice[:oldLen+1] 320 } 321 copy(out[index+1:], slice[index:]) 322 out[index] = elem 323 return 324 } 325 326 // Reverse is reserved for a generic implementation. 327 328 // ReverseSlice returns a new slice containing the elements of the given 329 // slice in reversed order. 330 // 331 // When inplace is true, the slice is reversed in place, it does not create 332 // a new slice, but returns the original slice with reversed order. 333 // 334 // The given slice must be not nil, otherwise it panics. 335 func ReverseSlice(slice interface{}, inplace bool) interface{} { 336 if slice == nil { 337 panicNilParams("ReverseSlice", "slice", slice) 338 } 339 sliceTyp := reflect.TypeOf(slice) 340 if sliceTyp.Kind() != reflect.Slice { 341 panic("ReverseSlice: " + errNotSliceType) 342 } 343 344 _, srcHeader := reflectx.UnpackSlice(slice) 345 length := srcHeader.Len 346 elemTyp := sliceTyp.Elem() 347 elemRType := reflectx.ToRType(elemTyp) 348 elemSize := elemRType.Size() 349 350 outSlice, outHeader := slice, srcHeader 351 if !inplace { 352 outSlice, outHeader = reflectx.MakeSlice(elemTyp, length, length) 353 reflectx.TypedSliceCopy(elemRType, *outHeader, *srcHeader) 354 } 355 tmp := reflect.New(elemTyp).Elem().Interface() 356 swap := reflectx.EfaceOf(&tmp).Word 357 for i, mid := 0, length/2; i < mid; i++ { 358 j := length - i - 1 359 pi := reflectx.ArrayAt(outHeader.Data, i, elemSize) 360 pj := reflectx.ArrayAt(outHeader.Data, j, elemSize) 361 reflectx.TypedMemMove(elemRType, swap, pi) 362 reflectx.TypedMemMove(elemRType, pi, pj) 363 reflectx.TypedMemMove(elemRType, pj, swap) 364 } 365 return outSlice 366 } 367 368 // ReverseInt32s returns a new slice of the elements in reversed order. 369 // 370 // When inplace is true, the slice is reversed in place, it does not create 371 // a new slice, but returns the original slice with reversed order. 372 func ReverseInt32s(slice []int32, inplace bool) []int32 { 373 length := len(slice) 374 out := slice 375 if !inplace { 376 out = make([]int32, length) 377 copy(out, slice) 378 } 379 for i, mid := 0, length/2; i < mid; i++ { 380 j := length - i - 1 381 out[i], out[j] = out[j], out[i] 382 } 383 return out 384 } 385 386 // ReverseInt64s returns a new slice of the elements in reversed order. 387 // 388 // When inplace is true, the slice is reversed in place, it does not create 389 // a new slice, but returns the original slice with reversed order. 390 func ReverseInt64s(slice []int64, inplace bool) []int64 { 391 length := len(slice) 392 out := slice 393 if !inplace { 394 out = make([]int64, length) 395 copy(out, slice) 396 } 397 for i, mid := 0, length/2; i < mid; i++ { 398 j := length - i - 1 399 out[i], out[j] = out[j], out[i] 400 } 401 return out 402 } 403 404 // ReverseStrings returns a new slice of the elements in reversed order. 405 // 406 // When inplace is true, the slice is reversed in place, it does not create 407 // a new slice, but returns the original slice with reversed order. 408 func ReverseStrings(slice []string, inplace bool) []string { 409 length := len(slice) 410 out := slice 411 if !inplace { 412 out = make([]string, length) 413 copy(out, slice) 414 } 415 for i, mid := 0, length/2; i < mid; i++ { 416 j := length - i - 1 417 out[i], out[j] = out[j], out[i] 418 } 419 return out 420 } 421 422 // UniqueSlice is reserved for a generic implementation. 423 424 // UniqueInt32s returns a new slice containing the elements of the given 425 // slice in same order, but filter out duplicate values. 426 // 427 // When inplace is true, it does not create a new slice, the unique values 428 // will be written to the input slice from the beginning. 429 func UniqueInt32s(slice []int32, inplace bool) []int32 { 430 seen := make(map[int32]struct{}) 431 out := slice[:0] 432 if !inplace { 433 out = make([]int32, 0) 434 } 435 for _, x := range slice { 436 if _, ok := seen[x]; ok { 437 continue 438 } 439 seen[x] = struct{}{} 440 out = append(out, x) 441 } 442 return out 443 } 444 445 // UniqueInt64s returns a new slice containing the elements of the given 446 // slice in same order, but filter out duplicate values. 447 // 448 // When inplace is true, it does not create a new slice, the unique values 449 // will be written to the input slice from the beginning. 450 func UniqueInt64s(slice []int64, inplace bool) []int64 { 451 seen := make(map[int64]struct{}) 452 out := slice[:0] 453 if !inplace { 454 out = make([]int64, 0) 455 } 456 for _, x := range slice { 457 if _, ok := seen[x]; ok { 458 continue 459 } 460 seen[x] = struct{}{} 461 out = append(out, x) 462 } 463 return out 464 } 465 466 // UniqueStrings returns a new slice containing the elements of the given 467 // slice in same order, but filter out duplicate values. 468 // 469 // When inplace is true, it does not create a new slice, the unique values 470 // will be written to the input slice from the beginning. 471 func UniqueStrings(slice []string, inplace bool) []string { 472 seen := make(map[string]struct{}) 473 out := slice[:0] 474 if !inplace { 475 out = make([]string, 0) 476 } 477 for _, x := range slice { 478 if _, ok := seen[x]; ok { 479 continue 480 } 481 seen[x] = struct{}{} 482 out = append(out, x) 483 } 484 return out 485 } 486 487 // DiffSlice is reserved for a generic implementation. 488 489 // DiffInt32s returns a new int32 slice containing the values which present 490 // in slice a but not present in slice b. 491 func DiffInt32s(a []int32, b []int32) []int32 { 492 bset := make(map[int32]struct{}, len(b)) 493 for _, x := range b { 494 bset[x] = struct{}{} 495 } 496 out := make([]int32, 0) 497 for _, x := range a { 498 if _, ok := bset[x]; !ok { 499 out = append(out, x) 500 } 501 } 502 return out 503 } 504 505 // DiffInt64s returns a new int64 slice containing the values which present 506 // in slice a but not present in slice b. 507 func DiffInt64s(a []int64, b []int64) []int64 { 508 bset := make(map[int64]struct{}, len(b)) 509 for _, x := range b { 510 bset[x] = struct{}{} 511 } 512 out := make([]int64, 0) 513 for _, x := range a { 514 if _, ok := bset[x]; !ok { 515 out = append(out, x) 516 } 517 } 518 return out 519 } 520 521 // DiffStrings returns a new string slice containing the values which 522 // present in slice a but not present in slice b. 523 func DiffStrings(a []string, b []string) []string { 524 bset := make(map[string]struct{}, len(b)) 525 for _, x := range b { 526 bset[x] = struct{}{} 527 } 528 out := make([]string, 0) 529 for _, x := range a { 530 if _, ok := bset[x]; !ok { 531 out = append(out, x) 532 } 533 } 534 return out 535 } 536 537 // ToMap converts the given slice of struct (or pointer to struct) to a map, 538 // with the field specified by keyField as key and the slice element as value. 539 // 540 // If slice is nil, keyField does not exists or the element of slice is not 541 // struct or pointer to struct, it panics. 542 func ToMap(slice interface{}, keyField string) interface{} { 543 if slice == nil { 544 panicNilParams("ToMap", "slice", slice) 545 } 546 sliceVal := reflect.ValueOf(slice) 547 sliceTyp := sliceVal.Type() 548 fieldInfo := assertSliceElemStructAndField("ToMap", sliceTyp, keyField) 549 keyTyp := fieldInfo.Type 550 if keyTyp.Kind() == reflect.Ptr { 551 keyTyp = keyTyp.Elem() 552 } 553 554 elemTyp := sliceTyp.Elem() 555 outVal := reflect.MakeMapWithSize(reflect.MapOf(keyTyp, elemTyp), sliceVal.Len()) 556 for i := 0; i < sliceVal.Len(); i++ { 557 elem := sliceVal.Index(i) 558 fieldVal := reflect.Indirect(reflect.Indirect(elem).FieldByName(keyField)) 559 outVal.SetMapIndex(fieldVal, elem) 560 } 561 return outVal.Interface() 562 } 563 564 // ToSliceMap converts the given slice of struct (or pointer to struct) to a map, 565 // with the field specified by keyField as key and a slice of elements which have 566 // same key as value. 567 // 568 // If slice is nil, keyField does not exists or the element of slice is not 569 // struct or pointer to struct, it panics. 570 func ToSliceMap(slice interface{}, keyField string) interface{} { 571 if slice == nil { 572 panicNilParams("ToSliceMap", "slice", slice) 573 } 574 sliceVal := reflect.ValueOf(slice) 575 sliceTyp := sliceVal.Type() 576 fieldInfo := assertSliceElemStructAndField("ToSliceMap", sliceTyp, keyField) 577 keyTyp := fieldInfo.Type 578 if keyTyp.Kind() == reflect.Ptr { 579 keyTyp = keyTyp.Elem() 580 } 581 582 elemTyp := sliceTyp.Elem() 583 elemSliceTyp := reflect.SliceOf(elemTyp) 584 outVal := reflect.MakeMap(reflect.MapOf(keyTyp, elemSliceTyp)) 585 for i := sliceVal.Len() - 1; i >= 0; i-- { 586 elem := sliceVal.Index(i) 587 fieldVal := reflect.Indirect(reflect.Indirect(elem).FieldByName(keyField)) 588 elemSlice := outVal.MapIndex(fieldVal) 589 if !elemSlice.IsValid() { 590 elemSlice = reflect.MakeSlice(elemSliceTyp, 0, 1) 591 } 592 elemSlice = reflect.Append(elemSlice, elem) 593 outVal.SetMapIndex(fieldVal, elemSlice) 594 } 595 return outVal.Interface() 596 } 597 598 // ToMapMap converts the given slice of struct (or pointer to struct) to a map, 599 // with the field specified by keyField as key. 600 // The returned map's value is another map with the field specified by 601 // subKeyField as key and thee slice element as value. 602 // 603 // If slice is nil, keyField or subKeyField does not exists or the element of 604 // slice is not struct or pointer to struct, it panics. 605 func ToMapMap(slice interface{}, keyField, subKeyField string) interface{} { 606 if slice == nil { 607 panicNilParams("ToMapMap", "slice", slice) 608 } 609 sliceVal := reflect.ValueOf(slice) 610 sliceTyp := sliceVal.Type() 611 fieldInfo1 := assertSliceElemStructAndField("ToMapMap", sliceTyp, keyField) 612 fieldInfo2 := assertSliceElemStructAndField("ToMapMap", sliceTyp, subKeyField) 613 keyTyp1 := fieldInfo1.Type 614 if keyTyp1.Kind() == reflect.Ptr { 615 keyTyp1 = keyTyp1.Elem() 616 } 617 keyTyp2 := fieldInfo2.Type 618 if keyTyp2.Kind() == reflect.Ptr { 619 keyTyp2 = keyTyp2.Elem() 620 } 621 622 elemTyp := sliceTyp.Elem() 623 elemMapTyp := reflect.MapOf(keyTyp2, elemTyp) 624 outVal := reflect.MakeMap(reflect.MapOf(keyTyp1, elemMapTyp)) 625 for i := sliceVal.Len() - 1; i >= 0; i-- { 626 elem := sliceVal.Index(i) 627 fieldVal1 := reflect.Indirect(reflect.Indirect(elem).FieldByName(keyField)) 628 fieldVal2 := reflect.Indirect(reflect.Indirect(elem).FieldByName(subKeyField)) 629 elemMap := outVal.MapIndex(fieldVal1) 630 if !elemMap.IsValid() { 631 elemMap = reflect.MakeMap(elemMapTyp) 632 outVal.SetMapIndex(fieldVal1, elemMap) 633 } 634 elemMap.SetMapIndex(fieldVal2, elem) 635 } 636 return outVal.Interface() 637 } 638 639 // ToInterfaceSlice returns a []interface{} containing elements from slice. 640 func ToInterfaceSlice(slice interface{}) []interface{} { 641 if slice == nil { 642 return nil 643 } 644 sliceTyp := reflect.TypeOf(slice) 645 if sliceTyp.Kind() != reflect.Slice { 646 panic("ToInterfaceSlice: " + errNotSliceType) 647 } 648 sliceVal := reflect.ValueOf(slice) 649 out := make([]interface{}, 0, sliceVal.Len()) 650 for i := 0; i < sliceVal.Len(); i++ { 651 elem := sliceVal.Index(i).Interface() 652 out = append(out, elem) 653 } 654 return out 655 } 656 657 // Find is reserved for a generic implementation. 658 659 // FindFunc returns the first element in the slice for which predicate returns true. 660 func FindFunc(slice interface{}, predicate func(i int) bool) interface{} { 661 if slice == nil { 662 return nil 663 } 664 sliceTyp := reflect.TypeOf(slice) 665 if sliceTyp.Kind() != reflect.Slice { 666 panic("FindFunc: " + errNotSliceType) 667 } 668 _, header := reflectx.UnpackSlice(slice) 669 for i := 0; i < header.Len; i++ { 670 if predicate(i) { 671 return reflect.ValueOf(slice).Index(i).Interface() 672 } 673 } 674 return nil 675 } 676 677 // Filter is reserved for a generic implementation. 678 679 // FilterFunc iterates the given slice, it calls predicate(i) for i in 680 // range [0, n), where n is the length of the slice. 681 // It returns a new slice of elements for which predicate(i) returns true. 682 // 683 // The parameter slice and predicate must not be nil, otherwise it panics. 684 func FilterFunc(slice interface{}, predicate func(i int) bool) interface{} { 685 if slice == nil { 686 panicNilParams("FilterFunc", "slice", slice) 687 } 688 sliceTyp := reflect.TypeOf(slice) 689 if sliceTyp.Kind() != reflect.Slice { 690 panic("FilterFunc: " + errNotSliceType) 691 } 692 693 sliceVal := reflect.ValueOf(slice) 694 length := sliceVal.Len() 695 outVal := reflect.MakeSlice(sliceVal.Type(), 0, max(length/4+1, 4)) 696 for i := 0; i < length; i++ { 697 if predicate(i) { 698 elem := sliceVal.Index(i) 699 outVal = reflect.Append(outVal, elem) 700 } 701 } 702 return outVal.Interface() 703 } 704 705 // FilterInt32s iterates the given slice, it calls predicate(i) for i in 706 // range [0, n), where n is the length of the slice. 707 // It returns a new slice of elements for which predicate(i) returns true. 708 func FilterInt32s(slice []int32, predicate func(i int) bool) []int32 { 709 length := len(slice) 710 out := make([]int32, 0, max(length/4+1, 4)) 711 for i := 0; i < length; i++ { 712 if predicate(i) { 713 out = append(out, slice[i]) 714 } 715 } 716 return out 717 } 718 719 // FilterInt64s iterates the given slice, it calls predicate(i) for i in 720 // range [0, n), where n is the length of the slice. 721 // It returns a new slice of elements for which predicate(i) returns true. 722 func FilterInt64s(slice []int64, predicate func(i int) bool) []int64 { 723 length := len(slice) 724 out := make([]int64, 0, max(length/4+1, 4)) 725 for i := 0; i < length; i++ { 726 if predicate(i) { 727 out = append(out, slice[i]) 728 } 729 } 730 return out 731 } 732 733 // FilterStrings iterates the given slice, it calls predicate(i) for i in 734 // range [0, n), where n is the length of the slice. 735 // It returns a new slice of elements for which predicate(i) returns true. 736 func FilterStrings(slice []string, predicate func(i int) bool) []string { 737 length := len(slice) 738 out := make([]string, 0, max(length/4+1, 4)) 739 for i := 0; i < length; i++ { 740 if predicate(i) { 741 out = append(out, slice[i]) 742 } 743 } 744 return out 745 } 746 747 // SumSlice returns the sum value of the elements in the given slice. 748 // If slice is nil or it's elements are not integers, it panics. 749 func SumSlice(slice interface{}) int64 { 750 if slice == nil { 751 panicNilParams("SumSlice", "slice", slice) 752 } 753 sliceTyp := reflect.TypeOf(slice) 754 assertSliceOfIntegers("SumSlice", sliceTyp) 755 756 var sum int64 757 elemTyp := sliceTyp.Elem() 758 elemKind := elemTyp.Kind() 759 elemSize := elemTyp.Size() 760 _, header := reflectx.UnpackSlice(slice) 761 for i := 0; i < header.Len; i++ { 762 ptr := reflectx.ArrayAt(header.Data, i, elemSize) 763 sum += reflectx.CastIntPointer(elemKind, ptr) 764 } 765 return sum 766 } 767 768 // ParseInt64s parses a number string separated by sep into a []int64 slice. 769 // If there is invalid number value, it reports malformed = true as the 770 // second return value. 771 func ParseInt64s(values, sep string, ignoreZero bool) (slice []int64, malformed bool) { 772 values = strings.TrimSpace(values) 773 values = strings.Trim(values, sep) 774 segments := strings.Split(values, sep) 775 slice = make([]int64, 0, len(segments)) 776 for _, x := range segments { 777 id, err := strconv.ParseInt(x, 10, 64) 778 if err != nil { 779 malformed = true 780 continue 781 } 782 if id == 0 && ignoreZero { 783 continue 784 } 785 slice = append(slice, id) 786 } 787 return 788 } 789 790 // JoinInt64s returns a string consisting of slice elements separated by sep. 791 func JoinInt64s(slice []int64, sep string) string { 792 if len(slice) == 0 { 793 return "" 794 } 795 if len(slice) == 1 { 796 return strconv.FormatInt(slice[0], 10) 797 } 798 var buf []byte 799 buf = strconv.AppendInt(buf, slice[0], 10) 800 for _, x := range slice[1:] { 801 buf = append(buf, sep...) 802 buf = strconv.AppendInt(buf, x, 10) 803 } 804 return unsafeheader.BytesToString(buf) 805 } 806 807 // IJ represents a slice index of I, J. 808 type IJ struct{ I, J int } 809 810 // SplitBatch splits a large number to batches, it's mainly designed to 811 // help operations with large slice, such as inserting lots of records 812 // into database, or logging lots of identifiers, etc. 813 func SplitBatch(total, batch int) []IJ { 814 if total <= 0 { 815 return nil 816 } 817 if batch <= 0 { 818 return []IJ{{0, total}} 819 } 820 n := total/batch + 1 821 ret := make([]IJ, n) 822 idx := 0 823 for i, j := 0, batch; idx < n && i < total; i, j = i+batch, j+batch { 824 if j > total { 825 j = total 826 } 827 ret[idx] = IJ{i, j} 828 idx++ 829 } 830 return ret[:idx] 831 } 832 833 // Split is reserved for a generic implementation. 834 835 // SplitSlice splits a large slice []T to batches, it returns a slice 836 // of slice of type [][]T. 837 // 838 // The given slice must not be nil, otherwise it panics. 839 func SplitSlice(slice interface{}, batch int) interface{} { 840 if slice == nil { 841 panicNilParams("SplitSlice", "slice", slice) 842 } 843 sliceTyp := reflectx.RTypeOf(slice) 844 if sliceTyp.Kind() != reflect.Slice { 845 panic("SplitSlice: " + errNotSliceType) 846 } 847 848 _, sliceHeader := reflectx.UnpackSlice(slice) 849 indexes := SplitBatch(sliceHeader.Len, batch) 850 elemTyp := sliceTyp.Elem() 851 elemSize := elemTyp.Size() 852 out := make([]reflectx.SliceHeader, len(indexes)) 853 for i, idx := range indexes { 854 subSlice := _takeSlice(sliceHeader.Data, elemSize, idx.I, idx.J) 855 out[i] = subSlice 856 } 857 858 outTyp := reflectx.SliceOf(sliceTyp) 859 return outTyp.PackInterface(unsafe.Pointer(&out)) 860 } 861 862 func _takeSlice(base unsafe.Pointer, elemSize uintptr, i, j int) (slice reflectx.SliceHeader) { 863 if length := j - i; length > 0 { 864 slice.Data = reflectx.ArrayAt(base, i, elemSize) 865 slice.Len = length 866 slice.Cap = length 867 } 868 return 869 } 870 871 // SplitInt64s splits a large int64 slice to batches. 872 func SplitInt64s(slice []int64, batch int) [][]int64 { 873 indexes := SplitBatch(len(slice), batch) 874 out := make([][]int64, len(indexes)) 875 for i, idx := range indexes { 876 out[i] = slice[idx.I:idx.J] 877 } 878 return out 879 } 880 881 // SplitInt32s splits a large int32 slice to batches. 882 func SplitInt32s(slice []int32, batch int) [][]int32 { 883 indexes := SplitBatch(len(slice), batch) 884 out := make([][]int32, len(indexes)) 885 for i, idx := range indexes { 886 out[i] = slice[idx.I:idx.J] 887 } 888 return out 889 } 890 891 // SplitStrings splits a large string slice to batches. 892 func SplitStrings(slice []string, batch int) [][]string { 893 indexes := SplitBatch(len(slice), batch) 894 out := make([][]string, len(indexes)) 895 for i, idx := range indexes { 896 out[i] = slice[idx.I:idx.J] 897 } 898 return out 899 } 900 901 func isIntTypeOrPtr(typ reflect.Type) bool { 902 if reflectx.IsIntType(typ.Kind()) || 903 (typ.Kind() == reflect.Ptr && reflectx.IsIntType(typ.Elem().Kind())) { 904 return true 905 } 906 return false 907 } 908 909 func isStringTypeOrPtr(typ reflect.Type) bool { 910 return typ.Kind() == reflect.String || 911 (typ.Kind() == reflect.Ptr && typ.Elem().Kind() == reflect.String) 912 } 913 914 func min(a, b int) int { 915 if a < b { 916 return a 917 } 918 return b 919 } 920 921 func max(a, b int) int { 922 if a > b { 923 return a 924 } 925 return b 926 }