diff options
Diffstat (limited to 'utilities')
| -rw-r--r-- | utilities/utilities.go | 55 | ||||
| -rw-r--r-- | utilities/utilities_test.go | 23 |
2 files changed, 78 insertions, 0 deletions
diff --git a/utilities/utilities.go b/utilities/utilities.go index 7b96bef..d4303ec 100644 --- a/utilities/utilities.go +++ b/utilities/utilities.go @@ -20,6 +20,8 @@ import ( "math/rand" "os" "reflect" + "sort" + "strings" "sync/atomic" "time" ) @@ -129,3 +131,56 @@ func Max(x, y uint64) uint64 { } return y } + +func ChannelToSlice[S any](channel <-chan S) (slice []S) { + slice = make([]S, 0) + for element := range channel { + slice = append(slice, element) + } + return +} + +func Fmap[S any, F any](elements []S, mapper func(S) F) []F { + result := make([]F, 0) + for _, s := range elements { + result = append(result, mapper(s)) + } + return result +} + +func CalculatePercentile[S float32 | int32 | float64 | int64](elements []S, percentile int) S { + sort.Slice(elements, func(a, b int) bool { return elements[a] < elements[b] }) + elementsCount := len(elements) + percentileIdx := elementsCount * (percentile / 100) + return elements[percentileIdx] +} + +func OrTimeout(f func(), timeout time.Duration) { + completeChannel := func() chan interface{} { + completed := make(chan interface{}) + go func() { + // This idea taken from https://stackoverflow.com/a/32843750. + // Closing the channel will let the read of it proceed immediately. + // Making that operation a defer ensures that it will happen even if + // the function f panics during its execution. + defer close(completed) + f() + }() + return completed + }() + select { + case _ = <-completeChannel: + break + case _ = <-time.After(timeout): + break + } +} + +func FilenameAppend(filename, appendage string) string { + pieces := strings.SplitN(filename, ".", 2) + result := pieces[0] + appendage + if len(pieces) > 1 { + result = result + "." + strings.Join(pieces[1:], ".") + } + return result +} diff --git a/utilities/utilities_test.go b/utilities/utilities_test.go index 72a11fb..703243c 100644 --- a/utilities/utilities_test.go +++ b/utilities/utilities_test.go @@ -37,3 +37,26 @@ func TestReadAfterCloseOnBufferedChannel(t *testing.T) { t.Fatalf("Did not read all sent items from a buffered channel after channel.") } } + +func TestOrTimeoutStopsInfiniteLoop(t *testing.T) { + const TimeoutTime = 2 * time.Second + infinity := func() { + for { + } + } + timeBefore := time.Now() + OrTimeout(infinity, TimeoutTime) + timeAfter := time.Now() + if timeAfter.Sub(timeBefore) < TimeoutTime { + t.Fatalf("OrTimeout failed to keep the infinite loop running for at least %v.", TimeoutTime) + } +} + +func TestFilenameAppend(t *testing.T) { + const basename = "testing.csv" + const expected = "testing-appended.csv" + result := FilenameAppend(basename, "-appended") + if expected != result { + t.Fatalf("%s != %s for FilenameAppend.", expected, result) + } +} |
