diff --git a/encrypt.go b/encrypt.go index 78b21f4..d1aa3b2 100644 --- a/encrypt.go +++ b/encrypt.go @@ -14,7 +14,7 @@ import ( "hash/fnv" "io" - "github.com/andeya/ameda" + "github.com/andeya/goutil/internal/ameda" ) // Md5 returns the MD5 checksum string of the data. diff --git a/internal/ameda/.gitignore b/internal/ameda/.gitignore new file mode 100644 index 0000000..6857290 --- /dev/null +++ b/internal/ameda/.gitignore @@ -0,0 +1,21 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +vendor/ + +*.sublime-project +*.sublime-workspace +.DS_Store +.idea +*.zip diff --git a/internal/ameda/LICENSE b/internal/ameda/LICENSE new file mode 100644 index 0000000..c27cf3a --- /dev/null +++ b/internal/ameda/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 andeya + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/internal/ameda/README.md b/internal/ameda/README.md new file mode 100644 index 0000000..523070c --- /dev/null +++ b/internal/ameda/README.md @@ -0,0 +1,7 @@ +# ameda [![report card](https://goreportcard.com/badge/github.com/henrylee2cn/ameda?style=flat-square)](http://goreportcard.com/report/henrylee2cn/ameda) [![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg?style=flat-square)](http://godoc.org/github.com/henrylee2cn/ameda) + +Powerful toolbox for golang data types. + +Yeah! + +**It is recommended to use [gust](https://github.com/andeya/gust) instead!** diff --git a/internal/ameda/atoi62.go b/internal/ameda/atoi62.go new file mode 100644 index 0000000..f2dba9b --- /dev/null +++ b/internal/ameda/atoi62.go @@ -0,0 +1,249 @@ +package ameda + +import ( + "errors" + "math" + "strconv" +) + +// ParseUint is like ParseInt but for unsigned numbers. +// NOTE: +// Compatible with standard package strconv. +func ParseUint(s string, base int, bitSize int) (uint64, error) { + // Ignore letter case + if base <= 36 { + return strconv.ParseUint(s, base, bitSize) + } + + const fnParseUint = "ParseUint" + + if base > 62 { + return 0, baseError(fnParseUint, s, base) + } + + if s == "" || !underscoreOK(s) { + return 0, syntaxError(fnParseUint, s) + } + + if bitSize == 0 { + bitSize = int(strconv.IntSize) + } else if bitSize < 0 || bitSize > 64 { + return 0, bitSizeError(fnParseUint, s, bitSize) + } + + // Cutoff is the smallest number such that cutoff*base > maxUint64. + // Use compile-time constants for common cases. + cutoff := math.MaxUint64/uint64(base) + 1 + + maxVal := uint64(1)<= byte(base) { + return 0, syntaxError(fnParseUint, s) + } + + if n >= cutoff { + // n*base overflows + return maxVal, rangeError(fnParseUint, s) + } + n *= uint64(base) + + n1 := n + uint64(d) + if n1 < n || n1 > maxVal { + // n+v overflows + return maxVal, rangeError(fnParseUint, s) + } + n = n1 + } + + return n, nil +} + +// ParseInt interprets a string s in the given base (0, 2 to 62) and +// bit size (0 to 64) and returns the corresponding value i. +// +// If base == 0, the base is implied by the string's prefix: +// base 2 for "0b", base 8 for "0" or "0o", base 16 for "0x", +// and base 10 otherwise. Also, for base == 0 only, underscore +// characters are permitted per the Go integer literal syntax. +// If base is below 0, is 1, or is above 62, an error is returned. +// +// The bitSize argument specifies the integer type +// that the result must fit into. Bit sizes 0, 8, 16, 32, and 64 +// correspond to int, int8, int16, int32, and int64. +// If bitSize is below 0 or above 64, an error is returned. +// +// The errors that ParseInt returns have concrete type *NumError +// and include err.Num = s. If s is empty or contains invalid +// digits, err.Err = ErrSyntax and the returned value is 0; +// if the value corresponding to s cannot be represented by a +// signed integer of the given size, err.Err = ErrRange and the +// returned value is the maximum magnitude integer of the +// appropriate bitSize and sign. +// NOTE: +// Compatible with standard package strconv. +func ParseInt(s string, base int, bitSize int) (i int64, err error) { + // Ignore letter case + if base <= 36 { + return strconv.ParseInt(s, base, bitSize) + } + + const fnParseInt = "ParseInt" + + if s == "" { + return 0, syntaxError(fnParseInt, s) + } + + // Pick off leading sign. + s0 := s + neg := false + if s[0] == '+' { + s = s[1:] + } else if s[0] == '-' { + neg = true + s = s[1:] + } + + // Convert unsigned and check range. + var un uint64 + un, err = ParseUint(s, base, bitSize) + if err != nil && err.(*strconv.NumError).Err != strconv.ErrRange { + err.(*strconv.NumError).Func = fnParseInt + err.(*strconv.NumError).Num = s0 + return 0, err + } + + if bitSize == 0 { + bitSize = int(strconv.IntSize) + } + + cutoff := uint64(1 << uint(bitSize-1)) + if !neg && un >= cutoff { + return int64(cutoff - 1), rangeError(fnParseInt, s0) + } + if neg && un > cutoff { + return -int64(cutoff), rangeError(fnParseInt, s0) + } + n := int64(un) + if neg { + n = -n + } + return n, nil +} + +// underscoreOK reports whether the underscores in s are allowed. +// Checking them in this one function lets all the parsers skip over them simply. +// Underscore must appear only between digits or between a base prefix and a digit. +func underscoreOK(s string) bool { + // saw tracks the last character (class) we saw: + // ^ for beginning of number, + // 0 for a digit or base prefix, + // _ for an underscore, + // ! for none of the above. + saw := '^' + i := 0 + + // Optional sign. + if len(s) >= 1 && (s[0] == '-' || s[0] == '+') { + s = s[1:] + } + + // Optional base prefix. + if len(s) >= 2 && s[0] == '0' && (lower(s[1]) == 'b' || lower(s[1]) == 'o' || lower(s[1]) == 'x') { + i = 2 + saw = '0' // base prefix counts as a digit for "underscore as digit separator" + } + + // Number proper. + for ; i < len(s); i++ { + // Digits are always okay. + if '0' <= s[i] && s[i] <= '9' || 'a' <= lower(s[i]) && lower(s[i]) <= 'z' { + saw = '0' + continue + } + // Underscore must follow digit. + if s[i] == '_' { + if saw != '0' { + return false + } + saw = '_' + continue + } + // Saw non-digit, non-underscore. + return false + } + return true +} + +// Atoi is equivalent to ParseInt(s, 10, 0), converted to type int. +func Atoi(s string) (int, error) { + const fnAtoi = "Atoi" + + sLen := len(s) + if strconv.IntSize == 32 && (0 < sLen && sLen < 10) || + strconv.IntSize == 64 && (0 < sLen && sLen < 19) { + // Fast path for small integers that fit int type. + s0 := s + if s[0] == '-' || s[0] == '+' { + s = s[1:] + if len(s) < 1 { + return 0, &strconv.NumError{fnAtoi, s0, strconv.ErrSyntax} + } + } + + n := 0 + for _, ch := range []byte(s) { + ch -= '0' + if ch > 9 { + return 0, &strconv.NumError{fnAtoi, s0, strconv.ErrSyntax} + } + n = n*10 + int(ch) + } + if s0[0] == '-' { + n = -n + } + return n, nil + } + + // Slow path for invalid, big, or underscored integers. + i64, err := ParseInt(s, 10, 0) + if nerr, ok := err.(*strconv.NumError); ok { + nerr.Func = fnAtoi + } + return int(i64), err +} + +// lower(c) is a lower-case letter if and only if +// c is either that lower-case letter or the equivalent upper-case letter. +// Instead of writing c == 'x' || c == 'X' one can write lower(c) == 'x'. +// Note that lower of non-letters can produce other non-letters. +func lower(c byte) byte { + return c | ('x' - 'X') +} +func syntaxError(fn, str string) *strconv.NumError { + return &strconv.NumError{fn, str, strconv.ErrSyntax} +} +func baseError(fn, str string, base int) *strconv.NumError { + return &strconv.NumError{fn, str, errors.New("invalid base " + strconv.Itoa(base))} +} +func rangeError(fn, str string) *strconv.NumError { + return &strconv.NumError{fn, str, strconv.ErrRange} +} +func bitSizeError(fn, str string, bitSize int) *strconv.NumError { + return &strconv.NumError{fn, str, errors.New("invalid bit size " + strconv.Itoa(bitSize))} +} diff --git a/internal/ameda/atoi_x.go b/internal/ameda/atoi_x.go new file mode 100644 index 0000000..221d110 --- /dev/null +++ b/internal/ameda/atoi_x.go @@ -0,0 +1,27 @@ +package ameda + +import ( + "bytes" + "errors" + "fmt" + "math" +) + +// ParseUintByDict convert numStr into corresponding uint64 according to dict. +func ParseUintByDict(dict []byte, numStr string) (uint64, error) { + if len(dict) == 0 { + return 0, errors.New("dict is empty") + } + base := float64(len(dict)) + len := len(numStr) + var number float64 + for i := 0; i < len; i++ { + char := numStr[i : i+1] + pos := bytes.IndexAny(dict, char) + if pos == -1 { + return 0, fmt.Errorf("found a char not included in the dict: %q", char) + } + number = math.Pow(base, float64(len-i-1))*float64(pos) + number + } + return uint64(number), nil +} diff --git a/internal/ameda/bool.go b/internal/ameda/bool.go new file mode 100644 index 0000000..ed12802 --- /dev/null +++ b/internal/ameda/bool.go @@ -0,0 +1,200 @@ +package ameda + +import ( + "strconv" +) + +// BoolToInterface converts bool to interface. +func BoolToInterface(v bool) interface{} { + return v +} + +// BoolToInterfacePtr converts bool to *interface. +func BoolToInterfacePtr(v bool) *interface{} { + r := BoolToInterface(v) + return &r +} + +// BoolToString converts bool to string. +func BoolToString(v bool) string { + return strconv.FormatBool(v) +} + +// BoolToStringPtr converts bool to *string. +func BoolToStringPtr(v bool) *string { + r := BoolToString(v) + return &r +} + +// BoolToBoolPtr converts bool to *bool. +func BoolToBoolPtr(v bool) *bool { + return &v +} + +// BoolToFloat32 converts bool to float32. +func BoolToFloat32(v bool) float32 { + if v { + return 1 + } + return 0 +} + +// BoolToFloat32Ptr converts bool to *float32. +func BoolToFloat32Ptr(v bool) *float32 { + r := BoolToFloat32(v) + return &r +} + +// BoolToFloat64 converts bool to float64. +func BoolToFloat64(v bool) float64 { + if v { + return 1 + } + return 0 +} + +// BoolToFloat64Ptr converts bool to *float64. +func BoolToFloat64Ptr(v bool) *float64 { + r := BoolToFloat64(v) + return &r +} + +// BoolToInt converts bool to int. +func BoolToInt(v bool) int { + if v { + return 1 + } + return 0 +} + +// BoolToIntPtr converts bool to *int. +func BoolToIntPtr(v bool) *int { + r := BoolToInt(v) + return &r +} + +// BoolToInt8 converts bool to int8. +func BoolToInt8(v bool) int8 { + if v { + return 1 + } + return 0 +} + +// BoolToInt8Ptr converts bool to *int8. +func BoolToInt8Ptr(v bool) *int8 { + r := BoolToInt8(v) + return &r +} + +// BoolToInt16 converts bool to int16. +func BoolToInt16(v bool) int16 { + if v { + return 1 + } + return 0 +} + +// BoolToInt16Ptr converts bool to *int16. +func BoolToInt16Ptr(v bool) *int16 { + r := BoolToInt16(v) + return &r +} + +// BoolToInt32 converts bool to int32. +func BoolToInt32(v bool) int32 { + if v { + return 1 + } + return 0 +} + +// BoolToInt32Ptr converts bool to *int32. +func BoolToInt32Ptr(v bool) *int32 { + r := BoolToInt32(v) + return &r +} + +// BoolToInt64 converts bool to int64. +func BoolToInt64(v bool) int64 { + if v { + return 1 + } + return 0 +} + +// BoolToInt64Ptr converts bool to *int64. +func BoolToInt64Ptr(v bool) *int64 { + r := BoolToInt64(v) + return &r +} + +// BoolToUint converts bool to uint. +func BoolToUint(v bool) uint { + if v { + return 1 + } + return 0 +} + +// BoolToUintPtr converts bool to *uint. +func BoolToUintPtr(v bool) *uint { + r := BoolToUint(v) + return &r +} + +// BoolToUint8 converts bool to uint8. +func BoolToUint8(v bool) uint8 { + if v { + return 1 + } + return 0 +} + +// BoolToUint8Ptr converts bool to *uint8. +func BoolToUint8Ptr(v bool) *uint8 { + r := BoolToUint8(v) + return &r +} + +// BoolToUint16 converts bool to uint16. +func BoolToUint16(v bool) uint16 { + if v { + return 1 + } + return 0 +} + +// BoolToUint16Ptr converts bool to *uint16. +func BoolToUint16Ptr(v bool) *uint16 { + r := BoolToUint16(v) + return &r +} + +// BoolToUint32 converts bool to uint32. +func BoolToUint32(v bool) uint32 { + if v { + return 1 + } + return 0 +} + +// BoolToUint32Ptr converts bool to *uint32. +func BoolToUint32Ptr(v bool) *uint32 { + r := BoolToUint32(v) + return &r +} + +// BoolToUint64 converts bool to uint64. +func BoolToUint64(v bool) uint64 { + if v { + return 1 + } + return 0 +} + +// BoolToUint64Ptr converts bool to *uint64. +func BoolToUint64Ptr(v bool) *uint64 { + r := BoolToUint64(v) + return &r +} diff --git a/internal/ameda/bools.go b/internal/ameda/bools.go new file mode 100644 index 0000000..1a734c1 --- /dev/null +++ b/internal/ameda/bools.go @@ -0,0 +1,580 @@ +package ameda + +// OneBool try to return the first element, otherwise return zero value. +func OneBool(b []bool) bool { + if len(b) > 0 { + return b[0] + } + return false +} + +// BoolsCopy creates a copy of the bool slice. +func BoolsCopy(b []bool) []bool { + r := make([]bool, len(b)) + copy(r, b) + return r +} + +// BoolsToInterfaces converts int8 slice to interface slice. +func BoolsToInterfaces(b []bool) []interface{} { + r := make([]interface{}, len(b)) + for k, v := range b { + r[k] = v + } + return r +} + +// BoolsToStrings converts int8 slice to string slice. +func BoolsToStrings(b []bool) []string { + r := make([]string, len(b)) + for k, v := range b { + r[k] = BoolToString(v) + } + return r +} + +// BoolsToFloat32s converts int8 slice to float32 slice. +func BoolsToFloat32s(b []bool) []float32 { + r := make([]float32, len(b)) + for k, v := range b { + r[k] = BoolToFloat32(v) + } + return r +} + +// BoolsToFloat64s converts int8 slice to float64 slice. +func BoolsToFloat64s(b []bool) []float64 { + r := make([]float64, len(b)) + for k, v := range b { + r[k] = BoolToFloat64(v) + } + return r +} + +// BoolsToInts converts int8 slice to int slice. +func BoolsToInts(b []bool) []int { + r := make([]int, len(b)) + for k, v := range b { + r[k] = BoolToInt(v) + } + return r +} + +// BoolsToInt16s converts int8 slice to int16 slice. +func BoolsToInt16s(b []bool) []int16 { + r := make([]int16, len(b)) + for k, v := range b { + r[k] = BoolToInt16(v) + } + return r +} + +// BoolsToInt32s converts int8 slice to int32 slice. +func BoolsToInt32s(b []bool) []int32 { + r := make([]int32, len(b)) + for k, v := range b { + r[k] = BoolToInt32(v) + } + return r +} + +// BoolsToInt64s converts int8 slice to int64 slice. +func BoolsToInt64s(b []bool) []int64 { + r := make([]int64, len(b)) + for k, v := range b { + r[k] = BoolToInt64(v) + } + return r +} + +// BoolsToUints converts bool slice to uint slice. +func BoolsToUints(b []bool) []uint { + r := make([]uint, len(b)) + for k, v := range b { + r[k] = BoolToUint(v) + } + return r +} + +// BoolsToUint8s converts bool slice to uint8 slice. +func BoolsToUint8s(b []bool) []uint8 { + r := make([]uint8, len(b)) + for k, v := range b { + r[k] = BoolToUint8(v) + } + return r +} + +// BoolsToUint16s converts bool slice to uint16 slice. +func BoolsToUint16s(b []bool) []uint16 { + r := make([]uint16, len(b)) + for k, v := range b { + r[k] = BoolToUint16(v) + } + return r +} + +// BoolsToUint32s converts bool slice to uint32 slice. +func BoolsToUint32s(b []bool) []uint32 { + r := make([]uint32, len(b)) + for k, v := range b { + r[k] = BoolToUint32(v) + } + return r +} + +// BoolsToUint64s converts bool slice to uint64 slice. +func BoolsToUint64s(b []bool) []uint64 { + r := make([]uint64, len(b)) + for k, v := range b { + r[k] = BoolToUint64(v) + } + return r +} + +// BoolsCopyWithin copies part of an slice to another location in the current slice. +// @target +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func BoolsCopyWithin(b []bool, target, start int, end ...int) { + target = fixIndex(len(b), target, true) + if target == len(b) { + return + } + sub := BoolsSlice(b, start, end...) + for k, v := range sub { + b[target+k] = v + } +} + +// BoolsEvery tests whether all elements in the slice pass the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice will return true for any condition! +func BoolsEvery(b []bool, fn func(b []bool, k int, v bool) bool) bool { + for k, v := range b { + if !fn(b, k, v) { + return false + } + } + return true +} + +// BoolsFill changes all elements in the current slice to a value, from a start index to an end index. +// @value +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func BoolsFill(b []bool, value bool, start int, end ...int) { + fixedStart, fixedEnd, ok := fixRange(len(b), start, end...) + if !ok { + return + } + for k := fixedStart; k < fixedEnd; k++ { + b[k] = value + } +} + +// BoolsFilter creates a new slice with all elements that pass the test implemented by the provided function. +func BoolsFilter(b []bool, fn func(b []bool, k int, v bool) bool) []bool { + ret := make([]bool, 0, 16) + for k, v := range b { + if fn(b, k, v) { + ret = append(ret, v) + } + } + return ret +} + +// BoolsFind returns the key-value of the first element in the provided slice that satisfies the provided testing function. +// NOTE: +// If not found, k = -1 +func BoolsFind(b []bool, fn func(b []bool, k int, v bool) bool) (k int, v bool) { + for k, v := range b { + if fn(b, k, v) { + return k, v + } + } + return -1, false +} + +// BoolsIncludes determines whether an slice includes a certain value among its entries. +// @fromIndex +// The index to start the search at. Defaults to 0. +func BoolsIncludes(b []bool, valueToFind bool, fromIndex ...int) bool { + return BoolsIndexOf(b, valueToFind, fromIndex...) > -1 +} + +// BoolsIndexOf returns the first index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func BoolsIndexOf(b []bool, searchElement bool, fromIndex ...int) int { + idx := getFromIndex(len(b), fromIndex...) + for k, v := range b[idx:] { + if searchElement == v { + return k + idx + } + } + return -1 +} + +// BoolsLastIndexOf returns the last index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func BoolsLastIndexOf(b []bool, searchElement bool, fromIndex ...int) int { + idx := getFromIndex(len(b), fromIndex...) + for k := len(b) - 1; k >= idx; k-- { + if searchElement == b[k] { + return k + } + } + return -1 +} + +// BoolsMap creates a new slice populated with the results of calling a provided function +// on every element in the calling slice. +func BoolsMap(b []bool, fn func(b []bool, k int, v bool) bool) []bool { + ret := make([]bool, len(b)) + for k, v := range b { + ret[k] = fn(b, k, v) + } + return ret +} + +// BoolsPop removes the last element from an slice and returns that element. +// This method changes the length of the slice. +func BoolsPop(b *[]bool) (elem bool, found bool) { + a := *b + if len(a) == 0 { + return false, false + } + lastIndex := len(a) - 1 + last := a[lastIndex] + a = a[:lastIndex] + *b = a[:len(a):len(a)] + return last, true +} + +// BoolsPush adds one or more elements to the end of an slice and returns the new length of the slice. +func BoolsPush(b *[]bool, element ...bool) int { + *b = append(*b, element...) + return len(*b) +} + +// BoolsPushDistinct adds one or more new elements that do not exist in the current slice at the end. +func BoolsPushDistinct(b []bool, element ...bool) []bool { +L: + for _, v := range element { + for _, vv := range b { + if vv == v { + continue L + } + } + b = append(b, v) + } + return b +} + +// BoolsReduce executes a reducer function (that you provide) on each element of the slice, +// resulting in a single output value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func BoolsReduce( + b []bool, + fn func(b []bool, k int, v, accumulator bool) bool, initialValue ...bool, +) bool { + if len(b) == 0 { + return false + } + start := 0 + acc := b[start] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + start += 1 + } + for k := start; k < len(b); k++ { + acc = fn(b, k, b[k], acc) + } + return acc +} + +// BoolsReduceRight applies a function against an accumulator and each value of the slice (from right-to-left) +// to reduce it to a single value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func BoolsReduceRight( + b []bool, + fn func(b []bool, k int, v, accumulator bool) bool, initialValue ...bool, +) bool { + if len(b) == 0 { + return false + } + end := len(b) - 1 + acc := b[end] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + end -= 1 + } + for k := end; k >= 0; k-- { + acc = fn(b, k, b[k], acc) + } + return acc +} + +// BoolsReverse reverses an slice in place. +func BoolsReverse(b []bool) { + first := 0 + last := len(b) - 1 + for first < last { + b[first], b[last] = b[last], b[first] + first++ + last-- + } +} + +// BoolsShift removes the first element from an slice and returns that removed element. +// This method changes the length of the slice. +func BoolsShift(b *[]bool) (element bool, found bool) { + a := *b + if len(a) == 0 { + return false, false + } + first := a[0] + a = a[1:] + *b = a[:len(a):len(a)] + return first, true +} + +// BoolsSlice returns a copy of a portion of an slice into a new slice object selected +// from begin to end (end not included) where begin and end represent the index of items in that slice. +// The original slice will not be modified. +func BoolsSlice(b []bool, begin int, end ...int) []bool { + fixedStart, fixedEnd, ok := fixRange(len(b), begin, end...) + if !ok { + return []bool{} + } + return BoolsCopy(b[fixedStart:fixedEnd]) +} + +// BoolsSome tests whether at least one element in the slice passes the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice returns false for any condition! +func BoolsSome(b []bool, fn func(b []bool, k int, v bool) bool) bool { + for k, v := range b { + if fn(b, k, v) { + return true + } + } + return false +} + +// BoolsSplice changes the contents of an slice by removing or replacing +// existing elements and/or adding new elements in place. +func BoolsSplice(b *[]bool, start, deleteCount int, items ...bool) { + a := *b + if deleteCount < 0 { + deleteCount = 0 + } + start, end, _ := fixRange(len(a), start, start+1+deleteCount) + deleteCount = end - start - 1 + for k := 0; k < len(items); k++ { + if deleteCount > 0 { + // replace + a[start] = items[k] + deleteCount-- + start++ + } else { + // insert + lastSlice := BoolsCopy(a[start:]) + items = items[k:] + a = append(a[:start], items...) + a = append(a[:start+len(items)], lastSlice...) + *b = a[:len(a):len(a)] + return + } + } + if deleteCount > 0 { + a = append(a[:start], a[start+1+deleteCount:]...) + } + *b = a[:len(a):len(a)] +} + +// BoolsUnshift adds one or more elements to the beginning of an slice and returns the new length of the slice. +func BoolsUnshift(b *[]bool, element ...bool) int { + *b = append(element, *b...) + return len(*b) +} + +// BoolsUnshiftDistinct adds one or more new elements that do not exist in the current slice to the beginning +// and returns the new length of the slice. +func BoolsUnshiftDistinct(b *[]bool, element ...bool) int { + a := *b + if len(element) == 0 { + return len(a) + } + m := make(map[bool]bool, len(element)) + r := make([]bool, 0, len(a)+len(element)) +L: + for _, v := range element { + if m[v] { + continue + } + m[v] = true + for _, vv := range a { + if vv == v { + continue L + } + } + r = append(r, v) + } + r = append(r, a...) + *b = r[:len(r):len(r)] + return len(r) +} + +// BoolsRemoveFirst removes the first matched element from the slice, +// and returns the new length of the slice. +func BoolsRemoveFirst(p *[]bool, elements ...bool) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for k, v := range a { + if v == element { + a = append(a[:k], a[k+1:]...) + break + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// BoolsRemoveEvery removes all the elements from the slice, +// and returns the new length of the slice. +func BoolsRemoveEvery(p *[]bool, elements ...bool) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for i := 0; i < len(a); i++ { + if a[i] == element { + a = append(a[:i], a[i+1:]...) + i-- + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// BoolsConcat is used to merge two or more slices. +// This method does not change the existing slices, but instead returns a new slice. +func BoolsConcat(b ...[]bool) []bool { + var totalLen int + for _, v := range b { + totalLen += len(v) + } + ret := make([]bool, totalLen) + dst := ret + for _, v := range b { + n := copy(dst, v) + dst = dst[n:] + } + return ret +} + +// BoolsIntersect calculates intersection of two or more slices, +// and returns the count of each element. +func BoolsIntersect(b ...[]bool) (intersectCount map[bool]int) { + if len(b) == 0 { + return nil + } + for _, v := range b { + if len(v) == 0 { + return nil + } + } + counts := make([]map[bool]int, len(b)) + for k, v := range b { + counts[k] = boolsDistinct(v, nil) + } + intersectCount = counts[0] +L: + for k, v := range intersectCount { + for _, c := range counts[1:] { + v2 := c[k] + if v2 == 0 { + delete(intersectCount, k) + continue L + } + if v > v2 { + v = v2 + } + } + intersectCount[k] = v + } + return intersectCount +} + +// BoolsDistinct calculates the count of each different element, +// and only saves these different elements in place if changeSlice is true. +func BoolsDistinct(b *[]bool, changeSlice bool) (distinctCount map[bool]int) { + if !changeSlice { + return boolsDistinct(*b, nil) + } + a := (*b)[:0] + distinctCount = boolsDistinct(*b, &a) + n := len(distinctCount) + *b = a[:n:n] + return distinctCount +} + +func boolsDistinct(src []bool, dst *[]bool) map[bool]int { + m := make(map[bool]int, len(src)) + if dst == nil { + for _, v := range src { + n := m[v] + m[v] = n + 1 + } + } else { + a := *dst + for _, v := range src { + n := m[v] + m[v] = n + 1 + if n == 0 { + a = append(a, v) + } + } + *dst = a + } + return m +} diff --git a/internal/ameda/float32.go b/internal/ameda/float32.go new file mode 100644 index 0000000..6bc9e67 --- /dev/null +++ b/internal/ameda/float32.go @@ -0,0 +1,217 @@ +package ameda + +import ( + "fmt" + "math" +) + +// Float32ToInterface converts float32 to interface. +func Float32ToInterface(v float32) interface{} { + return v +} + +// Float32ToInterfacePtr converts float32 to *interface. +func Float32ToInterfacePtr(v float32) *interface{} { + r := Float32ToInterface(v) + return &r +} + +// Float32ToString converts float32 to string. +func Float32ToString(v float32) string { + return fmt.Sprintf("%f", v) +} + +// Float32ToStringPtr converts float32 to *string. +func Float32ToStringPtr(v float32) *string { + r := Float32ToString(v) + return &r +} + +// Float32ToBool converts float32 to bool. +func Float32ToBool(v float32) bool { + return v != 0 +} + +// Float32ToBoolPtr converts float32 to *bool. +func Float32ToBoolPtr(v float32) *bool { + r := Float32ToBool(v) + return &r +} + +// Float32ToFloat32Ptr converts float32 to *float32. +func Float32ToFloat32Ptr(v float32) *float32 { + return &v +} + +// Float32ToFloat64 converts float32 to float64. +func Float32ToFloat64(v float32) float64 { + return float64(v) +} + +// Float32ToFloat64Ptr converts float32 to *float64. +func Float32ToFloat64Ptr(v float32) *float64 { + r := Float32ToFloat64(v) + return &r +} + +// Float32ToInt converts float32 to int. +func Float32ToInt(v float32) (int, error) { + if Host64bit { + if v > math.MaxInt64 || v < math.MinInt64 { + return 0, errOverflowValue + } + } else { + if v > math.MaxInt32 || v < math.MinInt32 { + return 0, errOverflowValue + } + } + return int(v), nil + +} + +// Float32ToInt8 converts float32 to int8. +func Float32ToInt8(v float32) (int8, error) { + if v > math.MaxInt8 || v < math.MinInt8 { + return 0, errOverflowValue + } + return int8(v), nil +} + +// Float32ToInt8Ptr converts float32 to *int8. +func Float32ToInt8Ptr(v float32) (*int8, error) { + r, err := Float32ToInt8(v) + return &r, err +} + +// Float32ToInt16 converts float32 to int16. +func Float32ToInt16(v float32) (int16, error) { + if v > math.MaxInt16 || v < math.MinInt16 { + return 0, errOverflowValue + } + return int16(v), nil +} + +// Float32ToInt16Ptr converts float32 to *int16. +func Float32ToInt16Ptr(v float32) (*int16, error) { + r, err := Float32ToInt16(v) + return &r, err +} + +// Float32ToInt32 converts float32 to int32. +func Float32ToInt32(v float32) (int32, error) { + if v > math.MaxInt32 || v < math.MinInt32 { + return 0, errOverflowValue + } + return int32(v), nil +} + +// Float32ToInt32Ptr converts float32 to *int32. +func Float32ToInt32Ptr(v float32) (*int32, error) { + r, err := Float32ToInt32(v) + return &r, err +} + +// Float32ToInt64 converts float32 to int64. +func Float32ToInt64(v float32) (int64, error) { + if v > math.MaxInt64 || v < math.MinInt64 { + return 0, errOverflowValue + } + return int64(v), nil +} + +// Float32ToInt64Ptr converts float32 to *int64. +func Float32ToInt64Ptr(v float32) (*int64, error) { + r, err := Float32ToInt64(v) + return &r, err +} + +// Float32ToUint converts float32 to uint. +func Float32ToUint(v float32) (uint, error) { + if v < 0 { + return 0, errNegativeValue + } + if Host64bit { + if v > math.MaxUint64 { + return 0, errOverflowValue + } + } else { + if v > math.MaxUint32 { + return 0, errOverflowValue + } + } + return uint(v), nil +} + +// Float32ToUintPtr converts float32 to *uint. +func Float32ToUintPtr(v float32) (*uint, error) { + r, err := Float32ToUint(v) + return &r, err +} + +// Float32ToUint8 converts float32 to uint8. +func Float32ToUint8(v float32) (uint8, error) { + if v < 0 { + return 0, errNegativeValue + } + if v > math.MaxUint8 { + return 0, errOverflowValue + } + return uint8(v), nil +} + +// Float32ToUint8Ptr converts float32 to *uint8. +func Float32ToUint8Ptr(v float32) (*uint8, error) { + r, err := Float32ToUint8(v) + return &r, err +} + +// Float32ToUint16 converts float32 to uint16. +func Float32ToUint16(v float32) (uint16, error) { + if v < 0 { + return 0, errNegativeValue + } + if v > math.MaxUint16 { + return 0, errOverflowValue + } + return uint16(v), nil +} + +// Float32ToUint16Ptr converts float32 to *uint16. +func Float32ToUint16Ptr(v float32) (*uint16, error) { + r, err := Float32ToUint16(v) + return &r, err +} + +// Float32ToUint32 converts float32 to uint32. +func Float32ToUint32(v float32) (uint32, error) { + if v < 0 { + return 0, errNegativeValue + } + if v > math.MaxUint32 { + return 0, errOverflowValue + } + return uint32(v), nil +} + +// Float32ToUint32Ptr converts float32 to *uint32. +func Float32ToUint32Ptr(v float32) (*uint32, error) { + r, err := Float32ToUint32(v) + return &r, err +} + +// Float32ToUint64 converts float32 to uint64. +func Float32ToUint64(v float32) (uint64, error) { + if v < 0 { + return 0, errNegativeValue + } + if v > math.MaxUint64 { + return 0, errOverflowValue + } + return uint64(v), nil +} + +// Float32ToUint64Ptr converts float32 to *uint64. +func Float32ToUint64Ptr(v float32) (*uint64, error) { + r, err := Float32ToUint64(v) + return &r, err +} diff --git a/internal/ameda/float32s.go b/internal/ameda/float32s.go new file mode 100644 index 0000000..0aee67e --- /dev/null +++ b/internal/ameda/float32s.go @@ -0,0 +1,680 @@ +package ameda + +// OneFloat32 try to return the first element, otherwise return zero value. +func OneFloat32(f []float32) float32 { + if len(f) > 0 { + return f[0] + } + return 0 +} + +// Float32sCopy creates a copy of the float32 slice. +func Float32sCopy(f []float32) []float32 { + b := make([]float32, len(f)) + copy(b, f) + return b +} + +// Float32sToInterfaces converts float32 slice to interface slice. +func Float32sToInterfaces(f []float32) []interface{} { + r := make([]interface{}, len(f)) + for k, v := range f { + r[k] = Float32ToInterface(v) + } + return r +} + +// Float32sToStrings converts float32 slice to string slice. +func Float32sToStrings(f []float32) []string { + r := make([]string, len(f)) + for k, v := range f { + r[k] = Float32ToString(v) + } + return r +} + +// Float32sToBools converts float32 slice to bool slice. +// NOTE: +// 0 is false, everything else is true +func Float32sToBools(f []float32) []bool { + r := make([]bool, len(f)) + for k, v := range f { + r[k] = Float32ToBool(v) + } + return r +} + +// Float32sToFloat64s converts float32 slice to float64 slice. +func Float32sToFloat64s(f []float32) []float64 { + r := make([]float64, len(f)) + for k, v := range f { + r[k] = Float32ToFloat64(v) + } + return r +} + +// Float32sToInts converts float32 slice to int slice. +func Float32sToInts(f []float32) ([]int, error) { + var err error + r := make([]int, len(f)) + for k, v := range f { + r[k], err = Float32ToInt(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Float32sToInt8s converts float32 slice to int8 slice. +func Float32sToInt8s(f []float32) ([]int8, error) { + var err error + r := make([]int8, len(f)) + for k, v := range f { + r[k], err = Float32ToInt8(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Float32sToInt16s converts float32 slice to int16 slice. +func Float32sToInt16s(f []float32) ([]int16, error) { + var err error + r := make([]int16, len(f)) + for k, v := range f { + r[k], err = Float32ToInt16(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Float32sToInt32s converts float32 slice to int32 slice. +func Float32sToInt32s(f []float32) ([]int32, error) { + var err error + r := make([]int32, len(f)) + for k, v := range f { + r[k], err = Float32ToInt32(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Float32sToInt64s converts float32 slice to int64 slice. +func Float32sToInt64s(f []float32) ([]int64, error) { + var err error + r := make([]int64, len(f)) + for k, v := range f { + r[k], err = Float32ToInt64(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Float32sToUints converts float32 slice to uint slice. +func Float32sToUints(f []float32) ([]uint, error) { + var err error + r := make([]uint, len(f)) + for k, v := range f { + r[k], err = Float32ToUint(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Float32sToUint8s converts float32 slice to uint8 slice. +func Float32sToUint8s(f []float32) ([]uint8, error) { + var err error + r := make([]uint8, len(f)) + for k, v := range f { + r[k], err = Float32ToUint8(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Float32sToUint16s converts float32 slice to uint16 slice. +func Float32sToUint16s(f []float32) ([]uint16, error) { + var err error + r := make([]uint16, len(f)) + for k, v := range f { + r[k], err = Float32ToUint16(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Float32sToUint32s converts float32 slice to uint32 slice. +func Float32sToUint32s(f []float32) ([]uint32, error) { + var err error + r := make([]uint32, len(f)) + for k, v := range f { + r[k], err = Float32ToUint32(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Float32sToUint64s converts float32 slice to uint64 slice. +func Float32sToUint64s(f []float32) ([]uint64, error) { + var err error + r := make([]uint64, len(f)) + for k, v := range f { + r[k], err = Float32ToUint64(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Float32sCopyWithin copies part of an slice to another location in the current slice. +// @target +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func Float32sCopyWithin(f []float32, target, start int, end ...int) { + target = fixIndex(len(f), target, true) + if target == len(f) { + return + } + sub := Float32sSlice(f, start, end...) + for k, v := range sub { + f[target+k] = v + } +} + +// Float32sEvery tests whether all elements in the slice pass the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice will return true for any condition! +func Float32sEvery(f []float32, fn func(f []float32, k int, v float32) bool) bool { + for k, v := range f { + if !fn(f, k, v) { + return false + } + } + return true +} + +// Float32sFill changes all elements in the current slice to a value, from a start index to an end index. +// @value +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func Float32sFill(f []float32, value float32, start int, end ...int) { + fixedStart, fixedEnd, ok := fixRange(len(f), start, end...) + if !ok { + return + } + for k := fixedStart; k < fixedEnd; k++ { + f[k] = value + } +} + +// Float32sFilter creates a new slice with all elements that pass the test implemented by the provided function. +func Float32sFilter(f []float32, fn func(f []float32, k int, v float32) bool) []float32 { + ret := make([]float32, 0) + for k, v := range f { + if fn(f, k, v) { + ret = append(ret, v) + } + } + return ret +} + +// Float32sFind returns the key-value of the first element in the provided slice that satisfies the provided testing function. +// NOTE: +// If not found, k = -1 +func Float32sFind(f []float32, fn func(f []float32, k int, v float32) bool) (k int, v float32) { + for k, v := range f { + if fn(f, k, v) { + return k, v + } + } + return -1, 0 +} + +// Float32sIncludes determines whether an slice includes a certain value among its entries. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Float32sIncludes(f []float32, valueToFind float32, fromIndex ...int) bool { + return Float32sIndexOf(f, valueToFind, fromIndex...) > -1 +} + +// Float32sIndexOf returns the first index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Float32sIndexOf(f []float32, searchElement float32, fromIndex ...int) int { + idx := getFromIndex(len(f), fromIndex...) + for k, v := range f[idx:] { + if searchElement == v { + return k + idx + } + } + return -1 +} + +// Float32sLastIndexOf returns the last index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Float32sLastIndexOf(f []float32, searchElement float32, fromIndex ...int) int { + idx := getFromIndex(len(f), fromIndex...) + for k := len(f) - 1; k >= idx; k-- { + if searchElement == f[k] { + return k + } + } + return -1 +} + +// Float32sMap creates a new slice populated with the results of calling a provided function +// on every element in the calling slice. +func Float32sMap(f []float32, fn func(f []float32, k int, v float32) float32) []float32 { + ret := make([]float32, len(f)) + for k, v := range f { + ret[k] = fn(f, k, v) + } + return ret +} + +// Float32sPop removes the last element from an slice and returns that element. +// This method changes the length of the slice. +func Float32sPop(f *[]float32) (float32, bool) { + a := *f + if len(a) == 0 { + return 0, false + } + lastIndex := len(a) - 1 + last := a[lastIndex] + a = a[:lastIndex] + *f = a[:len(a):len(a)] + return last, true +} + +// Float32sPush adds one or more elements to the end of an slice and returns the new length of the slice. +func Float32sPush(f *[]float32, element ...float32) int { + *f = append(*f, element...) + return len(*f) +} + +// Float32sPushDistinct adds one or more new elements that do not exist in the current slice at the end. +func Float32sPushDistinct(f []float32, element ...float32) []float32 { +L: + for _, v := range element { + for _, vv := range f { + if vv == v { + continue L + } + } + f = append(f, v) + } + return f +} + +// Float32sReduce executes a reducer function (that you provide) on each element of the slice, +// resulting in a single output value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func Float32sReduce( + f []float32, + fn func(f []float32, k int, v, accumulator float32) float32, initialValue ...float32, +) float32 { + if len(f) == 0 { + return 0 + } + start := 0 + acc := f[start] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + start += 1 + } + for k := start; k < len(f); k++ { + acc = fn(f, k, f[k], acc) + } + return acc +} + +// Float32sReduceRight applies a function against an accumulator and each value of the slice (from right-to-left) +// to reduce it to a single value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func Float32sReduceRight( + f []float32, + fn func(f []float32, k int, v, accumulator float32) float32, initialValue ...float32, +) float32 { + if len(f) == 0 { + return 0 + } + end := len(f) - 1 + acc := f[end] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + end -= 1 + } + for k := end; k >= 0; k-- { + acc = fn(f, k, f[k], acc) + } + return acc +} + +// Float32sReverse reverses an slice in place. +func Float32sReverse(f []float32) { + first := 0 + last := len(f) - 1 + for first < last { + f[first], f[last] = f[last], f[first] + first++ + last-- + } +} + +// Float32sShift removes the first element from an slice and returns that removed element. +// This method changes the length of the slice. +func Float32sShift(f *[]float32) (float32, bool) { + a := *f + if len(a) == 0 { + return 0, false + } + first := a[0] + a = a[1:] + *f = a[:len(a):len(a)] + return first, true +} + +// Float32sSlice returns a copy of a portion of an slice into a new slice object selected +// from begin to end (end not included) where begin and end represent the index of items in that slice. +// The original slice will not be modified. +func Float32sSlice(f []float32, begin int, end ...int) []float32 { + fixedStart, fixedEnd, ok := fixRange(len(f), begin, end...) + if !ok { + return []float32{} + } + return Float32sCopy(f[fixedStart:fixedEnd]) +} + +// Float32sSome tests whether at least one element in the slice passes the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice returns false for any condition! +func Float32sSome(f []float32, fn func(f []float32, k int, v float32) bool) bool { + for k, v := range f { + if fn(f, k, v) { + return true + } + } + return false +} + +// Float32sSplice changes the contents of an slice by removing or replacing +// existing elements and/or adding new elements in place. +func Float32sSplice(f *[]float32, start, deleteCount int, items ...float32) { + a := *f + if deleteCount < 0 { + deleteCount = 0 + } + start, end, _ := fixRange(len(a), start, start+1+deleteCount) + deleteCount = end - start - 1 + for k := 0; k < len(items); k++ { + if deleteCount > 0 { + // replace + a[start] = items[k] + deleteCount-- + start++ + } else { + // insert + lastSlice := Float32sCopy(a[start:]) + items = items[k:] + a = append(a[:start], items...) + a = append(a[:start+len(items)], lastSlice...) + *f = a[:len(a):len(a)] + return + } + } + if deleteCount > 0 { + a = append(a[:start], a[start+1+deleteCount:]...) + } + *f = a[:len(a):len(a)] +} + +// Float32sUnshift adds one or more elements to the beginning of an slice and returns the new length of the slice. +func Float32sUnshift(f *[]float32, element ...float32) int { + *f = append(element, *f...) + return len(*f) +} + +// Float32sUnshiftDistinct adds one or more new elements that do not exist in the current slice to the beginning +// and returns the new length of the slice. +func Float32sUnshiftDistinct(f *[]float32, element ...float32) int { + a := *f + if len(element) == 0 { + return len(a) + } + m := make(map[float32]bool, len(element)) + r := make([]float32, 0, len(a)+len(element)) +L: + for _, v := range element { + if m[v] { + continue + } + m[v] = true + for _, vv := range a { + if vv == v { + continue L + } + } + r = append(r, v) + } + r = append(r, a...) + *f = r[:len(r):len(r)] + return len(r) +} + +// Float32sRemoveFirst removes the first matched elements from the slice, +// and returns the new length of the slice. +func Float32sRemoveFirst(p *[]float32, elements ...float32) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for k, v := range a { + if v == element { + a = append(a[:k], a[k+1:]...) + break + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// Float32sRemoveEvery removes all the elements from the slice, +// and returns the new length of the slice. +func Float32sRemoveEvery(p *[]float32, elements ...float32) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for i := 0; i < len(a); i++ { + if a[i] == element { + a = append(a[:i], a[i+1:]...) + i-- + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// Float32sIntersect calculates intersection of two or more slices, +// and returns the count of each element. +func Float32sIntersect(f ...[]float32) (intersectCount map[float32]int) { + if len(f) == 0 { + return nil + } + for _, v := range f { + if len(v) == 0 { + return nil + } + } + counts := make([]map[float32]int, len(f)) + for k, v := range f { + counts[k] = float32sDistinct(v, nil) + } + intersectCount = counts[0] +L: + for k, v := range intersectCount { + for _, c := range counts[1:] { + v2 := c[k] + if v2 == 0 { + delete(intersectCount, k) + continue L + } + if v > v2 { + v = v2 + } + } + intersectCount[k] = v + } + return intersectCount +} + +// Float32sDistinct calculates the count of each different element, +// and only saves these different elements in place if changeSlice is true. +func Float32sDistinct(f *[]float32, changeSlice bool) (distinctCount map[float32]int) { + if !changeSlice { + return float32sDistinct(*f, nil) + } + a := (*f)[:0] + distinctCount = float32sDistinct(*f, &a) + n := len(distinctCount) + *f = a[:n:n] + return distinctCount +} + +func float32sDistinct(src []float32, dst *[]float32) map[float32]int { + m := make(map[float32]int, len(src)) + if dst == nil { + for _, v := range src { + n := m[v] + m[v] = n + 1 + } + } else { + a := *dst + for _, v := range src { + n := m[v] + m[v] = n + 1 + if n == 0 { + a = append(a, v) + } + } + *dst = a + } + return m +} + +// Float32SetUnion calculates between multiple collections: set1 ∪ set2 ∪ others... +// This method does not change the existing slices, but instead returns a new slice. +func Float32SetUnion(set1, set2 []float32, others ...[]float32) []float32 { + m := make(map[float32]struct{}, len(set1)+len(set2)) + r := make([]float32, 0, len(m)) + for _, set := range append([][]float32{set1, set2}, others...) { + for _, v := range set { + _, ok := m[v] + if ok { + continue + } + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} + +// Float32SetIntersect calculates between multiple collections: set1 ∩ set2 ∩ others... +// This method does not change the existing slices, but instead returns a new slice. +func Float32SetIntersect(set1, set2 []float32, others ...[]float32) []float32 { + sets := append([][]float32{set2}, others...) + setsCount := make([]map[float32]int, len(sets)) + for k, v := range sets { + setsCount[k] = float32sDistinct(v, nil) + } + m := make(map[float32]struct{}, len(set1)) + r := make([]float32, 0, len(m)) +L: + for _, v := range set1 { + if _, ok := m[v]; ok { + continue + } + m[v] = struct{}{} + for _, m2 := range setsCount { + if m2[v] == 0 { + continue L + } + } + r = append(r, v) + } + return r +} + +// Float32SetDifference calculates between multiple collections: set1 - set2 - others... +// This method does not change the existing slices, but instead returns a new slice. +func Float32SetDifference(set1, set2 []float32, others ...[]float32) []float32 { + m := make(map[float32]struct{}, len(set1)) + r := make([]float32, 0, len(set1)) + sets := append([][]float32{set2}, others...) + for _, v := range sets { + inter := Float32SetIntersect(set1, v) + for _, v := range inter { + m[v] = struct{}{} + } + } + for _, v := range set1 { + if _, ok := m[v]; !ok { + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} diff --git a/internal/ameda/float64.go b/internal/ameda/float64.go new file mode 100644 index 0000000..e5ea83d --- /dev/null +++ b/internal/ameda/float64.go @@ -0,0 +1,220 @@ +package ameda + +import ( + "fmt" + "math" +) + +// Float64ToInterface converts float64 to interface. +func Float64ToInterface(v float64) interface{} { + return v +} + +// Float64ToInterfacePtr converts float64 to *interface. +func Float64ToInterfacePtr(v float64) *interface{} { + r := Float64ToInterface(v) + return &r +} + +// Float64ToString converts float64 to string. +func Float64ToString(v float64) string { + return fmt.Sprintf("%f", v) +} + +// Float64ToStringPtr converts float64 to *string. +func Float64ToStringPtr(v float64) *string { + r := Float64ToString(v) + return &r +} + +// Float64ToBool converts float64 to bool. +func Float64ToBool(v float64) bool { + return v != 0 +} + +// Float64ToBoolPtr converts float64 to *bool. +func Float64ToBoolPtr(v float64) *bool { + r := Float64ToBool(v) + return &r +} + +// Float64ToFloat32 converts float64 to float32. +func Float64ToFloat32(v float64) (float32, error) { + if v > math.MaxFloat32 || v < -math.MaxFloat32 { + return 0, errOverflowValue + } + return float32(v), nil +} + +// Float64ToFloat32Ptr converts float64 to *float32. +func Float64ToFloat32Ptr(v float64) (*float32, error) { + r, err := Float64ToFloat32(v) + return &r, err +} + +// Float64ToFloat64Ptr converts float64 to *float64. +func Float64ToFloat64Ptr(v float64) *float64 { + return &v +} + +// Float64ToInt converts float64 to int. +func Float64ToInt(v float64) (int, error) { + if Host64bit { + if v > math.MaxInt64 || v < math.MinInt64 { + return 0, errOverflowValue + } + } else { + if v > math.MaxInt32 || v < math.MinInt32 { + return 0, errOverflowValue + } + } + return int(v), nil + +} + +// Float64ToInt8 converts float64 to int8. +func Float64ToInt8(v float64) (int8, error) { + if v > math.MaxInt8 || v < math.MinInt8 { + return 0, errOverflowValue + } + return int8(v), nil +} + +// Float64ToInt8Ptr converts float64 to *int8. +func Float64ToInt8Ptr(v float64) (*int8, error) { + r, err := Float64ToInt8(v) + return &r, err +} + +// Float64ToInt16 converts float64 to int16. +func Float64ToInt16(v float64) (int16, error) { + if v > math.MaxInt16 || v < math.MinInt16 { + return 0, errOverflowValue + } + return int16(v), nil +} + +// Float64ToInt16Ptr converts float64 to *int16. +func Float64ToInt16Ptr(v float64) (*int16, error) { + r, err := Float64ToInt16(v) + return &r, err +} + +// Float64ToInt32 converts float64 to int32. +func Float64ToInt32(v float64) (int32, error) { + if v > math.MaxInt32 || v < math.MinInt32 { + return 0, errOverflowValue + } + return int32(v), nil +} + +// Float64ToInt32Ptr converts float64 to *int32. +func Float64ToInt32Ptr(v float64) (*int32, error) { + r, err := Float64ToInt32(v) + return &r, err +} + +// Float64ToInt64 converts float64 to int64. +func Float64ToInt64(v float64) (int64, error) { + if v > math.MaxInt64 || v < math.MinInt64 { + return 0, errOverflowValue + } + return int64(v), nil +} + +// Float64ToInt64Ptr converts float64 to *int64. +func Float64ToInt64Ptr(v float64) (*int64, error) { + r, err := Float64ToInt64(v) + return &r, err +} + +// Float64ToUint converts float64 to uint. +func Float64ToUint(v float64) (uint, error) { + if v < 0 { + return 0, errNegativeValue + } + if Host64bit { + if v > math.MaxUint64 { + return 0, errOverflowValue + } + } else { + if v > math.MaxUint32 { + return 0, errOverflowValue + } + } + return uint(v), nil +} + +// Float64ToUintPtr converts float64 to *uint. +func Float64ToUintPtr(v float64) (*uint, error) { + r, err := Float64ToUint(v) + return &r, err +} + +// Float64ToUint8 converts float64 to uint8. +func Float64ToUint8(v float64) (uint8, error) { + if v < 0 { + return 0, errNegativeValue + } + if v > math.MaxUint8 { + return 0, errOverflowValue + } + return uint8(v), nil +} + +// Float64ToUint8Ptr converts float64 to *uint8. +func Float64ToUint8Ptr(v float64) (*uint8, error) { + r, err := Float64ToUint8(v) + return &r, err +} + +// Float64ToUint16 converts float64 to uint16. +func Float64ToUint16(v float64) (uint16, error) { + if v < 0 { + return 0, errNegativeValue + } + if v > math.MaxUint16 { + return 0, errOverflowValue + } + return uint16(v), nil +} + +// Float64ToUint16Ptr converts float64 to *uint16. +func Float64ToUint16Ptr(v float64) (*uint16, error) { + r, err := Float64ToUint16(v) + return &r, err +} + +// Float64ToUint32 converts float64 to uint32. +func Float64ToUint32(v float64) (uint32, error) { + if v < 0 { + return 0, errNegativeValue + } + if v > math.MaxUint32 { + return 0, errOverflowValue + } + return uint32(v), nil +} + +// Float64ToUint32Ptr converts float64 to *uint32. +func Float64ToUint32Ptr(v float64) (*uint32, error) { + r, err := Float64ToUint32(v) + return &r, err +} + +// Float64ToUint64 converts float64 to uint64. +func Float64ToUint64(v float64) (uint64, error) { + if v < 0 { + return 0, errNegativeValue + } + if v > math.MaxUint64 { + return 0, errOverflowValue + } + return uint64(v), nil +} + +// Float64ToUint64Ptr converts float64 to *uint64. +func Float64ToUint64Ptr(v float64) (*uint64, error) { + r, err := Float64ToUint64(v) + return &r, err +} diff --git a/internal/ameda/float64s.go b/internal/ameda/float64s.go new file mode 100644 index 0000000..2f456c4 --- /dev/null +++ b/internal/ameda/float64s.go @@ -0,0 +1,684 @@ +package ameda + +// OneFloat64 try to return the first element, otherwise return zero value. +func OneFloat64(f []float64) float64 { + if len(f) > 0 { + return f[0] + } + return 0 +} + +// Float64sCopy creates a copy of the float64 slice. +func Float64sCopy(f []float64) []float64 { + b := make([]float64, len(f)) + copy(b, f) + return b +} + +// Float64sToInterfaces converts float64 slice to interface slice. +func Float64sToInterfaces(f []float64) []interface{} { + r := make([]interface{}, len(f)) + for k, v := range f { + r[k] = Float64ToInterface(v) + } + return r +} + +// Float64sToStrings converts float64 slice to string slice. +func Float64sToStrings(f []float64) []string { + r := make([]string, len(f)) + for k, v := range f { + r[k] = Float64ToString(v) + } + return r +} + +// Float64sToBools converts float64 slice to bool slice. +// NOTE: +// 0 is false, everything else is true +func Float64sToBools(f []float64) []bool { + r := make([]bool, len(f)) + for k, v := range f { + r[k] = Float64ToBool(v) + } + return r +} + +// Float64sToFloat32s converts float64 slice to float32 slice. +func Float64sToFloat32s(f []float64) ([]float32, error) { + var err error + r := make([]float32, len(f)) + for k, v := range f { + r[k], err = Float64ToFloat32(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Float64sToInts converts float64 slice to int slice. +func Float64sToInts(f []float64) ([]int, error) { + var err error + r := make([]int, len(f)) + for k, v := range f { + r[k], err = Float64ToInt(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Float64sToInt8s converts float64 slice to int8 slice. +func Float64sToInt8s(f []float64) ([]int8, error) { + var err error + r := make([]int8, len(f)) + for k, v := range f { + r[k], err = Float64ToInt8(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Float64sToInt16s converts float64 slice to int16 slice. +func Float64sToInt16s(f []float64) ([]int16, error) { + var err error + r := make([]int16, len(f)) + for k, v := range f { + r[k], err = Float64ToInt16(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Float64sToInt32s converts float64 slice to int32 slice. +func Float64sToInt32s(f []float64) ([]int32, error) { + var err error + r := make([]int32, len(f)) + for k, v := range f { + r[k], err = Float64ToInt32(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Float64sToInt64s converts float64 slice to int64 slice. +func Float64sToInt64s(f []float64) ([]int64, error) { + var err error + r := make([]int64, len(f)) + for k, v := range f { + r[k], err = Float64ToInt64(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Float64sToUints converts float64 slice to uint slice. +func Float64sToUints(f []float64) ([]uint, error) { + var err error + r := make([]uint, len(f)) + for k, v := range f { + r[k], err = Float64ToUint(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Float64sToUint8s converts float64 slice to uint8 slice. +func Float64sToUint8s(f []float64) ([]uint8, error) { + var err error + r := make([]uint8, len(f)) + for k, v := range f { + r[k], err = Float64ToUint8(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Float64sToUint16s converts float64 slice to uint16 slice. +func Float64sToUint16s(f []float64) ([]uint16, error) { + var err error + r := make([]uint16, len(f)) + for k, v := range f { + r[k], err = Float64ToUint16(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Float64sToUint32s converts float64 slice to uint32 slice. +func Float64sToUint32s(f []float64) ([]uint32, error) { + var err error + r := make([]uint32, len(f)) + for k, v := range f { + r[k], err = Float64ToUint32(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Float64sToUint64s converts float64 slice to uint64 slice. +func Float64sToUint64s(f []float64) ([]uint64, error) { + var err error + r := make([]uint64, len(f)) + for k, v := range f { + r[k], err = Float64ToUint64(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Float64sCopyWithin copies part of an slice to another location in the current slice. +// @target +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func Float64sCopyWithin(f []float64, target, start int, end ...int) { + target = fixIndex(len(f), target, true) + if target == len(f) { + return + } + sub := Float64sSlice(f, start, end...) + for k, v := range sub { + f[target+k] = v + } +} + +// Float64sEvery tests whether all elements in the slice pass the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice will return true for any condition! +func Float64sEvery(f []float64, fn func(f []float64, k int, v float64) bool) bool { + for k, v := range f { + if !fn(f, k, v) { + return false + } + } + return true +} + +// Float64sFill changes all elements in the current slice to a value, from a start index to an end index. +// @value +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func Float64sFill(f []float64, value float64, start int, end ...int) { + fixedStart, fixedEnd, ok := fixRange(len(f), start, end...) + if !ok { + return + } + for k := fixedStart; k < fixedEnd; k++ { + f[k] = value + } +} + +// Float64sFilter creates a new slice with all elements that pass the test implemented by the provided function. +func Float64sFilter(f []float64, fn func(f []float64, k int, v float64) bool) []float64 { + ret := make([]float64, 0) + for k, v := range f { + if fn(f, k, v) { + ret = append(ret, v) + } + } + return ret +} + +// Float64sFind returns the key-value of the first element in the provided slice that satisfies the provided testing function. +// NOTE: +// If not found, k = -1 +func Float64sFind(f []float64, fn func(f []float64, k int, v float64) bool) (k int, v float64) { + for k, v := range f { + if fn(f, k, v) { + return k, v + } + } + return -1, 0 +} + +// Float64sIncludes determines whether an slice includes a certain value among its entries. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Float64sIncludes(f []float64, valueToFind float64, fromIndex ...int) bool { + return Float64sIndexOf(f, valueToFind, fromIndex...) > -1 +} + +// Float64sIndexOf returns the first index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Float64sIndexOf(f []float64, searchElement float64, fromIndex ...int) int { + idx := getFromIndex(len(f), fromIndex...) + for k, v := range f[idx:] { + if searchElement == v { + return k + idx + } + } + return -1 +} + +// Float64sLastIndexOf returns the last index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Float64sLastIndexOf(f []float64, searchElement float64, fromIndex ...int) int { + idx := getFromIndex(len(f), fromIndex...) + for k := len(f) - 1; k >= idx; k-- { + if searchElement == f[k] { + return k + } + } + return -1 +} + +// Float64sMap creates a new slice populated with the results of calling a provided function +// on every element in the calling slice. +func Float64sMap(f []float64, fn func(f []float64, k int, v float64) float64) []float64 { + ret := make([]float64, len(f)) + for k, v := range f { + ret[k] = fn(f, k, v) + } + return ret +} + +// Float64sPop removes the last element from an slice and returns that element. +// This method changes the length of the slice. +func Float64sPop(f *[]float64) (float64, bool) { + a := *f + if len(a) == 0 { + return 0, false + } + lastIndex := len(a) - 1 + last := a[lastIndex] + a = a[:lastIndex] + *f = a[:len(a):len(a)] + return last, true +} + +// Float64sPush adds one or more elements to the end of an slice and returns the new length of the slice. +func Float64sPush(f *[]float64, element ...float64) int { + *f = append(*f, element...) + return len(*f) +} + +// Float64sPushDistinct adds one or more new elements that do not exist in the current slice at the end. +func Float64sPushDistinct(f []float64, element ...float64) []float64 { +L: + for _, v := range element { + for _, vv := range f { + if vv == v { + continue L + } + } + f = append(f, v) + } + return f +} + +// Float64sReduce executes a reducer function (that you provide) on each element of the slice, +// resulting in a single output value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func Float64sReduce( + f []float64, + fn func(f []float64, k int, v, accumulator float64) float64, initialValue ...float64, +) float64 { + if len(f) == 0 { + return 0 + } + start := 0 + acc := f[start] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + start += 1 + } + for k := start; k < len(f); k++ { + acc = fn(f, k, f[k], acc) + } + return acc +} + +// Float64sReduceRight applies a function against an accumulator and each value of the slice (from right-to-left) +// to reduce it to a single value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func Float64sReduceRight( + f []float64, + fn func(f []float64, k int, v, accumulator float64) float64, initialValue ...float64, +) float64 { + if len(f) == 0 { + return 0 + } + end := len(f) - 1 + acc := f[end] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + end -= 1 + } + for k := end; k >= 0; k-- { + acc = fn(f, k, f[k], acc) + } + return acc +} + +// Float64sReverse reverses an slice in place. +func Float64sReverse(f []float64) { + first := 0 + last := len(f) - 1 + for first < last { + f[first], f[last] = f[last], f[first] + first++ + last-- + } +} + +// Float64sShift removes the first element from an slice and returns that removed element. +// This method changes the length of the slice. +func Float64sShift(f *[]float64) (float64, bool) { + a := *f + if len(a) == 0 { + return 0, false + } + first := a[0] + a = a[1:] + *f = a[:len(a):len(a)] + return first, true +} + +// Float64sSlice returns a copy of a portion of an slice into a new slice object selected +// from begin to end (end not included) where begin and end represent the index of items in that slice. +// The original slice will not be modified. +func Float64sSlice(f []float64, begin int, end ...int) []float64 { + fixedStart, fixedEnd, ok := fixRange(len(f), begin, end...) + if !ok { + return []float64{} + } + return Float64sCopy(f[fixedStart:fixedEnd]) +} + +// Float64sSome tests whether at least one element in the slice passes the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice returns false for any condition! +func Float64sSome(f []float64, fn func(f []float64, k int, v float64) bool) bool { + for k, v := range f { + if fn(f, k, v) { + return true + } + } + return false +} + +// Float64sSplice changes the contents of an slice by removing or replacing +// existing elements and/or adding new elements in place. +func Float64sSplice(f *[]float64, start, deleteCount int, items ...float64) { + a := *f + if deleteCount < 0 { + deleteCount = 0 + } + start, end, _ := fixRange(len(a), start, start+1+deleteCount) + deleteCount = end - start - 1 + for k := 0; k < len(items); k++ { + if deleteCount > 0 { + // replace + a[start] = items[k] + deleteCount-- + start++ + } else { + // insert + lastSlice := Float64sCopy(a[start:]) + items = items[k:] + a = append(a[:start], items...) + a = append(a[:start+len(items)], lastSlice...) + *f = a[:len(a):len(a)] + return + } + } + if deleteCount > 0 { + a = append(a[:start], a[start+1+deleteCount:]...) + } + *f = a[:len(a):len(a)] +} + +// Float64sUnshift adds one or more elements to the beginning of an slice and returns the new length of the slice. +func Float64sUnshift(f *[]float64, element ...float64) int { + *f = append(element, *f...) + return len(*f) +} + +// Float64sUnshiftDistinct adds one or more new elements that do not exist in the current slice to the beginning +// and returns the new length of the slice. +func Float64sUnshiftDistinct(f *[]float64, element ...float64) int { + a := *f + if len(element) == 0 { + return len(a) + } + m := make(map[float64]bool, len(element)) + r := make([]float64, 0, len(a)+len(element)) +L: + for _, v := range element { + if m[v] { + continue + } + m[v] = true + for _, vv := range a { + if vv == v { + continue L + } + } + r = append(r, v) + } + r = append(r, a...) + *f = r[:len(r):len(r)] + return len(r) +} + +// Float64sRemoveFirst removes the first matched elements from the slice, +// and returns the new length of the slice. +func Float64sRemoveFirst(p *[]float64, elements ...float64) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for k, v := range a { + if v == element { + a = append(a[:k], a[k+1:]...) + break + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// Float64sRemoveEvery removes all the elements from the slice, +// and returns the new length of the slice. +func Float64sRemoveEvery(p *[]float64, elements ...float64) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for i := 0; i < len(a); i++ { + if a[i] == element { + a = append(a[:i], a[i+1:]...) + i-- + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// Float64sIntersect calculates intersection of two or more slices, +// and returns the count of each element. +func Float64sIntersect(f ...[]float64) (intersectCount map[float64]int) { + if len(f) == 0 { + return nil + } + for _, v := range f { + if len(v) == 0 { + return nil + } + } + counts := make([]map[float64]int, len(f)) + for k, v := range f { + counts[k] = float64sDistinct(v, nil) + } + intersectCount = counts[0] +L: + for k, v := range intersectCount { + for _, c := range counts[1:] { + v2 := c[k] + if v2 == 0 { + delete(intersectCount, k) + continue L + } + if v > v2 { + v = v2 + } + } + intersectCount[k] = v + } + return intersectCount +} + +// Float64sDistinct calculates the count of each different element, +// and only saves these different elements in place if changeSlice is true. +func Float64sDistinct(f *[]float64, changeSlice bool) (distinctCount map[float64]int) { + if !changeSlice { + return float64sDistinct(*f, nil) + } + a := (*f)[:0] + distinctCount = float64sDistinct(*f, &a) + n := len(distinctCount) + *f = a[:n:n] + return distinctCount +} + +func float64sDistinct(src []float64, dst *[]float64) map[float64]int { + m := make(map[float64]int, len(src)) + if dst == nil { + for _, v := range src { + n := m[v] + m[v] = n + 1 + } + } else { + a := *dst + for _, v := range src { + n := m[v] + m[v] = n + 1 + if n == 0 { + a = append(a, v) + } + } + *dst = a + } + return m +} + +// Float64SetUnion calculates between multiple collections: set1 ∪ set2 ∪ others... +// This method does not change the existing slices, but instead returns a new slice. +func Float64SetUnion(set1, set2 []float64, others ...[]float64) []float64 { + m := make(map[float64]struct{}, len(set1)+len(set2)) + r := make([]float64, 0, len(m)) + for _, set := range append([][]float64{set1, set2}, others...) { + for _, v := range set { + _, ok := m[v] + if ok { + continue + } + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} + +// Float64SetIntersect calculates between multiple collections: set1 ∩ set2 ∩ others... +// This method does not change the existing slices, but instead returns a new slice. +func Float64SetIntersect(set1, set2 []float64, others ...[]float64) []float64 { + sets := append([][]float64{set2}, others...) + setsCount := make([]map[float64]int, len(sets)) + for k, v := range sets { + setsCount[k] = float64sDistinct(v, nil) + } + m := make(map[float64]struct{}, len(set1)) + r := make([]float64, 0, len(m)) +L: + for _, v := range set1 { + if _, ok := m[v]; ok { + continue + } + m[v] = struct{}{} + for _, m2 := range setsCount { + if m2[v] == 0 { + continue L + } + } + r = append(r, v) + } + return r +} + +// Float64SetDifference calculates between multiple collections: set1 - set2 - others... +// This method does not change the existing slices, but instead returns a new slice. +func Float64SetDifference(set1, set2 []float64, others ...[]float64) []float64 { + m := make(map[float64]struct{}, len(set1)) + r := make([]float64, 0, len(set1)) + sets := append([][]float64{set2}, others...) + for _, v := range sets { + inter := Float64SetIntersect(set1, v) + for _, v := range inter { + m[v] = struct{}{} + } + } + for _, v := range set1 { + if _, ok := m[v]; !ok { + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} diff --git a/internal/ameda/go.mod b/internal/ameda/go.mod new file mode 100644 index 0000000..cabfd59 --- /dev/null +++ b/internal/ameda/go.mod @@ -0,0 +1,5 @@ +module github.com/henrylee2cn/ameda + +go 1.13 + +require github.com/stretchr/testify v1.7.5 diff --git a/internal/ameda/initialize.go b/internal/ameda/initialize.go new file mode 100644 index 0000000..4addb87 --- /dev/null +++ b/internal/ameda/initialize.go @@ -0,0 +1,308 @@ +package ameda + +import ( + "reflect" +) + +// InitPointer initializes nil pointer with zero value. +func InitPointer(v reflect.Value) (done bool) { + for { + kind := v.Kind() + if kind == reflect.Interface { + v = v.Elem() + continue + } + if kind != reflect.Ptr { + return true + } + u := v.Elem() + if u.IsValid() { + v = u + continue + } + if !v.CanSet() { + return false + } + v2 := reflect.New(v.Type().Elem()) + v.Set(v2) + v = v.Elem() + } +} + +// InitString initializes empty string pointer with def. +func InitString(p *string, def string) (done bool) { + if p == nil { + return false + } + if *p == "" { + *p = def + } + return true +} + +// InitBool initializes false bool pointer with def. +func InitBool(p *bool, def bool) (done bool) { + if p == nil { + return false + } + if *p == false { + *p = def + } + return true +} + +// InitByte initializes zero byte pointer with def. +func InitByte(p *byte, def byte) (done bool) { + if p == nil { + return false + } + if *p == 0 { + *p = def + } + return true +} + +// InitInt initializes zero int pointer with def. +func InitInt(p *int, def int) (done bool) { + if p == nil { + return false + } + if *p == 0 { + *p = def + } + return true +} + +// InitInt8 initializes zero int8 pointer with def. +func InitInt8(p *int8, def int8) (done bool) { + if p == nil { + return false + } + if *p == 0 { + *p = def + } + return true +} + +// InitInt16 initializes zero int16 pointer with def. +func InitInt16(p *int16, def int16) (done bool) { + if p == nil { + return false + } + if *p == 0 { + *p = def + } + return true +} + +// InitInt32 initializes zero int32 pointer with def. +func InitInt32(p *int32, def int32) (done bool) { + if p == nil { + return false + } + if *p == 0 { + *p = def + } + return true +} + +// InitInt64 initializes zero int64 pointer with def. +func InitInt64(p *int64, def int64) (done bool) { + if p == nil { + return false + } + if *p == 0 { + *p = def + } + return true +} + +// InitUint initializes zero uint pointer with def. +func InitUint(p *uint, def uint) (done bool) { + if p == nil { + return false + } + if *p == 0 { + *p = def + } + return true +} + +// InitUint8 initializes zero uint8 pointer with def. +func InitUint8(p *uint8, def uint8) (done bool) { + if p == nil { + return false + } + if *p == 0 { + *p = def + } + return true +} + +// InitUint16 initializes zero uint16 pointer with def. +func InitUint16(p *uint16, def uint16) (done bool) { + if p == nil { + return false + } + if *p == 0 { + *p = def + } + return true +} + +// InitUint32 initializes zero uint32 pointer with def. +func InitUint32(p *uint32, def uint32) (done bool) { + if p == nil { + return false + } + if *p == 0 { + *p = def + } + return true +} + +// InitUint64 initializes zero uint64 pointer with def. +func InitUint64(p *uint64, def uint64) (done bool) { + if p == nil { + return false + } + if *p == 0 { + *p = def + } + return true +} + +// InitFloat32 initializes zero float32 pointer with def. +func InitFloat32(p *float32, def float32) (done bool) { + if p == nil { + return false + } + if *p == 0 { + *p = def + } + return true +} + +// InitFloat64 initializes zero float64 pointer with def. +func InitFloat64(p *float64, def float64) (done bool) { + if p == nil { + return false + } + if *p == 0 { + *p = def + } + return true +} + +// InitSampleValue initialize the given type with some non-zero value( "?", $max_number, 0.1, true) +func InitSampleValue(t reflect.Type, maxNestingDeep int) reflect.Value { + if maxNestingDeep <= 0 { + maxNestingDeep = 10 + } + ptrDepth := 0 + for t.Kind() == reflect.Ptr { + t = t.Elem() + ptrDepth++ + } + v := reflect.New(t) + v = initValue(v, 1, maxNestingDeep) + return ReferenceValue(v, ptrDepth-1) +} + +func initValue(v reflect.Value, curDeep int, maxDeep int) reflect.Value { + InitPointer(v) + if curDeep >= maxDeep { + return v + } + var numPtr int + for v.Kind() == reflect.Ptr { + v = v.Elem() + numPtr++ + } + if v.CanSet() { + switch v.Kind() { + case reflect.Struct: + curDeep++ + fieldNum := v.Type().NumField() + for i := 0; i < fieldNum; i++ { + e := v.Field(i) + InitPointer(e) + if e.CanSet() { + e.Set(initValue(e, curDeep, maxDeep)) + } + } + case reflect.Slice: + if v.Len() == 0 { + e := reflect.New(v.Type().Elem()) + InitPointer(e) + e = e.Elem() + e = initValue(e, curDeep, maxDeep) + if v.CanSet() { + v.Set(reflect.Append(v, e)) + } + } + case reflect.Array: + if v.Len() > 0 { + e := reflect.New(v.Type().Elem()) + InitPointer(e) + e = e.Elem() + e = initValue(e, curDeep, maxDeep) + vv := v.Index(0) + if vv.CanSet() { + vv.Set(reflect.Append(v, e)) + } + } + case reflect.Map: + if v.Len() == 0 { + v.Set(reflect.MakeMap(v.Type())) + k := reflect.New(v.Type().Key()) + InitPointer(k) + k = k.Elem() + k = initValue(k, curDeep, maxDeep) + e := reflect.New(v.Type().Elem()) + InitPointer(e) + e = e.Elem() + e = initValue(e, curDeep, maxDeep) + v.SetMapIndex(k, e) + } + case reflect.Int: + if Host32bit { + v.SetInt(-32) + } else { + v.SetInt(-64) + } + case reflect.Int8: + v.SetInt(-8) + case reflect.Int16: + v.SetInt(-16) + case reflect.Int32: + v.SetInt(-32) + case reflect.Int64: + v.SetInt(-64) + case reflect.Uint, reflect.Uintptr: + if Host32bit { + v.SetUint(32) + } else { + v.SetUint(64) + } + case reflect.Uint8: + v.SetUint(8) + case reflect.Uint16: + v.SetUint(16) + case reflect.Uint32: + v.SetUint(32) + case reflect.Uint64: + v.SetUint(64) + case reflect.Float32: + v.SetFloat(-0.32) + case reflect.Float64: + v.SetFloat(-0.64) + case reflect.Bool: + v.SetBool(true) + case reflect.String: + v.SetString("?") + default: + } + } + return ReferenceValue(v, numPtr) +} diff --git a/internal/ameda/int.go b/internal/ameda/int.go new file mode 100644 index 0000000..0409fc6 --- /dev/null +++ b/internal/ameda/int.go @@ -0,0 +1,203 @@ +package ameda + +import ( + "math" + "strconv" +) + +// MaxInt returns max int number for current os. +func MaxInt() int { + return MaxInteger +} + +// IntToInterface converts int to interface. +func IntToInterface(v int) interface{} { + return v +} + +// IntToInterfacePtr converts int to *interface. +func IntToInterfacePtr(v int) *interface{} { + r := IntToInterface(v) + return &r +} + +// IntToString converts int to string. +func IntToString(v int) string { + return strconv.Itoa(v) +} + +// IntToStringPtr converts int to *string. +func IntToStringPtr(v int) *string { + r := IntToString(v) + return &r +} + +// IntToBool converts int to bool. +func IntToBool(v int) bool { + return v != 0 +} + +// IntToBoolPtr converts int to *bool. +func IntToBoolPtr(v int) *bool { + r := IntToBool(v) + return &r +} + +// IntToFloat32 converts int to float32. +func IntToFloat32(v int) float32 { + return float32(v) +} + +// IntToFloat32Ptr converts int to *float32. +func IntToFloat32Ptr(v int) *float32 { + r := IntToFloat32(v) + return &r +} + +// IntToFloat64 converts int to float64. +func IntToFloat64(v int) float64 { + return float64(v) +} + +// IntToFloat64Ptr converts int to *float64. +func IntToFloat64Ptr(v int) *float64 { + r := IntToFloat64(v) + return &r +} + +// IntToIntPtr converts int to *int. +func IntToIntPtr(v int) *int { + return &v +} + +// IntToInt8 converts int to int8. +func IntToInt8(v int) (int8, error) { + if v > math.MaxInt8 || v < math.MinInt8 { + return 0, errOverflowValue + } + return int8(v), nil +} + +// IntToInt8Ptr converts int to *int8. +func IntToInt8Ptr(v int) (*int8, error) { + r, err := IntToInt8(v) + return &r, err +} + +// IntToInt16 converts int to int16. +func IntToInt16(v int) (int16, error) { + if v > math.MaxInt16 || v < math.MinInt16 { + return 0, errOverflowValue + } + return int16(v), nil +} + +// IntToInt16Ptr converts int to *int16. +func IntToInt16Ptr(v int) (*int16, error) { + r, err := IntToInt16(v) + return &r, err +} + +// IntToInt32 converts int to int32. +func IntToInt32(v int) (int32, error) { + if Host64bit && (v > math.MaxInt32 || v < math.MinInt32) { + return 0, errOverflowValue + } + return int32(v), nil +} + +// IntToInt32Ptr converts int to *int32. +func IntToInt32Ptr(v int) (*int32, error) { + r, err := IntToInt32(v) + return &r, err +} + +// IntToInt64 converts int to int64. +func IntToInt64(v int) int64 { + return int64(v) +} + +// IntToInt64Ptr converts int to *int64. +func IntToInt64Ptr(v int) *int64 { + r := IntToInt64(v) + return &r +} + +// IntToUint converts int to uint. +func IntToUint(v int) (uint, error) { + if v < 0 { + return 0, errNegativeValue + } + return uint(v), nil +} + +// IntToUintPtr converts int to *uint. +func IntToUintPtr(v int) (*uint, error) { + r, err := IntToUint(v) + return &r, err +} + +// IntToUint8 converts int to uint8. +func IntToUint8(v int) (uint8, error) { + if v < 0 { + return 0, errNegativeValue + } + if v > math.MaxUint8 { + return 0, errOverflowValue + } + return uint8(v), nil +} + +// IntToUint8Ptr converts int to *uint8. +func IntToUint8Ptr(v int) (*uint8, error) { + r, err := IntToUint8(v) + return &r, err +} + +// IntToUint16 converts int to uint16. +func IntToUint16(v int) (uint16, error) { + if v < 0 { + return 0, errNegativeValue + } + if v > math.MaxUint16 { + return 0, errOverflowValue + } + return uint16(v), nil +} + +// IntToUint16Ptr converts int to *uint16. +func IntToUint16Ptr(v int) (*uint16, error) { + r, err := IntToUint16(v) + return &r, err +} + +// IntToUint32 converts int to uint32. +func IntToUint32(v int) (uint32, error) { + if v < 0 { + return 0, errNegativeValue + } + if Host64bit && v > int(maxUint32) { + return 0, errOverflowValue + } + return uint32(v), nil +} + +// IntToUint32Ptr converts int to *uint32. +func IntToUint32Ptr(v int) (*uint32, error) { + r, err := IntToUint32(v) + return &r, err +} + +// IntToUint64 converts int to uint64. +func IntToUint64(v int) (uint64, error) { + if v < 0 { + return 0, errNegativeValue + } + return uint64(v), nil +} + +// IntToUint64Ptr converts int to *uint64. +func IntToUint64Ptr(v int) (*uint64, error) { + r, err := IntToUint64(v) + return &r, err +} diff --git a/internal/ameda/int16.go b/internal/ameda/int16.go new file mode 100644 index 0000000..73513d5 --- /dev/null +++ b/internal/ameda/int16.go @@ -0,0 +1,186 @@ +package ameda + +import ( + "math" + "strconv" +) + +// Int16ToInterface converts int16 to interface. +func Int16ToInterface(v int16) interface{} { + return v +} + +// Int16ToInterfacePtr converts int16 to *interface. +func Int16ToInterfacePtr(v int16) *interface{} { + r := Int16ToInterface(v) + return &r +} + +// Int16ToString converts int16 to string. +func Int16ToString(v int16) string { + return strconv.FormatInt(int64(v), 10) +} + +// Int16ToStringPtr converts int16 to *string. +func Int16ToStringPtr(v int16) *string { + r := Int16ToString(v) + return &r +} + +// Int16ToBool converts int16 to bool. +func Int16ToBool(v int16) bool { + return v != 0 +} + +// Int16ToBoolPtr converts int16 to *bool. +func Int16ToBoolPtr(v int16) *bool { + r := Int16ToBool(v) + return &r +} + +// Int16ToFloat32 converts int16 to float32. +func Int16ToFloat32(v int16) float32 { + return float32(v) +} + +// Int16ToFloat32Ptr converts int16 to *float32. +func Int16ToFloat32Ptr(v int16) *float32 { + r := Int16ToFloat32(v) + return &r +} + +// Int16ToFloat64 converts int16 to float64. +func Int16ToFloat64(v int16) float64 { + return float64(v) +} + +// Int16ToFloat64Ptr converts int16 to *float64. +func Int16ToFloat64Ptr(v int16) *float64 { + r := Int16ToFloat64(v) + return &r +} + +// Int16ToInt converts int16 to int. +func Int16ToInt(v int16) int { + return int(v) +} + +// Int16ToIntPtr converts int16 to *int. +func Int16ToIntPtr(v int16) *int { + r := Int16ToInt(v) + return &r +} + +// Int16ToInt8 converts int16 to int8. +func Int16ToInt8(v int16) (int8, error) { + if v > math.MaxInt8 || v < math.MinInt8 { + return 0, errOverflowValue + } + return int8(v), nil +} + +// Int16ToInt8Ptr converts int16 to *int8. +func Int16ToInt8Ptr(v int16) (*int8, error) { + r, err := Int16ToInt8(v) + return &r, err +} + +// Int16ToInt16Ptr converts int16 to *int16. +func Int16ToInt16Ptr(v int16) *int16 { + return &v +} + +// Int16ToInt32 converts int16 to int32. +func Int16ToInt32(v int16) int32 { + return int32(v) +} + +// Int16ToInt32Ptr converts int16 to *int32. +func Int16ToInt32Ptr(v int16) *int32 { + r := Int16ToInt32(v) + return &r +} + +// Int16ToInt64 converts int16 to int64. +func Int16ToInt64(v int16) int64 { + return int64(v) +} + +// Int16ToInt64Ptr converts int16 to *int64. +func Int16ToInt64Ptr(v int16) *int64 { + r := Int16ToInt64(v) + return &r +} + +// Int16ToUint converts int16 to uint. +func Int16ToUint(v int16) (uint, error) { + if v < 0 { + return 0, errNegativeValue + } + return uint(v), nil +} + +// Int16ToUintPtr converts int16 to *uint. +func Int16ToUintPtr(v int16) (*uint, error) { + r, err := Int16ToUint(v) + return &r, err +} + +// Int16ToUint8 converts int16 to uint8. +func Int16ToUint8(v int16) (uint8, error) { + if v < 0 { + return 0, errNegativeValue + } + if v > math.MaxUint8 { + return 0, errOverflowValue + } + return uint8(v), nil +} + +// Int16ToUint8Ptr converts int16 to *uint8. +func Int16ToUint8Ptr(v int16) (*uint8, error) { + r, err := Int16ToUint8(v) + return &r, err +} + +// Int16ToUint16 converts int16 to uint16. +func Int16ToUint16(v int16) (uint16, error) { + if v < 0 { + return 0, errNegativeValue + } + return uint16(v), nil +} + +// Int16ToUint16Ptr converts int16 to *uint16. +func Int16ToUint16Ptr(v int16) (*uint16, error) { + r, err := Int16ToUint16(v) + return &r, err +} + +// Int16ToUint32 converts int16 to uint32. +func Int16ToUint32(v int16) (uint32, error) { + if v < 0 { + return 0, errNegativeValue + } + return uint32(v), nil +} + +// Int16ToUint32Ptr converts int16 to *uint32. +func Int16ToUint32Ptr(v int16) (*uint32, error) { + r, err := Int16ToUint32(v) + return &r, err +} + +// Int16ToUint64 converts int16 to uint64. +func Int16ToUint64(v int16) (uint64, error) { + if v < 0 { + return 0, errNegativeValue + } + return uint64(v), nil +} + +// Int16ToUint64Ptr converts int16 to *uint64. +func Int16ToUint64Ptr(v int16) (*uint64, error) { + r, err := Int16ToUint64(v) + return &r, err +} diff --git a/internal/ameda/int16s.go b/internal/ameda/int16s.go new file mode 100644 index 0000000..13b35e2 --- /dev/null +++ b/internal/ameda/int16s.go @@ -0,0 +1,678 @@ +package ameda + +// OneInt16 try to return the first element, otherwise return zero value. +func OneInt16(i []int16) int16 { + if len(i) > 0 { + return i[0] + } + return 0 +} + +// Int16sCopy creates a copy of the int16 slice. +func Int16sCopy(i []int16) []int16 { + b := make([]int16, len(i)) + copy(b, i) + return b +} + +// Int16sToInterfaces converts int16 slice to interface slice. +func Int16sToInterfaces(i []int16) []interface{} { + r := make([]interface{}, len(i)) + for k, v := range i { + r[k] = v + } + return r +} + +// Int16sToStrings converts int16 slice to string slice. +func Int16sToStrings(i []int16) []string { + r := make([]string, len(i)) + for k, v := range i { + r[k] = Int16ToString(v) + } + return r +} + +// Int16sToBools converts int16 slice to bool slice. +// NOTE: +// 0 is false, everything else is true +func Int16sToBools(i []int16) []bool { + r := make([]bool, len(i)) + for k, v := range i { + r[k] = Int16ToBool(v) + } + return r +} + +// Int16sToFloat32s converts int16 slice to float32 slice. +func Int16sToFloat32s(i []int16) []float32 { + r := make([]float32, len(i)) + for k, v := range i { + r[k] = Int16ToFloat32(v) + } + return r +} + +// Int16sToFloat64s converts int16 slice to float64 slice. +func Int16sToFloat64s(i []int16) []float64 { + r := make([]float64, len(i)) + for k, v := range i { + r[k] = Int16ToFloat64(v) + } + return r +} + +// Int16sToInts converts int16 slice to int slice. +func Int16sToInts(i []int16) []int { + r := make([]int, len(i)) + for k, v := range i { + r[k] = Int16ToInt(v) + } + return r +} + +// Int16sToInt8s converts int16 slice to int8 slice. +func Int16sToInt8s(i []int16) ([]int8, error) { + var err error + r := make([]int8, len(i)) + for k, v := range i { + r[k], err = Int16ToInt8(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int16sToInt32s converts int16 slice to int32 slice. +func Int16sToInt32s(i []int16) []int32 { + r := make([]int32, len(i)) + for k, v := range i { + r[k] = Int16ToInt32(v) + } + return r +} + +// Int16sToInt64s converts int16 slice to int64 slice. +func Int16sToInt64s(i []int16) []int64 { + r := make([]int64, len(i)) + for k, v := range i { + r[k] = Int16ToInt64(v) + } + return r +} + +// Int16sToUints converts int16 slice to uint slice. +func Int16sToUints(i []int16) ([]uint, error) { + var err error + r := make([]uint, len(i)) + for k, v := range i { + r[k], err = Int16ToUint(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int16sToUint8s converts int16 slice to uint8 slice. +func Int16sToUint8s(i []int16) ([]uint8, error) { + var err error + r := make([]uint8, len(i)) + for k, v := range i { + r[k], err = Int16ToUint8(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int16sToUint16s converts int16 slice to uint16 slice. +func Int16sToUint16s(i []int16) ([]uint16, error) { + var err error + r := make([]uint16, len(i)) + for k, v := range i { + r[k], err = Int16ToUint16(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int16sToUint32s converts int16 slice to uint32 slice. +func Int16sToUint32s(i []int16) ([]uint32, error) { + var err error + r := make([]uint32, len(i)) + for k, v := range i { + r[k], err = Int16ToUint32(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int16sToUint64s converts int16 slice to uint64 slice. +func Int16sToUint64s(i []int16) ([]uint64, error) { + var err error + r := make([]uint64, len(i)) + for k, v := range i { + r[k], err = Int16ToUint64(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int16sCopyWithin copies part of an slice to another location in the current slice. +// @target +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func Int16sCopyWithin(i []int16, target, start int, end ...int) { + target = fixIndex(len(i), target, true) + if target == len(i) { + return + } + sub := Int16sSlice(i, start, end...) + for k, v := range sub { + i[target+k] = v + } +} + +// Int16sEvery tests whether all elements in the slice pass the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice will return true for any condition! +func Int16sEvery(i []int16, fn func(i []int16, k int, v int16) bool) bool { + for k, v := range i { + if !fn(i, k, v) { + return false + } + } + return true +} + +// Int16sFill changes all elements in the current slice to a value, from a start index to an end index. +// @value +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func Int16sFill(i []int16, value int16, start int, end ...int) { + fixedStart, fixedEnd, ok := fixRange(len(i), start, end...) + if !ok { + return + } + for k := fixedStart; k < fixedEnd; k++ { + i[k] = value + } +} + +// Int16sFilter creates a new slice with all elements that pass the test implemented by the provided function. +func Int16sFilter(i []int16, fn func(i []int16, k int, v int16) bool) []int16 { + ret := make([]int16, 0) + for k, v := range i { + if fn(i, k, v) { + ret = append(ret, v) + } + } + return ret +} + +// Int16sFind returns the key-value of the first element in the provided slice that satisfies the provided testing function. +// NOTE: +// If not found, k = -1 +func Int16sFind(i []int16, fn func(i []int16, k int, v int16) bool) (k int, v int16) { + for k, v := range i { + if fn(i, k, v) { + return k, v + } + } + return -1, 0 +} + +// Int16sIncludes determines whether an slice includes a certain value among its entries. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Int16sIncludes(i []int16, valueToFind int16, fromIndex ...int) bool { + return Int16sIndexOf(i, valueToFind, fromIndex...) > -1 +} + +// Int16sIndexOf returns the first index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Int16sIndexOf(i []int16, searchElement int16, fromIndex ...int) int { + idx := getFromIndex(len(i), fromIndex...) + for k, v := range i[idx:] { + if searchElement == v { + return k + idx + } + } + return -1 +} + +// Int16sLastIndexOf returns the last index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Int16sLastIndexOf(i []int16, searchElement int16, fromIndex ...int) int { + idx := getFromIndex(len(i), fromIndex...) + for k := len(i) - 1; k >= idx; k-- { + if searchElement == i[k] { + return k + } + } + return -1 +} + +// Int16sMap creates a new slice populated with the results of calling a provided function +// on every element in the calling slice. +func Int16sMap(i []int16, fn func(i []int16, k int, v int16) int16) []int16 { + ret := make([]int16, len(i)) + for k, v := range i { + ret[k] = fn(i, k, v) + } + return ret +} + +// Int16sPop removes the last element from an slice and returns that element. +// This method changes the length of the slice. +func Int16sPop(i *[]int16) (int16, bool) { + a := *i + if len(a) == 0 { + return 0, false + } + lastIndex := len(a) - 1 + last := a[lastIndex] + a = a[:lastIndex] + *i = a[:len(a):len(a)] + return last, true +} + +// Int16sPush adds one or more elements to the end of an slice and returns the new length of the slice. +func Int16sPush(i *[]int16, element ...int16) int { + *i = append(*i, element...) + return len(*i) +} + +// Int16sPushDistinct adds one or more new elements that do not exist in the current slice at the end. +func Int16sPushDistinct(i []int16, element ...int16) []int16 { +L: + for _, v := range element { + for _, vv := range i { + if vv == v { + continue L + } + } + i = append(i, v) + } + return i +} + +// Int16sReduce executes a reducer function (that you provide) on each element of the slice, +// resulting in a single output value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func Int16sReduce(i []int16, + fn func(i []int16, k int, v, accumulator int16) int16, initialValue ...int16, +) int16 { + if len(i) == 0 { + return 0 + } + start := 0 + acc := i[start] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + start += 1 + } + for k := start; k < len(i); k++ { + acc = fn(i, k, i[k], acc) + } + return acc +} + +// Int16sReduceRight applies a function against an accumulator and each value of the slice (from right-to-left) +// to reduce it to a single value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func Int16sReduceRight(i []int16, + fn func(i []int16, k int, v, accumulator int16) int16, initialValue ...int16, +) int16 { + if len(i) == 0 { + return 0 + } + end := len(i) - 1 + acc := i[end] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + end -= 1 + } + for k := end; k >= 0; k-- { + acc = fn(i, k, i[k], acc) + } + return acc +} + +// Int16sReverse reverses an slice in place. +func Int16sReverse(i []int16) { + first := 0 + last := len(i) - 1 + for first < last { + i[first], i[last] = i[last], i[first] + first++ + last-- + } +} + +// Int16sShift removes the first element from an slice and returns that removed element. +// This method changes the length of the slice. +func Int16sShift(i *[]int16) (int16, bool) { + a := *i + if len(a) == 0 { + return 0, false + } + first := a[0] + a = a[1:] + *i = a[:len(a):len(a)] + return first, true +} + +// Int16sSlice returns a copy of a portion of an slice into a new slice object selected +// from begin to end (end not included) where begin and end represent the index of items in that slice. +// The original slice will not be modified. +func Int16sSlice(i []int16, begin int, end ...int) []int16 { + fixedStart, fixedEnd, ok := fixRange(len(i), begin, end...) + if !ok { + return []int16{} + } + return Int16sCopy(i[fixedStart:fixedEnd]) +} + +// Int16sSome tests whether at least one element in the slice passes the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice returns false for any condition! +func Int16sSome(i []int16, fn func(i []int16, k int, v int16) bool) bool { + for k, v := range i { + if fn(i, k, v) { + return true + } + } + return false +} + +// Int16sSplice changes the contents of an slice by removing or replacing +// existing elements and/or adding new elements in place. +func Int16sSplice(i *[]int16, start, deleteCount int, items ...int16) { + a := *i + if deleteCount < 0 { + deleteCount = 0 + } + start, end, _ := fixRange(len(a), start, start+1+deleteCount) + deleteCount = end - start - 1 + for k := 0; k < len(items); k++ { + if deleteCount > 0 { + // replace + a[start] = items[k] + deleteCount-- + start++ + } else { + // insert + lastSlice := Int16sCopy(a[start:]) + items = items[k:] + a = append(a[:start], items...) + a = append(a[:start+len(items)], lastSlice...) + *i = a[:len(a):len(a)] + return + } + } + if deleteCount > 0 { + a = append(a[:start], a[start+1+deleteCount:]...) + } + *i = a[:len(a):len(a)] +} + +// Int16sUnshift adds one or more elements to the beginning of an slice and returns the new length of the slice. +func Int16sUnshift(i *[]int16, element ...int16) int { + *i = append(element, *i...) + return len(*i) +} + +// Int16sUnshiftDistinct adds one or more new elements that do not exist in the current slice to the beginning +// and returns the new length of the slice. +func Int16sUnshiftDistinct(i *[]int16, element ...int16) int { + a := *i + if len(element) == 0 { + return len(a) + } + m := make(map[int16]bool, len(element)) + r := make([]int16, 0, len(a)+len(element)) +L: + for _, v := range element { + if m[v] { + continue + } + m[v] = true + for _, vv := range a { + if vv == v { + continue L + } + } + r = append(r, v) + } + r = append(r, a...) + *i = r[:len(r):len(r)] + return len(r) +} + +// Int16sRemoveFirst removes the first matched elements from the slice, +// and returns the new length of the slice. +func Int16sRemoveFirst(p *[]int16, elements ...int16) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for k, v := range a { + if v == element { + a = append(a[:k], a[k+1:]...) + break + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// Int16sRemoveEvery removes all the elements from the slice, +// and returns the new length of the slice. +func Int16sRemoveEvery(p *[]int16, elements ...int16) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for i := 0; i < len(a); i++ { + if a[i] == element { + a = append(a[:i], a[i+1:]...) + i-- + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// Int16sConcat is used to merge two or more slices. +// This method does not change the existing slices, but instead returns a new slice. +func Int16sConcat(i ...[]int16) []int16 { + var totalLen int + for _, v := range i { + totalLen += len(v) + } + ret := make([]int16, totalLen) + dst := ret + for _, v := range i { + n := copy(dst, v) + dst = dst[n:] + } + return ret +} + +// Int16sIntersect calculates intersection of two or more slices, +// and returns the count of each element. +func Int16sIntersect(i ...[]int16) (intersectCount map[int16]int) { + if len(i) == 0 { + return nil + } + for _, v := range i { + if len(v) == 0 { + return nil + } + } + counts := make([]map[int16]int, len(i)) + for k, v := range i { + counts[k] = int16sDistinct(v, nil) + } + intersectCount = counts[0] +L: + for k, v := range intersectCount { + for _, c := range counts[1:] { + v2 := c[k] + if v2 == 0 { + delete(intersectCount, k) + continue L + } + if v > v2 { + v = v2 + } + } + intersectCount[k] = v + } + return intersectCount +} + +// Int16sDistinct calculates the count of each different element, +// and only saves these different elements in place if changeSlice is true. +func Int16sDistinct(i *[]int16, changeSlice bool) (distinctCount map[int16]int) { + if !changeSlice { + return int16sDistinct(*i, nil) + } + a := (*i)[:0] + distinctCount = int16sDistinct(*i, &a) + n := len(distinctCount) + *i = a[:n:n] + return distinctCount +} + +func int16sDistinct(src []int16, dst *[]int16) map[int16]int { + m := make(map[int16]int, len(src)) + if dst == nil { + for _, v := range src { + n := m[v] + m[v] = n + 1 + } + } else { + a := *dst + for _, v := range src { + n := m[v] + m[v] = n + 1 + if n == 0 { + a = append(a, v) + } + } + *dst = a + } + return m +} + +// Int16SetUnion calculates between multiple collections: set1 ∪ set2 ∪ others... +// This method does not change the existing slices, but instead returns a new slice. +func Int16SetUnion(set1, set2 []int16, others ...[]int16) []int16 { + m := make(map[int16]struct{}, len(set1)+len(set2)) + r := make([]int16, 0, len(m)) + for _, set := range append([][]int16{set1, set2}, others...) { + for _, v := range set { + _, ok := m[v] + if ok { + continue + } + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} + +// Int16SetIntersect calculates between multiple collections: set1 ∩ set2 ∩ others... +// This method does not change the existing slices, but instead returns a new slice. +func Int16SetIntersect(set1, set2 []int16, others ...[]int16) []int16 { + sets := append([][]int16{set2}, others...) + setsCount := make([]map[int16]int, len(sets)) + for k, v := range sets { + setsCount[k] = int16sDistinct(v, nil) + } + m := make(map[int16]struct{}, len(set1)) + r := make([]int16, 0, len(m)) +L: + for _, v := range set1 { + if _, ok := m[v]; ok { + continue + } + m[v] = struct{}{} + for _, m2 := range setsCount { + if m2[v] == 0 { + continue L + } + } + r = append(r, v) + } + return r +} + +// Int16SetDifference calculates between multiple collections: set1 - set2 - others... +// This method does not change the existing slices, but instead returns a new slice. +func Int16SetDifference(set1, set2 []int16, others ...[]int16) []int16 { + m := make(map[int16]struct{}, len(set1)) + r := make([]int16, 0, len(set1)) + sets := append([][]int16{set2}, others...) + for _, v := range sets { + inter := Int16SetIntersect(set1, v) + for _, v := range inter { + m[v] = struct{}{} + } + } + for _, v := range set1 { + if _, ok := m[v]; !ok { + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} diff --git a/internal/ameda/int32.go b/internal/ameda/int32.go new file mode 100644 index 0000000..6719926 --- /dev/null +++ b/internal/ameda/int32.go @@ -0,0 +1,192 @@ +package ameda + +import ( + "math" + "strconv" +) + +// Int32ToInterface converts int32 to interface. +func Int32ToInterface(v int32) interface{} { + return v +} + +// Int32ToInterfacePtr converts int32 to *interface. +func Int32ToInterfacePtr(v int32) *interface{} { + r := Int32ToInterface(v) + return &r +} + +// Int32ToString converts int32 to string. +func Int32ToString(v int32) string { + return strconv.FormatInt(int64(v), 10) +} + +// Int32ToStringPtr converts int32 to *string. +func Int32ToStringPtr(v int32) *string { + r := Int32ToString(v) + return &r +} + +// Int32ToBool converts int32 to bool. +func Int32ToBool(v int32) bool { + return v != 0 +} + +// Int32ToBoolPtr converts int32 to *bool. +func Int32ToBoolPtr(v int32) *bool { + r := Int32ToBool(v) + return &r +} + +// Int32ToFloat32 converts int32 to float32. +func Int32ToFloat32(v int32) float32 { + return float32(v) +} + +// Int32ToFloat32Ptr converts int32 to *float32. +func Int32ToFloat32Ptr(v int32) *float32 { + r := Int32ToFloat32(v) + return &r +} + +// Int32ToFloat64 converts int32 to float64. +func Int32ToFloat64(v int32) float64 { + return float64(v) +} + +// Int32ToFloat64Ptr converts int32 to *float64. +func Int32ToFloat64Ptr(v int32) *float64 { + r := Int32ToFloat64(v) + return &r +} + +// Int32ToInt converts int32 to int. +func Int32ToInt(v int32) int { + return int(v) +} + +// Int32ToIntPtr converts int32 to *int. +func Int32ToIntPtr(v int32) *int { + r := Int32ToInt(v) + return &r +} + +// Int32ToInt8 converts int32 to int8. +func Int32ToInt8(v int32) (int8, error) { + if v > math.MaxInt8 || v < math.MinInt8 { + return 0, errOverflowValue + } + return int8(v), nil +} + +// Int32ToInt8Ptr converts int32 to *int8. +func Int32ToInt8Ptr(v int32) (*int8, error) { + r, err := Int32ToInt8(v) + return &r, err +} + +// Int32ToInt16 converts int32 to int16. +func Int32ToInt16(v int32) (int16, error) { + if v > math.MaxInt16 || v < math.MinInt16 { + return 0, errOverflowValue + } + return int16(v), nil +} + +// Int32ToInt16Ptr converts int32 to *int16. +func Int32ToInt16Ptr(v int32) (*int16, error) { + r, err := Int32ToInt16(v) + return &r, err +} + +// Int32ToInt32Ptr converts int32 to *int32. +func Int32ToInt32Ptr(v int32) *int32 { + return &v +} + +// Int32ToInt64 converts int32 to int64. +func Int32ToInt64(v int32) int64 { + return int64(v) +} + +// Int32ToInt64Ptr converts int32 to *int64. +func Int32ToInt64Ptr(v int32) *int64 { + r := Int32ToInt64(v) + return &r +} + +// Int32ToUint converts int32 to uint. +func Int32ToUint(v int32) (uint, error) { + if v < 0 { + return 0, errNegativeValue + } + return uint(v), nil +} + +// Int32ToUintPtr converts int32 to *uint. +func Int32ToUintPtr(v int32) (*uint, error) { + r, err := Int32ToUint(v) + return &r, err +} + +// Int32ToUint8 converts int32 to uint8. +func Int32ToUint8(v int32) (uint8, error) { + if v < 0 { + return 0, errNegativeValue + } + if v > math.MaxUint8 { + return 0, errOverflowValue + } + return uint8(v), nil +} + +// Int32ToUint8Ptr converts int32 to *uint8. +func Int32ToUint8Ptr(v int32) (*uint8, error) { + r, err := Int32ToUint8(v) + return &r, err +} + +// Int32ToUint16 converts int32 to uint16. +func Int32ToUint16(v int32) (uint16, error) { + if v < 0 { + return 0, errNegativeValue + } + if v > math.MaxUint16 { + return 0, errOverflowValue + } + return uint16(v), nil +} + +// Int32ToUint16Ptr converts int32 to *uint16. +func Int32ToUint16Ptr(v int32) (*uint16, error) { + r, err := Int32ToUint16(v) + return &r, err +} + +// Int32ToUint32 converts int32 to uint32. +func Int32ToUint32(v int32) (uint32, error) { + if v < 0 { + return 0, errNegativeValue + } + return uint32(v), nil +} + +// Int32ToUint32Ptr converts int32 to *uint32. +func Int32ToUint32Ptr(v int32) (*uint32, error) { + r, err := Int32ToUint32(v) + return &r, err +} + +// Int32ToUint64 converts int32 to uint64. +func Int32ToUint64(v int32) (uint64, error) { + if v < 0 { + return 0, errNegativeValue + } + return uint64(v), nil +} + +// Int32ToUint64Ptr converts int32 to *uint64. +func Int32ToUint64Ptr(v int32) (*uint64, error) { + r, err := Int32ToUint64(v) + return &r, err +} diff --git a/internal/ameda/int32s.go b/internal/ameda/int32s.go new file mode 100644 index 0000000..0b32f47 --- /dev/null +++ b/internal/ameda/int32s.go @@ -0,0 +1,682 @@ +package ameda + +// OneInt32 try to return the first element, otherwise return zero value. +func OneInt32(i []int32) int32 { + if len(i) > 0 { + return i[0] + } + return 0 +} + +// Int32sCopy creates a copy of the int32 slice. +func Int32sCopy(i []int32) []int32 { + b := make([]int32, len(i)) + copy(b, i) + return b +} + +// Int32sToInterfaces converts int32 slice to interface slice. +func Int32sToInterfaces(i []int32) []interface{} { + r := make([]interface{}, len(i)) + for k, v := range i { + r[k] = Int32ToInterface(v) + } + return r +} + +// Int32sToStrings converts int32 slice to string slice. +func Int32sToStrings(i []int32) []string { + r := make([]string, len(i)) + for k, v := range i { + r[k] = Int32ToString(v) + } + return r +} + +// Int32sToBools converts int32 slice to bool slice. +// NOTE: +// 0 is false, everything else is true +func Int32sToBools(i []int32) []bool { + r := make([]bool, len(i)) + for k, v := range i { + r[k] = Int32ToBool(v) + } + return r +} + +// Int32sToFloat32s converts int32 slice to float32 slice. +func Int32sToFloat32s(i []int32) []float32 { + r := make([]float32, len(i)) + for k, v := range i { + r[k] = Int32ToFloat32(v) + } + return r +} + +// Int32sToFloat64s converts int32 slice to float64 slice. +func Int32sToFloat64s(i []int32) []float64 { + r := make([]float64, len(i)) + for k, v := range i { + r[k] = Int32ToFloat64(v) + } + return r +} + +// Int32sToInts converts int32 slice to int slice. +func Int32sToInts(i []int32) []int { + r := make([]int, len(i)) + for k, v := range i { + r[k] = Int32ToInt(v) + } + return r +} + +// Int32sToInt8s converts int32 slice to int8 slice. +func Int32sToInt8s(i []int32) ([]int8, error) { + var err error + r := make([]int8, len(i)) + for k, v := range i { + r[k], err = Int32ToInt8(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int32sToInt16s converts int32 slice to int16 slice. +func Int32sToInt16s(i []int32) ([]int16, error) { + var err error + r := make([]int16, len(i)) + for k, v := range i { + r[k], err = Int32ToInt16(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int32sToInt64s converts int32 slice to int64 slice. +func Int32sToInt64s(i []int32) []int64 { + r := make([]int64, len(i)) + for k, v := range i { + r[k] = Int32ToInt64(v) + } + return r +} + +// Int32sToUints converts int32 slice to uint slice. +func Int32sToUints(i []int32) ([]uint, error) { + var err error + r := make([]uint, len(i)) + for k, v := range i { + r[k], err = Int32ToUint(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int32sToUint8s converts int32 slice to uint8 slice. +func Int32sToUint8s(i []int32) ([]uint8, error) { + var err error + r := make([]uint8, len(i)) + for k, v := range i { + r[k], err = Int32ToUint8(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int32sToUint16s converts int32 slice to uint16 slice. +func Int32sToUint16s(i []int32) ([]uint16, error) { + var err error + r := make([]uint16, len(i)) + for k, v := range i { + r[k], err = Int32ToUint16(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int32sToUint32s converts int32 slice to uint32 slice. +func Int32sToUint32s(i []int32) ([]uint32, error) { + var err error + r := make([]uint32, len(i)) + for k, v := range i { + r[k], err = Int32ToUint32(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int32sToUint64s converts int32 slice to uint64 slice. +func Int32sToUint64s(i []int32) ([]uint64, error) { + var err error + r := make([]uint64, len(i)) + for k, v := range i { + r[k], err = Int32ToUint64(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int32sCopyWithin copies part of an slice to another location in the current slice. +// @target +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func Int32sCopyWithin(i []int32, target, start int, end ...int) { + target = fixIndex(len(i), target, true) + if target == len(i) { + return + } + sub := Int32sSlice(i, start, end...) + for k, v := range sub { + i[target+k] = v + } +} + +// Int32sEvery tests whether all elements in the slice pass the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice will return true for any condition! +func Int32sEvery(i []int32, fn func(i []int32, k int, v int32) bool) bool { + for k, v := range i { + if !fn(i, k, v) { + return false + } + } + return true +} + +// Int32sFill changes all elements in the current slice to a value, from a start index to an end index. +// @value +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func Int32sFill(i []int32, value int32, start int, end ...int) { + fixedStart, fixedEnd, ok := fixRange(len(i), start, end...) + if !ok { + return + } + for k := fixedStart; k < fixedEnd; k++ { + i[k] = value + } +} + +// Int32sFilter creates a new slice with all elements that pass the test implemented by the provided function. +func Int32sFilter(i []int32, fn func(i []int32, k int, v int32) bool) []int32 { + ret := make([]int32, 0) + for k, v := range i { + if fn(i, k, v) { + ret = append(ret, v) + } + } + return ret +} + +// Int32sFind returns the key-value of the first element in the provided slice that satisfies the provided testing function. +// NOTE: +// If not found, k = -1 +func Int32sFind(i []int32, fn func(i []int32, k int, v int32) bool) (k int, v int32) { + for k, v := range i { + if fn(i, k, v) { + return k, v + } + } + return -1, 0 +} + +// Int32sIncludes determines whether an slice includes a certain value among its entries. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Int32sIncludes(i []int32, valueToFind int32, fromIndex ...int) bool { + return Int32sIndexOf(i, valueToFind, fromIndex...) > -1 +} + +// Int32sIndexOf returns the first index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Int32sIndexOf(i []int32, searchElement int32, fromIndex ...int) int { + idx := getFromIndex(len(i), fromIndex...) + for k, v := range i[idx:] { + if searchElement == v { + return k + idx + } + } + return -1 +} + +// Int32sLastIndexOf returns the last index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Int32sLastIndexOf(i []int32, searchElement int32, fromIndex ...int) int { + idx := getFromIndex(len(i), fromIndex...) + for k := len(i) - 1; k >= idx; k-- { + if searchElement == i[k] { + return k + } + } + return -1 +} + +// Int32sMap creates a new slice populated with the results of calling a provided function +// on every element in the calling slice. +func Int32sMap(i []int32, fn func(i []int32, k int, v int32) int32) []int32 { + ret := make([]int32, len(i)) + for k, v := range i { + ret[k] = fn(i, k, v) + } + return ret +} + +// Int32sPop removes the last element from an slice and returns that element. +// This method changes the length of the slice. +func Int32sPop(i *[]int32) (int32, bool) { + a := *i + if len(a) == 0 { + return 0, false + } + lastIndex := len(a) - 1 + last := a[lastIndex] + a = a[:lastIndex] + *i = a[:len(a):len(a)] + return last, true +} + +// Int32sPush adds one or more elements to the end of an slice and returns the new length of the slice. +func Int32sPush(i *[]int32, element ...int32) int { + *i = append(*i, element...) + return len(*i) +} + +// Int32sPushDistinct adds one or more new elements that do not exist in the current slice at the end. +func Int32sPushDistinct(i []int32, element ...int32) []int32 { +L: + for _, v := range element { + for _, vv := range i { + if vv == v { + continue L + } + } + i = append(i, v) + } + return i +} + +// Int32sReduce executes a reducer function (that you provide) on each element of the slice, +// resulting in a single output value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func Int32sReduce(i []int32, + fn func(i []int32, k int, v, accumulator int32) int32, initialValue ...int32, +) int32 { + if len(i) == 0 { + return 0 + } + start := 0 + acc := i[start] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + start += 1 + } + for k := start; k < len(i); k++ { + acc = fn(i, k, i[k], acc) + } + return acc +} + +// Int32sReduceRight applies a function against an accumulator and each value of the slice (from right-to-left) +// to reduce it to a single value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func Int32sReduceRight(i []int32, + fn func(i []int32, k int, v, accumulator int32) int32, initialValue ...int32, +) int32 { + if len(i) == 0 { + return 0 + } + end := len(i) - 1 + acc := i[end] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + end -= 1 + } + for k := end; k >= 0; k-- { + acc = fn(i, k, i[k], acc) + } + return acc +} + +// Int32sReverse reverses an slice in place. +func Int32sReverse(i []int32) { + first := 0 + last := len(i) - 1 + for first < last { + i[first], i[last] = i[last], i[first] + first++ + last-- + } +} + +// Int32sShift removes the first element from an slice and returns that removed element. +// This method changes the length of the slice. +func Int32sShift(i *[]int32) (int32, bool) { + a := *i + if len(a) == 0 { + return 0, false + } + first := a[0] + a = a[1:] + *i = a[:len(a):len(a)] + return first, true +} + +// Int32sSlice returns a copy of a portion of an slice into a new slice object selected +// from begin to end (end not included) where begin and end represent the index of items in that slice. +// The original slice will not be modified. +func Int32sSlice(i []int32, begin int, end ...int) []int32 { + fixedStart, fixedEnd, ok := fixRange(len(i), begin, end...) + if !ok { + return []int32{} + } + return Int32sCopy(i[fixedStart:fixedEnd]) +} + +// Int32sSome tests whether at least one element in the slice passes the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice returns false for any condition! +func Int32sSome(i []int32, fn func(i []int32, k int, v int32) bool) bool { + for k, v := range i { + if fn(i, k, v) { + return true + } + } + return false +} + +// Int32sSplice changes the contents of an slice by removing or replacing +// existing elements and/or adding new elements in place. +func Int32sSplice(i *[]int32, start, deleteCount int, items ...int32) { + a := *i + if deleteCount < 0 { + deleteCount = 0 + } + start, end, _ := fixRange(len(a), start, start+1+deleteCount) + deleteCount = end - start - 1 + for k := 0; k < len(items); k++ { + if deleteCount > 0 { + // replace + a[start] = items[k] + deleteCount-- + start++ + } else { + // insert + lastSlice := Int32sCopy(a[start:]) + items = items[k:] + a = append(a[:start], items...) + a = append(a[:start+len(items)], lastSlice...) + *i = a[:len(a):len(a)] + return + } + } + if deleteCount > 0 { + a = append(a[:start], a[start+1+deleteCount:]...) + } + *i = a[:len(a):len(a)] +} + +// Int32sUnshift adds one or more elements to the beginning of an slice and returns the new length of the slice. +func Int32sUnshift(i *[]int32, element ...int32) int { + *i = append(element, *i...) + return len(*i) +} + +// Int32sUnshiftDistinct adds one or more new elements that do not exist in the current slice to the beginning +// and returns the new length of the slice. +func Int32sUnshiftDistinct(i *[]int32, element ...int32) int { + a := *i + if len(element) == 0 { + return len(a) + } + m := make(map[int32]bool, len(element)) + r := make([]int32, 0, len(a)+len(element)) +L: + for _, v := range element { + if m[v] { + continue + } + m[v] = true + for _, vv := range a { + if vv == v { + continue L + } + } + r = append(r, v) + } + r = append(r, a...) + *i = r[:len(r):len(r)] + return len(r) +} + +// Int32sRemoveFirst removes the first matched elements from the slice, +// and returns the new length of the slice. +func Int32sRemoveFirst(p *[]int32, elements ...int32) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for k, v := range a { + if v == element { + a = append(a[:k], a[k+1:]...) + break + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// Int32sRemoveEvery removes all the elements from the slice, +// and returns the new length of the slice. +func Int32sRemoveEvery(p *[]int32, elements ...int32) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for i := 0; i < len(a); i++ { + if a[i] == element { + a = append(a[:i], a[i+1:]...) + i-- + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// Int32sConcat is used to merge two or more slices. +// This method does not change the existing slices, but instead returns a new slice. +func Int32sConcat(i ...[]int32) []int32 { + var totalLen int + for _, v := range i { + totalLen += len(v) + } + ret := make([]int32, totalLen) + dst := ret + for _, v := range i { + n := copy(dst, v) + dst = dst[n:] + } + return ret +} + +// Int32sIntersect calculates intersection of two or more slices, +// and returns the count of each element. +func Int32sIntersect(i ...[]int32) (intersectCount map[int32]int) { + if len(i) == 0 { + return nil + } + for _, v := range i { + if len(v) == 0 { + return nil + } + } + counts := make([]map[int32]int, len(i)) + for k, v := range i { + counts[k] = int32sDistinct(v, nil) + } + intersectCount = counts[0] +L: + for k, v := range intersectCount { + for _, c := range counts[1:] { + v2 := c[k] + if v2 == 0 { + delete(intersectCount, k) + continue L + } + if v > v2 { + v = v2 + } + } + intersectCount[k] = v + } + return intersectCount +} + +// Int32sDistinct calculates the count of each different element, +// and only saves these different elements in place if changeSlice is true. +func Int32sDistinct(i *[]int32, changeSlice bool) (distinctCount map[int32]int) { + if !changeSlice { + return int32sDistinct(*i, nil) + } + a := (*i)[:0] + distinctCount = int32sDistinct(*i, &a) + n := len(distinctCount) + *i = a[:n:n] + return distinctCount +} + +func int32sDistinct(src []int32, dst *[]int32) map[int32]int { + m := make(map[int32]int, len(src)) + if dst == nil { + for _, v := range src { + n := m[v] + m[v] = n + 1 + } + } else { + a := *dst + for _, v := range src { + n := m[v] + m[v] = n + 1 + if n == 0 { + a = append(a, v) + } + } + *dst = a + } + return m +} + +// Int32SetUnion calculates between multiple collections: set1 ∪ set2 ∪ others... +// This method does not change the existing slices, but instead returns a new slice. +func Int32SetUnion(set1, set2 []int32, others ...[]int32) []int32 { + m := make(map[int32]struct{}, len(set1)+len(set2)) + r := make([]int32, 0, len(m)) + for _, set := range append([][]int32{set1, set2}, others...) { + for _, v := range set { + _, ok := m[v] + if ok { + continue + } + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} + +// Int32SetIntersect calculates between multiple collections: set1 ∩ set2 ∩ others... +// This method does not change the existing slices, but instead returns a new slice. +func Int32SetIntersect(set1, set2 []int32, others ...[]int32) []int32 { + sets := append([][]int32{set2}, others...) + setsCount := make([]map[int32]int, len(sets)) + for k, v := range sets { + setsCount[k] = int32sDistinct(v, nil) + } + m := make(map[int32]struct{}, len(set1)) + r := make([]int32, 0, len(m)) +L: + for _, v := range set1 { + if _, ok := m[v]; ok { + continue + } + m[v] = struct{}{} + for _, m2 := range setsCount { + if m2[v] == 0 { + continue L + } + } + r = append(r, v) + } + return r +} + +// Int32SetDifference calculates between multiple collections: set1 - set2 - others... +// This method does not change the existing slices, but instead returns a new slice. +func Int32SetDifference(set1, set2 []int32, others ...[]int32) []int32 { + m := make(map[int32]struct{}, len(set1)) + r := make([]int32, 0, len(set1)) + sets := append([][]int32{set2}, others...) + for _, v := range sets { + inter := Int32SetIntersect(set1, v) + for _, v := range inter { + m[v] = struct{}{} + } + } + for _, v := range set1 { + if _, ok := m[v]; !ok { + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} diff --git a/internal/ameda/int64.go b/internal/ameda/int64.go new file mode 100644 index 0000000..c04e746 --- /dev/null +++ b/internal/ameda/int64.go @@ -0,0 +1,201 @@ +package ameda + +import ( + "math" + "strconv" +) + +// Int64ToInterface converts int64 to interface. +func Int64ToInterface(v int64) interface{} { + return v +} + +// Int64ToInterfacePtr converts int64 to *interface. +func Int64ToInterfacePtr(v int64) *interface{} { + r := Int64ToInterface(v) + return &r +} + +// Int64ToString converts int64 to string. +func Int64ToString(v int64) string { + return strconv.FormatInt(v, 10) +} + +// Int64ToStringPtr converts int64 to *string. +func Int64ToStringPtr(v int64) *string { + r := Int64ToString(v) + return &r +} + +// Int64ToBool converts int64 to bool. +func Int64ToBool(v int64) bool { + return v != 0 +} + +// Int64ToBoolPtr converts int64 to *bool. +func Int64ToBoolPtr(v int64) *bool { + r := Int64ToBool(v) + return &r +} + +// Int64ToFloat32 converts int64 to float32. +func Int64ToFloat32(v int64) float32 { + return float32(v) +} + +// Int64ToFloat32Ptr converts int64 to *float32. +func Int64ToFloat32Ptr(v int64) *float32 { + r := Int64ToFloat32(v) + return &r +} + +// Int64ToFloat64 converts int64 to float64. +func Int64ToFloat64(v int64) float64 { + return float64(v) +} + +// Int64ToFloat64Ptr converts int64 to *float64. +func Int64ToFloat64Ptr(v int64) *float64 { + r := Int64ToFloat64(v) + return &r +} + +// Int64ToInt converts int64 to int. +func Int64ToInt(v int64) (int, error) { + if !Host64bit && v > math.MaxInt32 { + return 0, errOverflowValue + } + return int(v), nil +} + +// Int64ToIntPtr converts int64 to *int. +func Int64ToIntPtr(v int64) (*int, error) { + r, err := Int64ToInt(v) + return &r, err +} + +// Int64ToInt8 converts int64 to int8. +func Int64ToInt8(v int64) (int8, error) { + if v > math.MaxInt8 || v < math.MinInt8 { + return 0, errOverflowValue + } + return int8(v), nil +} + +// Int64ToInt8Ptr converts int64 to *int8. +func Int64ToInt8Ptr(v int64) (*int8, error) { + r, err := Int64ToInt8(v) + return &r, err +} + +// Int64ToInt16 converts int64 to int16. +func Int64ToInt16(v int64) (int16, error) { + if v > math.MaxInt16 || v < math.MinInt16 { + return 0, errOverflowValue + } + return int16(v), nil +} + +// Int64ToInt16Ptr converts int64 to *int16. +func Int64ToInt16Ptr(v int64) (*int16, error) { + r, err := Int64ToInt16(v) + return &r, err +} + +// Int64ToInt32 converts int64 to int32. +func Int64ToInt32(v int64) (int32, error) { + if v > math.MaxInt32 || v < math.MinInt32 { + return 0, errOverflowValue + } + return int32(v), nil +} + +// Int64ToInt32Ptr converts int64 to *int32. +func Int64ToInt32Ptr(v int64) (*int32, error) { + r, err := Int64ToInt32(v) + return &r, err +} + +// Int64ToInt64Ptr converts int64 to *int64. +func Int64ToInt64Ptr(v int64) *int64 { + return &v +} + +// Int64ToUint converts int64 to uint. +func Int64ToUint(v int64) (uint, error) { + if v < 0 { + return 0, errNegativeValue + } + if !Host64bit && v > math.MaxUint32 { + return 0, errOverflowValue + } + return uint(v), nil +} + +// Int64ToUintPtr converts int64 to *uint. +func Int64ToUintPtr(v int64) (*uint, error) { + r, err := Int64ToUint(v) + return &r, err +} + +// Int64ToUint8 converts int64 to uint8. +func Int64ToUint8(v int64) (uint8, error) { + if v < 0 { + return 0, errNegativeValue + } + if v > math.MaxUint8 { + return 0, errOverflowValue + } + return uint8(v), nil +} + +// Int64ToUint8Ptr converts int64 to *uint8. +func Int64ToUint8Ptr(v int64) (*uint8, error) { + r, err := Int64ToUint8(v) + return &r, err +} + +// Int64ToUint16 converts int64 to uint16. +func Int64ToUint16(v int64) (uint16, error) { + if v < 0 { + return 0, errNegativeValue + } + if v > math.MaxUint16 { + return 0, errOverflowValue + } + return uint16(v), nil +} + +// Int64ToUint16Ptr converts int64 to *uint16. +func Int64ToUint16Ptr(v int64) (*uint16, error) { + r, err := Int64ToUint16(v) + return &r, err +} + +// Int64ToUint32 converts int64 to uint32. +func Int64ToUint32(v int64) (uint32, error) { + if v < 0 { + return 0, errNegativeValue + } + return uint32(v), nil +} + +// Int64ToUint32Ptr converts int64 to *uint32. +func Int64ToUint32Ptr(v int64) (*uint32, error) { + r, err := Int64ToUint32(v) + return &r, err +} + +// Int64ToUint64 converts int64 to uint64. +func Int64ToUint64(v int64) (uint64, error) { + if v < 0 { + return 0, errNegativeValue + } + return uint64(v), nil +} + +// Int64ToUint64Ptr converts int64 to *uint64. +func Int64ToUint64Ptr(v int64) (*uint64, error) { + r, err := Int64ToUint64(v) + return &r, err +} diff --git a/internal/ameda/int64s.go b/internal/ameda/int64s.go new file mode 100644 index 0000000..6e62c55 --- /dev/null +++ b/internal/ameda/int64s.go @@ -0,0 +1,692 @@ +package ameda + +// OneInt64 try to return the first element, otherwise return zero value. +func OneInt64(i []int64) int64 { + if len(i) > 0 { + return i[0] + } + return 0 +} + +// Int64sCopy creates a copy of the int64 slice. +func Int64sCopy(i []int64) []int64 { + b := make([]int64, len(i)) + copy(b, i) + return b +} + +// Int64sToInterfaces converts int64 slice to interface slice. +func Int64sToInterfaces(i []int64) []interface{} { + r := make([]interface{}, len(i)) + for k, v := range i { + r[k] = Int64ToInterface(v) + } + return r +} + +// Int64sToStrings converts int64 slice to string slice. +func Int64sToStrings(i []int64) []string { + r := make([]string, len(i)) + for k, v := range i { + r[k] = Int64ToString(v) + } + return r +} + +// Int64sToBools converts int64 slice to bool slice. +// NOTE: +// 0 is false, everything else is true +func Int64sToBools(i []int64) []bool { + r := make([]bool, len(i)) + for k, v := range i { + r[k] = Int64ToBool(v) + } + return r +} + +// Int64sToFloat32s converts int64 slice to float32 slice. +func Int64sToFloat32s(i []int64) []float32 { + r := make([]float32, len(i)) + for k, v := range i { + r[k] = Int64ToFloat32(v) + } + return r +} + +// Int64sToFloat64s converts int64 slice to float64 slice. +func Int64sToFloat64s(i []int64) []float64 { + r := make([]float64, len(i)) + for k, v := range i { + r[k] = Int64ToFloat64(v) + } + return r +} + +// Int64sToInts converts int64 slice to int slice. +func Int64sToInts(i []int64) ([]int, error) { + var err error + r := make([]int, len(i)) + for k, v := range i { + r[k], err = Int64ToInt(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int64sToInt8s converts int64 slice to int8 slice. +func Int64sToInt8s(i []int64) ([]int8, error) { + var err error + r := make([]int8, len(i)) + for k, v := range i { + r[k], err = Int64ToInt8(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int64sToInt16s converts int64 slice to int16 slice. +func Int64sToInt16s(i []int64) ([]int16, error) { + var err error + r := make([]int16, len(i)) + for k, v := range i { + r[k], err = Int64ToInt16(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int64sToInt32s converts int64 slice to int32 slice. +func Int64sToInt32s(i []int64) ([]int32, error) { + var err error + r := make([]int32, len(i)) + for k, v := range i { + r[k], err = Int64ToInt32(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int64sToUints converts int64 slice to uint slice. +func Int64sToUints(i []int64) ([]uint, error) { + var err error + r := make([]uint, len(i)) + for k, v := range i { + r[k], err = Int64ToUint(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int64sToUint8s converts int64 slice to uint8 slice. +func Int64sToUint8s(i []int64) ([]uint8, error) { + var err error + r := make([]uint8, len(i)) + for k, v := range i { + r[k], err = Int64ToUint8(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int64sToUint16s converts int64 slice to uint16 slice. +func Int64sToUint16s(i []int64) ([]uint16, error) { + var err error + r := make([]uint16, len(i)) + for k, v := range i { + r[k], err = Int64ToUint16(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int64sToUint32s converts int64 slice to uint32 slice. +func Int64sToUint32s(i []int64) ([]uint32, error) { + var err error + r := make([]uint32, len(i)) + for k, v := range i { + r[k], err = Int64ToUint32(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int64sToUint64s converts int64 slice to uint64 slice. +func Int64sToUint64s(i []int64) ([]uint64, error) { + var err error + r := make([]uint64, len(i)) + for k, v := range i { + r[k], err = Int64ToUint64(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int64sCopyWithin copies part of an slice to another location in the current slice. +// @target +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func Int64sCopyWithin(i []int64, target, start int, end ...int) { + target = fixIndex(len(i), target, true) + if target == len(i) { + return + } + sub := Int64sSlice(i, start, end...) + for k, v := range sub { + i[target+k] = v + } +} + +// Int64sEvery tests whether all elements in the slice pass the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice will return true for any condition! +func Int64sEvery(i []int64, fn func(i []int64, k int, v int64) bool) bool { + for k, v := range i { + if !fn(i, k, v) { + return false + } + } + return true +} + +// Int64sFill changes all elements in the current slice to a value, from a start index to an end index. +// @value +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func Int64sFill(i []int64, value int64, start int, end ...int) { + fixedStart, fixedEnd, ok := fixRange(len(i), start, end...) + if !ok { + return + } + for k := fixedStart; k < fixedEnd; k++ { + i[k] = value + } +} + +// Int64sFilter creates a new slice with all elements that pass the test implemented by the provided function. +func Int64sFilter(i []int64, fn func(i []int64, k int, v int64) bool) []int64 { + ret := make([]int64, 0) + for k, v := range i { + if fn(i, k, v) { + ret = append(ret, v) + } + } + return ret +} + +// Int64sFind returns the key-value of the first element in the provided slice that satisfies the provided testing function. +// NOTE: +// If not found, k = -1 +func Int64sFind(i []int64, fn func(i []int64, k int, v int64) bool) (k int, v int64) { + for k, v := range i { + if fn(i, k, v) { + return k, v + } + } + return -1, 0 +} + +// Int64sIncludes determines whether an slice includes a certain value among its entries. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Int64sIncludes(i []int64, valueToFind int64, fromIndex ...int) bool { + return Int64sIndexOf(i, valueToFind, fromIndex...) > -1 +} + +// Int64sIndexOf returns the first index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Int64sIndexOf(i []int64, searchElement int64, fromIndex ...int) int { + idx := getFromIndex(len(i), fromIndex...) + for k, v := range i[idx:] { + if searchElement == v { + return k + idx + } + } + return -1 +} + +// Int64sLastIndexOf returns the last index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Int64sLastIndexOf(i []int64, searchElement int64, fromIndex ...int) int { + idx := getFromIndex(len(i), fromIndex...) + for k := len(i) - 1; k >= idx; k-- { + if searchElement == i[k] { + return k + } + } + return -1 +} + +// Int64sMap creates a new slice populated with the results of calling a provided function +// on every element in the calling slice. +func Int64sMap(i []int64, fn func(i []int64, k int, v int64) int64) []int64 { + ret := make([]int64, len(i)) + for k, v := range i { + ret[k] = fn(i, k, v) + } + return ret +} + +// Int64sPop removes the last element from an slice and returns that element. +// This method changes the length of the slice. +func Int64sPop(i *[]int64) (int64, bool) { + a := *i + if len(a) == 0 { + return 0, false + } + lastIndex := len(a) - 1 + last := a[lastIndex] + a = a[:lastIndex] + *i = a[:len(a):len(a)] + return last, true +} + +// Int64sPush adds one or more elements to the end of an slice and returns the new length of the slice. +func Int64sPush(i *[]int64, element ...int64) int { + *i = append(*i, element...) + return len(*i) +} + +// Int64sPushDistinct adds one or more new elements that do not exist in the current slice at the end. +func Int64sPushDistinct(i []int64, element ...int64) []int64 { +L: + for _, v := range element { + for _, vv := range i { + if vv == v { + continue L + } + } + i = append(i, v) + } + return i +} + +// Int64sReduce executes a reducer function (that you provide) on each element of the slice, +// resulting in a single output value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func Int64sReduce( + i []int64, + fn func(i []int64, k int, v, accumulator int64) int64, initialValue ...int64, +) int64 { + if len(i) == 0 { + return 0 + } + start := 0 + acc := i[start] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + start += 1 + } + for k := start; k < len(i); k++ { + acc = fn(i, k, i[k], acc) + } + return acc +} + +// Int64sReduceRight applies a function against an accumulator and each value of the slice (from right-to-left) +// to reduce it to a single value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func Int64sReduceRight( + i []int64, + fn func(i []int64, k int, v, accumulator int64) int64, initialValue ...int64, +) int64 { + if len(i) == 0 { + return 0 + } + end := len(i) - 1 + acc := i[end] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + end -= 1 + } + for k := end; k >= 0; k-- { + acc = fn(i, k, i[k], acc) + } + return acc +} + +// Int64sReverse reverses an slice in place. +func Int64sReverse(i []int64) { + first := 0 + last := len(i) - 1 + for first < last { + i[first], i[last] = i[last], i[first] + first++ + last-- + } +} + +// Int64sShift removes the first element from an slice and returns that removed element. +// This method changes the length of the slice. +func Int64sShift(i *[]int64) (int64, bool) { + a := *i + if len(a) == 0 { + return 0, false + } + first := a[0] + a = a[1:] + *i = a[:len(a):len(a)] + return first, true +} + +// Int64sSlice returns a copy of a portion of an slice into a new slice object selected +// from begin to end (end not included) where begin and end represent the index of items in that slice. +// The original slice will not be modified. +func Int64sSlice(i []int64, begin int, end ...int) []int64 { + fixedStart, fixedEnd, ok := fixRange(len(i), begin, end...) + if !ok { + return []int64{} + } + return Int64sCopy(i[fixedStart:fixedEnd]) +} + +// Int64sSome tests whether at least one element in the slice passes the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice returns false for any condition! +func Int64sSome(i []int64, fn func(i []int64, k int, v int64) bool) bool { + for k, v := range i { + if fn(i, k, v) { + return true + } + } + return false +} + +// Int64sSplice changes the contents of an slice by removing or replacing +// existing elements and/or adding new elements in place. +func Int64sSplice(i *[]int64, start, deleteCount int, items ...int64) { + a := *i + if deleteCount < 0 { + deleteCount = 0 + } + start, end, _ := fixRange(len(a), start, start+1+deleteCount) + deleteCount = end - start - 1 + for k := 0; k < len(items); k++ { + if deleteCount > 0 { + // replace + a[start] = items[k] + deleteCount-- + start++ + } else { + // insert + lastSlice := Int64sCopy(a[start:]) + items = items[k:] + a = append(a[:start], items...) + a = append(a[:start+len(items)], lastSlice...) + *i = a[:len(a):len(a)] + return + } + } + if deleteCount > 0 { + a = append(a[:start], a[start+1+deleteCount:]...) + } + *i = a[:len(a):len(a)] +} + +// Int64sUnshift adds one or more elements to the beginning of an slice and returns the new length of the slice. +func Int64sUnshift(i *[]int64, element ...int64) int { + *i = append(element, *i...) + return len(*i) +} + +// Int64sUnshiftDistinct adds one or more new elements that do not exist in the current slice to the beginning +// and returns the new length of the slice. +func Int64sUnshiftDistinct(i *[]int64, element ...int64) int { + a := *i + if len(element) == 0 { + return len(a) + } + m := make(map[int64]bool, len(element)) + r := make([]int64, 0, len(a)+len(element)) +L: + for _, v := range element { + if m[v] { + continue + } + m[v] = true + for _, vv := range a { + if vv == v { + continue L + } + } + r = append(r, v) + } + r = append(r, a...) + *i = r[:len(r):len(r)] + return len(r) +} + +// Int64sRemoveFirst removes the first matched elements from the slice, +// and returns the new length of the slice. +func Int64sRemoveFirst(p *[]int64, elements ...int64) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for k, v := range a { + if v == element { + a = append(a[:k], a[k+1:]...) + break + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// Int64sRemoveEvery removes all the elements from the slice, +// and returns the new length of the slice. +func Int64sRemoveEvery(p *[]int64, elements ...int64) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for i := 0; i < len(a); i++ { + if a[i] == element { + a = append(a[:i], a[i+1:]...) + i-- + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// Int64sConcat is used to merge two or more slices. +// This method does not change the existing slices, but instead returns a new slice. +func Int64sConcat(i ...[]int64) []int64 { + var totalLen int + for _, v := range i { + totalLen += len(v) + } + ret := make([]int64, totalLen) + dst := ret + for _, v := range i { + n := copy(dst, v) + dst = dst[n:] + } + return ret +} + +// Int64sIntersect calculates intersection of two or more slices, +// and returns the count of each element. +func Int64sIntersect(i ...[]int64) (intersectCount map[int64]int) { + if len(i) == 0 { + return nil + } + for _, v := range i { + if len(v) == 0 { + return nil + } + } + counts := make([]map[int64]int, len(i)) + for k, v := range i { + counts[k] = int64sDistinct(v, nil) + } + intersectCount = counts[0] +L: + for k, v := range intersectCount { + for _, c := range counts[1:] { + v2 := c[k] + if v2 == 0 { + delete(intersectCount, k) + continue L + } + if v > v2 { + v = v2 + } + } + intersectCount[k] = v + } + return intersectCount +} + +// Int64sDistinct calculates the count of each different element, +// and only saves these different elements in place if changeSlice is true. +func Int64sDistinct(i *[]int64, changeSlice bool) (distinctCount map[int64]int) { + if !changeSlice { + return int64sDistinct(*i, nil) + } + a := (*i)[:0] + distinctCount = int64sDistinct(*i, &a) + n := len(distinctCount) + *i = a[:n:n] + return distinctCount +} + +func int64sDistinct(src []int64, dst *[]int64) map[int64]int { + m := make(map[int64]int, len(src)) + if dst == nil { + for _, v := range src { + n := m[v] + m[v] = n + 1 + } + } else { + a := *dst + for _, v := range src { + n := m[v] + m[v] = n + 1 + if n == 0 { + a = append(a, v) + } + } + *dst = a + } + return m +} + +// Int64SetUnion calculates between multiple collections: set1 ∪ set2 ∪ others... +// This method does not change the existing slices, but instead returns a new slice. +func Int64SetUnion(set1, set2 []int64, others ...[]int64) []int64 { + m := make(map[int64]struct{}, len(set1)+len(set2)) + r := make([]int64, 0, len(m)) + for _, set := range append([][]int64{set1, set2}, others...) { + for _, v := range set { + _, ok := m[v] + if ok { + continue + } + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} + +// Int64SetIntersect calculates between multiple collections: set1 ∩ set2 ∩ others... +// This method does not change the existing slices, but instead returns a new slice. +func Int64SetIntersect(set1, set2 []int64, others ...[]int64) []int64 { + sets := append([][]int64{set2}, others...) + setsCount := make([]map[int64]int, len(sets)) + for k, v := range sets { + setsCount[k] = int64sDistinct(v, nil) + } + m := make(map[int64]struct{}, len(set1)) + r := make([]int64, 0, len(m)) +L: + for _, v := range set1 { + if _, ok := m[v]; ok { + continue + } + m[v] = struct{}{} + for _, m2 := range setsCount { + if m2[v] == 0 { + continue L + } + } + r = append(r, v) + } + return r +} + +// Int64SetDifference calculates between multiple collections: set1 - set2 - others... +// This method does not change the existing slices, but instead returns a new slice. +func Int64SetDifference(set1, set2 []int64, others ...[]int64) []int64 { + m := make(map[int64]struct{}, len(set1)) + r := make([]int64, 0, len(set1)) + sets := append([][]int64{set2}, others...) + for _, v := range sets { + inter := Int64SetIntersect(set1, v) + for _, v := range inter { + m[v] = struct{}{} + } + } + for _, v := range set1 { + if _, ok := m[v]; !ok { + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} diff --git a/internal/ameda/int8.go b/internal/ameda/int8.go new file mode 100644 index 0000000..5c89c97 --- /dev/null +++ b/internal/ameda/int8.go @@ -0,0 +1,179 @@ +package ameda + +import ( + "strconv" +) + +// Int8ToInterface converts int8 to interface. +func Int8ToInterface(v int8) interface{} { + return v +} + +// Int8ToInterfacePtr converts int8 to *interface. +func Int8ToInterfacePtr(v int8) *interface{} { + r := Int8ToInterface(v) + return &r +} + +// Int8ToString converts int8 to string. +func Int8ToString(v int8) string { + return strconv.FormatInt(int64(v), 10) +} + +// Int8ToStringPtr converts int8 to *string. +func Int8ToStringPtr(v int8) *string { + r := Int8ToString(v) + return &r +} + +// Int8ToBool converts int8 to bool. +func Int8ToBool(v int8) bool { + return v != 0 +} + +// Int8ToBoolPtr converts int8 to *bool. +func Int8ToBoolPtr(v int8) *bool { + r := Int8ToBool(v) + return &r +} + +// Int8ToFloat32 converts int8 to float32. +func Int8ToFloat32(v int8) float32 { + return float32(v) +} + +// Int8ToFloat32Ptr converts int8 to *float32. +func Int8ToFloat32Ptr(v int8) *float32 { + r := Int8ToFloat32(v) + return &r +} + +// Int8ToFloat64 converts int8 to float64. +func Int8ToFloat64(v int8) float64 { + return float64(v) +} + +// Int8ToFloat64Ptr converts int8 to *float64. +func Int8ToFloat64Ptr(v int8) *float64 { + r := Int8ToFloat64(v) + return &r +} + +// Int8ToInt converts int8 to int. +func Int8ToInt(v int8) int { + return int(v) +} + +// Int8ToIntPtr converts int8 to *int. +func Int8ToIntPtr(v int8) *int { + r := Int8ToInt(v) + return &r +} + +// Int8ToInt8Ptr converts int8 to *int8. +func Int8ToInt8Ptr(v int8) *int8 { + return &v +} + +// Int8ToInt16 converts int8 to int16. +func Int8ToInt16(v int8) int16 { + return int16(v) +} + +// Int8ToInt16Ptr converts int8 to *int16. +func Int8ToInt16Ptr(v int8) *int16 { + r := Int8ToInt16(v) + return &r +} + +// Int8ToInt32 converts int8 to int32. +func Int8ToInt32(v int8) int32 { + return int32(v) +} + +// Int8ToInt32Ptr converts int8 to *int32. +func Int8ToInt32Ptr(v int8) *int32 { + r := Int8ToInt32(v) + return &r +} + +// Int8ToInt64 converts int8 to int64. +func Int8ToInt64(v int8) int64 { + return int64(v) +} + +// Int8ToInt64Ptr converts int8 to *int64. +func Int8ToInt64Ptr(v int8) *int64 { + r := Int8ToInt64(v) + return &r +} + +// Int8ToUint converts int8 to uint. +func Int8ToUint(v int8) (uint, error) { + if v < 0 { + return 0, errNegativeValue + } + return uint(v), nil +} + +// Int8ToUintPtr converts int8 to *uint. +func Int8ToUintPtr(v int8) (*uint, error) { + r, err := Int8ToUint(v) + return &r, err +} + +// Int8ToUint8 converts int8 to uint8. +func Int8ToUint8(v int8) (uint8, error) { + if v < 0 { + return 0, errNegativeValue + } + return uint8(v), nil +} + +// Int8ToUint8Ptr converts int8 to *uint8. +func Int8ToUint8Ptr(v int8) (*uint8, error) { + r, err := Int8ToUint8(v) + return &r, err +} + +// Int8ToUint16 converts int8 to uint16. +func Int8ToUint16(v int8) (uint16, error) { + if v < 0 { + return 0, errNegativeValue + } + return uint16(v), nil +} + +// Int8ToUint16Ptr converts int8 to *uint16. +func Int8ToUint16Ptr(v int8) (*uint16, error) { + r, err := Int8ToUint16(v) + return &r, err +} + +// Int8ToUint32 converts int8 to uint32. +func Int8ToUint32(v int8) (uint32, error) { + if v < 0 { + return 0, errNegativeValue + } + return uint32(v), nil +} + +// Int8ToUint32Ptr converts int8 to *uint32. +func Int8ToUint32Ptr(v int8) (*uint32, error) { + r, err := Int8ToUint32(v) + return &r, err +} + +// Int8ToUint64 converts int8 to uint64. +func Int8ToUint64(v int8) (uint64, error) { + if v < 0 { + return 0, errNegativeValue + } + return uint64(v), nil +} + +// Int8ToUint64Ptr converts int8 to *uint64. +func Int8ToUint64Ptr(v int8) (*uint64, error) { + r, err := Int8ToUint64(v) + return &r, err +} diff --git a/internal/ameda/int8s.go b/internal/ameda/int8s.go new file mode 100644 index 0000000..1189b55 --- /dev/null +++ b/internal/ameda/int8s.go @@ -0,0 +1,679 @@ +package ameda + +// OneInt8 try to return the first element, otherwise return zero value. +func OneInt8(i []int8) int8 { + if len(i) > 0 { + return i[0] + } + return 0 +} + +// Int8sCopy creates a copy of the int8 slice. +func Int8sCopy(i []int8) []int8 { + b := make([]int8, len(i)) + copy(b, i) + return b +} + +// Int8sToInterfaces converts int8 slice to interface slice. +func Int8sToInterfaces(i []int8) []interface{} { + r := make([]interface{}, len(i)) + for k, v := range i { + r[k] = v + } + return r +} + +// Int8sToStrings converts int8 slice to string slice. +func Int8sToStrings(i []int8) []string { + r := make([]string, len(i)) + for k, v := range i { + r[k] = Int8ToString(v) + } + return r +} + +// Int8sToBools converts int8 slice to bool slice. +// NOTE: +// 0 is false, everything else is true +func Int8sToBools(i []int8) []bool { + r := make([]bool, len(i)) + for k, v := range i { + r[k] = Int8ToBool(v) + } + return r +} + +// Int8sToFloat32s converts int8 slice to float32 slice. +func Int8sToFloat32s(i []int8) []float32 { + r := make([]float32, len(i)) + for k, v := range i { + r[k] = Int8ToFloat32(v) + } + return r +} + +// Int8sToFloat64s converts int8 slice to float64 slice. +func Int8sToFloat64s(i []int8) []float64 { + r := make([]float64, len(i)) + for k, v := range i { + r[k] = Int8ToFloat64(v) + } + return r +} + +// Int8sToInts converts int8 slice to int slice. +func Int8sToInts(i []int8) []int { + r := make([]int, len(i)) + for k, v := range i { + r[k] = Int8ToInt(v) + } + return r +} + +// Ints converts int8 slice to int slice. +func Int8sInts(i []int8) []int { + return Int8sToInts(i) +} + +// Int8sToInt16s converts int8 slice to int16 slice. +func Int8sToInt16s(i []int8) []int16 { + r := make([]int16, len(i)) + for k, v := range i { + r[k] = Int8ToInt16(v) + } + return r +} + +// Int8sToInt32s converts int8 slice to int32 slice. +func Int8sToInt32s(i []int8) []int32 { + r := make([]int32, len(i)) + for k, v := range i { + r[k] = Int8ToInt32(v) + } + return r +} + +// Int8sToInt64s converts int8 slice to int64 slice. +func Int8sToInt64s(i []int8) []int64 { + r := make([]int64, len(i)) + for k, v := range i { + r[k] = Int8ToInt64(v) + } + return r +} + +// Int8sToUints converts int8 slice to uint slice. +func Int8sToUints(i []int8) ([]uint, error) { + var err error + r := make([]uint, len(i)) + for k, v := range i { + r[k], err = Int8ToUint(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int8sToUint8s converts int8 slice to uint8 slice. +func Int8sToUint8s(i []int8) ([]uint8, error) { + var err error + r := make([]uint8, len(i)) + for k, v := range i { + r[k], err = Int8ToUint8(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int8sToUint16s converts int8 slice to uint16 slice. +func Int8sToUint16s(i []int8) ([]uint16, error) { + var err error + r := make([]uint16, len(i)) + for k, v := range i { + r[k], err = Int8ToUint16(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int8sToUint32s converts int8 slice to uint32 slice. +func Int8sToUint32s(i []int8) ([]uint32, error) { + var err error + r := make([]uint32, len(i)) + for k, v := range i { + r[k], err = Int8ToUint32(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int8sToUint64s converts int8 slice to uint64 slice. +func Int8sToUint64s(i []int8) ([]uint64, error) { + var err error + r := make([]uint64, len(i)) + for k, v := range i { + r[k], err = Int8ToUint64(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int8sCopyWithin copies part of an slice to another location in the current slice. +// @target +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func Int8sCopyWithin(i []int8, target, start int, end ...int) { + target = fixIndex(len(i), target, true) + if target == len(i) { + return + } + sub := Int8sSlice(i, start, end...) + for k, v := range sub { + i[target+k] = v + } +} + +// Int8sEvery tests whether all elements in the slice pass the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice will return true for any condition! +func Int8sEvery(i []int8, fn func(i []int8, k int, v int8) bool) bool { + for k, v := range i { + if !fn(i, k, v) { + return false + } + } + return true +} + +// Int8sFill changes all elements in the current slice to a value, from a start index to an end index. +// @value +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func Int8sFill(i []int8, value int8, start int, end ...int) { + fixedStart, fixedEnd, ok := fixRange(len(i), start, end...) + if !ok { + return + } + for k := fixedStart; k < fixedEnd; k++ { + i[k] = value + } +} + +// Int8sFilter creates a new slice with all elements that pass the test implemented by the provided function. +func Int8sFilter(i []int8, fn func(i []int8, k int, v int8) bool) []int8 { + ret := make([]int8, 0) + for k, v := range i { + if fn(i, k, v) { + ret = append(ret, v) + } + } + return ret +} + +// Int8sFind returns the key-value of the first element in the provided slice that satisfies the provided testing function. +// NOTE: +// If not found, k = -1 +func Int8sFind(i []int8, fn func(i []int8, k int, v int8) bool) (k int, v int8) { + for k, v := range i { + if fn(i, k, v) { + return k, v + } + } + return -1, 0 +} + +// Int8sIncludes determines whether an slice includes a certain value among its entries. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Int8sIncludes(i []int8, valueToFind int8, fromIndex ...int) bool { + return Int8sIndexOf(i, valueToFind, fromIndex...) > -1 +} + +// Int8sIndexOf returns the first index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Int8sIndexOf(i []int8, searchElement int8, fromIndex ...int) int { + idx := getFromIndex(len(i), fromIndex...) + for k, v := range i[idx:] { + if searchElement == v { + return k + idx + } + } + return -1 +} + +// Int8sLastIndexOf returns the last index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Int8sLastIndexOf(i []int8, searchElement int8, fromIndex ...int) int { + idx := getFromIndex(len(i), fromIndex...) + for k := len(i) - 1; k >= idx; k-- { + if searchElement == i[k] { + return k + } + } + return -1 +} + +// Int8sMap creates a new slice populated with the results of calling a provided function +// on every element in the calling slice. +func Int8sMap(i []int8, fn func(i []int8, k int, v int8) int8) []int8 { + ret := make([]int8, len(i)) + for k, v := range i { + ret[k] = fn(i, k, v) + } + return ret +} + +// Int8sPop removes the last element from an slice and returns that element. +// This method changes the length of the slice. +func Int8sPop(i *[]int8) (int8, bool) { + a := *i + if len(a) == 0 { + return 0, false + } + lastIndex := len(a) - 1 + last := a[lastIndex] + a = a[:lastIndex] + *i = a[:len(a):len(a)] + return last, true +} + +// Int8sPush adds one or more elements to the end of an slice and returns the new length of the slice. +func Int8sPush(i *[]int8, element ...int8) int { + *i = append(*i, element...) + return len(*i) +} + +// Int8sPushDistinct adds one or more new elements that do not exist in the current slice at the end. +func Int8sPushDistinct(i []int8, element ...int8) []int8 { +L: + for _, v := range element { + for _, vv := range i { + if vv == v { + continue L + } + } + i = append(i, v) + } + return i +} + +// Int8sReduce executes a reducer function (that you provide) on each element of the slice, +// resulting in a single output value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func Int8sReduce(i []int8, + fn func(i []int8, k int, v, accumulator int8) int8, initialValue ...int8, +) int8 { + if len(i) == 0 { + return 0 + } + start := 0 + acc := i[start] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + start += 1 + } + for k := start; k < len(i); k++ { + acc = fn(i, k, i[k], acc) + } + return acc +} + +// Int8sReduceRight applies a function against an accumulator and each value of the slice (from right-to-left) +// to reduce it to a single value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func Int8sReduceRight(i []int8, + fn func(i []int8, k int, v, accumulator int8) int8, initialValue ...int8, +) int8 { + if len(i) == 0 { + return 0 + } + end := len(i) - 1 + acc := i[end] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + end -= 1 + } + for k := end; k >= 0; k-- { + acc = fn(i, k, i[k], acc) + } + return acc +} + +// Int8sReverse reverses an slice in place. +func Int8sReverse(i []int8) { + first := 0 + last := len(i) - 1 + for first < last { + i[first], i[last] = i[last], i[first] + first++ + last-- + } +} + +// Int8sShift removes the first element from an slice and returns that removed element. +// This method changes the length of the slice. +func Int8sShift(i *[]int8) (int8, bool) { + a := *i + if len(a) == 0 { + return 0, false + } + first := a[0] + a = a[1:] + *i = a[:len(a):len(a)] + return first, true +} + +// Int8sSlice returns a copy of a portion of an slice into a new slice object selected +// from begin to end (end not included) where begin and end represent the index of items in that slice. +// The original slice will not be modified. +func Int8sSlice(i []int8, begin int, end ...int) []int8 { + fixedStart, fixedEnd, ok := fixRange(len(i), begin, end...) + if !ok { + return []int8{} + } + return Int8sCopy(i[fixedStart:fixedEnd]) +} + +// Int8sSome tests whether at least one element in the slice passes the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice returns false for any condition! +func Int8sSome(i []int8, fn func(i []int8, k int, v int8) bool) bool { + for k, v := range i { + if fn(i, k, v) { + return true + } + } + return false +} + +// Int8sSplice changes the contents of an slice by removing or replacing +// existing elements and/or adding new elements in place. +func Int8sSplice(i *[]int8, start, deleteCount int, items ...int8) { + a := *i + if deleteCount < 0 { + deleteCount = 0 + } + start, end, _ := fixRange(len(a), start, start+1+deleteCount) + deleteCount = end - start - 1 + for k := 0; k < len(items); k++ { + if deleteCount > 0 { + // replace + a[start] = items[k] + deleteCount-- + start++ + } else { + // insert + lastSlice := Int8sCopy(a[start:]) + items = items[k:] + a = append(a[:start], items...) + a = append(a[:start+len(items)], lastSlice...) + *i = a[:len(a):len(a)] + return + } + } + if deleteCount > 0 { + a = append(a[:start], a[start+1+deleteCount:]...) + } + *i = a[:len(a):len(a)] +} + +// Int8sUnshift adds one or more elements to the beginning of an slice and returns the new length of the slice. +func Int8sUnshift(i *[]int8, element ...int8) int { + *i = append(element, *i...) + return len(*i) +} + +// Int8sUnshiftDistinct adds one or more new elements that do not exist in the current slice to the beginning +// and returns the new length of the slice. +func Int8sUnshiftDistinct(i *[]int8, element ...int8) int { + a := *i + if len(element) == 0 { + return len(a) + } + m := make(map[int8]bool, len(element)) + r := make([]int8, 0, len(a)+len(element)) +L: + for _, v := range element { + if m[v] { + continue + } + m[v] = true + for _, vv := range a { + if vv == v { + continue L + } + } + r = append(r, v) + } + r = append(r, a...) + *i = r[:len(r):len(r)] + return len(r) +} + +// Int8sRemoveFirst removes the first matched elements from the slice, +// and returns the new length of the slice. +func Int8sRemoveFirst(p *[]int8, elements ...int8) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for k, v := range a { + if v == element { + a = append(a[:k], a[k+1:]...) + break + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// Int8sRemoveEvery removes all the elements from the slice, +// and returns the new length of the slice. +func Int8sRemoveEvery(p *[]int8, elements ...int8) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for i := 0; i < len(a); i++ { + if a[i] == element { + a = append(a[:i], a[i+1:]...) + i-- + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// Int8sConcat is used to merge two or more slices. +// This method does not change the existing slices, but instead returns a new slice. +func Int8sConcat(i ...[]int8) []int8 { + var totalLen int + for _, v := range i { + totalLen += len(v) + } + ret := make([]int8, totalLen) + dst := ret + for _, v := range i { + n := copy(dst, v) + dst = dst[n:] + } + return ret +} + +// Int8sIntersect calculates intersection of two or more slices, +// and returns the count of each element. +func Int8sIntersect(i ...[]int8) (intersectCount map[int8]int) { + if len(i) == 0 { + return nil + } + for _, v := range i { + if len(v) == 0 { + return nil + } + } + counts := make([]map[int8]int, len(i)) + for k, v := range i { + counts[k] = int8sDistinct(v, nil) + } + intersectCount = counts[0] +L: + for k, v := range intersectCount { + for _, c := range counts[1:] { + v2 := c[k] + if v2 == 0 { + delete(intersectCount, k) + continue L + } + if v > v2 { + v = v2 + } + } + intersectCount[k] = v + } + return intersectCount +} + +// Int8sDistinct calculates the count of each different element, +// and only saves these different elements in place if changeSlice is true. +func Int8sDistinct(i *[]int8, changeSlice bool) (distinctCount map[int8]int) { + if !changeSlice { + return int8sDistinct(*i, nil) + } + a := (*i)[:0] + distinctCount = int8sDistinct(*i, &a) + n := len(distinctCount) + *i = a[:n:n] + return distinctCount +} + +func int8sDistinct(src []int8, dst *[]int8) map[int8]int { + m := make(map[int8]int, len(src)) + if dst == nil { + for _, v := range src { + n := m[v] + m[v] = n + 1 + } + } else { + a := *dst + for _, v := range src { + n := m[v] + m[v] = n + 1 + if n == 0 { + a = append(a, v) + } + } + *dst = a + } + return m +} + +// Int8SetUnion calculates between multiple collections: set1 ∪ set2 ∪ others... +// This method does not change the existing slices, but instead returns a new slice. +func Int8SetUnion(set1, set2 []int8, others ...[]int8) []int8 { + m := make(map[int8]struct{}, len(set1)+len(set2)) + r := make([]int8, 0, len(m)) + for _, set := range append([][]int8{set1, set2}, others...) { + for _, v := range set { + _, ok := m[v] + if ok { + continue + } + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} + +// Int8SetIntersect calculates between multiple collections: set1 ∩ set2 ∩ others... +// This method does not change the existing slices, but instead returns a new slice. +func Int8SetIntersect(set1, set2 []int8, others ...[]int8) []int8 { + sets := append([][]int8{set2}, others...) + setsCount := make([]map[int8]int, len(sets)) + for k, v := range sets { + setsCount[k] = int8sDistinct(v, nil) + } + m := make(map[int8]struct{}, len(set1)) + r := make([]int8, 0, len(m)) +L: + for _, v := range set1 { + if _, ok := m[v]; ok { + continue + } + m[v] = struct{}{} + for _, m2 := range setsCount { + if m2[v] == 0 { + continue L + } + } + r = append(r, v) + } + return r +} + +// Int8SetDifference calculates between multiple collections: set1 - set2 - others... +// This method does not change the existing slices, but instead returns a new slice. +func Int8SetDifference(set1, set2 []int8, others ...[]int8) []int8 { + m := make(map[int8]struct{}, len(set1)) + r := make([]int8, 0, len(set1)) + sets := append([][]int8{set2}, others...) + for _, v := range sets { + inter := Int8SetIntersect(set1, v) + for _, v := range inter { + m[v] = struct{}{} + } + } + for _, v := range set1 { + if _, ok := m[v]; !ok { + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} diff --git a/internal/ameda/interface.go b/internal/ameda/interface.go new file mode 100644 index 0000000..1805a47 --- /dev/null +++ b/internal/ameda/interface.go @@ -0,0 +1,812 @@ +package ameda + +import ( + "fmt" + "reflect" +) + +// InterfaceToInterfacePtr converts interface to *interface. +func InterfaceToInterfacePtr(i interface{}) *interface{} { + return &i +} + +// InterfaceToString converts interface to string. +func InterfaceToString(i interface{}) string { + return fmt.Sprintf("%v", i) +} + +// InterfaceToStringPtr converts interface to *string. +func InterfaceToStringPtr(i interface{}) *string { + v := InterfaceToString(i) + return &v +} + +// InterfaceToBool converts interface to bool. +// NOTE: +// 0 is false, other numbers are true +func InterfaceToBool(i interface{}, emptyAsFalse ...bool) (bool, error) { + switch v := i.(type) { + case bool: + return v, nil + case nil: + return false, nil + case float32: + return Float32ToBool(v), nil + case float64: + return Float64ToBool(v), nil + case int: + return IntToBool(v), nil + case int8: + return Int8ToBool(v), nil + case int16: + return Int16ToBool(v), nil + case int32: + return Int32ToBool(v), nil + case int64: + return Int64ToBool(v), nil + case uint: + return UintToBool(v), nil + case uint8: + return Uint8ToBool(v), nil + case uint16: + return Uint16ToBool(v), nil + case uint32: + return Uint32ToBool(v), nil + case uint64: + return Uint64ToBool(v), nil + case uintptr: + return v != 0, nil + case string: + return StringToBool(v, emptyAsFalse...) + default: + r := IndirectValue(reflect.ValueOf(i)) + switch r.Kind() { + case reflect.Bool: + return r.Bool(), nil + case reflect.Invalid: + return false, nil + case reflect.Float32, reflect.Float64: + return Float64ToBool(r.Float()), nil + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return Int64ToBool(r.Int()), nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return Uint64ToBool(r.Uint()), nil + case reflect.String: + return StringToBool(r.String(), emptyAsFalse...) + } + if isEmptyAsZero(emptyAsFalse) { + return !isZero(r), nil + } + return false, fmt.Errorf("cannot convert %#v of type %T to bool", i, i) + } +} + +// InterfaceToBoolPtr converts interface to *bool. +// NOTE: +// 0 is false, other numbers are true +func InterfaceToBoolPtr(i interface{}, emptyAsFalse ...bool) (*bool, error) { + r, err := InterfaceToBool(i, emptyAsFalse...) + return &r, err +} + +// InterfaceToFloat32 converts interface to float32. +func InterfaceToFloat32(i interface{}, emptyStringAsZero ...bool) (float32, error) { + switch v := i.(type) { + case bool: + return BoolToFloat32(v), nil + case nil: + return 0, nil + case int: + return IntToFloat32(v), nil + case int8: + return Int8ToFloat32(v), nil + case int16: + return Int16ToFloat32(v), nil + case int32: + return Int32ToFloat32(v), nil + case int64: + return Int64ToFloat32(v), nil + case uint: + return UintToFloat32(v), nil + case uint8: + return Uint8ToFloat32(v), nil + case uint16: + return Uint16ToFloat32(v), nil + case uint32: + return Uint32ToFloat32(v), nil + case uint64: + return Uint64ToFloat32(v), nil + case uintptr: + return UintToFloat32(uint(v)), nil + case string: + return StringToFloat32(v, emptyStringAsZero...) + default: + r := IndirectValue(reflect.ValueOf(i)) + switch r.Kind() { + case reflect.Bool: + return BoolToFloat32(r.Bool()), nil + case reflect.Invalid: + return 0, nil + case reflect.Float32: + return float32(r.Float()), nil + case reflect.Float64: + return Float64ToFloat32(r.Float()) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return Int64ToFloat32(r.Int()), nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return Uint64ToFloat32(r.Uint()), nil + case reflect.String: + return StringToFloat32(r.String(), emptyStringAsZero...) + } + if isEmptyAsZero(emptyStringAsZero) { + return BoolToFloat32(!isZero(r)), nil + } + return 0, fmt.Errorf("cannot convert %#v of type %T to float32", i, i) + } +} + +// InterfaceToFloat32Ptr converts interface to *float32. +func InterfaceToFloat32Ptr(i interface{}, emptyAsFalse ...bool) (*float32, error) { + r, err := InterfaceToFloat32(i, emptyAsFalse...) + return &r, err +} + +// InterfaceToFloat64 converts interface to float64. +func InterfaceToFloat64(i interface{}, emptyStringAsZero ...bool) (float64, error) { + switch v := i.(type) { + case bool: + return BoolToFloat64(v), nil + case nil: + return 0, nil + case int: + return IntToFloat64(v), nil + case int8: + return Int8ToFloat64(v), nil + case int16: + return Int16ToFloat64(v), nil + case int32: + return Int32ToFloat64(v), nil + case int64: + return Int64ToFloat64(v), nil + case uint: + return UintToFloat64(v), nil + case uint8: + return Uint8ToFloat64(v), nil + case uint16: + return Uint16ToFloat64(v), nil + case uint32: + return Uint32ToFloat64(v), nil + case uint64: + return Uint64ToFloat64(v), nil + case uintptr: + return UintToFloat64(uint(v)), nil + case string: + return StringToFloat64(v, emptyStringAsZero...) + default: + r := IndirectValue(reflect.ValueOf(i)) + switch r.Kind() { + case reflect.Bool: + return BoolToFloat64(r.Bool()), nil + case reflect.Invalid: + return 0, nil + case reflect.Float32, reflect.Float64: + return r.Float(), nil + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return Int64ToFloat64(r.Int()), nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return Uint64ToFloat64(r.Uint()), nil + case reflect.String: + return StringToFloat64(r.String(), emptyStringAsZero...) + } + if isEmptyAsZero(emptyStringAsZero) { + return BoolToFloat64(!isZero(r)), nil + } + return 0, fmt.Errorf("cannot convert %#v of type %T to float64", i, i) + } +} + +// InterfaceToFloat64Ptr converts interface to *float64. +func InterfaceToFloat64Ptr(i interface{}, emptyAsFalse ...bool) (*float64, error) { + r, err := InterfaceToFloat64(i, emptyAsFalse...) + return &r, err +} + +// InterfaceToInt converts interface to int. +func InterfaceToInt(i interface{}, emptyStringAsZero ...bool) (int, error) { + switch v := i.(type) { + case bool: + return BoolToInt(v), nil + case nil: + return 0, nil + case int: + return v, nil + case int8: + return Int8ToInt(v), nil + case int16: + return Int16ToInt(v), nil + case int32: + return Int32ToInt(v), nil + case int64: + return Int64ToInt(v) + case uint: + return UintToInt(v) + case uint8: + return Uint8ToInt(v), nil + case uint16: + return Uint16ToInt(v), nil + case uint32: + return Uint32ToInt(v), nil + case uint64: + return Uint64ToInt(v), nil + case uintptr: + return UintToInt(uint(v)) + case string: + return StringToInt(v, emptyStringAsZero...) + default: + r := IndirectValue(reflect.ValueOf(i)) + switch r.Kind() { + case reflect.Bool: + return BoolToInt(r.Bool()), nil + case reflect.Invalid: + return 0, nil + case reflect.Float32, reflect.Float64: + return Float64ToInt(r.Float()) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return Int64ToInt(r.Int()) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return Uint64ToInt(r.Uint()), nil + case reflect.String: + return StringToInt(r.String(), emptyStringAsZero...) + } + if isEmptyAsZero(emptyStringAsZero) { + return BoolToInt(!isZero(r)), nil + } + return 0, fmt.Errorf("cannot convert %#v of type %T to int", i, i) + } +} + +// InterfaceToIntPtr converts interface to *float64. +func InterfaceToIntPtr(i interface{}, emptyAsFalse ...bool) (*int, error) { + r, err := InterfaceToInt(i, emptyAsFalse...) + return &r, err +} + +// InterfaceToInt8 converts interface to int8. +func InterfaceToInt8(i interface{}, emptyStringAsZero ...bool) (int8, error) { + switch v := i.(type) { + case bool: + return BoolToInt8(v), nil + case nil: + return 0, nil + case int: + return IntToInt8(v) + case int8: + return v, nil + case int16: + return Int16ToInt8(v) + case int32: + return Int32ToInt8(v) + case int64: + return Int64ToInt8(v) + case uint: + return UintToInt8(v) + case uint8: + return Uint8ToInt8(v) + case uint16: + return Uint16ToInt8(v) + case uint32: + return Uint32ToInt8(v) + case uint64: + return Uint64ToInt8(v) + case uintptr: + return UintToInt8(uint(v)) + case string: + return StringToInt8(v, emptyStringAsZero...) + default: + r := IndirectValue(reflect.ValueOf(i)) + switch r.Kind() { + case reflect.Bool: + return BoolToInt8(r.Bool()), nil + case reflect.Invalid: + return 0, nil + case reflect.Float32, reflect.Float64: + return Float64ToInt8(r.Float()) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return Int64ToInt8(r.Int()) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return Uint64ToInt8(r.Uint()) + case reflect.String: + return StringToInt8(r.String(), emptyStringAsZero...) + } + if isEmptyAsZero(emptyStringAsZero) { + return BoolToInt8(!isZero(r)), nil + } + return 0, fmt.Errorf("cannot convert %#v of type %T to int8", i, i) + } +} + +// InterfaceToInt8Ptr converts interface to *int8. +func InterfaceToInt8Ptr(i interface{}, emptyAsFalse ...bool) (*int8, error) { + r, err := InterfaceToInt8(i, emptyAsFalse...) + return &r, err +} + +// InterfaceToInt16 converts interface to int16. +func InterfaceToInt16(i interface{}, emptyStringAsZero ...bool) (int16, error) { + switch v := i.(type) { + case bool: + return BoolToInt16(v), nil + case nil: + return 0, nil + case int: + return IntToInt16(v) + case int8: + return Int8ToInt16(v), nil + case int16: + return v, nil + case int32: + return Int32ToInt16(v) + case int64: + return Int64ToInt16(v) + case uint: + return UintToInt16(v) + case uint8: + return Uint8ToInt16(v), nil + case uint16: + return Uint16ToInt16(v) + case uint32: + return Uint32ToInt16(v) + case uint64: + return Uint64ToInt16(v) + case uintptr: + return UintToInt16(uint(v)) + case string: + return StringToInt16(v, emptyStringAsZero...) + default: + r := IndirectValue(reflect.ValueOf(i)) + switch r.Kind() { + case reflect.Bool: + return BoolToInt16(r.Bool()), nil + case reflect.Invalid: + return 0, nil + case reflect.Float32, reflect.Float64: + return Float64ToInt16(r.Float()) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return Int64ToInt16(r.Int()) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return Uint64ToInt16(r.Uint()) + case reflect.String: + return StringToInt16(r.String(), emptyStringAsZero...) + } + if isEmptyAsZero(emptyStringAsZero) { + return BoolToInt16(!isZero(r)), nil + } + return 0, fmt.Errorf("cannot convert %#v of type %T to int16", i, i) + } +} + +// InterfaceToInt16Ptr converts interface to *int16. +func InterfaceToInt16Ptr(i interface{}, emptyAsFalse ...bool) (*int16, error) { + r, err := InterfaceToInt16(i, emptyAsFalse...) + return &r, err +} + +// InterfaceToInt32 converts interface to int32. +func InterfaceToInt32(i interface{}, emptyStringAsZero ...bool) (int32, error) { + switch v := i.(type) { + case bool: + return BoolToInt32(v), nil + case nil: + return 0, nil + case int: + return IntToInt32(v) + case int8: + return Int8ToInt32(v), nil + case int16: + return Int16ToInt32(v), nil + case int32: + return v, nil + case int64: + return Int64ToInt32(v) + case uint: + return UintToInt32(v) + case uint8: + return Uint8ToInt32(v), nil + case uint16: + return Uint16ToInt32(v), nil + case uint32: + return Uint32ToInt32(v) + case uint64: + return Uint64ToInt32(v) + case uintptr: + return UintToInt32(uint(v)) + case string: + return StringToInt32(v, emptyStringAsZero...) + default: + r := IndirectValue(reflect.ValueOf(i)) + switch r.Kind() { + case reflect.Bool: + return BoolToInt32(r.Bool()), nil + case reflect.Invalid: + return 0, nil + case reflect.Float32, reflect.Float64: + return Float64ToInt32(r.Float()) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return Int64ToInt32(r.Int()) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return Uint64ToInt32(r.Uint()) + case reflect.String: + return StringToInt32(r.String(), emptyStringAsZero...) + } + if isEmptyAsZero(emptyStringAsZero) { + return BoolToInt32(!isZero(r)), nil + } + return 0, fmt.Errorf("cannot convert %#v of type %T to int32", i, i) + } +} + +// InterfaceToInt32Ptr converts interface to *int32. +func InterfaceToInt32Ptr(i interface{}, emptyAsFalse ...bool) (*int32, error) { + r, err := InterfaceToInt32(i, emptyAsFalse...) + return &r, err +} + +// InterfaceToInt64 converts interface to int64. +func InterfaceToInt64(i interface{}, emptyStringAsZero ...bool) (int64, error) { + switch v := i.(type) { + case bool: + return BoolToInt64(v), nil + case nil: + return 0, nil + case int: + return IntToInt64(v), nil + case int8: + return Int8ToInt64(v), nil + case int16: + return Int16ToInt64(v), nil + case int32: + return Int32ToInt64(v), nil + case int64: + return v, nil + case uint: + return UintToInt64(v) + case uint8: + return Uint8ToInt64(v), nil + case uint16: + return Uint16ToInt64(v), nil + case uint32: + return Uint32ToInt64(v), nil + case uint64: + return Uint64ToInt64(v) + case uintptr: + return UintToInt64(uint(v)) + case string: + return StringToInt64(v, emptyStringAsZero...) + default: + r := IndirectValue(reflect.ValueOf(i)) + switch r.Kind() { + case reflect.Bool: + return BoolToInt64(r.Bool()), nil + case reflect.Invalid: + return 0, nil + case reflect.Float32, reflect.Float64: + return Float64ToInt64(r.Float()) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return r.Int(), nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return Uint64ToInt64(r.Uint()) + case reflect.String: + return StringToInt64(r.String(), emptyStringAsZero...) + } + if isEmptyAsZero(emptyStringAsZero) { + return BoolToInt64(!isZero(r)), nil + } + return 0, fmt.Errorf("cannot convert %#v of type %T to int64", i, i) + } +} + +// InterfaceToInt64Ptr converts interface to *int64. +func InterfaceToInt64Ptr(i interface{}, emptyAsFalse ...bool) (*int64, error) { + r, err := InterfaceToInt64(i, emptyAsFalse...) + return &r, err +} + +// InterfaceToUint converts interface to uint. +func InterfaceToUint(i interface{}, emptyStringAsZero ...bool) (uint, error) { + switch v := i.(type) { + case bool: + return BoolToUint(v), nil + case nil: + return 0, nil + case int: + return IntToUint(v) + case int8: + return Int8ToUint(v) + case int16: + return Int16ToUint(v) + case int32: + return Int32ToUint(v) + case int64: + return Int64ToUint(v) + case uint: + return v, nil + case uint8: + return Uint8ToUint(v), nil + case uint16: + return Uint16ToUint(v), nil + case uint32: + return Uint32ToUint(v), nil + case uint64: + return Uint64ToUint(v) + case uintptr: + return uint(v), nil + case string: + return StringToUint(v, emptyStringAsZero...) + default: + r := IndirectValue(reflect.ValueOf(i)) + switch r.Kind() { + case reflect.Bool: + return BoolToUint(r.Bool()), nil + case reflect.Invalid: + return 0, nil + case reflect.Float32, reflect.Float64: + return Float64ToUint(r.Float()) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return Int64ToUint(r.Int()) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return Uint64ToUint(r.Uint()) + case reflect.String: + return StringToUint(r.String(), emptyStringAsZero...) + } + if isEmptyAsZero(emptyStringAsZero) { + return BoolToUint(!isZero(r)), nil + } + return 0, fmt.Errorf("cannot convert %#v of type %T to uint", i, i) + } +} + +// InterfaceToUintPtr converts interface to *uint. +func InterfaceToUintPtr(i interface{}, emptyAsFalse ...bool) (*uint, error) { + r, err := InterfaceToUint(i, emptyAsFalse...) + return &r, err +} + +// InterfaceToUint8 converts interface to uint8. +func InterfaceToUint8(i interface{}, emptyStringAsZero ...bool) (uint8, error) { + switch v := i.(type) { + case bool: + return BoolToUint8(v), nil + case nil: + return 0, nil + case int: + return IntToUint8(v) + case int8: + return Int8ToUint8(v) + case int16: + return Int16ToUint8(v) + case int32: + return Int32ToUint8(v) + case int64: + return Int64ToUint8(v) + case uint: + return UintToUint8(v) + case uint8: + return v, nil + case uint16: + return Uint16ToUint8(v) + case uint32: + return Uint32ToUint8(v) + case uint64: + return Uint64ToUint8(v) + case uintptr: + return UintToUint8(uint(v)) + case string: + return StringToUint8(v, emptyStringAsZero...) + default: + r := IndirectValue(reflect.ValueOf(i)) + switch r.Kind() { + case reflect.Bool: + return BoolToUint8(r.Bool()), nil + case reflect.Invalid: + return 0, nil + case reflect.Float32, reflect.Float64: + return Float64ToUint8(r.Float()) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return Int64ToUint8(r.Int()) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return Uint64ToUint8(r.Uint()) + case reflect.String: + return StringToUint8(r.String(), emptyStringAsZero...) + } + if isEmptyAsZero(emptyStringAsZero) { + return BoolToUint8(!isZero(r)), nil + } + return 0, fmt.Errorf("cannot convert %#v of type %T to uint8", i, i) + } +} + +// InterfaceToUint8Ptr converts interface to *uint8. +func InterfaceToUint8Ptr(i interface{}, emptyAsFalse ...bool) (*uint8, error) { + r, err := InterfaceToUint8(i, emptyAsFalse...) + return &r, err +} + +// InterfaceToUint16 converts interface to uint16. +func InterfaceToUint16(i interface{}, emptyStringAsZero ...bool) (uint16, error) { + switch v := i.(type) { + case bool: + return BoolToUint16(v), nil + case nil: + return 0, nil + case int: + return IntToUint16(v) + case int8: + return Int8ToUint16(v) + case int16: + return Int16ToUint16(v) + case int32: + return Int32ToUint16(v) + case int64: + return Int64ToUint16(v) + case uint: + return UintToUint16(v) + case uint8: + return Uint8ToUint16(v), nil + case uint16: + return v, nil + case uint32: + return Uint32ToUint16(v) + case uint64: + return Uint64ToUint16(v) + case uintptr: + return UintToUint16(uint(v)) + case string: + return StringToUint16(v, emptyStringAsZero...) + default: + r := IndirectValue(reflect.ValueOf(i)) + switch r.Kind() { + case reflect.Bool: + return BoolToUint16(r.Bool()), nil + case reflect.Invalid: + return 0, nil + case reflect.Float32, reflect.Float64: + return Float64ToUint16(r.Float()) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return Int64ToUint16(r.Int()) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return Uint64ToUint16(r.Uint()) + case reflect.String: + return StringToUint16(r.String(), emptyStringAsZero...) + } + if isEmptyAsZero(emptyStringAsZero) { + return BoolToUint16(!isZero(r)), nil + } + return 0, fmt.Errorf("cannot convert %#v of type %T to uint16", i, i) + } +} + +// InterfaceToUint16Ptr converts interface to *uint16. +func InterfaceToUint16Ptr(i interface{}, emptyAsFalse ...bool) (*uint16, error) { + r, err := InterfaceToUint16(i, emptyAsFalse...) + return &r, err +} + +// InterfaceToUint32 converts interface to uint32. +func InterfaceToUint32(i interface{}, emptyStringAsZero ...bool) (uint32, error) { + switch v := i.(type) { + case bool: + return BoolToUint32(v), nil + case nil: + return 0, nil + case int: + return IntToUint32(v) + case int8: + return Int8ToUint32(v) + case int16: + return Int16ToUint32(v) + case int32: + return Int32ToUint32(v) + case int64: + return Int64ToUint32(v) + case uint: + return UintToUint32(v) + case uint8: + return Uint8ToUint32(v), nil + case uint16: + return Uint16ToUint32(v), nil + case uint32: + return v, nil + case uint64: + return Uint64ToUint32(v) + case uintptr: + return UintToUint32(uint(v)) + case string: + return StringToUint32(v, emptyStringAsZero...) + default: + r := IndirectValue(reflect.ValueOf(i)) + switch r.Kind() { + case reflect.Bool: + return BoolToUint32(r.Bool()), nil + case reflect.Invalid: + return 0, nil + case reflect.Float32, reflect.Float64: + return Float64ToUint32(r.Float()) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return Int64ToUint32(r.Int()) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return Uint64ToUint32(r.Uint()) + case reflect.String: + return StringToUint32(r.String(), emptyStringAsZero...) + } + if isEmptyAsZero(emptyStringAsZero) { + return BoolToUint32(!isZero(r)), nil + } + return 0, fmt.Errorf("cannot convert %#v of type %T to uint32", i, i) + } +} + +// InterfaceToUint32Ptr converts interface to *uint32. +func InterfaceToUint32Ptr(i interface{}, emptyAsFalse ...bool) (*uint32, error) { + r, err := InterfaceToUint32(i, emptyAsFalse...) + return &r, err +} + +// InterfaceToUint64 converts interface to uint64. +func InterfaceToUint64(i interface{}, emptyStringAsZero ...bool) (uint64, error) { + switch v := i.(type) { + case bool: + return BoolToUint64(v), nil + case nil: + return 0, nil + case int: + return IntToUint64(v) + case int8: + return Int8ToUint64(v) + case int16: + return Int16ToUint64(v) + case int32: + return Int32ToUint64(v) + case int64: + return Int64ToUint64(v) + case uint: + return UintToUint64(v), nil + case uint8: + return Uint8ToUint64(v), nil + case uint16: + return Uint16ToUint64(v), nil + case uint32: + return Uint32ToUint64(v), nil + case uint64: + return v, nil + case uintptr: + return UintToUint64(uint(v)), nil + case string: + return StringToUint64(v, emptyStringAsZero...) + default: + r := IndirectValue(reflect.ValueOf(i)) + switch r.Kind() { + case reflect.Bool: + return BoolToUint64(r.Bool()), nil + case reflect.Invalid: + return 0, nil + case reflect.Float32, reflect.Float64: + return Float64ToUint64(r.Float()) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return Int64ToUint64(r.Int()) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return r.Uint(), nil + case reflect.String: + return StringToUint64(r.String(), emptyStringAsZero...) + } + if isEmptyAsZero(emptyStringAsZero) { + return BoolToUint64(!isZero(r)), nil + } + return 0, fmt.Errorf("cannot convert %#v of type %T to uint64", i, i) + } +} + +// InterfaceToUint64Ptr converts interface to *uint64. +func InterfaceToUint64Ptr(i interface{}, emptyAsFalse ...bool) (*uint64, error) { + r, err := InterfaceToUint64(i, emptyAsFalse...) + return &r, err +} diff --git a/internal/ameda/interfaces.go b/internal/ameda/interfaces.go new file mode 100644 index 0000000..5a1135f --- /dev/null +++ b/internal/ameda/interfaces.go @@ -0,0 +1,643 @@ +package ameda + +// OneInterface try to return the first element, otherwise return zero value. +func OneInterface(i []interface{}) interface{} { + if len(i) > 0 { + return i[0] + } + return nil +} + +// InterfacesCopy creates a copy of the interface slice. +func InterfacesCopy(i []interface{}) []interface{} { + b := make([]interface{}, len(i)) + copy(b, i) + return b +} + +// InterfacesToStrings converts interface slice to string slice. +func InterfacesToStrings(i []interface{}) []string { + r := make([]string, len(i)) + for k, v := range i { + r[k] = InterfaceToString(v) + } + return r +} + +// InterfacesToBools converts interface slice to bool slice. +// NOTE: +// 0 is false, other numbers are true +func InterfacesToBools(i []interface{}) ([]bool, error) { + var err error + r := make([]bool, len(i)) + for k, v := range i { + r[k], err = InterfaceToBool(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// InterfacesToFloat32s converts interface slice to float32 slice. +func InterfacesToFloat32s(i []interface{}) ([]float32, error) { + var err error + r := make([]float32, len(i)) + for k, v := range i { + r[k], err = InterfaceToFloat32(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// InterfacesToFloat64s converts interface slice to float64 slice. +func InterfacesToFloat64s(i []interface{}) ([]float64, error) { + var err error + r := make([]float64, len(i)) + for k, v := range i { + r[k], err = InterfaceToFloat64(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// InterfacesToInts converts interface slice to int slice. +func InterfacesToInts(i []interface{}) ([]int, error) { + var err error + r := make([]int, len(i)) + for k, v := range i { + r[k], err = InterfaceToInt(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// InterfacesToInt8s converts interface slice to int8 slice. +func InterfacesToInt8s(i []interface{}) ([]int8, error) { + var err error + r := make([]int8, len(i)) + for k, v := range i { + r[k], err = InterfaceToInt8(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// InterfacesToInt16s converts interface slice to int16 slice. +func InterfacesToInt16s(i []interface{}) ([]int16, error) { + var err error + r := make([]int16, len(i)) + for k, v := range i { + r[k], err = InterfaceToInt16(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// InterfacesToInt32s converts interface slice to int32 slice. +func InterfacesToInt32s(i []interface{}) ([]int32, error) { + var err error + r := make([]int32, len(i)) + for k, v := range i { + r[k], err = InterfaceToInt32(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// InterfacesToInt64s converts interface slice to int64 slice. +func InterfacesToInt64s(i []interface{}) ([]int64, error) { + var err error + r := make([]int64, len(i)) + for k, v := range i { + r[k], err = InterfaceToInt64(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// InterfacesToUints converts interface slice to uint slice. +func InterfacesToUints(i []interface{}) ([]uint, error) { + var err error + r := make([]uint, len(i)) + for k, v := range i { + r[k], err = InterfaceToUint(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// InterfacesToUint8s converts interface slice to uint8 slice. +func InterfacesToUint8s(i []interface{}) ([]uint8, error) { + var err error + r := make([]uint8, len(i)) + for k, v := range i { + r[k], err = InterfaceToUint8(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// InterfacesToUint16s converts interface slice to uint16 slice. +func InterfacesToUint16s(i []interface{}) ([]uint16, error) { + var err error + r := make([]uint16, len(i)) + for k, v := range i { + r[k], err = InterfaceToUint16(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// InterfacesToUint32s converts interface slice to uint32 slice. +func InterfacesToUint32s(i []interface{}) ([]uint32, error) { + var err error + r := make([]uint32, len(i)) + for k, v := range i { + r[k], err = InterfaceToUint32(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// InterfacesToUint64s converts interface slice to uint64 slice. +func InterfacesToUint64s(i []interface{}) ([]uint64, error) { + var err error + r := make([]uint64, len(i)) + for k, v := range i { + r[k], err = InterfaceToUint64(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// InterfacesCopyWithin copies part of an slice to another location in the current slice. +// @target +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func InterfacesCopyWithin(i []interface{}, target, start int, end ...int) { + target = fixIndex(len(i), target, true) + if target == len(i) { + return + } + sub := InterfacesSlice(i, start, end...) + for k, v := range sub { + i[target+k] = v + } +} + +// InterfacesEvery tests whether all elements in the slice pass the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice will return true for any condition! +func InterfacesEvery(i []interface{}, fn func(i []interface{}, k int, v interface{}) bool) bool { + for k, v := range i { + if !fn(i, k, v) { + return false + } + } + return true +} + +// InterfacesFill changes all elements in the current slice to a value, from a start index to an end index. +// @value +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func InterfacesFill(i []interface{}, value []interface{}, start int, end ...int) { + fixedStart, fixedEnd, ok := fixRange(len(i), start, end...) + if !ok { + return + } + for k := fixedStart; k < fixedEnd; k++ { + i[k] = value + } +} + +// InterfacesFilter creates a new slice with all elements that pass the test implemented by the provided function. +func InterfacesFilter(i []interface{}, fn func(i []interface{}, k int, v interface{}) bool) []interface{} { + ret := make([]interface{}, 0) + for k, v := range i { + if fn(i, k, v) { + ret = append(ret, v) + } + } + return ret +} + +// InterfacesFind returns the key-value of the first element in the provided slice that satisfies the provided testing function. +// NOTE: +// If not found, k = -1 +func InterfacesFind(i []interface{}, fn func(i []interface{}, k int, v interface{}) bool) (k int, v interface{}) { + for k, v := range i { + if fn(i, k, v) { + return k, v + } + } + return -1, 0 +} + +// InterfacesIncludes determines whether an slice includes a certain value among its entries. +// @fromIndex +// The index to start the search at. Defaults to 0. +func InterfacesIncludes(i []interface{}, valueToFind int64, fromIndex ...int) bool { + return InterfacesIndexOf(i, valueToFind, fromIndex...) > -1 +} + +// InterfacesIndexOf returns the first index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func InterfacesIndexOf(i []interface{}, searchElement int64, fromIndex ...int) int { + idx := getFromIndex(len(i), fromIndex...) + for k, v := range i[idx:] { + if searchElement == v { + return k + idx + } + } + return -1 +} + +// InterfacesLastIndexOf returns the last index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func InterfacesLastIndexOf(i []interface{}, searchElement int64, fromIndex ...int) int { + idx := getFromIndex(len(i), fromIndex...) + for k := len(i) - 1; k >= idx; k-- { + if searchElement == i[k] { + return k + } + } + return -1 +} + +// InterfacesMap creates a new slice populated with the results of calling a provided function +// on every element in the calling slice. +func InterfacesMap(i []interface{}, fn func(i []interface{}, k int, v interface{}) int64) []int64 { + ret := make([]int64, len(i)) + for k, v := range i { + ret[k] = fn(i, k, v) + } + return ret +} + +// InterfacesPop removes the last element from an slice and returns that element. +// This method changes the length of the slice. +func InterfacesPop(i *[]interface{}) (interface{}, bool) { + a := *i + if len(a) == 0 { + return 0, false + } + lastIndex := len(a) - 1 + last := a[lastIndex] + a = a[:lastIndex] + *i = a[:len(a):len(a)] + return last, true +} + +// InterfacesPush adds one or more elements to the end of an slice and returns the new length of the slice. +func InterfacesPush(i *[]interface{}, element ...interface{}) int { + *i = append(*i, element...) + return len(*i) +} + +// InterfacesPushDistinct adds one or more new elements that do not exist in the current slice at the end. +func InterfacesPushDistinct(i []interface{}, element ...interface{}) []interface{} { +L: + for _, v := range element { + for _, vv := range i { + if vv == v { + continue L + } + } + i = append(i, v) + } + return i +} + +// InterfacesReduce executes a reducer function (that you provide) on each element of the slice, +// resulting in a single output value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func InterfacesReduce( + i []interface{}, + fn func(i []interface{}, k int, v, accumulator interface{}) interface{}, initialValue ...interface{}, +) interface{} { + if len(i) == 0 { + return 0 + } + start := 0 + acc := i[start] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + start += 1 + } + for k := start; k < len(i); k++ { + acc = fn(i, k, i[k], acc) + } + return acc +} + +// InterfacesReduceRight applies a function against an accumulator and each value of the slice (from right-to-left) +// to reduce it to a single value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func InterfacesReduceRight( + i []interface{}, + fn func(i []interface{}, k int, v, accumulator interface{}) interface{}, initialValue ...interface{}, +) interface{} { + if len(i) == 0 { + return 0 + } + end := len(i) - 1 + acc := i[end] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + end -= 1 + } + for k := end; k >= 0; k-- { + acc = fn(i, k, i[k], acc) + } + return acc +} + +// InterfacesReverse reverses an slice in place. +func InterfacesReverse(i []interface{}) { + first := 0 + last := len(i) - 1 + for first < last { + i[first], i[last] = i[last], i[first] + first++ + last-- + } +} + +// InterfacesShift removes the first element from an slice and returns that removed element. +// This method changes the length of the slice. +func InterfacesShift(i *[]interface{}) (interface{}, bool) { + a := *i + if len(a) == 0 { + return 0, false + } + first := a[0] + a = a[1:] + *i = a[:len(a):len(a)] + return first, true +} + +// InterfacesSlice returns a copy of a portion of an slice into a new slice object selected +// from begin to end (end not included) where begin and end represent the index of items in that slice. +// The original slice will not be modified. +func InterfacesSlice(i []interface{}, begin int, end ...int) []interface{} { + fixedStart, fixedEnd, ok := fixRange(len(i), begin, end...) + if !ok { + return []interface{}{} + } + return InterfacesCopy(i[fixedStart:fixedEnd]) +} + +// InterfacesSome tests whether at least one element in the slice passes the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice returns false for any condition! +func InterfacesSome(i []interface{}, fn func(i []interface{}, k int, v interface{}) bool) bool { + for k, v := range i { + if fn(i, k, v) { + return true + } + } + return false +} + +// InterfacesSplice changes the contents of an slice by removing or replacing +// existing elements and/or adding new elements in place. +func InterfacesSplice(i *[]interface{}, start, deleteCount int, items ...interface{}) { + a := *i + if deleteCount < 0 { + deleteCount = 0 + } + start, end, _ := fixRange(len(a), start, start+1+deleteCount) + deleteCount = end - start - 1 + for k := 0; k < len(items); k++ { + if deleteCount > 0 { + // replace + a[start] = items[k] + deleteCount-- + start++ + } else { + // insert + lastSlice := InterfacesCopy(a[start:]) + items = items[k:] + a = append(a[:start], items...) + a = append(a[:start+len(items)], lastSlice...) + *i = a[:len(a):len(a)] + return + } + } + if deleteCount > 0 { + a = append(a[:start], a[start+1+deleteCount:]...) + } + *i = a[:len(a):len(a)] +} + +// InterfacesUnshift adds one or more elements to the beginning of an slice and returns the new length of the slice. +func InterfacesUnshift(i *[]interface{}, element ...interface{}) int { + *i = append(element, *i...) + return len(*i) +} + +// InterfacesUnshiftDistinct adds one or more new elements that do not exist in the current slice to the beginning +// and returns the new length of the slice. +func InterfacesUnshiftDistinct(i *[]interface{}, element ...interface{}) int { + a := *i + if len(element) == 0 { + return len(a) + } + m := make(map[interface{}]bool, len(element)) + r := make([]interface{}, 0, len(a)+len(element)) +L: + for _, v := range element { + if m[v] { + continue + } + m[v] = true + for _, vv := range a { + if vv == v { + continue L + } + } + r = append(r, v) + } + r = append(r, a...) + *i = r[:len(r):len(r)] + return len(r) +} + +// InterfacesRemoveFirst removes the first matched elements from the slice, +// and returns the new length of the slice. +func InterfacesRemoveFirst(p *[]interface{}, elements ...interface{}) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for k, v := range a { + if v == element { + a = append(a[:k], a[k+1:]...) + break + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// InterfacesRemoveEvery removes all the elements from the slice, +// and returns the new length of the slice. +func InterfacesRemoveEvery(p *[]interface{}, elements ...interface{}) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for i := 0; i < len(a); i++ { + if a[i] == element { + a = append(a[:i], a[i+1:]...) + i-- + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// InterfacesConcat is used to merge two or more slices. +// This method does not change the existing slices, but instead returns a new slice. +func InterfacesConcat(i ...[]interface{}) []interface{} { + var totalLen int + for _, v := range i { + totalLen += len(v) + } + ret := make([]interface{}, totalLen) + dst := ret + for _, v := range i { + n := copy(dst, v) + dst = dst[n:] + } + return ret +} + +// InterfacesIntersect calculates intersection of two or more slices, +// and returns the count of each element. +func InterfacesIntersect(i ...[]interface{}) (intersectCount map[interface{}]int) { + if len(i) == 0 { + return nil + } + for _, v := range i { + if len(v) == 0 { + return nil + } + } + counts := make([]map[interface{}]int, len(i)) + for k, v := range i { + counts[k] = interfacesDistinct(v, nil) + } + intersectCount = counts[0] +L: + for k, v := range intersectCount { + for _, c := range counts[1:] { + v2 := c[k] + if v2 == 0 { + delete(intersectCount, k) + continue L + } + if v > v2 { + v = v2 + } + } + intersectCount[k] = v + } + return intersectCount +} + +// InterfacesDistinct calculates the count of each different element, +// and only saves these different elements in place if changeSlice is true. +func InterfacesDistinct(i *[]interface{}, changeSlice bool) (distinctCount map[interface{}]int) { + if !changeSlice { + return interfacesDistinct(*i, nil) + } + a := (*i)[:0] + distinctCount = interfacesDistinct(*i, &a) + n := len(distinctCount) + *i = a[:n:n] + return distinctCount +} + +func interfacesDistinct(src []interface{}, dst *[]interface{}) map[interface{}]int { + m := make(map[interface{}]int, len(src)) + if dst == nil { + for _, v := range src { + n := m[v] + m[v] = n + 1 + } + } else { + a := *dst + for _, v := range src { + n := m[v] + m[v] = n + 1 + if n == 0 { + a = append(a, v) + } + } + *dst = a + } + return m +} diff --git a/internal/ameda/ints.go b/internal/ameda/ints.go new file mode 100644 index 0000000..0bc8cb0 --- /dev/null +++ b/internal/ameda/ints.go @@ -0,0 +1,682 @@ +package ameda + +// OneInt try to return the first element, otherwise return zero value. +func OneInt(i []int) int { + if len(i) > 0 { + return i[0] + } + return 0 +} + +// IntsCopy creates a copy of the int slice. +func IntsCopy(i []int) []int { + b := make([]int, len(i)) + copy(b, i) + return b +} + +// IntsToInterfaces converts int slice to interface slice. +func IntsToInterfaces(i []int) []interface{} { + r := make([]interface{}, len(i)) + for k, v := range i { + r[k] = IntToInterface(v) + } + return r +} + +// IntsToStrings converts int slice to string slice. +func IntsToStrings(i []int) []string { + r := make([]string, len(i)) + for k, v := range i { + r[k] = IntToString(v) + } + return r +} + +// IntsToBools converts int slice to bool slice. +// NOTE: +// 0 is false, everything else is true +func IntsToBools(i []int) []bool { + r := make([]bool, len(i)) + for k, v := range i { + r[k] = IntToBool(v) + } + return r +} + +// IntsToFloat32s converts int slice to float32 slice. +func IntsToFloat32s(i []int) []float32 { + r := make([]float32, len(i)) + for k, v := range i { + r[k] = IntToFloat32(v) + } + return r +} + +// IntsToFloat64s converts int slice to float64 slice. +func IntsToFloat64s(i []int) []float64 { + r := make([]float64, len(i)) + for k, v := range i { + r[k] = IntToFloat64(v) + } + return r +} + +// IntsToInt8s converts int slice to int8 slice. +func IntsToInt8s(i []int) ([]int8, error) { + var err error + r := make([]int8, len(i)) + for k, v := range i { + r[k], err = IntToInt8(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// IntsToInt16s converts int slice to int16 slice. +func IntsToInt16s(i []int) ([]int16, error) { + var err error + r := make([]int16, len(i)) + for k, v := range i { + r[k], err = IntToInt16(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// IntsToInt32s converts int slice to int32 slice. +func IntsToInt32s(i []int) ([]int32, error) { + var err error + r := make([]int32, len(i)) + for k, v := range i { + r[k], err = IntToInt32(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// IntsToInt64s converts int slice to int64 slice. +func IntsToInt64s(i []int) []int64 { + r := make([]int64, len(i)) + for k, v := range i { + r[k] = IntToInt64(v) + } + return r +} + +// IntsToUints converts int slice to uint slice. +func IntsToUints(i []int) ([]uint, error) { + var err error + r := make([]uint, len(i)) + for k, v := range i { + r[k], err = IntToUint(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// IntsToUint8s converts int slice to uint8 slice. +func IntsToUint8s(i []int) ([]uint8, error) { + var err error + r := make([]uint8, len(i)) + for k, v := range i { + r[k], err = IntToUint8(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// IntsToUint16s converts int slice to uint16 slice. +func IntsToUint16s(i []int) ([]uint16, error) { + var err error + r := make([]uint16, len(i)) + for k, v := range i { + r[k], err = IntToUint16(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// IntsToUint32s converts int slice to uint32 slice. +func IntsToUint32s(i []int) ([]uint32, error) { + var err error + r := make([]uint32, len(i)) + for k, v := range i { + r[k], err = IntToUint32(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// IntsToUint64s converts int slice to uint64 slice. +func IntsToUint64s(i []int) ([]uint64, error) { + var err error + r := make([]uint64, len(i)) + for k, v := range i { + r[k], err = IntToUint64(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// IntsCopyWithin copies part of an slice to another location in the current slice. +// @target +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func IntsCopyWithin(i []int, target, start int, end ...int) { + target = fixIndex(len(i), target, true) + if target == len(i) { + return + } + sub := IntsSlice(i, start, end...) + for k, v := range sub { + i[target+k] = v + } +} + +// IntsEvery tests whether all elements in the slice pass the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice will return true for any condition! +func IntsEvery(i []int, fn func(i []int, k int, v int) bool) bool { + for k, v := range i { + if !fn(i, k, v) { + return false + } + } + return true +} + +// IntsFill changes all elements in the current slice to a value, from a start index to an end index. +// @value +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func IntsFill(i []int, value int, start int, end ...int) { + fixedStart, fixedEnd, ok := fixRange(len(i), start, end...) + if !ok { + return + } + for k := fixedStart; k < fixedEnd; k++ { + i[k] = value + } +} + +// IntsFilter creates a new slice with all elements that pass the test implemented by the provided function. +func IntsFilter(i []int, fn func(i []int, k int, v int) bool) []int { + ret := make([]int, 0) + for k, v := range i { + if fn(i, k, v) { + ret = append(ret, v) + } + } + return ret +} + +// IntsFind returns the key-value of the first element in the provided slice that satisfies the provided testing function. +// NOTE: +// If not found, k = -1 +func IntsFind(i []int, fn func(i []int, k int, v int) bool) (k int, v int) { + for k, v := range i { + if fn(i, k, v) { + return k, v + } + } + return -1, 0 +} + +// IntsIncludes determines whether an slice includes a certain value among its entries. +// @fromIndex +// The index to start the search at. Defaults to 0. +func IntsIncludes(i []int, valueToFind int, fromIndex ...int) bool { + return IntsIndexOf(i, valueToFind, fromIndex...) > -1 +} + +// IntsIndexOf returns the first index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func IntsIndexOf(i []int, searchElement int, fromIndex ...int) int { + idx := getFromIndex(len(i), fromIndex...) + for k, v := range i[idx:] { + if searchElement == v { + return k + idx + } + } + return -1 +} + +// IntsLastIndexOf returns the last index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func IntsLastIndexOf(i []int, searchElement int, fromIndex ...int) int { + idx := getFromIndex(len(i), fromIndex...) + for k := len(i) - 1; k >= idx; k-- { + if searchElement == i[k] { + return k + } + } + return -1 +} + +// IntsMap creates a new slice populated with the results of calling a provided function +// on every element in the calling slice. +func IntsMap(i []int, fn func(i []int, k int, v int) int) []int { + ret := make([]int, len(i)) + for k, v := range i { + ret[k] = fn(i, k, v) + } + return ret +} + +// IntsPop removes the last element from an slice and returns that element. +// This method changes the length of the slice. +func IntsPop(i *[]int) (int, bool) { + a := *i + if len(a) == 0 { + return 0, false + } + lastIndex := len(a) - 1 + last := a[lastIndex] + a = a[:lastIndex] + *i = a[:len(a):len(a)] + return last, true +} + +// IntsPush adds one or more elements to the end of an slice and returns the new length of the slice. +func IntsPush(i *[]int, element ...int) int { + *i = append(*i, element...) + return len(*i) +} + +// IntsPushDistinct adds one or more new elements that do not exist in the current slice at the end. +func IntsPushDistinct(i []int, element ...int) []int { +L: + for _, v := range element { + for _, vv := range i { + if vv == v { + continue L + } + } + i = append(i, v) + } + return i +} + +// IntsReduce executes a reducer function (that you provide) on each element of the slice, +// resulting in a single output value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func IntsReduce(i []int, fn func(i []int, k int, v, accumulator int) int, initialValue ...int) int { + if len(i) == 0 { + return 0 + } + start := 0 + acc := i[start] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + start += 1 + } + for k := start; k < len(i); k++ { + acc = fn(i, k, i[k], acc) + } + return acc +} + +// IntsReduceRight applies a function against an accumulator and each value of the slice (from right-to-left) +// to reduce it to a single value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func IntsReduceRight(i []int, fn func(i []int, k int, v, accumulator int) int, initialValue ...int) int { + if len(i) == 0 { + return 0 + } + end := len(i) - 1 + acc := i[end] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + end -= 1 + } + for k := end; k >= 0; k-- { + acc = fn(i, k, i[k], acc) + } + return acc +} + +// IntsReverse reverses an slice in place. +func IntsReverse(i []int) { + first := 0 + last := len(i) - 1 + for first < last { + i[first], i[last] = i[last], i[first] + first++ + last-- + } +} + +// IntsShift removes the first element from an slice and returns that removed element. +// This method changes the length of the slice. +func IntsShift(i *[]int) (int, bool) { + a := *i + if len(a) == 0 { + return 0, false + } + first := a[0] + a = a[1:] + *i = a[:len(a):len(a)] + return first, true +} + +// IntsSlice returns a copy of a portion of an slice into a new slice object selected +// from begin to end (end not included) where begin and end represent the index of items in that slice. +// The original slice will not be modified. +func IntsSlice(i []int, begin int, end ...int) []int { + fixedStart, fixedEnd, ok := fixRange(len(i), begin, end...) + if !ok { + return []int{} + } + return IntsCopy(i[fixedStart:fixedEnd]) +} + +// IntsSome tests whether at least one element in the slice passes the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice returns false for any condition! +func IntsSome(i []int, fn func(i []int, k int, v int) bool) bool { + for k, v := range i { + if fn(i, k, v) { + return true + } + } + return false +} + +// IntsSplice changes the contents of an slice by removing or replacing +// existing elements and/or adding new elements in place. +func IntsSplice(i *[]int, start, deleteCount int, items ...int) { + a := *i + if deleteCount < 0 { + deleteCount = 0 + } + start, end, _ := fixRange(len(a), start, start+1+deleteCount) + deleteCount = end - start - 1 + for k := 0; k < len(items); k++ { + if deleteCount > 0 { + // replace + a[start] = items[k] + deleteCount-- + start++ + } else { + // insert + lastSlice := IntsCopy(a[start:]) + items = items[k:] + a = append(a[:start], items...) + a = append(a[:start+len(items)], lastSlice...) + *i = a[:len(a):len(a)] + return + } + } + if deleteCount > 0 { + a = append(a[:start], a[start+1+deleteCount:]...) + } + *i = a[:len(a):len(a)] +} + +// IntsUnshift adds one or more elements to the beginning of an slice and returns the new length of the slice. +func IntsUnshift(i *[]int, element ...int) int { + *i = append(element, *i...) + return len(*i) +} + +// IntsUnshiftDistinct adds one or more new elements that do not exist in the current slice to the beginning +// and returns the new length of the slice. +func IntsUnshiftDistinct(i *[]int, element ...int) int { + a := *i + if len(element) == 0 { + return len(a) + } + m := make(map[int]bool, len(element)) + r := make([]int, 0, len(a)+len(element)) +L: + for _, v := range element { + if m[v] { + continue + } + m[v] = true + for _, vv := range a { + if vv == v { + continue L + } + } + r = append(r, v) + } + r = append(r, a...) + *i = r[:len(r):len(r)] + return len(r) +} + +// IntsRemoveFirst removes the first matched elements from the slice, +// and returns the new length of the slice. +func IntsRemoveFirst(p *[]int, elements ...int) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for k, v := range a { + if v == element { + a = append(a[:k], a[k+1:]...) + break + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// IntsRemoveEvery removes all the elements from the slice, +// and returns the new length of the slice. +func IntsRemoveEvery(p *[]int, elements ...int) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for i := 0; i < len(a); i++ { + if a[i] == element { + a = append(a[:i], a[i+1:]...) + i-- + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// IntsConcat is used to merge two or more slices. +// This method does not change the existing slices, but instead returns a new slice. +func IntsConcat(i ...[]int) []int { + var totalLen int + for _, v := range i { + totalLen += len(v) + } + ret := make([]int, totalLen) + dst := ret + for _, v := range i { + n := copy(dst, v) + dst = dst[n:] + } + return ret +} + +// IntsIntersect calculates intersection of two or more slices, +// and returns the count of each element. +func IntsIntersect(i ...[]int) (intersectCount map[int]int) { + if len(i) == 0 { + return nil + } + for _, v := range i { + if len(v) == 0 { + return nil + } + } + counts := make([]map[int]int, len(i)) + for k, v := range i { + counts[k] = intsDistinct(v, nil) + } + intersectCount = counts[0] +L: + for k, v := range intersectCount { + for _, c := range counts[1:] { + v2 := c[k] + if v2 == 0 { + delete(intersectCount, k) + continue L + } + if v > v2 { + v = v2 + } + } + intersectCount[k] = v + } + return intersectCount +} + +// IntsDistinct calculates the count of each different element, +// and only saves these different elements in place if changeSlice is true. +func IntsDistinct(i *[]int, changeSlice bool) (distinctCount map[int]int) { + if !changeSlice { + return intsDistinct(*i, nil) + } + a := (*i)[:0] + distinctCount = intsDistinct(*i, &a) + n := len(distinctCount) + *i = a[:n:n] + return distinctCount +} + +func intsDistinct(src []int, dst *[]int) map[int]int { + m := make(map[int]int, len(src)) + if dst == nil { + for _, v := range src { + n := m[v] + m[v] = n + 1 + } + } else { + a := *dst + for _, v := range src { + n := m[v] + m[v] = n + 1 + if n == 0 { + a = append(a, v) + } + } + *dst = a + } + return m +} + +// IntSetUnion calculates between multiple collections: set1 ∪ set2 ∪ others... +// This method does not change the existing slices, but instead returns a new slice. +func IntSetUnion(set1, set2 []int, others ...[]int) []int { + m := make(map[int]struct{}, len(set1)+len(set2)) + r := make([]int, 0, len(m)) + for _, set := range append([][]int{set1, set2}, others...) { + for _, v := range set { + _, ok := m[v] + if ok { + continue + } + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} + +// IntSetIntersect calculates between multiple collections: set1 ∩ set2 ∩ others... +// This method does not change the existing slices, but instead returns a new slice. +func IntSetIntersect(set1, set2 []int, others ...[]int) []int { + sets := append([][]int{set2}, others...) + setsCount := make([]map[int]int, len(sets)) + for k, v := range sets { + setsCount[k] = intsDistinct(v, nil) + } + m := make(map[int]struct{}, len(set1)) + r := make([]int, 0, len(m)) +L: + for _, v := range set1 { + if _, ok := m[v]; ok { + continue + } + m[v] = struct{}{} + for _, m2 := range setsCount { + if m2[v] == 0 { + continue L + } + } + r = append(r, v) + } + return r +} + +// IntSetDifference calculates between multiple collections: set1 - set2 - others... +// This method does not change the existing slices, but instead returns a new slice. +func IntSetDifference(set1, set2 []int, others ...[]int) []int { + m := make(map[int]struct{}, len(set1)) + r := make([]int, 0, len(set1)) + sets := append([][]int{set2}, others...) + for _, v := range sets { + inter := IntSetIntersect(set1, v) + for _, v := range inter { + m[v] = struct{}{} + } + } + for _, v := range set1 { + if _, ok := m[v]; !ok { + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} diff --git a/internal/ameda/itoa62.go b/internal/ameda/itoa62.go new file mode 100644 index 0000000..6aaa07a --- /dev/null +++ b/internal/ameda/itoa62.go @@ -0,0 +1,210 @@ +package ameda + +import "math/bits" + +// FormatUint returns the string representation of i in the given base, +// for 2 <= base <= 62. +// NOTE: +// Compatible with standard package strconv. +func FormatUint(i uint64, base int) string { + if fastSmalls && i < nSmalls && base == 10 { + return small(int(i)) + } + _, s := formatBits(nil, i, base, false, false) + return s +} + +// FormatInt returns the string representation of i in the given base, +// for 2 <= base <= 62. +// NOTE: +// Compatible with standard package strconv. +func FormatInt(i int64, base int) string { + if fastSmalls && 0 <= i && i < nSmalls && base == 10 { + return small(int(i)) + } + _, s := formatBits(nil, uint64(i), base, i < 0, false) + return s +} + +// Itoa is equivalent to FormatInt(int64(i), 10). +// NOTE: +// Compatible with standard package strconv. +func Itoa(i int) string { + return FormatInt(int64(i), 10) +} + +// AppendInt appends the string form of the integer i, +// as generated by FormatInt, to dst and returns the extended buffer. +// NOTE: +// Compatible with standard package strconv. +func AppendInt(dst []byte, i int64, base int) []byte { + if fastSmalls && 0 <= i && i < nSmalls && base == 10 { + return append(dst, small(int(i))...) + } + dst, _ = formatBits(dst, uint64(i), base, i < 0, true) + return dst +} + +// AppendUint appends the string form of the unsigned integer i, +// as generated by FormatUint, to dst and returns the extended buffer. +// NOTE: +// Compatible with standard package strconv. +func AppendUint(dst []byte, i uint64, base int) []byte { + if fastSmalls && i < nSmalls && base == 10 { + return append(dst, small(int(i))...) + } + dst, _ = formatBits(dst, i, base, false, true) + return dst +} + +const ( + digits = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" +) + +const ( + fastSmalls = true // enable fast path for small integers + nSmalls = 100 + smallsString = "00010203040506070809" + + "10111213141516171819" + + "20212223242526272829" + + "30313233343536373839" + + "40414243444546474849" + + "50515253545556575859" + + "60616263646566676869" + + "70717273747576777879" + + "80818283848586878889" + + "90919293949596979899" +) + +// small returns the string for an i with 0 <= i < nSmalls. +func small(i int) string { + if i < 10 { + return digits[i : i+1] + } + return smallsString[i*2 : i*2+2] +} + +// formatBits computes the string representation of u in the given base. +// If neg is set, u is treated as negative int64 value. If append_ is +// set, the string is appended to dst and the resulting byte slice is +// returned as the first result value; otherwise the string is returned +// as the second result value. +// +func formatBits(dst []byte, u uint64, base int, neg, append_ bool) (d []byte, s string) { + if base < 2 || base > len(digits) { + panic("ameda(strconv): illegal AppendInt/FormatInt base") + } + // 2 <= base && base <= len(digits) + + var a [64 + 1]byte // +1 for sign of 64bit value in base 2 + i := len(a) + + if neg { + u = -u + } + + // convert bits + // We use uint values where we can because those will + // fit into a single register even on a 32bit machine. + if base == 10 { + // common case: use constants for / because + // the compiler can optimize it into a multiply+shift + + if Host32bit { + // convert the lower digits using 32bit operations + for u >= 1e9 { + // Avoid using r = a%b in addition to q = a/b + // since 64bit division and modulo operations + // are calculated by runtime functions on 32bit machines. + q := u / 1e9 + us := uint(u - q*1e9) // u % 1e9 fits into a uint + for j := 4; j > 0; j-- { + is := us % 100 * 2 + us /= 100 + i -= 2 + a[i+1] = smallsString[is+1] + a[i+0] = smallsString[is+0] + } + + // us < 10, since it contains the last digit + // from the initial 9-digit us. + i-- + a[i] = smallsString[us*2+1] + + u = q + } + // u < 1e9 + } + + // u guaranteed to fit into a uint + us := uint(u) + for us >= 100 { + is := us % 100 * 2 + us /= 100 + i -= 2 + a[i+1] = smallsString[is+1] + a[i+0] = smallsString[is+0] + } + + // us < 100 + is := us * 2 + i-- + a[i] = smallsString[is+1] + if us >= 10 { + i-- + a[i] = smallsString[is] + } + + } else if isPowerOfTwo(base) { + // Use shifts and masks instead of / and %. + // Base is a power of 2 and 2 <= base <= len(digits) where len(digits) is 62. + // The largest power of 2 below or equal to 62 is 32, which is 1 << 5; + // i.e., the largest possible shift count is 5. By &-ind that value with + // the constant 7 we tell the compiler that the shift count is always + // less than 8 which is smaller than any register width. This allows + // the compiler to generate better code for the shift operation. + shift := uint(bits.TrailingZeros(uint(base))) & 7 + b := uint64(base) + m := uint(base) - 1 // == 1<= b { + i-- + a[i] = digits[uint(u)&m] + u >>= shift + } + // u < base + i-- + a[i] = digits[uint(u)] + } else { + // general case + b := uint64(base) + for u >= b { + i-- + // Avoid using r = a%b in addition to q = a/b + // since 64bit division and modulo operations + // are calculated by runtime functions on 32bit machines. + q := u / b + a[i] = digits[uint(u-q*b)] + u = q + } + // u < base + i-- + a[i] = digits[uint(u)] + } + + // add sign, if any + if neg { + i-- + a[i] = '-' + } + + if append_ { + d = append(dst, a[i:]...) + return + } + s = string(a[i:]) + return +} + +func isPowerOfTwo(x int) bool { + return x&(x-1) == 0 +} diff --git a/internal/ameda/itoa_x.go b/internal/ameda/itoa_x.go new file mode 100644 index 0000000..68aee00 --- /dev/null +++ b/internal/ameda/itoa_x.go @@ -0,0 +1,21 @@ +package ameda + +// FormatUintByDict convert num into corresponding string according to dict. +func FormatUintByDict(dict []byte, num uint64) string { + var base = uint64(len(dict)) + if base == 0 { + return "" + } + var str []byte + for { + tmp := make([]byte, len(str)+1) + tmp[0] = dict[num%base] + copy(tmp[1:], str) + str = tmp + num = num / base + if num == 0 { + break + } + } + return string(str) +} diff --git a/internal/ameda/string.go b/internal/ameda/string.go new file mode 100644 index 0000000..f169b67 --- /dev/null +++ b/internal/ameda/string.go @@ -0,0 +1,242 @@ +package ameda + +import ( + "strconv" +) + +// StringToInterface converts string to interface. +func StringToInterface(v string) interface{} { + return v +} + +// StringToInterfacePtr converts string to *interface. +func StringToInterfacePtr(v string) *interface{} { + r := StringToInterface(v) + return &r +} + +// StringToStringPtr converts string to *string. +func StringToStringPtr(v string) *string { + return &v +} + +// StringToBool converts string to bool. +func StringToBool(v string, emptyAsFalse ...bool) (bool, error) { + r, err := strconv.ParseBool(v) + if err != nil { + if !isEmptyAsZero(emptyAsFalse) { + return false, err + } + } + return r, nil +} + +// StringToBoolPtr converts string to *bool. +func StringToBoolPtr(v string, emptyAsFalse ...bool) (*bool, error) { + r, err := StringToBool(v, emptyAsFalse...) + return &r, err +} + +// StringToFloat32 converts string to float32. +func StringToFloat32(v string, emptyAsZero ...bool) (float32, error) { + i, err := strconv.ParseFloat(v, 32) + if err != nil { + if !isEmptyAsZero(emptyAsZero) { + return 0, err + } + } + return float32(i), nil +} + +// StringToFloat32Ptr converts string to *float32. +func StringToFloat32Ptr(v string, emptyAsZero ...bool) (*float32, error) { + r, err := StringToFloat32(v, emptyAsZero...) + return &r, err +} + +// StringToFloat64 converts string to float64. +func StringToFloat64(v string, emptyAsZero ...bool) (float64, error) { + i, err := strconv.ParseFloat(v, 64) + if err != nil { + if !isEmptyAsZero(emptyAsZero) { + return 0, err + } + } + return i, nil +} + +// StringToFloat64Ptr converts string to *float64. +func StringToFloat64Ptr(v string, emptyAsZero ...bool) (*float64, error) { + r, err := StringToFloat64(v, emptyAsZero...) + return &r, err +} + +// StringToInt converts string to int. +func StringToInt(v string, emptyAsZero ...bool) (int, error) { + i, err := strconv.Atoi(v) + if err != nil { + if !isEmptyAsZero(emptyAsZero) { + return 0, err + } + } + return i, nil +} + +// StringToIntPtr converts string to *int. +func StringToIntPtr(v string, emptyAsZero ...bool) (*int, error) { + r, err := StringToInt(v, emptyAsZero...) + return &r, err +} + +// StringToInt8 converts string to int8. +func StringToInt8(v string, emptyAsZero ...bool) (int8, error) { + i, err := strconv.ParseInt(v, 10, 8) + if err != nil { + if !isEmptyAsZero(emptyAsZero) { + return 0, err + } + } + return int8(i), nil +} + +// StringToInt8Ptr converts string to *int8. +func StringToInt8Ptr(v string, emptyAsZero ...bool) (*int8, error) { + r, err := StringToInt8(v, emptyAsZero...) + return &r, err +} + +// StringToInt16 converts string to int16. +func StringToInt16(v string, emptyAsZero ...bool) (int16, error) { + i, err := strconv.ParseInt(v, 10, 16) + if err != nil { + if !isEmptyAsZero(emptyAsZero) { + return 0, err + } + } + return int16(i), nil +} + +// StringToInt16Ptr converts string to *int16. +func StringToInt16Ptr(v string, emptyAsZero ...bool) (*int16, error) { + r, err := StringToInt16(v, emptyAsZero...) + return &r, err +} + +// StringToInt32 converts string to int32. +func StringToInt32(v string, emptyAsZero ...bool) (int32, error) { + i, err := strconv.ParseInt(v, 10, 32) + if err != nil { + if !isEmptyAsZero(emptyAsZero) { + return 0, err + } + } + return int32(i), nil +} + +// StringToInt32Ptr converts string to *int32. +func StringToInt32Ptr(v string, emptyAsZero ...bool) (*int32, error) { + r, err := StringToInt32(v, emptyAsZero...) + return &r, err +} + +// StringToInt64 converts string to int64. +func StringToInt64(v string, emptyAsZero ...bool) (int64, error) { + i, err := strconv.ParseInt(v, 10, 64) + if err != nil { + if !isEmptyAsZero(emptyAsZero) { + return 0, err + } + } + return i, nil +} + +// StringToInt64Ptr converts string to *int64. +func StringToInt64Ptr(v string, emptyAsZero ...bool) (*int64, error) { + r, err := StringToInt64(v, emptyAsZero...) + return &r, err +} + +// StringToUint converts string to uint. +func StringToUint(v string, emptyAsZero ...bool) (uint, error) { + u, err := strconv.ParseUint(v, 10, strconv.IntSize) + if err != nil { + if !isEmptyAsZero(emptyAsZero) { + return 0, err + } + } + return uint(u), nil +} + +// StringToUintPtr converts string to *uint. +func StringToUintPtr(v string, emptyAsZero ...bool) (*uint, error) { + r, err := StringToUint(v, emptyAsZero...) + return &r, err +} + +// StringToUint8 converts string to uint8. +func StringToUint8(v string, emptyAsZero ...bool) (uint8, error) { + u, err := strconv.ParseUint(v, 10, 8) + if err != nil { + if !isEmptyAsZero(emptyAsZero) { + return 0, err + } + } + return uint8(u), nil +} + +// StringToUint8Ptr converts string to *uint8. +func StringToUint8Ptr(v string, emptyAsZero ...bool) (*uint8, error) { + r, err := StringToUint8(v, emptyAsZero...) + return &r, err +} + +// StringToUint16 converts string to uint16. +func StringToUint16(v string, emptyAsZero ...bool) (uint16, error) { + u, err := strconv.ParseUint(v, 10, 16) + if err != nil { + if !isEmptyAsZero(emptyAsZero) { + return 0, err + } + } + return uint16(u), nil +} + +// StringToUint16Ptr converts string to *uint16. +func StringToUint16Ptr(v string, emptyAsZero ...bool) (*uint16, error) { + r, err := StringToUint16(v, emptyAsZero...) + return &r, err +} + +// StringToUint32 converts string to uint32. +func StringToUint32(v string, emptyAsZero ...bool) (uint32, error) { + u, err := strconv.ParseUint(v, 10, 32) + if err != nil { + if !isEmptyAsZero(emptyAsZero) { + return 0, err + } + } + return uint32(u), nil +} + +// StringToUint32Ptr converts string to *uint32. +func StringToUint32Ptr(v string, emptyAsZero ...bool) (*uint32, error) { + r, err := StringToUint32(v, emptyAsZero...) + return &r, err +} + +// StringToUint64 converts string to uint64. +func StringToUint64(v string, emptyAsZero ...bool) (uint64, error) { + u, err := strconv.ParseUint(v, 10, 64) + if err != nil { + if !isEmptyAsZero(emptyAsZero) { + return 0, err + } + } + return u, nil +} + +// StringToUint64Ptr converts string to *uint64. +func StringToUint64Ptr(v string, emptyAsZero ...bool) (*uint64, error) { + r, err := StringToUint64(v, emptyAsZero...) + return &r, err +} diff --git a/internal/ameda/strings.go b/internal/ameda/strings.go new file mode 100644 index 0000000..2643b57 --- /dev/null +++ b/internal/ameda/strings.go @@ -0,0 +1,710 @@ +package ameda + +import ( + "strings" +) + +// OneString try to return the first element, otherwise return zero value. +func OneString(s []string) string { + if len(s) > 0 { + return s[0] + } + return "" +} + +// StringsCopy creates a copy of the string slice. +func StringsCopy(s []string) []string { + b := make([]string, len(s)) + copy(b, s) + return b +} + +// StringsToInterfaces converts string slice to interface slice. +func StringsToInterfaces(s []string) []interface{} { + r := make([]interface{}, len(s)) + for k, v := range s { + r[k] = StringToInterface(v) + } + return r +} + +// StringsToBools converts string slice to bool slice. +func StringsToBools(s []string, emptyAsZero ...bool) ([]bool, error) { + var err error + r := make([]bool, len(s)) + for k, v := range s { + r[k], err = StringToBool(v, emptyAsZero...) + if err != nil { + return r, err + } + } + return r, nil +} + +// StringsToFloat32s converts string slice to float32 slice. +func StringsToFloat32s(s []string, emptyAsZero ...bool) ([]float32, error) { + var err error + r := make([]float32, len(s)) + for k, v := range s { + r[k], err = StringToFloat32(v, emptyAsZero...) + if err != nil { + return r, err + } + } + return r, nil +} + +// StringsToFloat64s converts string slice to float64 slice. +func StringsToFloat64s(s []string, emptyAsZero ...bool) ([]float64, error) { + var err error + r := make([]float64, len(s)) + for k, v := range s { + r[k], err = StringToFloat64(v, emptyAsZero...) + if err != nil { + return r, err + } + } + return r, nil +} + +// StringsToInts converts string slice to int slice. +func StringsToInts(s []string, emptyAsZero ...bool) ([]int, error) { + var err error + r := make([]int, len(s)) + for k, v := range s { + r[k], err = StringToInt(v, emptyAsZero...) + if err != nil { + return r, err + } + } + return r, nil +} + +// StringsToInt8s converts string slice to int8 slice. +func StringsToInt8s(s []string, emptyAsZero ...bool) ([]int8, error) { + var err error + r := make([]int8, len(s)) + for k, v := range s { + r[k], err = StringToInt8(v, emptyAsZero...) + if err != nil { + return r, err + } + } + return r, nil +} + +// StringsToInt16s converts string slice to int16 slice. +func StringsToInt16s(s []string, emptyAsZero ...bool) ([]int16, error) { + var err error + r := make([]int16, len(s)) + for k, v := range s { + r[k], err = StringToInt16(v, emptyAsZero...) + if err != nil { + return r, err + } + } + return r, nil +} + +// StringsToInt32s converts string slice to int32 slice. +func StringsToInt32s(s []string, emptyAsZero ...bool) ([]int32, error) { + var err error + r := make([]int32, len(s)) + for k, v := range s { + r[k], err = StringToInt32(v, emptyAsZero...) + if err != nil { + return r, err + } + } + return r, nil +} + +// StringsToInt64s converts string slice to int64 slice. +func StringsToInt64s(s []string, emptyAsZero ...bool) ([]int64, error) { + var err error + r := make([]int64, len(s)) + for k, v := range s { + r[k], err = StringToInt64(v, emptyAsZero...) + if err != nil { + return r, err + } + } + return r, nil +} + +// StringsToUints converts string slice to uint slice. +func StringsToUints(s []string, emptyAsZero ...bool) ([]uint, error) { + var err error + r := make([]uint, len(s)) + for k, v := range s { + r[k], err = StringToUint(v, emptyAsZero...) + if err != nil { + return r, err + } + } + return r, nil +} + +// StringsToUint8s converts string slice to uint8 slice. +func StringsToUint8s(s []string, emptyAsZero ...bool) ([]uint8, error) { + var err error + r := make([]uint8, len(s)) + for k, v := range s { + r[k], err = StringToUint8(v, emptyAsZero...) + if err != nil { + return r, err + } + } + return r, nil +} + +// StringsToUint16s converts string slice to uint16 slice. +func StringsToUint16s(s []string, emptyAsZero ...bool) ([]uint16, error) { + var err error + r := make([]uint16, len(s)) + for k, v := range s { + r[k], err = StringToUint16(v, emptyAsZero...) + if err != nil { + return r, err + } + } + return r, nil +} + +// StringsToUint32s converts string slice to uint32 slice. +func StringsToUint32s(s []string, emptyAsZero ...bool) ([]uint32, error) { + var err error + r := make([]uint32, len(s)) + for k, v := range s { + r[k], err = StringToUint32(v, emptyAsZero...) + if err != nil { + return r, err + } + } + return r, nil +} + +// StringsToUint64s converts string slice to uint64 slice. +func StringsToUint64s(s []string, emptyAsZero ...bool) ([]uint64, error) { + var err error + r := make([]uint64, len(s)) + for k, v := range s { + r[k], err = StringToUint64(v, emptyAsZero...) + if err != nil { + return r, err + } + } + return r, nil +} + +// StringsCopyWithin copies part of an slice to another location in the current slice. +// @target +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func StringsCopyWithin(s []string, target, start int, end ...int) { + target = fixIndex(len(s), target, true) + if target == len(s) { + return + } + sub := StringsSlice(s, start, end...) + for i, v := range sub { + s[target+i] = v + } +} + +// StringsEvery tests whether all elements in the slice pass the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice will return true for any condition! +func StringsEvery(s []string, fn func(s []string, k int, v string) bool) bool { + for k, v := range s { + if !fn(s, k, v) { + return false + } + } + return true +} + +// StringsFill changes all elements in the current slice to a value, from a start index to an end index. +// @value +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func StringsFill(s []string, value string, start int, end ...int) { + fixedStart, fixedEnd, ok := fixRange(len(s), start, end...) + if !ok { + return + } + for i := fixedStart; i < fixedEnd; i++ { + s[i] = value + } +} + +// StringsFilter creates a new slice with all elements that pass the test implemented by the provided function. +func StringsFilter(s []string, fn func(s []string, k int, v string) bool) []string { + ret := make([]string, 0) + for k, v := range s { + if fn(s, k, v) { + ret = append(ret, v) + } + } + return ret +} + +// StringsFind returns the key-value of the first element in the provided slice that satisfies the provided testing function. +// NOTE: +// If not found, k = -1 +func StringsFind(s []string, fn func(s []string, k int, v string) bool) (k int, v string) { + for k, v := range s { + if fn(s, k, v) { + return k, v + } + } + return -1, "" +} + +// StringsIncludes determines whether an slice includes a certain value among its entries. +// @fromIndex +// The index to start the search at. Defaults to 0. +func StringsIncludes(s []string, valueToFind string, fromIndex ...int) bool { + return StringsIndexOf(s, valueToFind, fromIndex...) > -1 +} + +// StringsIndexOf returns the first index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func StringsIndexOf(s []string, searchElement string, fromIndex ...int) int { + idx := getFromIndex(len(s), fromIndex...) + for k, v := range s[idx:] { + if searchElement == v { + return k + idx + } + } + return -1 +} + +// StringsJoin concatenates the elements of s to create a single string. The separator string +// sep is placed between elements in the resulting string. +func StringsJoin(s []string, sep string) string { + return strings.Join(s, sep) +} + +// StringsLastIndexOf returns the last index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func StringsLastIndexOf(s []string, searchElement string, fromIndex ...int) int { + idx := getFromIndex(len(s), fromIndex...) + for i := len(s) - 1; i >= idx; i-- { + if searchElement == s[i] { + return i + } + } + return -1 +} + +// StringsMap creates a new slice populated with the results of calling a provided function +// on every element in the calling slice. +func StringsMap(s []string, fn func(s []string, k int, v string) string) []string { + ret := make([]string, len(s)) + for k, v := range s { + ret[k] = fn(s, k, v) + } + return ret +} + +// StringsPop removes the last element from an slice and returns that element. +// This method changes the length of the slice. +func StringsPop(s *[]string) (string, bool) { + a := *s + if len(a) == 0 { + return "", false + } + lastIndex := len(a) - 1 + last := a[lastIndex] + a = a[:lastIndex] + *s = a[:len(a):len(a)] + return last, true +} + +// StringsPush adds one or more elements to the end of an slice and returns the new length of the slice. +func StringsPush(s *[]string, element ...string) int { + *s = append(*s, element...) + return len(*s) +} + +// StringsPushDistinct adds one or more new elements that do not exist in the current slice at the end. +func StringsPushDistinct(s []string, element ...string) []string { +L: + for _, v := range element { + for _, vv := range s { + if vv == v { + continue L + } + } + s = append(s, v) + } + return s +} + +// StringsReduce executes a reducer function (that you provide) on each element of the slice, +// resulting in a single output value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func StringsReduce(s []string, fn func(s []string, k int, v, accumulator string) string, initialValue ...string) string { + if len(s) == 0 { + return "" + } + start := 0 + acc := s[start] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + start += 1 + } + for i := start; i < len(s); i++ { + acc = fn(s, i, s[i], acc) + } + return acc +} + +// StringsReduceRight applies a function against an accumulator and each value of the slice (from right-to-left) +// to reduce it to a single value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func StringsReduceRight(s []string, fn func(s []string, k int, v, accumulator string) string, initialValue ...string) string { + if len(s) == 0 { + return "" + } + end := len(s) - 1 + acc := s[end] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + end -= 1 + } + for i := end; i >= 0; i-- { + acc = fn(s, i, s[i], acc) + } + return acc +} + +// StringsReverse reverses an slice in place. +func StringsReverse(s []string) { + first := 0 + last := len(s) - 1 + for first < last { + s[first], s[last] = s[last], s[first] + first++ + last-- + } +} + +// StringsShift removes the first element from an slice and returns that removed element. +// This method changes the length of the slice. +func StringsShift(s *[]string) (string, bool) { + a := *s + if len(a) == 0 { + return "", false + } + first := a[0] + a = a[1:] + *s = a[:len(a):len(a)] + return first, true +} + +// StringsSlice returns a copy of a portion of an slice into a new slice object selected +// from begin to end (end not included) where begin and end represent the index of items in that slice. +// The original slice will not be modified. +func StringsSlice(s []string, begin int, end ...int) []string { + fixedStart, fixedEnd, ok := fixRange(len(s), begin, end...) + if !ok { + return []string{} + } + return StringsCopy(s[fixedStart:fixedEnd]) +} + +// StringsSome tests whether at least one element in the slice passes the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice returns false for any condition! +func StringsSome(s []string, fn func(s []string, k int, v string) bool) bool { + for k, v := range s { + if fn(s, k, v) { + return true + } + } + return false +} + +// StringsSplice changes the contents of an slice by removing or replacing +// existing elements and/or adding new elements in place. +func StringsSplice(s *[]string, start, deleteCount int, items ...string) { + a := *s + if deleteCount < 0 { + deleteCount = 0 + } + start, end, _ := fixRange(len(a), start, start+1+deleteCount) + deleteCount = end - start - 1 + for i := 0; i < len(items); i++ { + if deleteCount > 0 { + // replace + a[start] = items[i] + deleteCount-- + start++ + } else { + // insert + lastSlice := StringsCopy(a[start:]) + items = items[i:] + a = append(a[:start], items...) + a = append(a[:start+len(items)], lastSlice...) + *s = a[:len(a):len(a)] + return + } + } + if deleteCount > 0 { + a = append(a[:start], a[start+1+deleteCount:]...) + } + *s = a[:len(a):len(a)] +} + +// StringsUnshift adds one or more elements to the beginning of an slice and returns the new length of the slice. +func StringsUnshift(s *[]string, element ...string) int { + *s = append(element, *s...) + return len(*s) +} + +// StringsUnshiftDistinct adds one or more new elements that do not exist in the current slice to the beginning +// and returns the new length of the slice. +func StringsUnshiftDistinct(s *[]string, element ...string) int { + a := *s + if len(element) == 0 { + return len(a) + } + m := make(map[string]bool, len(element)) + r := make([]string, 0, len(a)+len(element)) +L: + for _, v := range element { + if m[v] { + continue + } + m[v] = true + for _, vv := range a { + if vv == v { + continue L + } + } + r = append(r, v) + } + r = append(r, a...) + *s = r[:len(r):len(r)] + return len(r) +} + +// StringsRemoveFirst removes the first matched elements from the slice, +// and returns the new length of the slice. +func StringsRemoveFirst(p *[]string, elements ...string) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for k, v := range a { + if v == element { + a = append(a[:k], a[k+1:]...) + break + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// StringsRemoveEvery removes all the elements from the slice, +// and returns the new length of the slice. +func StringsRemoveEvery(p *[]string, elements ...string) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for i := 0; i < len(a); i++ { + if a[i] == element { + a = append(a[:i], a[i+1:]...) + i-- + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// StringsConcat is used to merge two or more slices. +// This method does not change the existing slices, but instead returns a new slice. +func StringsConcat(s ...[]string) []string { + var totalLen int + for _, v := range s { + totalLen += len(v) + } + ret := make([]string, totalLen) + dst := ret + for _, v := range s { + n := copy(dst, v) + dst = dst[n:] + } + return ret +} + +// StringsIntersect calculates intersection of two or more slices, +// and returns the count of each element. +func StringsIntersect(s ...[]string) (intersectCount map[string]int) { + if len(s) == 0 { + return nil + } + for _, v := range s { + if len(v) == 0 { + return nil + } + } + counts := make([]map[string]int, len(s)) + for k, v := range s { + counts[k] = stringsDistinct(v, nil) + } + intersectCount = counts[0] +L: + for k, v := range intersectCount { + for _, c := range counts[1:] { + v2 := c[k] + if v2 == 0 { + delete(intersectCount, k) + continue L + } + if v > v2 { + v = v2 + } + } + intersectCount[k] = v + } + return intersectCount +} + +// StringsDistinct calculates the count of each different element, +// and only saves these different elements in place if changeSlice is true. +func StringsDistinct(s *[]string, changeSlice bool) (distinctCount map[string]int) { + if !changeSlice { + return stringsDistinct(*s, nil) + } + a := (*s)[:0] + distinctCount = stringsDistinct(*s, &a) + n := len(distinctCount) + *s = a[:n:n] + return distinctCount +} + +func stringsDistinct(src []string, dst *[]string) map[string]int { + m := make(map[string]int, len(src)) + if dst == nil { + for _, v := range src { + n := m[v] + m[v] = n + 1 + } + } else { + a := *dst + for _, v := range src { + n := m[v] + m[v] = n + 1 + if n == 0 { + a = append(a, v) + } + } + *dst = a + } + return m +} + +// StringSetUnion calculates between multiple collections: set1 ∪ set2 ∪ others... +// This method does not change the existing slices, but instead returns a new slice. +func StringSetUnion(set1, set2 []string, others ...[]string) []string { + m := make(map[string]struct{}, len(set1)+len(set2)) + r := make([]string, 0, len(m)) + for _, set := range append([][]string{set1, set2}, others...) { + for _, v := range set { + _, ok := m[v] + if ok { + continue + } + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} + +// StringSetIntersect calculates between multiple collections: set1 ∩ set2 ∩ others... +// This method does not change the existing slices, but instead returns a new slice. +func StringSetIntersect(set1, set2 []string, others ...[]string) []string { + sets := append([][]string{set2}, others...) + setsCount := make([]map[string]int, len(sets)) + for k, v := range sets { + setsCount[k] = stringsDistinct(v, nil) + } + m := make(map[string]struct{}, len(set1)) + r := make([]string, 0, len(m)) +L: + for _, v := range set1 { + if _, ok := m[v]; ok { + continue + } + m[v] = struct{}{} + for _, m2 := range setsCount { + if m2[v] == 0 { + continue L + } + } + r = append(r, v) + } + return r +} + +// StringSetDifference calculates between multiple collections: set1 - set2 - others... +// This method does not change the existing slices, but instead returns a new slice. +func StringSetDifference(set1, set2 []string, others ...[]string) []string { + m := make(map[string]struct{}, len(set1)) + r := make([]string, 0, len(set1)) + sets := append([][]string{set2}, others...) + for _, v := range sets { + inter := StringSetIntersect(set1, v) + for _, v := range inter { + m[v] = struct{}{} + } + } + for _, v := range set1 { + if _, ok := m[v]; !ok { + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} diff --git a/internal/ameda/typconv.go b/internal/ameda/typconv.go new file mode 100644 index 0000000..46036a3 --- /dev/null +++ b/internal/ameda/typconv.go @@ -0,0 +1,141 @@ +package ameda + +import ( + "reflect" + "unsafe" +) + +// UnsafeBytesToString convert []byte type to string type. +func UnsafeBytesToString(b []byte) string { + return *(*string)(unsafe.Pointer(&b)) +} + +// UnsafeStringToBytes convert string type to []byte type. +// NOTE: +// panic if modify the member value of the []byte. +func UnsafeStringToBytes(s string) []byte { + return *(*[]byte)(unsafe.Pointer( + &struct { + string + Cap int + }{s, len(s)}, + )) +} + +// IndirectValue gets the indirect value. +func IndirectValue(v reflect.Value) reflect.Value { + if !v.IsValid() { + return v + } + if v.Kind() != reflect.Ptr { + // Avoid creating a reflect.Value if it's not a pointer. + return v + } + for v.Kind() == reflect.Ptr && !v.IsNil() { + v = v.Elem() + } + return v +} + +// DereferenceType dereference, get the underlying non-pointer type. +func DereferenceType(t reflect.Type) reflect.Type { + for t.Kind() == reflect.Ptr { + t = t.Elem() + } + return t +} + +// DereferenceValue dereference and unpack interface, +// get the underlying non-pointer and non-interface value. +func DereferenceValue(v reflect.Value) reflect.Value { + for v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface { + v = v.Elem() + } + return v +} + +// DereferencePtrValue returns the underlying non-pointer type value. +func DereferencePtrValue(v reflect.Value) reflect.Value { + for v.Kind() == reflect.Ptr { + v = v.Elem() + } + return v +} + +// DereferenceInterfaceValue returns the value of the underlying type that implements the interface v. +func DereferenceInterfaceValue(v reflect.Value) reflect.Value { + for v.Kind() == reflect.Interface { + v = v.Elem() + } + return v +} + +// DereferenceImplementType returns the underlying type of the value that implements the interface v. +func DereferenceImplementType(v reflect.Value) reflect.Type { + return DereferenceType(DereferenceInterfaceValue(v).Type()) +} + +// DereferenceSlice convert []*T to []T. +func DereferenceSlice(v reflect.Value) reflect.Value { + m := v.Len() - 1 + if m < 0 { + return reflect.New(reflect.SliceOf(DereferenceType(v.Type().Elem()))).Elem() + } + s := make([]reflect.Value, m+1) + for ; m >= 0; m-- { + s[m] = DereferenceValue(v.Index(m)) + } + v = reflect.New(reflect.SliceOf(s[0].Type())).Elem() + v = reflect.Append(v, s...) + return v +} + +// ReferenceSlice convert []T to []*T, the ptrDepth is the count of '*'. +func ReferenceSlice(v reflect.Value, ptrDepth int) reflect.Value { + if ptrDepth <= 0 { + return v + } + m := v.Len() - 1 + if m < 0 { + return reflect.New(reflect.SliceOf(ReferenceType(v.Type().Elem(), ptrDepth))).Elem() + } + s := make([]reflect.Value, m+1) + for ; m >= 0; m-- { + s[m] = ReferenceValue(v.Index(m), ptrDepth) + } + v = reflect.New(reflect.SliceOf(s[0].Type())).Elem() + v = reflect.Append(v, s...) + return v +} + +// ReferenceType convert T to *T, the ptrDepth is the count of '*'. +func ReferenceType(t reflect.Type, ptrDepth int) reflect.Type { + switch { + case ptrDepth > 0: + for ; ptrDepth > 0; ptrDepth-- { + t = reflect.PtrTo(t) + } + case ptrDepth < 0: + for ; ptrDepth < 0 && t.Kind() == reflect.Ptr; ptrDepth++ { + t = t.Elem() + } + } + return t +} + +// ReferenceValue convert T to *T, the ptrDepth is the count of '*'. +func ReferenceValue(v reflect.Value, ptrDepth int) reflect.Value { + switch { + case ptrDepth > 0: + for ; ptrDepth > 0; ptrDepth-- { + vv := reflect.New(v.Type()) + vv.Elem().Set(v) + v = vv + } + case ptrDepth < 0: + for ; ptrDepth < 0 && v.Kind() == reflect.Ptr; ptrDepth++ { + v = v.Elem() + } + } + return v +} diff --git a/internal/ameda/uint.go b/internal/ameda/uint.go new file mode 100644 index 0000000..8113d5b --- /dev/null +++ b/internal/ameda/uint.go @@ -0,0 +1,200 @@ +package ameda + +import ( + "math" + "strconv" +) + +// MaxUint returns max uint number for current os. +func MaxUint() uint { + return MaxUnsignedInt +} + +// UintToInterface converts uint to interface. +func UintToInterface(v uint) interface{} { + return v +} + +// UintToInterfacePtr converts uint to *interface. +func UintToInterfacePtr(v uint) *interface{} { + r := UintToInterface(v) + return &r +} + +// UintToString converts uint to string. +func UintToString(v uint) string { + return strconv.FormatUint(uint64(v), 10) +} + +// UintToStringPtr converts uint to *string. +func UintToStringPtr(v uint) *string { + r := UintToString(v) + return &r +} + +// UintToBool converts uint to bool. +func UintToBool(v uint) bool { + return v != 0 +} + +// UintToBoolPtr converts uint to *bool. +func UintToBoolPtr(v uint) *bool { + r := UintToBool(v) + return &r +} + +// UintToFloat32 converts uint to float32. +func UintToFloat32(v uint) float32 { + return float32(v) +} + +// UintToFloat32Ptr converts uint to *float32. +func UintToFloat32Ptr(v uint) *float32 { + r := UintToFloat32(v) + return &r +} + +// UintToFloat64 converts uint to float64. +func UintToFloat64(v uint) float64 { + return float64(v) +} + +// UintToFloat64Ptr converts uint to *float64. +func UintToFloat64Ptr(v uint) *float64 { + r := UintToFloat64(v) + return &r +} + +// UintToInt converts uint to int. +func UintToInt(v uint) (int, error) { + if Host64bit { + if v > uint(maxInt64) { + return 0, errOverflowValue + } + } else { + if v > math.MaxInt32 { + return 0, errOverflowValue + } + } + return int(v), nil +} + +// UintToIntPtr converts uint to *int. +func UintToIntPtr(v uint) (*int, error) { + r, err := UintToInt(v) + return &r, err +} + +// UintToInt8 converts uint to int8. +func UintToInt8(v uint) (int8, error) { + if v > math.MaxInt8 { + return 0, errOverflowValue + } + return int8(v), nil +} + +// UintToInt8Ptr converts uint to *int8. +func UintToInt8Ptr(v uint) (*int8, error) { + r, err := UintToInt8(v) + return &r, err +} + +// UintToInt16 converts uint to int16. +func UintToInt16(v uint) (int16, error) { + if v > math.MaxInt16 { + return 0, errOverflowValue + } + return int16(v), nil +} + +// UintToInt16Ptr converts uint to *int16. +func UintToInt16Ptr(v uint) (*int16, error) { + r, err := UintToInt16(v) + return &r, err +} + +// UintToInt32 converts uint to int32. +func UintToInt32(v uint) (int32, error) { + if v > math.MaxInt32 { + return 0, errOverflowValue + } + return int32(v), nil +} + +// UintToInt32Ptr converts uint to *int32. +func UintToInt32Ptr(v uint) (*int32, error) { + r, err := UintToInt32(v) + return &r, err +} + +// UintToInt64 converts uint to int64. +func UintToInt64(v uint) (int64, error) { + if Host64bit && v > uint(maxInt64) { + return 0, errOverflowValue + } + return int64(v), nil +} + +// UintToInt64Ptr converts uint to *int64. +func UintToInt64Ptr(v uint) (*int64, error) { + r, err := UintToInt64(v) + return &r, err +} + +// UintToUintPtr converts uint to *uint. +func UintToUintPtr(v uint) *uint { + return &v +} + +// UintToUint8 converts uint to uint8. +func UintToUint8(v uint) (uint8, error) { + if v > math.MaxUint8 { + return 0, errOverflowValue + } + return uint8(v), nil +} + +// UintToUint8Ptr converts uint to *uint8. +func UintToUint8Ptr(v uint) (*uint8, error) { + r, err := UintToUint8(v) + return &r, err +} + +// UintToUint16 converts uint to uint16. +func UintToUint16(v uint) (uint16, error) { + if v > math.MaxUint16 { + return 0, errOverflowValue + } + return uint16(v), nil +} + +// UintToUint16Ptr converts uint to *uint16. +func UintToUint16Ptr(v uint) (*uint16, error) { + r, err := UintToUint16(v) + return &r, err +} + +// UintToUint32 converts uint to uint32. +func UintToUint32(v uint) (uint32, error) { + if Host64bit && v > math.MaxUint32 { + return 0, errOverflowValue + } + return uint32(v), nil +} + +// UintToUint32Ptr converts uint to *uint32. +func UintToUint32Ptr(v uint) (*uint32, error) { + r, err := UintToUint32(v) + return &r, err +} + +// UintToUint64 converts uint to uint64. +func UintToUint64(v uint) uint64 { + return uint64(v) +} + +// UintToUint64Ptr converts uint to *uint64. +func UintToUint64Ptr(v uint) *uint64 { + r := UintToUint64(v) + return &r +} diff --git a/internal/ameda/uint16.go b/internal/ameda/uint16.go new file mode 100644 index 0000000..3f2336e --- /dev/null +++ b/internal/ameda/uint16.go @@ -0,0 +1,174 @@ +package ameda + +import ( + "math" + "strconv" +) + +// Uint16ToInterface converts uint16 to interface. +func Uint16ToInterface(v uint16) interface{} { + return v +} + +// Uint16ToInterfacePtr converts uint16 to *interface. +func Uint16ToInterfacePtr(v uint16) *interface{} { + r := Uint16ToInterface(v) + return &r +} + +// Uint16ToString converts uint16 to string. +func Uint16ToString(v uint16) string { + return strconv.FormatUint(uint64(v), 10) +} + +// Uint16ToStringPtr converts uint16 to *string. +func Uint16ToStringPtr(v uint16) *string { + r := Uint16ToString(v) + return &r +} + +// Uint16ToBool converts uint16 to bool. +func Uint16ToBool(v uint16) bool { + return v != 0 +} + +// Uint16ToBoolPtr converts uint16 to *bool. +func Uint16ToBoolPtr(v uint16) *bool { + r := Uint16ToBool(v) + return &r +} + +// Uint16ToFloat32 converts uint16 to float32. +func Uint16ToFloat32(v uint16) float32 { + return float32(v) +} + +// Uint16ToFloat32Ptr converts uint16 to *float32. +func Uint16ToFloat32Ptr(v uint16) *float32 { + r := Uint16ToFloat32(v) + return &r +} + +// Uint16ToFloat64 converts uint16 to float64. +func Uint16ToFloat64(v uint16) float64 { + return float64(v) +} + +// Uint16ToFloat64Ptr converts uint16 to *float64. +func Uint16ToFloat64Ptr(v uint16) *float64 { + r := Uint16ToFloat64(v) + return &r +} + +// Uint16ToInt converts uint16 to int. +func Uint16ToInt(v uint16) int { + return int(v) +} + +// Uint16ToIntPtr converts uint16 to *int. +func Uint16ToIntPtr(v uint16) *int { + r := Uint16ToInt(v) + return &r +} + +// Uint16ToInt8 converts uint16 to int8. +func Uint16ToInt8(v uint16) (int8, error) { + if v > math.MaxInt8 { + return 0, errOverflowValue + } + return int8(v), nil +} + +// Uint16ToInt8Ptr converts uint16 to *int8. +func Uint16ToInt8Ptr(v uint16) (*int8, error) { + r, err := Uint16ToInt8(v) + return &r, err +} + +// Uint16ToInt16 converts uint16 to int16. +func Uint16ToInt16(v uint16) (int16, error) { + if v > math.MaxInt16 { + return 0, errOverflowValue + } + return int16(v), nil +} + +// Uint16ToInt16Ptr converts uint16 to *int16. +func Uint16ToInt16Ptr(v uint16) (*int16, error) { + r, err := Uint16ToInt16(v) + return &r, err +} + +// Uint16ToInt32 converts uint16 to int32. +func Uint16ToInt32(v uint16) int32 { + return int32(v) +} + +// Uint16ToInt32Ptr converts uint16 to *int32. +func Uint16ToInt32Ptr(v uint16) *int32 { + r := Uint16ToInt32(v) + return &r +} + +// Uint16ToInt64 converts uint16 to int64. +func Uint16ToInt64(v uint16) int64 { + return int64(v) +} + +// Uint16ToInt64Ptr converts uint16 to *int64. +func Uint16ToInt64Ptr(v uint16) *int64 { + r := Uint16ToInt64(v) + return &r +} + +// Uint16ToUint converts uint16 to uint. +func Uint16ToUint(v uint16) uint { + return uint(v) +} + +// Uint16ToUintPtr converts uint16 to *uint. +func Uint16ToUintPtr(v uint16) *uint { + r := Uint16ToUint(v) + return &r +} + +// Uint16ToUint8 converts uint16 to uint8. +func Uint16ToUint8(v uint16) (uint8, error) { + if v > math.MaxUint8 { + return 0, errOverflowValue + } + return uint8(v), nil +} + +// Uint16ToUint8Ptr converts uint16 to *uint8. +func Uint16ToUint8Ptr(v uint16) (*uint8, error) { + r, err := Uint16ToUint8(v) + return &r, err +} + +// Uint16ToUint16Ptr converts uint16 to *uint16. +func Uint16ToUint16Ptr(v uint16) *uint16 { + return &v +} + +// Uint16ToUint32 converts uint16 to uint32. +func Uint16ToUint32(v uint16) uint32 { + return uint32(v) +} + +// Uint16ToUint32Ptr converts uint16 to *uint32. +func Uint16ToUint32Ptr(v uint16) *uint32 { + r := Uint16ToUint32(v) + return &r +} + +// Uint16ToUint64 converts uint16 to uint64. +func Uint16ToUint64(v uint16) uint64 { + return uint64(v) +} + +// Uint16ToUint64Ptr converts uint16 to *uint64. +func Uint16ToUint64Ptr(v uint16) *uint64 { + r := Uint16ToUint64(v) + return &r +} diff --git a/internal/ameda/uint16s.go b/internal/ameda/uint16s.go new file mode 100644 index 0000000..af352d1 --- /dev/null +++ b/internal/ameda/uint16s.go @@ -0,0 +1,668 @@ +package ameda + +// OneUint16 try to return the first element, otherwise return zero value. +func OneUint16(u []uint16) uint16 { + if len(u) > 0 { + return u[0] + } + return 0 +} + +// Uint16sCopy creates a copy of the uint16 slice. +func Uint16sCopy(u []uint16) []uint16 { + b := make([]uint16, len(u)) + copy(b, u) + return b +} + +// Uint16sToInterfaces converts uint16 slice to interface slice. +func Uint16sToInterfaces(u []uint16) []interface{} { + r := make([]interface{}, len(u)) + for k, v := range u { + r[k] = Uint16ToInterface(v) + } + return r +} + +// Uint16sToStrings converts uint16 slice to string slice. +func Uint16sToStrings(u []uint16) []string { + r := make([]string, len(u)) + for k, v := range u { + r[k] = Uint16ToString(v) + } + return r +} + +// Uint16sToBools converts uint16 slice to bool slice. +// NOTE: +// 0 is false, everything else is true +func Uint16sToBools(u []uint16) []bool { + r := make([]bool, len(u)) + for k, v := range u { + r[k] = Uint16ToBool(v) + } + return r +} + +// Uint16sToFloat32s converts uint16 slice to float32 slice. +func Uint16sToFloat32s(u []uint16) []float32 { + r := make([]float32, len(u)) + for k, v := range u { + r[k] = Uint16ToFloat32(v) + } + return r +} + +// Uint16sToFloat64s converts uint16 slice to float64 slice. +func Uint16sToFloat64s(u []uint16) []float64 { + r := make([]float64, len(u)) + for k, v := range u { + r[k] = Uint16ToFloat64(v) + } + return r +} + +// Uint16sToInts converts uint16 slice to int slice. +func Uint16sToInts(u []uint16) []int { + r := make([]int, len(u)) + for k, v := range u { + r[k] = Uint16ToInt(v) + } + return r +} + +// Uint16sToInt8s converts uint16 slice to int8 slice. +func Uint16sToInt8s(u []uint16) ([]int8, error) { + var err error + r := make([]int8, len(u)) + for k, v := range u { + r[k], err = Uint16ToInt8(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Uint16sToInt16s converts uint16 slice to int16 slice. +func Uint16sToInt16s(u []uint16) ([]int16, error) { + var err error + r := make([]int16, len(u)) + for k, v := range u { + r[k], err = Uint16ToInt16(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Uint16sToInt32s converts uint16 slice to int32 slice. +func Uint16sToInt32s(u []uint16) []int32 { + r := make([]int32, len(u)) + for k, v := range u { + r[k] = Uint16ToInt32(v) + } + return r +} + +// Uint16sToInt64s converts uint16 slice to int64 slice. +func Uint16sToInt64s(u []uint16) []int64 { + r := make([]int64, len(u)) + for k, v := range u { + r[k] = Uint16ToInt64(v) + } + return r +} + +// Uint16sToUints converts uint16 slice to uint slice. +func Uint16sToUints(u []uint16) []uint { + r := make([]uint, len(u)) + for k, v := range u { + r[k] = Uint16ToUint(v) + } + return r +} + +// Uint16sToUint8s converts uint16 slice to uint8 slice. +func Uint16sToUint8s(u []uint16) ([]uint8, error) { + var err error + r := make([]uint8, len(u)) + for k, v := range u { + r[k], err = Uint16ToUint8(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Uint16sToUint32s converts uint16 slice to uint32 slice. +func Uint16sToUint32s(u []uint16) []uint32 { + r := make([]uint32, len(u)) + for k, v := range u { + r[k] = Uint16ToUint32(v) + } + return r +} + +// Uint16sToUint64s converts uint16 slice to uint64 slice. +func Uint16sToUint64s(u []uint16) []uint64 { + r := make([]uint64, len(u)) + for k, v := range u { + r[k] = Uint16ToUint64(v) + } + return r +} + +// Uint16sCopyWithin copies part of an slice to another location in the current slice. +// @target +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func Uint16sCopyWithin(u []uint16, target, start int, end ...int) { + target = fixIndex(len(u), target, true) + if target == len(u) { + return + } + sub := Uint16sSlice(u, start, end...) + for k, v := range sub { + u[target+k] = v + } +} + +// Uint16sEvery tests whether all elements in the slice pass the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice will return true for any condition! +func Uint16sEvery(u []uint16, fn func(u []uint16, k int, v uint16) bool) bool { + for k, v := range u { + if !fn(u, k, v) { + return false + } + } + return true +} + +// Uint16sFill changes all elements in the current slice to a value, from a start index to an end index. +// @value +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func Uint16sFill(u []uint16, value uint16, start int, end ...int) { + fixedStart, fixedEnd, ok := fixRange(len(u), start, end...) + if !ok { + return + } + for k := fixedStart; k < fixedEnd; k++ { + u[k] = value + } +} + +// Uint16sFilter creates a new slice with all elements that pass the test implemented by the provided function. +func Uint16sFilter(u []uint16, fn func(u []uint16, k int, v uint16) bool) []uint16 { + ret := make([]uint16, 0) + for k, v := range u { + if fn(u, k, v) { + ret = append(ret, v) + } + } + return ret +} + +// Uint16sFind returns the key-value of the first element in the provided slice that satisfies the provided testing function. +// NOTE: +// If not found, k = -1 +func Uint16sFind(u []uint16, fn func(u []uint16, k int, v uint16) bool) (k int, v uint16) { + for k, v := range u { + if fn(u, k, v) { + return k, v + } + } + return -1, 0 +} + +// Uint16sIncludes determines whether an slice includes a certain value among its entries. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Uint16sIncludes(u []uint16, valueToFind uint16, fromIndex ...int) bool { + return Uint16sIndexOf(u, valueToFind, fromIndex...) > -1 +} + +// Uint16sIndexOf returns the first index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Uint16sIndexOf(u []uint16, searchElement uint16, fromIndex ...int) int { + idx := getFromIndex(len(u), fromIndex...) + for k, v := range u[idx:] { + if searchElement == v { + return k + idx + } + } + return -1 +} + +// Uint16sLastIndexOf returns the last index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Uint16sLastIndexOf(u []uint16, searchElement uint16, fromIndex ...int) int { + idx := getFromIndex(len(u), fromIndex...) + for k := len(u) - 1; k >= idx; k-- { + if searchElement == u[k] { + return k + } + } + return -1 +} + +// Uint16sMap creates a new slice populated with the results of calling a provided function +// on every element in the calling slice. +func Uint16sMap(u []uint16, fn func(u []uint16, k int, v uint16) uint16) []uint16 { + ret := make([]uint16, len(u)) + for k, v := range u { + ret[k] = fn(u, k, v) + } + return ret +} + +// Uint16sPop removes the last element from an slice and returns that element. +// This method changes the length of the slice. +func Uint16sPop(u *[]uint16) (uint16, bool) { + a := *u + if len(a) == 0 { + return 0, false + } + lastIndex := len(a) - 1 + last := a[lastIndex] + a = a[:lastIndex] + *u = a[:len(a):len(a)] + return last, true +} + +// Uint16sPush adds one or more elements to the end of an slice and returns the new length of the slice. +func Uint16sPush(u *[]uint16, element ...uint16) int { + *u = append(*u, element...) + return len(*u) +} + +// Uint16sPushDistinct adds one or more new elements that do not exist in the current slice at the end. +func Uint16sPushDistinct(u []uint16, element ...uint16) []uint16 { +L: + for _, v := range element { + for _, vv := range u { + if vv == v { + continue L + } + } + u = append(u, v) + } + return u +} + +// Uint16sReduce executes a reducer function (that you provide) on each element of the slice, +// resulting in a single output value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func Uint16sReduce( + u []uint16, + fn func(u []uint16, k int, v, accumulator uint16) uint16, initialValue ...uint16, +) uint16 { + if len(u) == 0 { + return 0 + } + start := 0 + acc := u[start] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + start += 1 + } + for k := start; k < len(u); k++ { + acc = fn(u, k, u[k], acc) + } + return acc +} + +// Uint16sReduceRight applies a function against an accumulator and each value of the slice (from right-to-left) +// to reduce it to a single value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func Uint16sReduceRight( + u []uint16, + fn func(u []uint16, k int, v, accumulator uint16) uint16, initialValue ...uint16, +) uint16 { + if len(u) == 0 { + return 0 + } + end := len(u) - 1 + acc := u[end] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + end -= 1 + } + for k := end; k >= 0; k-- { + acc = fn(u, k, u[k], acc) + } + return acc +} + +// Uint16sReverse reverses an slice in place. +func Uint16sReverse(u []uint16) { + first := 0 + last := len(u) - 1 + for first < last { + u[first], u[last] = u[last], u[first] + first++ + last-- + } +} + +// Uint16sShift removes the first element from an slice and returns that removed element. +// This method changes the length of the slice. +func Uint16sShift(u *[]uint16) (uint16, bool) { + a := *u + if len(a) == 0 { + return 0, false + } + first := a[0] + a = a[1:] + *u = a[:len(a):len(a)] + return first, true +} + +// Uint16sSlice returns a copy of a portion of an slice into a new slice object selected +// from begin to end (end not included) where begin and end represent the index of items in that slice. +// The original slice will not be modified. +func Uint16sSlice(u []uint16, begin int, end ...int) []uint16 { + fixedStart, fixedEnd, ok := fixRange(len(u), begin, end...) + if !ok { + return []uint16{} + } + return Uint16sCopy(u[fixedStart:fixedEnd]) +} + +// Uint16sSome tests whether at least one element in the slice passes the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice returns false for any condition! +func Uint16sSome(u []uint16, fn func(u []uint16, k int, v uint16) bool) bool { + for k, v := range u { + if fn(u, k, v) { + return true + } + } + return false +} + +// Uint16sSplice changes the contents of an slice by removing or replacing +// existing elements and/or adding new elements in place. +func Uint16sSplice(u *[]uint16, start, deleteCount int, items ...uint16) { + a := *u + if deleteCount < 0 { + deleteCount = 0 + } + start, end, _ := fixRange(len(a), start, start+1+deleteCount) + deleteCount = end - start - 1 + for k := 0; k < len(items); k++ { + if deleteCount > 0 { + // replace + a[start] = items[k] + deleteCount-- + start++ + } else { + // insert + lastSlice := Uint16sCopy(a[start:]) + items = items[k:] + a = append(a[:start], items...) + a = append(a[:start+len(items)], lastSlice...) + *u = a[:len(a):len(a)] + return + } + } + if deleteCount > 0 { + a = append(a[:start], a[start+1+deleteCount:]...) + } + *u = a[:len(a):len(a)] +} + +// Uint16sUnshift adds one or more elements to the beginning of an slice and returns the new length of the slice. +func Uint16sUnshift(u *[]uint16, element ...uint16) int { + *u = append(element, *u...) + return len(*u) +} + +// Uint16sUnshiftDistinct adds one or more new elements that do not exist in the current slice to the beginning +// and returns the new length of the slice. +func Uint16sUnshiftDistinct(u *[]uint16, element ...uint16) int { + a := *u + if len(element) == 0 { + return len(a) + } + m := make(map[uint16]bool, len(element)) + r := make([]uint16, 0, len(a)+len(element)) +L: + for _, v := range element { + if m[v] { + continue + } + m[v] = true + for _, vv := range a { + if vv == v { + continue L + } + } + r = append(r, v) + } + r = append(r, a...) + *u = r[:len(r):len(r)] + return len(r) +} + +// Uint16sRemoveFirst removes the first matched elements from the slice, +// and returns the new length of the slice. +func Uint16sRemoveFirst(p *[]uint16, elements ...uint16) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for k, v := range a { + if v == element { + a = append(a[:k], a[k+1:]...) + break + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// Uint16sRemoveEvery removes all the elements from the slice, +// and returns the new length of the slice. +func Uint16sRemoveEvery(p *[]uint16, elements ...uint16) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for i := 0; i < len(a); i++ { + if a[i] == element { + a = append(a[:i], a[i+1:]...) + i-- + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// Uint16sConcat is used to merge two or more slices. +// This method does not change the existing slices, but instead returns a new slice. +func Uint16sConcat(u ...[]uint16) []uint16 { + var totalLen int + for _, v := range u { + totalLen += len(v) + } + ret := make([]uint16, totalLen) + dst := ret + for _, v := range u { + n := copy(dst, v) + dst = dst[n:] + } + return ret +} + +// Uint16sIntersect calculates intersection of two or more slices, +// and returns the count of each element. +func Uint16sIntersect(u ...[]uint16) (intersectCount map[uint16]int) { + if len(u) == 0 { + return nil + } + for _, v := range u { + if len(v) == 0 { + return nil + } + } + counts := make([]map[uint16]int, len(u)) + for k, v := range u { + counts[k] = uint16sDistinct(v, nil) + } + intersectCount = counts[0] +L: + for k, v := range intersectCount { + for _, c := range counts[1:] { + v2 := c[k] + if v2 == 0 { + delete(intersectCount, k) + continue L + } + if v > v2 { + v = v2 + } + } + intersectCount[k] = v + } + return intersectCount +} + +// Uint16sDistinct calculates the count of each different element, +// and only saves these different elements in place if changeSlice is true. +func Uint16sDistinct(i *[]uint16, changeSlice bool) (distinctCount map[uint16]int) { + if !changeSlice { + return uint16sDistinct(*i, nil) + } + a := (*i)[:0] + distinctCount = uint16sDistinct(*i, &a) + n := len(distinctCount) + *i = a[:n:n] + return distinctCount +} + +func uint16sDistinct(src []uint16, dst *[]uint16) map[uint16]int { + m := make(map[uint16]int, len(src)) + if dst == nil { + for _, v := range src { + n := m[v] + m[v] = n + 1 + } + } else { + a := *dst + for _, v := range src { + n := m[v] + m[v] = n + 1 + if n == 0 { + a = append(a, v) + } + } + *dst = a + } + return m +} + +// Uint16SetUnion calculates between multiple collections: set1 ∪ set2 ∪ others... +// This method does not change the existing slices, but instead returns a new slice. +func Uint16SetUnion(set1, set2 []uint16, others ...[]uint16) []uint16 { + m := make(map[uint16]struct{}, len(set1)+len(set2)) + r := make([]uint16, 0, len(m)) + for _, set := range append([][]uint16{set1, set2}, others...) { + for _, v := range set { + _, ok := m[v] + if ok { + continue + } + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} + +// Uint16SetIntersect calculates between multiple collections: set1 ∩ set2 ∩ others... +// This method does not change the existing slices, but instead returns a new slice. +func Uint16SetIntersect(set1, set2 []uint16, others ...[]uint16) []uint16 { + sets := append([][]uint16{set2}, others...) + setsCount := make([]map[uint16]int, len(sets)) + for k, v := range sets { + setsCount[k] = uint16sDistinct(v, nil) + } + m := make(map[uint16]struct{}, len(set1)) + r := make([]uint16, 0, len(m)) +L: + for _, v := range set1 { + if _, ok := m[v]; ok { + continue + } + m[v] = struct{}{} + for _, m2 := range setsCount { + if m2[v] == 0 { + continue L + } + } + r = append(r, v) + } + return r +} + +// Uint16SetDifference calculates between multiple collections: set1 - set2 - others... +// This method does not change the existing slices, but instead returns a new slice. +func Uint16SetDifference(set1, set2 []uint16, others ...[]uint16) []uint16 { + m := make(map[uint16]struct{}, len(set1)) + r := make([]uint16, 0, len(set1)) + sets := append([][]uint16{set2}, others...) + for _, v := range sets { + inter := Uint16SetIntersect(set1, v) + for _, v := range inter { + m[v] = struct{}{} + } + } + for _, v := range set1 { + if _, ok := m[v]; !ok { + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} diff --git a/internal/ameda/uint32.go b/internal/ameda/uint32.go new file mode 100644 index 0000000..63b9775 --- /dev/null +++ b/internal/ameda/uint32.go @@ -0,0 +1,180 @@ +package ameda + +import ( + "math" + "strconv" +) + +// Uint32ToInterface converts uint32 to interface. +func Uint32ToInterface(v uint32) interface{} { + return v +} + +// Uint32ToInterfacePtr converts uint32 to *interface. +func Uint32ToInterfacePtr(v uint32) *interface{} { + r := Uint32ToInterface(v) + return &r +} + +// Uint32ToString converts uint32 to string. +func Uint32ToString(v uint32) string { + return strconv.FormatUint(uint64(v), 10) +} + +// Uint32ToStringPtr converts uint32 to *string. +func Uint32ToStringPtr(v uint32) *string { + r := Uint32ToString(v) + return &r +} + +// Uint32ToBool converts uint32 to bool. +func Uint32ToBool(v uint32) bool { + return v != 0 +} + +// Uint32ToBoolPtr converts uint32 to *bool. +func Uint32ToBoolPtr(v uint32) *bool { + r := Uint32ToBool(v) + return &r +} + +// Uint32ToFloat32 converts uint32 to float32. +func Uint32ToFloat32(v uint32) float32 { + return float32(v) +} + +// Uint32ToFloat32Ptr converts uint32 to *float32. +func Uint32ToFloat32Ptr(v uint32) *float32 { + r := Uint32ToFloat32(v) + return &r +} + +// Uint32ToFloat64 converts uint32 to float64. +func Uint32ToFloat64(v uint32) float64 { + return float64(v) +} + +// Uint32ToFloat64Ptr converts uint32 to *float64. +func Uint32ToFloat64Ptr(v uint32) *float64 { + r := Uint32ToFloat64(v) + return &r +} + +// Uint32ToInt converts uint32 to int. +func Uint32ToInt(v uint32) int { + return int(v) +} + +// Uint32ToIntPtr converts uint32 to *int. +func Uint32ToIntPtr(v uint32) *int { + r := Uint32ToInt(v) + return &r +} + +// Uint32ToInt8 converts uint32 to int8. +func Uint32ToInt8(v uint32) (int8, error) { + if v > math.MaxInt8 { + return 0, errOverflowValue + } + return int8(v), nil +} + +// Uint32ToInt8Ptr converts uint32 to *int8. +func Uint32ToInt8Ptr(v uint32) (*int8, error) { + r, err := Uint32ToInt8(v) + return &r, err +} + +// Uint32ToInt16 converts uint32 to int16. +func Uint32ToInt16(v uint32) (int16, error) { + if v > math.MaxInt16 { + return 0, errOverflowValue + } + return int16(v), nil +} + +// Uint32ToInt16Ptr converts uint32 to *int16. +func Uint32ToInt16Ptr(v uint32) (*int16, error) { + r, err := Uint32ToInt16(v) + return &r, err +} + +// Uint32ToInt32 converts uint32 to int32. +func Uint32ToInt32(v uint32) (int32, error) { + if v > math.MaxInt32 { + return 0, errOverflowValue + } + return int32(v), nil +} + +// Uint32ToInt32Ptr converts uint32 to *int32. +func Uint32ToInt32Ptr(v uint32) (*int32, error) { + r, err := Uint32ToInt32(v) + return &r, err +} + +// Uint32ToInt64 converts uint32 to int64. +func Uint32ToInt64(v uint32) int64 { + return int64(v) +} + +// Uint32ToInt64Ptr converts uint32 to *int64. +func Uint32ToInt64Ptr(v uint32) *int64 { + r := Uint32ToInt64(v) + return &r +} + +// Uint32ToUint converts uint32 to uint. +func Uint32ToUint(v uint32) uint { + return uint(v) +} + +// Uint32ToUintPtr converts uint32 to *uint. +func Uint32ToUintPtr(v uint32) *uint { + r := Uint32ToUint(v) + return &r +} + +// Uint32ToUint8 converts uint32 to uint8. +func Uint32ToUint8(v uint32) (uint8, error) { + if v > math.MaxUint8 { + return 0, errOverflowValue + } + return uint8(v), nil +} + +// Uint32ToUint8Ptr converts uint32 to *uint8. +func Uint32ToUint8Ptr(v uint32) (*uint8, error) { + r, err := Uint32ToUint8(v) + return &r, err +} + +// Uint32ToUint16 converts uint32 to uint16. +func Uint32ToUint16(v uint32) (uint16, error) { + if v > math.MaxUint16 { + return 0, errOverflowValue + } + return uint16(v), nil +} + +// Uint32ToUint16Ptr converts uint32 to *uint16. +func Uint32ToUint16Ptr(v uint32) (*uint16, error) { + r, err := Uint32ToUint16(v) + return &r, err +} + +// Uint32ToUint32Ptr converts uint32 to *uint32. +func Uint32ToUint32Ptr(v uint32) *uint32 { + return &v +} + +// Uint32ToUint64 converts uint32 to uint64. +func Uint32ToUint64(v uint32) uint64 { + return uint64(v) +} + +// Uint32ToUint64Ptr converts uint32 to *uint64. +func Uint32ToUint64Ptr(v uint32) *uint64 { + r := Uint32ToUint64(v) + return &r +} diff --git a/internal/ameda/uint32s.go b/internal/ameda/uint32s.go new file mode 100644 index 0000000..075a305 --- /dev/null +++ b/internal/ameda/uint32s.go @@ -0,0 +1,676 @@ +package ameda + +// OneUint32 try to return the first element, otherwise return zero value. +func OneUint32(u []uint32) uint32 { + if len(u) > 0 { + return u[0] + } + return 0 +} + +// Uint32sCopy creates a copy of the uint32 slice. +func Uint32sCopy(u []uint32) []uint32 { + b := make([]uint32, len(u)) + copy(b, u) + return b +} + +// Uint32sToInterfaces converts uint32 slice to interface slice. +func Uint32sToInterfaces(u []uint32) []interface{} { + r := make([]interface{}, len(u)) + for k, v := range u { + r[k] = Uint32ToInterface(v) + } + return r +} + +// Uint32sToStrings converts uint32 slice to string slice. +func Uint32sToStrings(u []uint32) []string { + r := make([]string, len(u)) + for k, v := range u { + r[k] = Uint32ToString(v) + } + return r +} + +// Uint32sToBools converts uint32 slice to bool slice. +// NOTE: +// 0 is false, everything else is true +func Uint32sToBools(u []uint32) []bool { + r := make([]bool, len(u)) + for k, v := range u { + r[k] = Uint32ToBool(v) + } + return r +} + +// Uint32sToFloat32s converts uint32 slice to float32 slice. +func Uint32sToFloat32s(u []uint32) []float32 { + r := make([]float32, len(u)) + for k, v := range u { + r[k] = Uint32ToFloat32(v) + } + return r +} + +// Uint32sToFloat64s converts uint32 slice to float64 slice. +func Uint32sToFloat64s(u []uint32) []float64 { + r := make([]float64, len(u)) + for k, v := range u { + r[k] = Uint32ToFloat64(v) + } + return r +} + +// Uint32sToInts converts uint32 slice to int slice. +func Uint32sToInts(u []uint32) []int { + r := make([]int, len(u)) + for k, v := range u { + r[k] = Uint32ToInt(v) + } + return r +} + +// Uint32sToInt8s converts uint32 slice to int8 slice. +func Uint32sToInt8s(u []uint32) ([]int8, error) { + var err error + r := make([]int8, len(u)) + for k, v := range u { + r[k], err = Uint32ToInt8(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Uint32sToInt16s converts uint32 slice to int16 slice. +func Uint32sToInt16s(u []uint32) ([]int16, error) { + var err error + r := make([]int16, len(u)) + for k, v := range u { + r[k], err = Uint32ToInt16(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Uint32sToInt32s converts uint32 slice to int32 slice. +func Uint32sToInt32s(u []uint32) ([]int32, error) { + var err error + r := make([]int32, len(u)) + for k, v := range u { + r[k], err = Uint32ToInt32(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Uint32sToInt64s converts uint32 slice to int64 slice. +func Uint32sToInt64s(u []uint32) []int64 { + r := make([]int64, len(u)) + for k, v := range u { + r[k] = Uint32ToInt64(v) + } + return r +} + +// Uint32sToUints converts uint32 slice to uint slice. +func Uint32sToUints(u []uint32) []uint { + r := make([]uint, len(u)) + for k, v := range u { + r[k] = Uint32ToUint(v) + } + return r +} + +// Uint32sToUint8s converts uint32 slice to uint8 slice. +func Uint32sToUint8s(u []uint32) ([]uint8, error) { + var err error + r := make([]uint8, len(u)) + for k, v := range u { + r[k], err = Uint32ToUint8(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Uint32sToUint16s converts uint32 slice to uint16 slice. +func Uint32sToUint16s(u []uint32) ([]uint16, error) { + var err error + r := make([]uint16, len(u)) + for k, v := range u { + r[k], err = Uint32ToUint16(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Uint32sToUint64s converts uint32 slice to uint64 slice. +func Uint32sToUint64s(u []uint32) []uint64 { + r := make([]uint64, len(u)) + for k, v := range u { + r[k] = Uint32ToUint64(v) + } + return r +} + +// Uint32sCopyWithin copies part of an slice to another location in the current slice. +// @target +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func Uint32sCopyWithin(u []uint32, target, start int, end ...int) { + target = fixIndex(len(u), target, true) + if target == len(u) { + return + } + sub := Uint32sSlice(u, start, end...) + for k, v := range sub { + u[target+k] = v + } +} + +// Uint32sEvery tests whether all elements in the slice pass the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice will return true for any condition! +func Uint32sEvery(u []uint32, fn func(u []uint32, k int, v uint32) bool) bool { + for k, v := range u { + if !fn(u, k, v) { + return false + } + } + return true +} + +// Uint32sFill changes all elements in the current slice to a value, from a start index to an end index. +// @value +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func Uint32sFill(u []uint32, value uint32, start int, end ...int) { + fixedStart, fixedEnd, ok := fixRange(len(u), start, end...) + if !ok { + return + } + for k := fixedStart; k < fixedEnd; k++ { + u[k] = value + } +} + +// Uint32sFilter creates a new slice with all elements that pass the test implemented by the provided function. +func Uint32sFilter(u []uint32, fn func(u []uint32, k int, v uint32) bool) []uint32 { + ret := make([]uint32, 0) + for k, v := range u { + if fn(u, k, v) { + ret = append(ret, v) + } + } + return ret +} + +// Uint32sFind returns the key-value of the first element in the provided slice that satisfies the provided testing function. +// NOTE: +// If not found, k = -1 +func Uint32sFind(u []uint32, fn func(u []uint32, k int, v uint32) bool) (k int, v uint32) { + for k, v := range u { + if fn(u, k, v) { + return k, v + } + } + return -1, 0 +} + +// Uint32sIncludes determines whether an slice includes a certain value among its entries. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Uint32sIncludes(u []uint32, valueToFind uint32, fromIndex ...int) bool { + return Uint32sIndexOf(u, valueToFind, fromIndex...) > -1 +} + +// Uint32sIndexOf returns the first index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Uint32sIndexOf(u []uint32, searchElement uint32, fromIndex ...int) int { + idx := getFromIndex(len(u), fromIndex...) + for k, v := range u[idx:] { + if searchElement == v { + return k + idx + } + } + return -1 +} + +// Uint32sLastIndexOf returns the last index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Uint32sLastIndexOf(u []uint32, searchElement uint32, fromIndex ...int) int { + idx := getFromIndex(len(u), fromIndex...) + for k := len(u) - 1; k >= idx; k-- { + if searchElement == u[k] { + return k + } + } + return -1 +} + +// Uint32sMap creates a new slice populated with the results of calling a provided function +// on every element in the calling slice. +func Uint32sMap(u []uint32, fn func(u []uint32, k int, v uint32) uint32) []uint32 { + ret := make([]uint32, len(u)) + for k, v := range u { + ret[k] = fn(u, k, v) + } + return ret +} + +// Uint32sPop removes the last element from an slice and returns that element. +// This method changes the length of the slice. +func Uint32sPop(u *[]uint32) (uint32, bool) { + a := *u + if len(a) == 0 { + return 0, false + } + lastIndex := len(a) - 1 + last := a[lastIndex] + a = a[:lastIndex] + *u = a[:len(a):len(a)] + return last, true +} + +// Uint32sPush adds one or more elements to the end of an slice and returns the new length of the slice. +func Uint32sPush(u *[]uint32, element ...uint32) int { + *u = append(*u, element...) + return len(*u) +} + +// Uint32sPushDistinct adds one or more new elements that do not exist in the current slice at the end. +func Uint32sPushDistinct(u []uint32, element ...uint32) []uint32 { +L: + for _, v := range element { + for _, vv := range u { + if vv == v { + continue L + } + } + u = append(u, v) + } + return u +} + +// Uint32sReduce executes a reducer function (that you provide) on each element of the slice, +// resulting in a single output value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func Uint32sReduce( + u []uint32, + fn func(u []uint32, k int, v, accumulator uint32) uint32, initialValue ...uint32, +) uint32 { + if len(u) == 0 { + return 0 + } + start := 0 + acc := u[start] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + start += 1 + } + for k := start; k < len(u); k++ { + acc = fn(u, k, u[k], acc) + } + return acc +} + +// Uint32sReduceRight applies a function against an accumulator and each value of the slice (from right-to-left) +// to reduce it to a single value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func Uint32sReduceRight( + u []uint32, + fn func(u []uint32, k int, v, accumulator uint32) uint32, initialValue ...uint32, +) uint32 { + if len(u) == 0 { + return 0 + } + end := len(u) - 1 + acc := u[end] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + end -= 1 + } + for k := end; k >= 0; k-- { + acc = fn(u, k, u[k], acc) + } + return acc +} + +// Uint32sReverse reverses an slice in place. +func Uint32sReverse(u []uint32) { + first := 0 + last := len(u) - 1 + for first < last { + u[first], u[last] = u[last], u[first] + first++ + last-- + } +} + +// Uint32sShift removes the first element from an slice and returns that removed element. +// This method changes the length of the slice. +func Uint32sShift(u *[]uint32) (uint32, bool) { + a := *u + if len(a) == 0 { + return 0, false + } + first := a[0] + a = a[1:] + *u = a[:len(a):len(a)] + return first, true +} + +// Uint32sSlice returns a copy of a portion of an slice into a new slice object selected +// from begin to end (end not included) where begin and end represent the index of items in that slice. +// The original slice will not be modified. +func Uint32sSlice(u []uint32, begin int, end ...int) []uint32 { + fixedStart, fixedEnd, ok := fixRange(len(u), begin, end...) + if !ok { + return []uint32{} + } + return Uint32sCopy(u[fixedStart:fixedEnd]) +} + +// Uint32sSome tests whether at least one element in the slice passes the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice returns false for any condition! +func Uint32sSome(u []uint32, fn func(u []uint32, k int, v uint32) bool) bool { + for k, v := range u { + if fn(u, k, v) { + return true + } + } + return false +} + +// Uint32sSplice changes the contents of an slice by removing or replacing +// existing elements and/or adding new elements in place. +func Uint32sSplice(u *[]uint32, start, deleteCount int, items ...uint32) { + a := *u + if deleteCount < 0 { + deleteCount = 0 + } + start, end, _ := fixRange(len(a), start, start+1+deleteCount) + deleteCount = end - start - 1 + for k := 0; k < len(items); k++ { + if deleteCount > 0 { + // replace + a[start] = items[k] + deleteCount-- + start++ + } else { + // insert + lastSlice := Uint32sCopy(a[start:]) + items = items[k:] + a = append(a[:start], items...) + a = append(a[:start+len(items)], lastSlice...) + *u = a[:len(a):len(a)] + return + } + } + if deleteCount > 0 { + a = append(a[:start], a[start+1+deleteCount:]...) + } + *u = a[:len(a):len(a)] +} + +// Uint32sUnshift adds one or more elements to the beginning of an slice and returns the new length of the slice. +func Uint32sUnshift(u *[]uint32, element ...uint32) int { + *u = append(element, *u...) + return len(*u) +} + +// Uint32sUnshiftDistinct adds one or more new elements that do not exist in the current slice to the beginning +// and returns the new length of the slice. +func Uint32sUnshiftDistinct(u *[]uint32, element ...uint32) int { + a := *u + if len(element) == 0 { + return len(a) + } + m := make(map[uint32]bool, len(element)) + r := make([]uint32, 0, len(a)+len(element)) +L: + for _, v := range element { + if m[v] { + continue + } + m[v] = true + for _, vv := range a { + if vv == v { + continue L + } + } + r = append(r, v) + } + r = append(r, a...) + *u = r[:len(r):len(r)] + return len(r) +} + +// Uint32sRemoveFirst removes the first matched elements from the slice, +// and returns the new length of the slice. +func Uint32sRemoveFirst(p *[]uint32, elements ...uint32) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for k, v := range a { + if v == element { + a = append(a[:k], a[k+1:]...) + break + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// Uint32sRemoveEvery removes all the elements from the slice, +// and returns the new length of the slice. +func Uint32sRemoveEvery(p *[]uint32, elements ...uint32) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for i := 0; i < len(a); i++ { + if a[i] == element { + a = append(a[:i], a[i+1:]...) + i-- + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// Uint32sConcat is used to merge two or more slices. +// This method does not change the existing slices, but instead returns a new slice. +func Uint32sConcat(u ...[]uint32) []uint32 { + var totalLen int + for _, v := range u { + totalLen += len(v) + } + ret := make([]uint32, totalLen) + dst := ret + for _, v := range u { + n := copy(dst, v) + dst = dst[n:] + } + return ret +} + +// Uint32sIntersect calculates intersection of two or more slices, +// and returns the count of each element. +func Uint32sIntersect(u ...[]uint32) (intersectCount map[uint32]int) { + if len(u) == 0 { + return nil + } + for _, v := range u { + if len(v) == 0 { + return nil + } + } + counts := make([]map[uint32]int, len(u)) + for k, v := range u { + counts[k] = uint32sDistinct(v, nil) + } + intersectCount = counts[0] +L: + for k, v := range intersectCount { + for _, c := range counts[1:] { + v2 := c[k] + if v2 == 0 { + delete(intersectCount, k) + continue L + } + if v > v2 { + v = v2 + } + } + intersectCount[k] = v + } + return intersectCount +} + +// Uint32sDistinct calculates the count of each different element, +// and only saves these different elements in place if changeSlice is true. +func Uint32sDistinct(i *[]uint32, changeSlice bool) (distinctCount map[uint32]int) { + if !changeSlice { + return uint32sDistinct(*i, nil) + } + a := (*i)[:0] + distinctCount = uint32sDistinct(*i, &a) + n := len(distinctCount) + *i = a[:n:n] + return distinctCount +} + +func uint32sDistinct(src []uint32, dst *[]uint32) map[uint32]int { + m := make(map[uint32]int, len(src)) + if dst == nil { + for _, v := range src { + n := m[v] + m[v] = n + 1 + } + } else { + a := *dst + for _, v := range src { + n := m[v] + m[v] = n + 1 + if n == 0 { + a = append(a, v) + } + } + *dst = a + } + return m +} + +// Uint32SetUnion calculates between multiple collections: set1 ∪ set2 ∪ others... +// This method does not change the existing slices, but instead returns a new slice. +func Uint32SetUnion(set1, set2 []uint32, others ...[]uint32) []uint32 { + m := make(map[uint32]struct{}, len(set1)+len(set2)) + r := make([]uint32, 0, len(m)) + for _, set := range append([][]uint32{set1, set2}, others...) { + for _, v := range set { + _, ok := m[v] + if ok { + continue + } + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} + +// Uint32SetIntersect calculates between multiple collections: set1 ∩ set2 ∩ others... +// This method does not change the existing slices, but instead returns a new slice. +func Uint32SetIntersect(set1, set2 []uint32, others ...[]uint32) []uint32 { + sets := append([][]uint32{set2}, others...) + setsCount := make([]map[uint32]int, len(sets)) + for k, v := range sets { + setsCount[k] = uint32sDistinct(v, nil) + } + m := make(map[uint32]struct{}, len(set1)) + r := make([]uint32, 0, len(m)) +L: + for _, v := range set1 { + if _, ok := m[v]; ok { + continue + } + m[v] = struct{}{} + for _, m2 := range setsCount { + if m2[v] == 0 { + continue L + } + } + r = append(r, v) + } + return r +} + +// Uint32SetDifference calculates between multiple collections: set1 - set2 - others... +// This method does not change the existing slices, but instead returns a new slice. +func Uint32SetDifference(set1, set2 []uint32, others ...[]uint32) []uint32 { + m := make(map[uint32]struct{}, len(set1)) + r := make([]uint32, 0, len(set1)) + sets := append([][]uint32{set2}, others...) + for _, v := range sets { + inter := Uint32SetIntersect(set1, v) + for _, v := range inter { + m[v] = struct{}{} + } + } + for _, v := range set1 { + if _, ok := m[v]; !ok { + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} diff --git a/internal/ameda/uint64.go b/internal/ameda/uint64.go new file mode 100644 index 0000000..ece9446 --- /dev/null +++ b/internal/ameda/uint64.go @@ -0,0 +1,189 @@ +package ameda + +import ( + "math" + "strconv" +) + +// Uint64ToInterface converts uint64 to interface. +func Uint64ToInterface(v uint64) interface{} { + return v +} + +// Uint64ToInterfacePtr converts uint64 to *interface. +func Uint64ToInterfacePtr(v uint64) *interface{} { + r := Uint64ToInterface(v) + return &r +} + +// Uint64ToString converts uint64 to string. +func Uint64ToString(v uint64) string { + return strconv.FormatUint(uint64(v), 10) +} + +// Uint64ToStringPtr converts uint64 to *string. +func Uint64ToStringPtr(v uint64) *string { + r := Uint64ToString(v) + return &r +} + +// Uint64ToBool converts uint64 to bool. +func Uint64ToBool(v uint64) bool { + return v != 0 +} + +// Uint64ToBoolPtr converts uint64 to *bool. +func Uint64ToBoolPtr(v uint64) *bool { + r := Uint64ToBool(v) + return &r +} + +// Uint64ToFloat32 converts uint64 to float32. +func Uint64ToFloat32(v uint64) float32 { + return float32(v) +} + +// Uint64ToFloat32Ptr converts uint64 to *float32. +func Uint64ToFloat32Ptr(v uint64) *float32 { + r := Uint64ToFloat32(v) + return &r +} + +// Uint64ToFloat64 converts uint64 to float64. +func Uint64ToFloat64(v uint64) float64 { + return float64(v) +} + +// Uint64ToFloat64Ptr converts uint64 to *float64. +func Uint64ToFloat64Ptr(v uint64) *float64 { + r := Uint64ToFloat64(v) + return &r +} + +// Uint64ToInt converts uint64 to int. +func Uint64ToInt(v uint64) int { + return int(v) +} + +// Uint64ToIntPtr converts uint64 to *int. +func Uint64ToIntPtr(v uint64) *int { + r := Uint64ToInt(v) + return &r +} + +// Uint64ToInt8 converts uint64 to int8. +func Uint64ToInt8(v uint64) (int8, error) { + if v > math.MaxInt8 { + return 0, errOverflowValue + } + return int8(v), nil +} + +// Uint64ToInt8Ptr converts uint64 to *int8. +func Uint64ToInt8Ptr(v uint64) (*int8, error) { + r, err := Uint64ToInt8(v) + return &r, err +} + +// Uint64ToInt16 converts uint64 to int16. +func Uint64ToInt16(v uint64) (int16, error) { + if v > math.MaxInt16 { + return 0, errOverflowValue + } + return int16(v), nil +} + +// Uint64ToInt16Ptr converts uint64 to *int16. +func Uint64ToInt16Ptr(v uint64) (*int16, error) { + r, err := Uint64ToInt16(v) + return &r, err +} + +// Uint64ToInt32 converts uint64 to int32. +func Uint64ToInt32(v uint64) (int32, error) { + if v > math.MaxInt32 { + return 0, errOverflowValue + } + return int32(v), nil +} + +// Uint64ToInt32Ptr converts uint64 to *int32. +func Uint64ToInt32Ptr(v uint64) (*int32, error) { + r, err := Uint64ToInt32(v) + return &r, err +} + +// Uint64ToInt64 converts uint64 to int64. +func Uint64ToInt64(v uint64) (int64, error) { + if v > math.MaxInt64 { + return 0, errOverflowValue + } + return int64(v), nil +} + +// Uint64ToInt64Ptr converts uint64 to *int64. +func Uint64ToInt64Ptr(v uint64) (*int64, error) { + r, err := Uint64ToInt64(v) + return &r, err +} + +// Uint64ToUint converts uint64 to uint. +func Uint64ToUint(v uint64) (uint, error) { + if !Host64bit && v > math.MaxUint32 { + return 0, errOverflowValue + } + return uint(v), nil +} + +// Uint64ToUintPtr converts uint64 to *uint. +func Uint64ToUintPtr(v uint64) (*uint, error) { + r, err := Uint64ToUint(v) + return &r, err +} + +// Uint64ToUint8 converts uint64 to uint8. +func Uint64ToUint8(v uint64) (uint8, error) { + if v > math.MaxUint8 { + return 0, errOverflowValue + } + return uint8(v), nil +} + +// Uint64ToUint8Ptr converts uint64 to *uint8. +func Uint64ToUint8Ptr(v uint64) (*uint8, error) { + r, err := Uint64ToUint8(v) + return &r, err +} + +// Uint64ToUint16 converts uint64 to uint16. +func Uint64ToUint16(v uint64) (uint16, error) { + if v > math.MaxUint16 { + return 0, errOverflowValue + } + return uint16(v), nil +} + +// Uint64ToUint16Ptr converts uint64 to *uint16. +func Uint64ToUint16Ptr(v uint64) (*uint16, error) { + r, err := Uint64ToUint16(v) + return &r, err +} + +// Uint64ToUint32 converts uint64 to uint32. +func Uint64ToUint32(v uint64) (uint32, error) { + if v > math.MaxUint32 { + return 0, errOverflowValue + } + return uint32(v), nil +} + +// Uint64ToUint32Ptr converts uint64 to *uint32. +func Uint64ToUint32Ptr(v uint64) (*uint32, error) { + r, err := Uint64ToUint32(v) + return &r, err +} + +// Uint64ToUint64Ptr converts uint64 to *uint64. +func Uint64ToUint64Ptr(v uint64) *uint64 { + return &v +} diff --git a/internal/ameda/uint64s.go b/internal/ameda/uint64s.go new file mode 100644 index 0000000..4a0f535 --- /dev/null +++ b/internal/ameda/uint64s.go @@ -0,0 +1,688 @@ +package ameda + +// OneUint64 try to return the first element, otherwise return zero value. +func OneUint64(u []uint64) uint64 { + if len(u) > 0 { + return u[0] + } + return 0 +} + +// Uint64sCopy creates a copy of the uint64 slice. +func Uint64sCopy(u []uint64) []uint64 { + b := make([]uint64, len(u)) + copy(b, u) + return b +} + +// Uint64sToInterfaces converts uint64 slice to interface slice. +func Uint64sToInterfaces(u []uint64) []interface{} { + r := make([]interface{}, len(u)) + for k, v := range u { + r[k] = Uint64ToInterface(v) + } + return r +} + +// Uint64sToStrings converts uint64 slice to string slice. +func Uint64sToStrings(u []uint64) []string { + r := make([]string, len(u)) + for k, v := range u { + r[k] = Uint64ToString(v) + } + return r +} + +// Uint64sToBools converts uint64 slice to bool slice. +// NOTE: +// 0 is false, everything else is true +func Uint64sToBools(u []uint64) []bool { + r := make([]bool, len(u)) + for k, v := range u { + r[k] = Uint64ToBool(v) + } + return r +} + +// Uint64sToFloat32s converts uint64 slice to float32 slice. +func Uint64sToFloat32s(u []uint64) []float32 { + r := make([]float32, len(u)) + for k, v := range u { + r[k] = Uint64ToFloat32(v) + } + return r +} + +// Uint64sToFloat64s converts uint64 slice to float64 slice. +func Uint64sToFloat64s(u []uint64) []float64 { + r := make([]float64, len(u)) + for k, v := range u { + r[k] = Uint64ToFloat64(v) + } + return r +} + +// Uint64sToInts converts uint64 slice to int slice. +func Uint64sToInts(u []uint64) []int { + r := make([]int, len(u)) + for k, v := range u { + r[k] = Uint64ToInt(v) + } + return r +} + +// Uint64sToInt8s converts uint64 slice to int8 slice. +func Uint64sToInt8s(u []uint64) ([]int8, error) { + var err error + r := make([]int8, len(u)) + for k, v := range u { + r[k], err = Uint64ToInt8(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Uint64sToInt16s converts uint64 slice to int16 slice. +func Uint64sToInt16s(u []uint64) ([]int16, error) { + var err error + r := make([]int16, len(u)) + for k, v := range u { + r[k], err = Uint64ToInt16(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Uint64sToInt32s converts uint64 slice to int32 slice. +func Uint64sToInt32s(u []uint64) ([]int32, error) { + var err error + r := make([]int32, len(u)) + for k, v := range u { + r[k], err = Uint64ToInt32(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Uint64sToInt64s converts uint64 slice to int64 slice. +func Uint64sToInt64s(u []uint64) ([]int64, error) { + var err error + r := make([]int64, len(u)) + for k, v := range u { + r[k], err = Uint64ToInt64(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Uint64sToUints converts uint64 slice to uint slice. +func Uint64sToUints(u []uint64) ([]uint, error) { + var err error + r := make([]uint, len(u)) + for k, v := range u { + r[k], err = Uint64ToUint(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Uint64sToUint8s converts uint64 slice to uint8 slice. +func Uint64sToUint8s(u []uint64) ([]uint8, error) { + var err error + r := make([]uint8, len(u)) + for k, v := range u { + r[k], err = Uint64ToUint8(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Uint64sToUint16s converts uint64 slice to uint16 slice. +func Uint64sToUint16s(u []uint64) ([]uint16, error) { + var err error + r := make([]uint16, len(u)) + for k, v := range u { + r[k], err = Uint64ToUint16(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Uint64sToUint32s converts uint64 slice to uint32 slice. +func Uint64sToUint32s(u []uint64) ([]uint32, error) { + var err error + r := make([]uint32, len(u)) + for k, v := range u { + r[k], err = Uint64ToUint32(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Uint64sCopyWithin copies part of an slice to another location in the current slice. +// @target +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func Uint64sCopyWithin(u []uint64, target, start int, end ...int) { + target = fixIndex(len(u), target, true) + if target == len(u) { + return + } + sub := Uint64sSlice(u, start, end...) + for k, v := range sub { + u[target+k] = v + } +} + +// Uint64sEvery tests whether all elements in the slice pass the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice will return true for any condition! +func Uint64sEvery(u []uint64, fn func(u []uint64, k int, v uint64) bool) bool { + for k, v := range u { + if !fn(u, k, v) { + return false + } + } + return true +} + +// Uint64sFill changes all elements in the current slice to a value, from a start index to an end index. +// @value +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func Uint64sFill(u []uint64, value uint64, start int, end ...int) { + fixedStart, fixedEnd, ok := fixRange(len(u), start, end...) + if !ok { + return + } + for k := fixedStart; k < fixedEnd; k++ { + u[k] = value + } +} + +// Uint64sFilter creates a new slice with all elements that pass the test implemented by the provided function. +func Uint64sFilter(u []uint64, fn func(u []uint64, k int, v uint64) bool) []uint64 { + ret := make([]uint64, 0) + for k, v := range u { + if fn(u, k, v) { + ret = append(ret, v) + } + } + return ret +} + +// Uint64sFind returns the key-value of the first element in the provided slice that satisfies the provided testing function. +// NOTE: +// If not found, k = -1 +func Uint64sFind(u []uint64, fn func(u []uint64, k int, v uint64) bool) (k int, v uint64) { + for k, v := range u { + if fn(u, k, v) { + return k, v + } + } + return -1, 0 +} + +// Uint64sIncludes determines whether an slice includes a certain value among its entries. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Uint64sIncludes(u []uint64, valueToFind uint64, fromIndex ...int) bool { + return Uint64sIndexOf(u, valueToFind, fromIndex...) > -1 +} + +// Uint64sIndexOf returns the first index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Uint64sIndexOf(u []uint64, searchElement uint64, fromIndex ...int) int { + idx := getFromIndex(len(u), fromIndex...) + for k, v := range u[idx:] { + if searchElement == v { + return k + idx + } + } + return -1 +} + +// Uint64sLastIndexOf returns the last index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Uint64sLastIndexOf(u []uint64, searchElement uint64, fromIndex ...int) int { + idx := getFromIndex(len(u), fromIndex...) + for k := len(u) - 1; k >= idx; k-- { + if searchElement == u[k] { + return k + } + } + return -1 +} + +// Uint64sMap creates a new slice populated with the results of calling a provided function +// on every element in the calling slice. +func Uint64sMap(u []uint64, fn func(u []uint64, k int, v uint64) uint64) []uint64 { + ret := make([]uint64, len(u)) + for k, v := range u { + ret[k] = fn(u, k, v) + } + return ret +} + +// Uint64sPop removes the last element from an slice and returns that element. +// This method changes the length of the slice. +func Uint64sPop(u *[]uint64) (uint64, bool) { + a := *u + if len(a) == 0 { + return 0, false + } + lastIndex := len(a) - 1 + last := a[lastIndex] + a = a[:lastIndex] + *u = a[:len(a):len(a)] + return last, true +} + +// Uint64sPush adds one or more elements to the end of an slice and returns the new length of the slice. +func Uint64sPush(u *[]uint64, element ...uint64) int { + *u = append(*u, element...) + return len(*u) +} + +// Uint64sPushDistinct adds one or more new elements that do not exist in the current slice at the end. +func Uint64sPushDistinct(u []uint64, element ...uint64) []uint64 { +L: + for _, v := range element { + for _, vv := range u { + if vv == v { + continue L + } + } + u = append(u, v) + } + return u +} + +// Uint64sReduce executes a reducer function (that you provide) on each element of the slice, +// resulting in a single output value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func Uint64sReduce( + u []uint64, + fn func(u []uint64, k int, v, accumulator uint64) uint64, initialValue ...uint64, +) uint64 { + if len(u) == 0 { + return 0 + } + start := 0 + acc := u[start] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + start += 1 + } + for k := start; k < len(u); k++ { + acc = fn(u, k, u[k], acc) + } + return acc +} + +// Uint64sReduceRight applies a function against an accumulator and each value of the slice (from right-to-left) +// to reduce it to a single value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func Uint64sReduceRight( + u []uint64, + fn func(u []uint64, k int, v, accumulator uint64) uint64, initialValue ...uint64, +) uint64 { + if len(u) == 0 { + return 0 + } + end := len(u) - 1 + acc := u[end] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + end -= 1 + } + for k := end; k >= 0; k-- { + acc = fn(u, k, u[k], acc) + } + return acc +} + +// Uint64sReverse reverses an slice in place. +func Uint64sReverse(u []uint64) { + first := 0 + last := len(u) - 1 + for first < last { + u[first], u[last] = u[last], u[first] + first++ + last-- + } +} + +// Uint64sShift removes the first element from an slice and returns that removed element. +// This method changes the length of the slice. +func Uint64sShift(u *[]uint64) (uint64, bool) { + a := *u + if len(a) == 0 { + return 0, false + } + first := a[0] + a = a[1:] + *u = a[:len(a):len(a)] + return first, true +} + +// Uint64sSlice returns a copy of a portion of an slice into a new slice object selected +// from begin to end (end not included) where begin and end represent the index of items in that slice. +// The original slice will not be modified. +func Uint64sSlice(u []uint64, begin int, end ...int) []uint64 { + fixedStart, fixedEnd, ok := fixRange(len(u), begin, end...) + if !ok { + return []uint64{} + } + return Uint64sCopy(u[fixedStart:fixedEnd]) +} + +// Uint64sSome tests whether at least one element in the slice passes the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice returns false for any condition! +func Uint64sSome(u []uint64, fn func(u []uint64, k int, v uint64) bool) bool { + for k, v := range u { + if fn(u, k, v) { + return true + } + } + return false +} + +// Uint64sSplice changes the contents of an slice by removing or replacing +// existing elements and/or adding new elements in place. +func Uint64sSplice(u *[]uint64, start, deleteCount int, items ...uint64) { + a := *u + if deleteCount < 0 { + deleteCount = 0 + } + start, end, _ := fixRange(len(a), start, start+1+deleteCount) + deleteCount = end - start - 1 + for k := 0; k < len(items); k++ { + if deleteCount > 0 { + // replace + a[start] = items[k] + deleteCount-- + start++ + } else { + // insert + lastSlice := Uint64sCopy(a[start:]) + items = items[k:] + a = append(a[:start], items...) + a = append(a[:start+len(items)], lastSlice...) + *u = a[:len(a):len(a)] + return + } + } + if deleteCount > 0 { + a = append(a[:start], a[start+1+deleteCount:]...) + } + *u = a[:len(a):len(a)] +} + +// Uint64sUnshift adds one or more elements to the beginning of an slice and returns the new length of the slice. +func Uint64sUnshift(u *[]uint64, element ...uint64) int { + *u = append(element, *u...) + return len(*u) +} + +// Uint64sUnshiftDistinct adds one or more new elements that do not exist in the current slice to the beginning +// and returns the new length of the slice. +func Uint64sUnshiftDistinct(u *[]uint64, element ...uint64) int { + a := *u + if len(element) == 0 { + return len(a) + } + m := make(map[uint64]bool, len(element)) + r := make([]uint64, 0, len(a)+len(element)) +L: + for _, v := range element { + if m[v] { + continue + } + m[v] = true + for _, vv := range a { + if vv == v { + continue L + } + } + r = append(r, v) + } + r = append(r, a...) + *u = r[:len(r):len(r)] + return len(r) +} + +// Uint64sRemoveFirst removes the first matched elements from the slice, +// and returns the new length of the slice. +func Uint64sRemoveFirst(p *[]uint64, elements ...uint64) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for k, v := range a { + if v == element { + a = append(a[:k], a[k+1:]...) + break + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// Uint64sRemoveEvery removes all the elements from the slice, +// and returns the new length of the slice. +func Uint64sRemoveEvery(p *[]uint64, elements ...uint64) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for i := 0; i < len(a); i++ { + if a[i] == element { + a = append(a[:i], a[i+1:]...) + i-- + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// Uint64sConcat is used to merge two or more slices. +// This method does not change the existing slices, but instead returns a new slice. +func Uint64sConcat(u ...[]uint64) []uint64 { + var totalLen int + for _, v := range u { + totalLen += len(v) + } + ret := make([]uint64, totalLen) + dst := ret + for _, v := range u { + n := copy(dst, v) + dst = dst[n:] + } + return ret +} + +// Uint64sIntersect calculates intersection of two or more slices, +// and returns the count of each element. +func Uint64sIntersect(u ...[]uint64) (intersectCount map[uint64]int) { + if len(u) == 0 { + return nil + } + for _, v := range u { + if len(v) == 0 { + return nil + } + } + counts := make([]map[uint64]int, len(u)) + for k, v := range u { + counts[k] = uint64sDistinct(v, nil) + } + intersectCount = counts[0] +L: + for k, v := range intersectCount { + for _, c := range counts[1:] { + v2 := c[k] + if v2 == 0 { + delete(intersectCount, k) + continue L + } + if v > v2 { + v = v2 + } + } + intersectCount[k] = v + } + return intersectCount +} + +// Uint64sDistinct calculates the count of each different element, +// and only saves these different elements in place if changeSlice is true. +func Uint64sDistinct(i *[]uint64, changeSlice bool) (distinctCount map[uint64]int) { + if !changeSlice { + return uint64sDistinct(*i, nil) + } + a := (*i)[:0] + distinctCount = uint64sDistinct(*i, &a) + n := len(distinctCount) + *i = a[:n:n] + return distinctCount +} + +func uint64sDistinct(src []uint64, dst *[]uint64) map[uint64]int { + m := make(map[uint64]int, len(src)) + if dst == nil { + for _, v := range src { + n := m[v] + m[v] = n + 1 + } + } else { + a := *dst + for _, v := range src { + n := m[v] + m[v] = n + 1 + if n == 0 { + a = append(a, v) + } + } + *dst = a + } + return m +} + +// Uint64SetUnion calculates between multiple collections: set1 ∪ set2 ∪ others... +// This method does not change the existing slices, but instead returns a new slice. +func Uint64SetUnion(set1, set2 []uint64, others ...[]uint64) []uint64 { + m := make(map[uint64]struct{}, len(set1)+len(set2)) + r := make([]uint64, 0, len(m)) + for _, set := range append([][]uint64{set1, set2}, others...) { + for _, v := range set { + _, ok := m[v] + if ok { + continue + } + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} + +// Uint64SetIntersect calculates between multiple collections: set1 ∩ set2 ∩ others... +// This method does not change the existing slices, but instead returns a new slice. +func Uint64SetIntersect(set1, set2 []uint64, others ...[]uint64) []uint64 { + sets := append([][]uint64{set2}, others...) + setsCount := make([]map[uint64]int, len(sets)) + for k, v := range sets { + setsCount[k] = uint64sDistinct(v, nil) + } + m := make(map[uint64]struct{}, len(set1)) + r := make([]uint64, 0, len(m)) +L: + for _, v := range set1 { + if _, ok := m[v]; ok { + continue + } + m[v] = struct{}{} + for _, m2 := range setsCount { + if m2[v] == 0 { + continue L + } + } + r = append(r, v) + } + return r +} + +// Uint64SetDifference calculates between multiple collections: set1 - set2 - others... +// This method does not change the existing slices, but instead returns a new slice. +func Uint64SetDifference(set1, set2 []uint64, others ...[]uint64) []uint64 { + m := make(map[uint64]struct{}, len(set1)) + r := make([]uint64, 0, len(set1)) + sets := append([][]uint64{set2}, others...) + for _, v := range sets { + inter := Uint64SetIntersect(set1, v) + for _, v := range inter { + m[v] = struct{}{} + } + } + for _, v := range set1 { + if _, ok := m[v]; !ok { + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} diff --git a/internal/ameda/uint8.go b/internal/ameda/uint8.go new file mode 100644 index 0000000..bb2d939 --- /dev/null +++ b/internal/ameda/uint8.go @@ -0,0 +1,168 @@ +package ameda + +import ( + "math" + "strconv" +) + +// Uint8ToInterface converts uint8 to interface. +func Uint8ToInterface(v uint8) interface{} { + return v +} + +// Uint8ToInterfacePtr converts uint8 to *interface. +func Uint8ToInterfacePtr(v uint8) *interface{} { + r := Uint8ToInterface(v) + return &r +} + +// Uint8ToString converts uint8 to string. +func Uint8ToString(v uint8) string { + return strconv.FormatUint(uint64(v), 10) +} + +// Uint8ToStringPtr converts uint8 to *string. +func Uint8ToStringPtr(v uint8) *string { + r := Uint8ToString(v) + return &r +} + +// Uint8ToBool converts uint8 to bool. +func Uint8ToBool(v uint8) bool { + return v != 0 +} + +// Uint8ToBoolPtr converts uint8 to *bool. +func Uint8ToBoolPtr(v uint8) *bool { + r := Uint8ToBool(v) + return &r +} + +// Uint8ToFloat32 converts uint8 to float32. +func Uint8ToFloat32(v uint8) float32 { + return float32(v) +} + +// Uint8ToFloat32Ptr converts uint8 to *float32. +func Uint8ToFloat32Ptr(v uint8) *float32 { + r := Uint8ToFloat32(v) + return &r +} + +// Uint8ToFloat64 converts uint8 to float64. +func Uint8ToFloat64(v uint8) float64 { + return float64(v) +} + +// Uint8ToFloat64Ptr converts uint8 to *float64. +func Uint8ToFloat64Ptr(v uint8) *float64 { + r := Uint8ToFloat64(v) + return &r +} + +// Uint8ToInt converts uint8 to int. +func Uint8ToInt(v uint8) int { + return int(v) +} + +// Uint8ToIntPtr converts uint8 to *int. +func Uint8ToIntPtr(v uint8) *int { + r := Uint8ToInt(v) + return &r +} + +// Uint8ToInt8 converts uint8 to int8. +func Uint8ToInt8(v uint8) (int8, error) { + if v > math.MaxInt8 { + return 0, errOverflowValue + } + return int8(v), nil +} + +// Uint8ToInt8Ptr converts uint8 to *int8. +func Uint8ToInt8Ptr(v uint8) (*int8, error) { + r, err := Uint8ToInt8(v) + return &r, err +} + +// Uint8ToInt16 converts uint8 to int16. +func Uint8ToInt16(v uint8) int16 { + return int16(v) +} + +// Uint8ToInt16Ptr converts uint8 to *int16. +func Uint8ToInt16Ptr(v uint8) *int16 { + r := Uint8ToInt16(v) + return &r +} + +// Uint8ToInt32 converts uint8 to int32. +func Uint8ToInt32(v uint8) int32 { + return int32(v) +} + +// Uint8ToInt32Ptr converts uint8 to *int32. +func Uint8ToInt32Ptr(v uint8) *int32 { + r := Uint8ToInt32(v) + return &r +} + +// Uint8ToInt64 converts uint8 to int64. +func Uint8ToInt64(v uint8) int64 { + return int64(v) +} + +// Uint8ToInt64Ptr converts uint8 to *int64. +func Uint8ToInt64Ptr(v uint8) *int64 { + r := Uint8ToInt64(v) + return &r +} + +// Uint8ToUint converts uint8 to uint. +func Uint8ToUint(v uint8) uint { + return uint(v) +} + +// Uint8ToUintPtr converts uint8 to *uint. +func Uint8ToUintPtr(v uint8) *uint { + r := Uint8ToUint(v) + return &r +} + +// Uint8ToUint8Ptr converts uint8 to *uint8. +func Uint8ToUint8Ptr(v uint8) *uint8 { + return &v +} + +// Uint8ToUint16 converts uint8 to uint16. +func Uint8ToUint16(v uint8) uint16 { + return uint16(v) +} + +// Uint8ToUint16Ptr converts uint8 to *uint16. +func Uint8ToUint16Ptr(v uint8) *uint16 { + r := Uint8ToUint16(v) + return &r +} + +// Uint8ToUint32 converts uint8 to uint32. +func Uint8ToUint32(v uint8) uint32 { + return uint32(v) +} + +// Uint8ToUint32Ptr converts uint8 to *uint32. +func Uint8ToUint32Ptr(v uint8) *uint32 { + r := Uint8ToUint32(v) + return &r +} + +// Uint8ToUint64 converts uint8 to uint64. +func Uint8ToUint64(v uint8) uint64 { + return uint64(v) +} + +// Uint8ToUint64Ptr converts uint8 to *uint64. +func Uint8ToUint64Ptr(v uint8) *uint64 { + r := Uint8ToUint64(v) + return &r +} diff --git a/internal/ameda/uint8s.go b/internal/ameda/uint8s.go new file mode 100644 index 0000000..c30964a --- /dev/null +++ b/internal/ameda/uint8s.go @@ -0,0 +1,658 @@ +package ameda + +// OneUint8 try to return the first element, otherwise return zero value. +func OneUint8(u []uint8) uint8 { + if len(u) > 0 { + return u[0] + } + return 0 +} + +// Uint8sCopy creates a copy of the uint8 slice. +func Uint8sCopy(u []uint8) []uint8 { + b := make([]uint8, len(u)) + copy(b, u) + return b +} + +// Uint8sToInterfaces converts uint8 slice to interface slice. +func Uint8sToInterfaces(u []uint8) []interface{} { + r := make([]interface{}, len(u)) + for k, v := range u { + r[k] = Uint8ToInterface(v) + } + return r +} + +// Uint8sToStrings converts uint8 slice to string slice. +func Uint8sToStrings(u []uint8) []string { + r := make([]string, len(u)) + for k, v := range u { + r[k] = Uint8ToString(v) + } + return r +} + +// Uint8sToBools converts uint8 slice to bool slice. +// NOTE: +// 0 is false, everything else is true +func Uint8sToBools(u []uint8) []bool { + r := make([]bool, len(u)) + for k, v := range u { + r[k] = Uint8ToBool(v) + } + return r +} + +// Uint8sToFloat32s converts uint8 slice to float32 slice. +func Uint8sToFloat32s(u []uint8) []float32 { + r := make([]float32, len(u)) + for k, v := range u { + r[k] = Uint8ToFloat32(v) + } + return r +} + +// Uint8sToFloat64s converts uint8 slice to float64 slice. +func Uint8sToFloat64s(u []uint8) []float64 { + r := make([]float64, len(u)) + for k, v := range u { + r[k] = Uint8ToFloat64(v) + } + return r +} + +// Uint8sToInts converts uint8 slice to int slice. +func Uint8sToInts(u []uint8) []int { + r := make([]int, len(u)) + for k, v := range u { + r[k] = Uint8ToInt(v) + } + return r +} + +// Uint8sToInt8s converts uint8 slice to int8 slice. +func Uint8sToInt8s(u []uint8) ([]int8, error) { + var err error + r := make([]int8, len(u)) + for k, v := range u { + r[k], err = Uint8ToInt8(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Uint8sToInt16s converts uint8 slice to int16 slice. +func Uint8sToInt16s(u []uint8) []int16 { + r := make([]int16, len(u)) + for k, v := range u { + r[k] = Uint8ToInt16(v) + } + return r +} + +// Uint8sToInt32s converts uint8 slice to int32 slice. +func Uint8sToInt32s(u []uint8) []int32 { + r := make([]int32, len(u)) + for k, v := range u { + r[k] = Uint8ToInt32(v) + } + return r +} + +// Uint8sToInt64s converts uint8 slice to int64 slice. +func Uint8sToInt64s(u []uint8) []int64 { + r := make([]int64, len(u)) + for k, v := range u { + r[k] = Uint8ToInt64(v) + } + return r +} + +// Uint8sToUints converts uint8 slice to uint slice. +func Uint8sToUints(u []uint8) []uint { + r := make([]uint, len(u)) + for k, v := range u { + r[k] = Uint8ToUint(v) + } + return r +} + +// Uint8sToUint16s converts uint8 slice to uint16 slice. +func Uint8sToUint16s(u []uint8) []uint16 { + r := make([]uint16, len(u)) + for k, v := range u { + r[k] = Uint8ToUint16(v) + } + return r +} + +// Uint8sToUint32s converts uint8 slice to uint32 slice. +func Uint8sToUint32s(u []uint8) []uint32 { + r := make([]uint32, len(u)) + for k, v := range u { + r[k] = Uint8ToUint32(v) + } + return r +} + +// Uint8sToUint64s converts uint8 slice to uint64 slice. +func Uint8sToUint64s(u []uint8) []uint64 { + r := make([]uint64, len(u)) + for k, v := range u { + r[k] = Uint8ToUint64(v) + } + return r +} + +// Uint8sCopyWithin copies part of an slice to another location in the current slice. +// @target +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func Uint8sCopyWithin(u []uint8, target, start int, end ...int) { + target = fixIndex(len(u), target, true) + if target == len(u) { + return + } + sub := Uint8sSlice(u, start, end...) + for k, v := range sub { + u[target+k] = v + } +} + +// Uint8sEvery tests whether all elements in the slice pass the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice will return true for any condition! +func Uint8sEvery(u []uint8, fn func(u []uint8, k int, v uint8) bool) bool { + for k, v := range u { + if !fn(u, k, v) { + return false + } + } + return true +} + +// Uint8sFill changes all elements in the current slice to a value, from a start index to an end index. +// @value +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func Uint8sFill(u []uint8, value uint8, start int, end ...int) { + fixedStart, fixedEnd, ok := fixRange(len(u), start, end...) + if !ok { + return + } + for k := fixedStart; k < fixedEnd; k++ { + u[k] = value + } +} + +// Uint8sFilter creates a new slice with all elements that pass the test implemented by the provided function. +func Uint8sFilter(u []uint8, fn func(u []uint8, k int, v uint8) bool) []uint8 { + ret := make([]uint8, 0) + for k, v := range u { + if fn(u, k, v) { + ret = append(ret, v) + } + } + return ret +} + +// Uint8sFind returns the key-value of the first element in the provided slice that satisfies the provided testing function. +// NOTE: +// If not found, k = -1 +func Uint8sFind(u []uint8, fn func(u []uint8, k int, v uint8) bool) (k int, v uint8) { + for k, v := range u { + if fn(u, k, v) { + return k, v + } + } + return -1, 0 +} + +// Uint8sIncludes determines whether an slice includes a certain value among its entries. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Uint8sIncludes(u []uint8, valueToFind uint8, fromIndex ...int) bool { + return Uint8sIndexOf(u, valueToFind, fromIndex...) > -1 +} + +// Uint8sIndexOf returns the first index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Uint8sIndexOf(u []uint8, searchElement uint8, fromIndex ...int) int { + idx := getFromIndex(len(u), fromIndex...) + for k, v := range u[idx:] { + if searchElement == v { + return k + idx + } + } + return -1 +} + +// Uint8sLastIndexOf returns the last index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Uint8sLastIndexOf(u []uint8, searchElement uint8, fromIndex ...int) int { + idx := getFromIndex(len(u), fromIndex...) + for k := len(u) - 1; k >= idx; k-- { + if searchElement == u[k] { + return k + } + } + return -1 +} + +// Uint8sMap creates a new slice populated with the results of calling a provided function +// on every element in the calling slice. +func Uint8sMap(u []uint8, fn func(u []uint8, k int, v uint8) uint8) []uint8 { + ret := make([]uint8, len(u)) + for k, v := range u { + ret[k] = fn(u, k, v) + } + return ret +} + +// Uint8sPop removes the last element from an slice and returns that element. +// This method changes the length of the slice. +func Uint8sPop(u *[]uint8) (uint8, bool) { + a := *u + if len(a) == 0 { + return 0, false + } + lastIndex := len(a) - 1 + last := a[lastIndex] + a = a[:lastIndex] + *u = a[:len(a):len(a)] + return last, true +} + +// Uint8sPush adds one or more elements to the end of an slice and returns the new length of the slice. +func Uint8sPush(u *[]uint8, element ...uint8) int { + *u = append(*u, element...) + return len(*u) +} + +// Uint8sPushDistinct adds one or more new elements that do not exist in the current slice at the end. +func Uint8sPushDistinct(u []uint8, element ...uint8) []uint8 { +L: + for _, v := range element { + for _, vv := range u { + if vv == v { + continue L + } + } + u = append(u, v) + } + return u +} + +// Uint8sReduce executes a reducer function (that you provide) on each element of the slice, +// resulting in a single output value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func Uint8sReduce(u []uint8, + fn func(u []uint8, k int, v, accumulator uint8) uint8, initialValue ...uint8, +) uint8 { + if len(u) == 0 { + return 0 + } + start := 0 + acc := u[start] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + start += 1 + } + for k := start; k < len(u); k++ { + acc = fn(u, k, u[k], acc) + } + return acc +} + +// Uint8sReduceRight applies a function against an accumulator and each value of the slice (from right-to-left) +// to reduce it to a single value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func Uint8sReduceRight(u []uint8, + fn func(u []uint8, k int, v, accumulator uint8) uint8, initialValue ...uint8, +) uint8 { + if len(u) == 0 { + return 0 + } + end := len(u) - 1 + acc := u[end] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + end -= 1 + } + for k := end; k >= 0; k-- { + acc = fn(u, k, u[k], acc) + } + return acc +} + +// Uint8sReverse reverses an slice in place. +func Uint8sReverse(u []uint8) { + first := 0 + last := len(u) - 1 + for first < last { + u[first], u[last] = u[last], u[first] + first++ + last-- + } +} + +// Uint8sShift removes the first element from an slice and returns that removed element. +// This method changes the length of the slice. +func Uint8sShift(u *[]uint8) (uint8, bool) { + a := *u + if len(a) == 0 { + return 0, false + } + first := a[0] + a = a[1:] + *u = a[:len(a):len(a)] + return first, true +} + +// Uint8sSlice returns a copy of a portion of an slice into a new slice object selected +// from begin to end (end not included) where begin and end represent the index of items in that slice. +// The original slice will not be modified. +func Uint8sSlice(u []uint8, begin int, end ...int) []uint8 { + fixedStart, fixedEnd, ok := fixRange(len(u), begin, end...) + if !ok { + return []uint8{} + } + return Uint8sCopy(u[fixedStart:fixedEnd]) +} + +// Uint8sSome tests whether at least one element in the slice passes the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice returns false for any condition! +func Uint8sSome(u []uint8, fn func(u []uint8, k int, v uint8) bool) bool { + for k, v := range u { + if fn(u, k, v) { + return true + } + } + return false +} + +// Uint8sSplice changes the contents of an slice by removing or replacing +// existing elements and/or adding new elements in place. +func Uint8sSplice(u *[]uint8, start, deleteCount int, items ...uint8) { + a := *u + if deleteCount < 0 { + deleteCount = 0 + } + start, end, _ := fixRange(len(a), start, start+1+deleteCount) + deleteCount = end - start - 1 + for k := 0; k < len(items); k++ { + if deleteCount > 0 { + // replace + a[start] = items[k] + deleteCount-- + start++ + } else { + // insert + lastSlice := Uint8sCopy(a[start:]) + items = items[k:] + a = append(a[:start], items...) + a = append(a[:start+len(items)], lastSlice...) + *u = a[:len(a):len(a)] + return + } + } + if deleteCount > 0 { + a = append(a[:start], a[start+1+deleteCount:]...) + } + *u = a[:len(a):len(a)] +} + +// Uint8sUnshift adds one or more elements to the beginning of an slice and returns the new length of the slice. +func Uint8sUnshift(u *[]uint8, element ...uint8) int { + *u = append(element, *u...) + return len(*u) +} + +// Uint8sUnshiftDistinct adds one or more new elements that do not exist in the current slice to the beginning +// and returns the new length of the slice. +func Uint8sUnshiftDistinct(u *[]uint8, element ...uint8) int { + a := *u + if len(element) == 0 { + return len(a) + } + m := make(map[uint8]bool, len(element)) + r := make([]uint8, 0, len(a)+len(element)) +L: + for _, v := range element { + if m[v] { + continue + } + m[v] = true + for _, vv := range a { + if vv == v { + continue L + } + } + r = append(r, v) + } + r = append(r, a...) + *u = r[:len(r):len(r)] + return len(r) +} + +// Uint8sRemoveFirst removes the first matched elements from the slice, +// and returns the new length of the slice. +func Uint8sRemoveFirst(p *[]uint8, elements ...uint8) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for k, v := range a { + if v == element { + a = append(a[:k], a[k+1:]...) + break + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// Uint8sRemoveEvery removes all the elements from the slice, +// and returns the new length of the slice. +func Uint8sRemoveEvery(p *[]uint8, elements ...uint8) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for i := 0; i < len(a); i++ { + if a[i] == element { + a = append(a[:i], a[i+1:]...) + i-- + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// Uint8sConcat is used to merge two or more slices. +// This method does not change the existing slices, but instead returns a new slice. +func Uint8sConcat(u ...[]uint8) []uint8 { + var totalLen int + for _, v := range u { + totalLen += len(v) + } + ret := make([]uint8, totalLen) + dst := ret + for _, v := range u { + n := copy(dst, v) + dst = dst[n:] + } + return ret +} + +// Uint8sIntersect calculates intersection of two or more slices, +// and returns the count of each element. +func Uint8sIntersect(u ...[]uint8) (intersectCount map[uint8]int) { + if len(u) == 0 { + return nil + } + for _, v := range u { + if len(v) == 0 { + return nil + } + } + counts := make([]map[uint8]int, len(u)) + for k, v := range u { + counts[k] = uint8sDistinct(v, nil) + } + intersectCount = counts[0] +L: + for k, v := range intersectCount { + for _, c := range counts[1:] { + v2 := c[k] + if v2 == 0 { + delete(intersectCount, k) + continue L + } + if v > v2 { + v = v2 + } + } + intersectCount[k] = v + } + return intersectCount +} + +// Uint8sDistinct calculates the count of each different element, +// and only saves these different elements in place if changeSlice is true. +func Uint8sDistinct(i *[]uint8, changeSlice bool) (distinctCount map[uint8]int) { + if !changeSlice { + return uint8sDistinct(*i, nil) + } + a := (*i)[:0] + distinctCount = uint8sDistinct(*i, &a) + n := len(distinctCount) + *i = a[:n:n] + return distinctCount +} + +func uint8sDistinct(src []uint8, dst *[]uint8) map[uint8]int { + m := make(map[uint8]int, len(src)) + if dst == nil { + for _, v := range src { + n := m[v] + m[v] = n + 1 + } + } else { + a := *dst + for _, v := range src { + n := m[v] + m[v] = n + 1 + if n == 0 { + a = append(a, v) + } + } + *dst = a + } + return m +} + +// Uint8SetUnion calculates between multiple collections: set1 ∪ set2 ∪ others... +// This method does not change the existing slices, but instead returns a new slice. +func Uint8SetUnion(set1, set2 []uint8, others ...[]uint8) []uint8 { + m := make(map[uint8]struct{}, len(set1)+len(set2)) + r := make([]uint8, 0, len(m)) + for _, set := range append([][]uint8{set1, set2}, others...) { + for _, v := range set { + _, ok := m[v] + if ok { + continue + } + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} + +// Uint8SetIntersect calculates between multiple collections: set1 ∩ set2 ∩ others... +// This method does not change the existing slices, but instead returns a new slice. +func Uint8SetIntersect(set1, set2 []uint8, others ...[]uint8) []uint8 { + sets := append([][]uint8{set2}, others...) + setsCount := make([]map[uint8]int, len(sets)) + for k, v := range sets { + setsCount[k] = uint8sDistinct(v, nil) + } + m := make(map[uint8]struct{}, len(set1)) + r := make([]uint8, 0, len(m)) +L: + for _, v := range set1 { + if _, ok := m[v]; ok { + continue + } + m[v] = struct{}{} + for _, m2 := range setsCount { + if m2[v] == 0 { + continue L + } + } + r = append(r, v) + } + return r +} + +// Uint8SetDifference calculates between multiple collections: set1 - set2 - others... +// This method does not change the existing slices, but instead returns a new slice. +func Uint8SetDifference(set1, set2 []uint8, others ...[]uint8) []uint8 { + m := make(map[uint8]struct{}, len(set1)) + r := make([]uint8, 0, len(set1)) + sets := append([][]uint8{set2}, others...) + for _, v := range sets { + inter := Uint8SetIntersect(set1, v) + for _, v := range inter { + m[v] = struct{}{} + } + } + for _, v := range set1 { + if _, ok := m[v]; !ok { + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} diff --git a/internal/ameda/uints.go b/internal/ameda/uints.go new file mode 100644 index 0000000..c42d101 --- /dev/null +++ b/internal/ameda/uints.go @@ -0,0 +1,686 @@ +package ameda + +// OneUint try to return the first element, otherwise return zero value. +func OneUint(u []uint) uint { + if len(u) > 0 { + return u[0] + } + return 0 +} + +// UintsCopy creates a copy of the uint slice. +func UintsCopy(u []uint) []uint { + b := make([]uint, len(u)) + copy(b, u) + return b +} + +// UintsToInterfaces converts uint slice to interface slice. +func UintsToInterfaces(u []uint) []interface{} { + r := make([]interface{}, len(u)) + for k, v := range u { + r[k] = UintToInterface(v) + } + return r +} + +// UintsToStrings converts uint slice to string slice. +func UintsToStrings(u []uint) []string { + r := make([]string, len(u)) + for k, v := range u { + r[k] = UintToString(v) + } + return r +} + +// UintsToBools converts uint slice to bool slice. +// NOTE: +// 0 is false, everything else is true +func UintsToBools(u []uint) []bool { + r := make([]bool, len(u)) + for k, v := range u { + r[k] = UintToBool(v) + } + return r +} + +// UintsToFloat32s converts uint slice to float32 slice. +func UintsToFloat32s(u []uint) []float32 { + r := make([]float32, len(u)) + for k, v := range u { + r[k] = UintToFloat32(v) + } + return r +} + +// UintsToFloat64s converts uint slice to float64 slice. +func UintsToFloat64s(u []uint) []float64 { + r := make([]float64, len(u)) + for k, v := range u { + r[k] = UintToFloat64(v) + } + return r +} + +// UintsToInts converts uint slice to int slice. +func UintsToInts(u []uint) ([]int, error) { + var err error + r := make([]int, len(u)) + for k, v := range u { + r[k], err = UintToInt(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// UintsToInt8s converts uint slice to int8 slice. +func UintsToInt8s(u []uint) ([]int8, error) { + var err error + r := make([]int8, len(u)) + for k, v := range u { + r[k], err = UintToInt8(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// UintsToInt16s converts uint slice to int16 slice. +func UintsToInt16s(u []uint) ([]int16, error) { + var err error + r := make([]int16, len(u)) + for k, v := range u { + r[k], err = UintToInt16(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// UintsToInt32s converts uint slice to int32 slice. +func UintsToInt32s(u []uint) ([]int32, error) { + var err error + r := make([]int32, len(u)) + for k, v := range u { + r[k], err = UintToInt32(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// UintsToInt64s converts uint slice to int64 slice. +func UintsToInt64s(u []uint) ([]int64, error) { + var err error + r := make([]int64, len(u)) + for k, v := range u { + r[k], err = UintToInt64(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// UintsToUint8s converts uint slice to uint8 slice. +func UintsToUint8s(u []uint) ([]uint8, error) { + var err error + r := make([]uint8, len(u)) + for k, v := range u { + r[k], err = UintToUint8(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// UintsToUint16s converts uint slice to uint16 slice. +func UintsToUint16s(u []uint) ([]uint16, error) { + var err error + r := make([]uint16, len(u)) + for k, v := range u { + r[k], err = UintToUint16(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// UintsToUint32s converts uint slice to uint32 slice. +func UintsToUint32s(u []uint) ([]uint32, error) { + var err error + r := make([]uint32, len(u)) + for k, v := range u { + r[k], err = UintToUint32(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// UintsToUint64s converts uint slice to uint64 slice. +func UintsToUint64s(u []uint) []uint64 { + r := make([]uint64, len(u)) + for k, v := range u { + r[k] = UintToUint64(v) + } + return r +} + +// UintsCopyWithin copies part of an slice to another location in the current slice. +// @target +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func UintsCopyWithin(u []uint, target, start int, end ...int) { + target = fixIndex(len(u), target, true) + if target == len(u) { + return + } + sub := UintsSlice(u, start, end...) + for k, v := range sub { + u[target+k] = v + } +} + +// UintsEvery tests whether all elements in the slice pass the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice will return true for any condition! +func UintsEvery(u []uint, fn func(u []uint, k int, v uint) bool) bool { + for k, v := range u { + if !fn(u, k, v) { + return false + } + } + return true +} + +// UintsFill changes all elements in the current slice to a value, from a start index to an end index. +// @value +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func UintsFill(u []uint, value uint, start int, end ...int) { + fixedStart, fixedEnd, ok := fixRange(len(u), start, end...) + if !ok { + return + } + for k := fixedStart; k < fixedEnd; k++ { + u[k] = value + } +} + +// UintsFilter creates a new slice with all elements that pass the test implemented by the provided function. +func UintsFilter(u []uint, fn func(u []uint, k int, v uint) bool) []uint { + ret := make([]uint, 0) + for k, v := range u { + if fn(u, k, v) { + ret = append(ret, v) + } + } + return ret +} + +// UintsFind returns the key-value of the first element in the provided slice that satisfies the provided testing function. +// NOTE: +// If not found, k = -1 +func UintsFind(u []uint, fn func(u []uint, k int, v uint) bool) (k int, v uint) { + for k, v := range u { + if fn(u, k, v) { + return k, v + } + } + return -1, 0 +} + +// UintsIncludes determines whether an slice includes a certain value among its entries. +// @fromIndex +// The index to start the search at. Defaults to 0. +func UintsIncludes(u []uint, valueToFind uint, fromIndex ...int) bool { + return UintsIndexOf(u, valueToFind, fromIndex...) > -1 +} + +// UintsIndexOf returns the first index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func UintsIndexOf(u []uint, searchElement uint, fromIndex ...int) int { + idx := getFromIndex(len(u), fromIndex...) + for k, v := range u[idx:] { + if searchElement == v { + return k + idx + } + } + return -1 +} + +// UintsLastIndexOf returns the last index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func UintsLastIndexOf(u []uint, searchElement uint, fromIndex ...int) int { + idx := getFromIndex(len(u), fromIndex...) + for k := len(u) - 1; k >= idx; k-- { + if searchElement == u[k] { + return k + } + } + return -1 +} + +// UintsMap creates a new slice populated with the results of calling a provided function +// on every element in the calling slice. +func UintsMap(u []uint, fn func(u []uint, k int, v uint) uint) []uint { + ret := make([]uint, len(u)) + for k, v := range u { + ret[k] = fn(u, k, v) + } + return ret +} + +// UintsPop removes the last element from an slice and returns that element. +// This method changes the length of the slice. +func UintsPop(u *[]uint) (uint, bool) { + a := *u + if len(a) == 0 { + return 0, false + } + lastIndex := len(a) - 1 + last := a[lastIndex] + a = a[:lastIndex] + *u = a[:len(a):len(a)] + return last, true +} + +// UintsPush adds one or more elements to the end of an slice and returns the new length of the slice. +func UintsPush(u *[]uint, element ...uint) int { + *u = append(*u, element...) + return len(*u) +} + +// UintsPushDistinct adds one or more new elements that do not exist in the current slice at the end. +func UintsPushDistinct(u []uint, element ...uint) []uint { +L: + for _, v := range element { + for _, vv := range u { + if vv == v { + continue L + } + } + u = append(u, v) + } + return u +} + +// UintsReduce executes a reducer function (that you provide) on each element of the slice, +// resulting in a single output value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func UintsReduce(u []uint, + fn func(u []uint, k int, v, accumulator uint) uint, initialValue ...uint, +) uint { + if len(u) == 0 { + return 0 + } + start := 0 + acc := u[start] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + start += 1 + } + for k := start; k < len(u); k++ { + acc = fn(u, k, u[k], acc) + } + return acc +} + +// UintsReduceRight applies a function against an accumulator and each value of the slice (from right-to-left) +// to reduce it to a single value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func UintsReduceRight(u []uint, + fn func(u []uint, k int, v, accumulator uint) uint, initialValue ...uint, +) uint { + if len(u) == 0 { + return 0 + } + end := len(u) - 1 + acc := u[end] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + end -= 1 + } + for k := end; k >= 0; k-- { + acc = fn(u, k, u[k], acc) + } + return acc +} + +// UintsReverse reverses an slice in place. +func UintsReverse(u []uint) { + first := 0 + last := len(u) - 1 + for first < last { + u[first], u[last] = u[last], u[first] + first++ + last-- + } +} + +// UintsShift removes the first element from an slice and returns that removed element. +// This method changes the length of the slice. +func UintsShift(u *[]uint) (uint, bool) { + a := *u + if len(a) == 0 { + return 0, false + } + first := a[0] + a = a[1:] + *u = a[:len(a):len(a)] + return first, true +} + +// UintsSlice returns a copy of a portion of an slice into a new slice object selected +// from begin to end (end not included) where begin and end represent the index of items in that slice. +// The original slice will not be modified. +func UintsSlice(u []uint, begin int, end ...int) []uint { + fixedStart, fixedEnd, ok := fixRange(len(u), begin, end...) + if !ok { + return []uint{} + } + return UintsCopy(u[fixedStart:fixedEnd]) +} + +// UintsSome tests whether at least one element in the slice passes the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice returns false for any condition! +func UintsSome(u []uint, fn func(u []uint, k int, v uint) bool) bool { + for k, v := range u { + if fn(u, k, v) { + return true + } + } + return false +} + +// UintsSplice changes the contents of an slice by removing or replacing +// existing elements and/or adding new elements in place. +func UintsSplice(u *[]uint, start, deleteCount int, items ...uint) { + a := *u + if deleteCount < 0 { + deleteCount = 0 + } + start, end, _ := fixRange(len(a), start, start+1+deleteCount) + deleteCount = end - start - 1 + for k := 0; k < len(items); k++ { + if deleteCount > 0 { + // replace + a[start] = items[k] + deleteCount-- + start++ + } else { + // insert + lastSlice := UintsCopy(a[start:]) + items = items[k:] + a = append(a[:start], items...) + a = append(a[:start+len(items)], lastSlice...) + *u = a[:len(a):len(a)] + return + } + } + if deleteCount > 0 { + a = append(a[:start], a[start+1+deleteCount:]...) + } + *u = a[:len(a):len(a)] +} + +// UintsUnshift adds one or more elements to the beginning of an slice and returns the new length of the slice. +func UintsUnshift(u *[]uint, element ...uint) int { + *u = append(element, *u...) + return len(*u) +} + +// UintsUnshiftDistinct adds one or more new elements that do not exist in the current slice to the beginning +// and returns the new length of the slice. +func UintsUnshiftDistinct(u *[]uint, element ...uint) int { + a := *u + if len(element) == 0 { + return len(a) + } + m := make(map[uint]bool, len(element)) + r := make([]uint, 0, len(a)+len(element)) +L: + for _, v := range element { + if m[v] { + continue + } + m[v] = true + for _, vv := range a { + if vv == v { + continue L + } + } + r = append(r, v) + } + r = append(r, a...) + *u = r[:len(r):len(r)] + return len(r) +} + +// UintsRemoveFirst removes the first matched elements from the slice, +// and returns the new length of the slice. +func UintsRemoveFirst(p *[]uint, elements ...uint) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for k, v := range a { + if v == element { + a = append(a[:k], a[k+1:]...) + break + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// UintsRemoveEvery removes all the elements from the slice, +// and returns the new length of the slice. +func UintsRemoveEvery(p *[]uint, elements ...uint) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for i := 0; i < len(a); i++ { + if a[i] == element { + a = append(a[:i], a[i+1:]...) + i-- + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// UintsConcat is used to merge two or more slices. +// This method does not change the existing slices, but instead returns a new slice. +func UintsConcat(u ...[]uint) []uint { + var totalLen int + for _, v := range u { + totalLen += len(v) + } + ret := make([]uint, totalLen) + dst := ret + for _, v := range u { + n := copy(dst, v) + dst = dst[n:] + } + return ret +} + +// UintsIntersect calculates intersection of two or more slices, +// and returns the count of each element. +func UintsIntersect(u ...[]uint) (intersectCount map[uint]int) { + if len(u) == 0 { + return nil + } + for _, v := range u { + if len(v) == 0 { + return nil + } + } + counts := make([]map[uint]int, len(u)) + for k, v := range u { + counts[k] = uintsDistinct(v, nil) + } + intersectCount = counts[0] +L: + for k, v := range intersectCount { + for _, c := range counts[1:] { + v2 := c[k] + if v2 == 0 { + delete(intersectCount, k) + continue L + } + if v > v2 { + v = v2 + } + } + intersectCount[k] = v + } + return intersectCount +} + +// UintsDistinct calculates the count of each different element, +// and only saves these different elements in place if changeSlice is true. +func UintsDistinct(i *[]uint, changeSlice bool) (distinctCount map[uint]int) { + if !changeSlice { + return uintsDistinct(*i, nil) + } + a := (*i)[:0] + distinctCount = uintsDistinct(*i, &a) + n := len(distinctCount) + *i = a[:n:n] + return distinctCount +} + +func uintsDistinct(src []uint, dst *[]uint) map[uint]int { + m := make(map[uint]int, len(src)) + if dst == nil { + for _, v := range src { + n := m[v] + m[v] = n + 1 + } + } else { + a := *dst + for _, v := range src { + n := m[v] + m[v] = n + 1 + if n == 0 { + a = append(a, v) + } + } + *dst = a + } + return m +} + +// UintSetUnion calculates between multiple collections: set1 ∪ set2 ∪ others... +// This method does not change the existing slices, but instead returns a new slice. +func UintSetUnion(set1, set2 []uint, others ...[]uint) []uint { + m := make(map[uint]struct{}, len(set1)+len(set2)) + r := make([]uint, 0, len(m)) + for _, set := range append([][]uint{set1, set2}, others...) { + for _, v := range set { + _, ok := m[v] + if ok { + continue + } + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} + +// UintSetIntersect calculates between multiple collections: set1 ∩ set2 ∩ others... +// This method does not change the existing slices, but instead returns a new slice. +func UintSetIntersect(set1, set2 []uint, others ...[]uint) []uint { + sets := append([][]uint{set2}, others...) + setsCount := make([]map[uint]int, len(sets)) + for k, v := range sets { + setsCount[k] = uintsDistinct(v, nil) + } + m := make(map[uint]struct{}, len(set1)) + r := make([]uint, 0, len(m)) +L: + for _, v := range set1 { + if _, ok := m[v]; ok { + continue + } + m[v] = struct{}{} + for _, m2 := range setsCount { + if m2[v] == 0 { + continue L + } + } + r = append(r, v) + } + return r +} + +// UintSetDifference calculates between multiple collections: set1 - set2 - others... +// This method does not change the existing slices, but instead returns a new slice. +func UintSetDifference(set1, set2 []uint, others ...[]uint) []uint { + m := make(map[uint]struct{}, len(set1)) + r := make([]uint, 0, len(set1)) + sets := append([][]uint{set2}, others...) + for _, v := range sets { + inter := UintSetIntersect(set1, v) + for _, v := range inter { + m[v] = struct{}{} + } + } + for _, v := range set1 { + if _, ok := m[v]; !ok { + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} diff --git a/internal/ameda/utils.go b/internal/ameda/utils.go new file mode 100644 index 0000000..6d19de8 --- /dev/null +++ b/internal/ameda/utils.go @@ -0,0 +1,111 @@ +package ameda + +import ( + "errors" + "math" + "reflect" + "strconv" +) + +const ( + Host64bit = strconv.IntSize == 64 + Host32bit = ^uint(0)>>32 == 0 + MaxUnsignedInt = ^uint(0) + MinUnsignedInt = 0 + MaxInteger = int(MaxUnsignedInt >> 1) + MinInteger = -MaxInteger - 1 +) + +var ( + errNegativeValue = errors.New("contains negative value") + errOverflowValue = errors.New("contains overflow value") +) + +var ( + maxUint32 = uint32(math.MaxUint32) + maxInt64 = int64(math.MaxInt64) +) + +func isEmptyAsZero(emptyAsZero []bool) bool { + return len(emptyAsZero) > 0 && emptyAsZero[0] +} + +func getFromIndex(length int, fromIndex ...int) int { + if len(fromIndex) > 0 { + return fixIndex(length, fromIndex[0], true) + } + return 0 +} + +func fixRange(length, start int, end ...int) (fixedStart, fixedEnd int, ok bool) { + fixedStart = fixIndex(length, start, true) + if fixedStart == length { + return + } + fixedEnd = length + if len(end) > 0 { + fixedEnd = fixIndex(length, end[0], true) + } + if fixedEnd-fixedStart <= 0 { + return + } + ok = true + return +} + +func fixIndex(length int, idx int, canLen bool) int { + if idx < 0 { + idx = length + idx + if idx < 0 { + return 0 + } + return idx + } + if idx >= length { + if canLen { + return length + } + return length - 1 + } + return idx +} + +// isZero reports whether v is the zero value for its type. +// It panics if the argument is invalid. +func isZero(v reflect.Value) bool { + switch v.Kind() { + case reflect.Bool: + return !v.Bool() + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return v.Int() == 0 + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return v.Uint() == 0 + case reflect.Float32, reflect.Float64: + return math.Float64bits(v.Float()) == 0 + case reflect.Complex64, reflect.Complex128: + c := v.Complex() + return math.Float64bits(real(c)) == 0 && math.Float64bits(imag(c)) == 0 + case reflect.Array: + for i := 0; i < v.Len(); i++ { + if !isZero(v.Index(i)) { + return false + } + } + return true + case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice, reflect.UnsafePointer: + return v.IsNil() + case reflect.String: + return v.Len() == 0 + case reflect.Struct: + for i := 0; i < v.NumField(); i++ { + if !isZero(v.Field(i)) { + return false + } + } + return true + default: + // This should never happens, but will act as a safeguard for + // later, as a default value doesn't makes sense here. + panic(&reflect.ValueError{"reflect.Value.IsZero", v.Kind()}) + } +} diff --git a/internal/ameda/value.go b/internal/ameda/value.go new file mode 100644 index 0000000..0921d7a --- /dev/null +++ b/internal/ameda/value.go @@ -0,0 +1,301 @@ +package ameda + +import ( + "fmt" + "reflect" + "runtime" + "strings" + "unsafe" +) + +// Value go underlying type data +type Value struct { + flag + typPtr uintptr + ptr unsafe.Pointer + _iPtr unsafe.Pointer // avoid being GC +} + +// ValueOf unpacks i to go underlying type data. +func ValueOf(i interface{}) Value { + checkValueUsable() + return newT(unsafe.Pointer(&i)) +} + +// ValueFrom gets go underlying type data from reflect.Value. +func ValueFrom(v reflect.Value) Value { + return ValueFrom2(&v) +} + +// ValueFrom2 gets go underlying type data from *reflect.Value. +func ValueFrom2(v *reflect.Value) Value { + checkValueUsable() + vv := newT(unsafe.Pointer(v)) + if v.CanAddr() { + vv.flag |= flagAddr + } + return vv +} + +//go:nocheckptr +func newT(iPtr unsafe.Pointer) Value { + typPtr := *(*uintptr)(iPtr) + return Value{ + typPtr: typPtr, + flag: getFlag(typPtr), + ptr: pointerElem(unsafe.Pointer(uintptr(iPtr) + ptrOffset)), + _iPtr: iPtr, + } +} + +// RuntimeTypeIDOf returns the underlying type ID in current runtime from interface object. +// NOTE: +// +// *A and A returns the different runtime type ID; +// It is 10 times performance of t.String(). +// +//go:nocheckptr +func RuntimeTypeIDOf(i interface{}) uintptr { + checkValueUsable() + iPtr := unsafe.Pointer(&i) + typPtr := *(*uintptr)(iPtr) + return typPtr +} + +// RuntimeTypeID returns the underlying type ID in current runtime from reflect.Type. +// NOTE: +// +// *A and A returns the different runtime type ID; +// It is 10 times performance of t.String(). +// +//go:nocheckptr +func RuntimeTypeID(t reflect.Type) uintptr { + checkValueUsable() + typPtr := uintptrElem(uintptr(unsafe.Pointer(&t)) + ptrOffset) + return typPtr +} + +// RuntimeTypeID gets the underlying type ID in current runtime. +// NOTE: +// +// *A and A gets the different runtime type ID; +// It is 10 times performance of reflect.TypeOf(i).String(). +// +//go:nocheckptr +func (v Value) RuntimeTypeID() uintptr { + return v.typPtr +} + +// Kind gets the reflect.Kind fastly. +func (v Value) Kind() reflect.Kind { + return reflect.Kind(v.flag & flagKindMask) +} + +// CanAddr reports whether the value's address can be obtained with Addr. +// Such values are called addressable. A value is addressable if it is +// an element of a slice, an element of an addressable array, +// a field of an addressable struct, or the result of dereferencing a pointer. +func (v Value) CanAddr() bool { + return v.flag&flagAddr != 0 +} + +// Elem returns the Value that the interface i contains +// or that the pointer i points to. +// +//go:nocheckptr +func (v Value) Elem() Value { + k := v.Kind() + switch k { + default: + return v + case reflect.Interface: + return newT(v.ptr) + case reflect.Ptr: + flag2, typPtr2, has := typeUnderlying(v.flag, v.typPtr) + if has { + v.typPtr = typPtr2 + v.flag = flag2 + if v.Kind() == reflect.Ptr { + v.ptr = pointerElem(v.ptr) + } + } + return v + } +} + +// UnderlyingElem returns the underlying Value that the interface i contains +// or that the pointer i points to. +// +//go:nocheckptr +func (v Value) UnderlyingElem() Value { + for kind := v.Kind(); kind == reflect.Ptr || kind == reflect.Interface; kind = v.Kind() { + v = v.Elem() + } + return v +} + +// Pointer gets the pointer of i. +// NOTE: +// +// *T and T, gets diffrent pointer +// +//go:nocheckptr +func (v Value) Pointer() uintptr { + switch v.Kind() { + case reflect.Invalid: + return 0 + case reflect.Slice: + return uintptrElem(uintptr(v.ptr)) + sliceDataOffset + default: + return uintptr(v.ptr) + } +} + +// IsNil reports whether its argument i is nil. +// +//go:nocheckptr +func (v Value) IsNil() bool { + return unsafe.Pointer(v.Pointer()) == nil +} + +// FuncForPC returns a *Func describing the function that contains the +// given program counter address, or else nil. +// +// If pc represents multiple functions because of inlining, it returns +// the a *Func describing the innermost function, but with an entry +// of the outermost function. +// +// NOTE: Its kind must be a reflect.Func, otherwise it returns nil +// +//go:nocheckptr +func (v Value) FuncForPC() *runtime.Func { + return runtime.FuncForPC(*(*uintptr)(v.ptr)) +} + +//go:nocheckptr +func typeUnderlying(flagVal flag, typPtr uintptr) (flag, uintptr, bool) { + typPtr2 := uintptrElem(typPtr + elemOffset) + if unsafe.Pointer(typPtr2) == nil { + return flagVal, typPtr, false + } + tt := (*ptrType)(unsafe.Pointer(typPtr2)) + flagVal2 := flagVal&flagRO | flagIndir | flagAddr + flagVal2 |= flag(tt.kind) & flagKindMask + return flagVal2, typPtr2, true +} + +//go:nocheckptr +func getFlag(typPtr uintptr) flag { + if unsafe.Pointer(typPtr) == nil { + return 0 + } + return *(*flag)(unsafe.Pointer(typPtr + kindOffset)) +} + +//go:nocheckptr +func uintptrElem(ptr uintptr) uintptr { + return *(*uintptr)(unsafe.Pointer(ptr)) +} + +//go:nocheckptr +func pointerElem(p unsafe.Pointer) unsafe.Pointer { + return *(*unsafe.Pointer)(p) +} + +var errValueUsable error + +func init() { + if errValueUsable == nil { + errValueUsable = checkGoVersion(runtime.Version()) + } +} + +func checkGoVersion(goVer string) error { + const s = "go1." + if strings.HasPrefix(goVer, s) || strings.Contains(goVer, " "+s) { + return nil + } + return fmt.Errorf("ameda Value: required go<2.0, but current version is '%s'", goVer) +} + +func checkValueUsable() { + if errValueUsable != nil { + panic(errValueUsable) + } +} + +var ( + e = emptyInterface{typ: new(rtype)} + ptrOffset = func() uintptr { + return unsafe.Offsetof(e.word) + }() + kindOffset = func() uintptr { + return unsafe.Offsetof(e.typ.kind) + }() + elemOffset = func() uintptr { + return unsafe.Offsetof(new(ptrType).elem) + }() + sliceDataOffset = func() uintptr { + return unsafe.Offsetof(new(reflect.SliceHeader).Data) + }() + // valueFlagOffset = func() uintptr { + // t := reflect.TypeOf(reflect.Value{}) + // s, ok := t.FieldByName("flag") + // if !ok { + // errValueUsable = errors.New("not found reflect.Value.flag field") + // return 0 + // } + // return s.Offset + // }() +) + +// NOTE: The following definitions must be consistent with those in the standard package!!! + +const ( + flagKindWidth = 5 // there are 27 kinds + flagKindMask flag = 1<