mirror of
https://github.com/aykhans/go-utils.git
synced 2025-10-16 02:35:58 +00:00
first commit
This commit is contained in:
92
slice/slice.go
Normal file
92
slice/slice.go
Normal file
@@ -0,0 +1,92 @@
|
||||
package slice
|
||||
|
||||
import (
|
||||
"math/rand/v2"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Cycle returns a function that cycles through the provided items infinitely.
|
||||
// Each call to the returned function returns the next item in sequence, wrapping
|
||||
// back to the first item after the last one is returned.
|
||||
//
|
||||
// If no items are provided, the returned function will always return the zero
|
||||
// value for type T.
|
||||
//
|
||||
// The returned function is not safe for concurrent use. If you need to call it
|
||||
// from multiple goroutines, you must synchronize access with a mutex or similar.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// next := Cycle(1, 2, 3)
|
||||
// fmt.Println(next()) // 1
|
||||
// fmt.Println(next()) // 2
|
||||
// fmt.Println(next()) // 3
|
||||
// fmt.Println(next()) // 1
|
||||
func Cycle[T any](items ...T) func() T {
|
||||
if len(items) == 0 {
|
||||
var zero T
|
||||
return func() T { return zero }
|
||||
}
|
||||
|
||||
index := 0
|
||||
return func() T {
|
||||
item := items[index]
|
||||
index = (index + 1) % len(items)
|
||||
return item
|
||||
}
|
||||
}
|
||||
|
||||
// RandomCycle returns a function that cycles through the provided items with
|
||||
// randomization. It cycles through all items sequentially, but when it completes
|
||||
// a full cycle, it randomly picks a new starting point for the next cycle.
|
||||
//
|
||||
// The localRand parameter can be used to provide a custom random number generator.
|
||||
// If nil, a new generator will be created using the current time as the seed.
|
||||
//
|
||||
// The returned function is not safe for concurrent use. If you need to call it
|
||||
// from multiple goroutines, you must synchronize access with a mutex or similar.
|
||||
//
|
||||
// Special cases:
|
||||
// - If no items are provided, the returned function always returns the zero value for type T.
|
||||
// - If only one item is provided, the returned function always returns that item.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// next := RandomCycle(nil, "a", "b", "c")
|
||||
// // Might produce: "b", "c", "a", "c", "a", "b", ...
|
||||
// // (cycles through all items, then starts from a random position)
|
||||
func RandomCycle[T any](localRand *rand.Rand, items ...T) func() T {
|
||||
switch sliceLen := len(items); sliceLen {
|
||||
case 0:
|
||||
var zero T
|
||||
return func() T { return zero }
|
||||
case 1:
|
||||
return func() T { return items[0] }
|
||||
default:
|
||||
if localRand == nil {
|
||||
//nolint:gosec
|
||||
localRand = rand.New(
|
||||
rand.NewPCG(
|
||||
uint64(time.Now().UnixNano()),
|
||||
uint64(time.Now().UnixNano()>>32),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
currentIndex := localRand.IntN(sliceLen)
|
||||
stopIndex := currentIndex
|
||||
return func() T {
|
||||
item := items[currentIndex]
|
||||
currentIndex++
|
||||
if currentIndex == sliceLen {
|
||||
currentIndex = 0
|
||||
}
|
||||
if currentIndex == stopIndex {
|
||||
currentIndex = localRand.IntN(sliceLen)
|
||||
stopIndex = currentIndex
|
||||
}
|
||||
|
||||
return item
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user