gotosocial/vendor/codeberg.org/gruf/go-split/join.go

113 lines
3.7 KiB
Go
Raw Normal View History

package split
import (
"strconv"
"time"
"unsafe"
"codeberg.org/gruf/go-bytesize"
)
// joinFunc will join given slice of elements, using the passed function to append each element at index
// from the slice, forming a combined comma-space separated string. Passed size is for buffer preallocation.
func JoinFunc[T any](slice []T, each func(buf []byte, value T) []byte, size int) string {
// Move nil check
// outside main loop.
if each == nil {
panic("nil func")
}
// Catch easiest case
if len(slice) == 0 {
return ""
}
// Preallocate string buffer (size + commas)
buf := make([]byte, 0, size+len(slice)-1)
for _, value := range slice {
// Append each item
buf = each(buf, value)
buf = append(buf, ',', ' ')
}
// Drop final comma-space
buf = buf[:len(buf)-2]
// Directly cast buf to string
data := unsafe.SliceData(buf)
return unsafe.String(data, len(buf))
}
// JoinStrings will pass string slice to JoinFunc(), quoting where
// necessary and combining into a single comma-space separated string.
func JoinStrings[String ~string](slice []String) string {
var size int
for _, str := range slice {
size += len(str)
}
return JoinFunc(slice, func(buf []byte, value String) []byte {
return appendQuote(buf, string(value))
}, size)
}
// JoinBools will pass bool slice to JoinFunc(), formatting
// and combining into a single comma-space separated string.
func JoinBools[Bool ~bool](slice []Bool) string {
return JoinFunc(slice, func(buf []byte, value Bool) []byte {
return strconv.AppendBool(buf, bool(value))
}, len(slice)*5 /* len("false") */)
}
// JoinInts will pass signed integer slice to JoinFunc(), formatting
// and combining into a single comma-space separated string.
func JoinInts[Int Signed](slice []Int) string {
return JoinFunc(slice, func(buf []byte, value Int) []byte {
return strconv.AppendInt(buf, int64(value), 10)
}, len(slice)*20) // max signed int str len
}
// JoinUints will pass unsigned integer slice to JoinFunc(),
// formatting and combining into a single comma-space separated string.
func JoinUints[Uint Unsigned](slice []Uint) string {
return JoinFunc(slice, func(buf []byte, value Uint) []byte {
return strconv.AppendUint(buf, uint64(value), 10)
}, len(slice)*20) // max unsigned int str len
}
// JoinFloats will pass float slice to JoinFunc(), formatting
// and combining into a single comma-space separated string.
func JoinFloats[Float_ Float](slice []Float_) string {
bits := int(unsafe.Sizeof(Float_(0)) * 8) // param type bits
return JoinFunc(slice, func(buf []byte, value Float_) []byte {
return strconv.AppendFloat(buf, float64(value), 'g', -1, bits)
}, len(slice)*20) // max signed int str len (it's a good guesstimate)
}
// JoinSizes will pass byte size slice to JoinFunc(), formatting
// and combining into a single comma-space separated string.
func JoinSizes(slice []bytesize.Size) string {
const iecLen = 7 // max IEC string length
return JoinFunc(slice, func(buf []byte, value bytesize.Size) []byte {
return value.AppendFormatIEC(buf)
}, len(slice)*iecLen)
}
// JoinDurations will pass duration slice to JoinFunc(), formatting
// and combining into a single comma-space separated string.
func JoinDurations(slice []time.Duration) string {
const durLen = 10 // max duration string length
return JoinFunc(slice, func(buf []byte, value time.Duration) []byte {
return append(buf, value.String()...)
}, len(slice)*durLen)
}
// JoinTimes will pass time slice to JoinFunc(), formatting
// and combining into a single comma-space separated string.
func JoinTimes(slice []time.Time, format string) string {
return JoinFunc(slice, func(buf []byte, value time.Time) []byte {
return value.AppendFormat(buf, format)
}, len(slice)*len(format))
}