2023-06-19 16:19:24 +09:00
|
|
|
package gocommon
|
2023-05-24 15:10:15 +09:00
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"encoding/binary"
|
|
|
|
|
"encoding/json"
|
|
|
|
|
"fmt"
|
|
|
|
|
"io"
|
|
|
|
|
"math/rand"
|
2023-06-16 12:22:16 +09:00
|
|
|
"path"
|
2023-05-24 15:10:15 +09:00
|
|
|
"reflect"
|
|
|
|
|
"strconv"
|
|
|
|
|
"strings"
|
|
|
|
|
"sync/atomic"
|
|
|
|
|
"time"
|
2023-06-21 14:13:30 +09:00
|
|
|
|
|
|
|
|
"repositories.action2quare.com/ayo/gocommon/flagx"
|
2023-05-24 15:10:15 +09:00
|
|
|
)
|
|
|
|
|
|
2023-06-21 14:13:30 +09:00
|
|
|
var devflag = flagx.Bool("dev", false, "")
|
|
|
|
|
|
2023-05-24 15:10:15 +09:00
|
|
|
var sequenceStart = rand.Uint32()
|
|
|
|
|
|
2024-05-17 09:59:42 +09:00
|
|
|
func MakeHttpHandlerPattern(n ...string) (r string) {
|
|
|
|
|
r = "/" + path.Join(n...)
|
|
|
|
|
defer func() {
|
|
|
|
|
for strings.Contains(r, "//") {
|
|
|
|
|
r = strings.ReplaceAll(r, "//", "/")
|
|
|
|
|
}
|
|
|
|
|
}()
|
|
|
|
|
|
2023-06-16 12:22:16 +09:00
|
|
|
if strings.HasSuffix(n[len(n)-1], "/") {
|
|
|
|
|
return r + "/"
|
2023-06-16 12:14:50 +09:00
|
|
|
}
|
|
|
|
|
|
2023-05-24 15:10:15 +09:00
|
|
|
return r
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func MakeLocalUniqueId() string {
|
|
|
|
|
var b [10]byte
|
|
|
|
|
|
|
|
|
|
now := time.Now()
|
|
|
|
|
binary.BigEndian.PutUint32(b[6:10], uint32(now.Unix()))
|
|
|
|
|
binary.BigEndian.PutUint32(b[3:7], uint32(now.Nanosecond()))
|
|
|
|
|
binary.BigEndian.PutUint32(b[0:4], atomic.AddUint32(&sequenceStart, 1))
|
|
|
|
|
|
|
|
|
|
u := binary.LittleEndian.Uint64(b[2:])
|
|
|
|
|
a := strconv.FormatUint(u, 36)
|
|
|
|
|
return a[1:]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func SerializeInterface(w io.Writer, val interface{}) (err error) {
|
|
|
|
|
if val == nil {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
value := reflect.ValueOf(val)
|
|
|
|
|
encoder := json.NewEncoder(w)
|
|
|
|
|
|
|
|
|
|
switch value.Kind() {
|
|
|
|
|
case reflect.String:
|
|
|
|
|
_, err = w.Write([]byte(value.String()))
|
|
|
|
|
|
|
|
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
|
|
|
_, err = w.Write([]byte(fmt.Sprintf("%d", value.Int())))
|
|
|
|
|
|
|
|
|
|
case reflect.Float32, reflect.Float64:
|
|
|
|
|
_, err = w.Write([]byte(fmt.Sprintf("%f", value.Float())))
|
|
|
|
|
|
|
|
|
|
case reflect.Bool:
|
|
|
|
|
if value.Bool() {
|
|
|
|
|
_, err = w.Write([]byte("true"))
|
|
|
|
|
} else {
|
|
|
|
|
_, err = w.Write([]byte("false"))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case reflect.Slice:
|
|
|
|
|
switch value.Type().Elem().Kind() {
|
|
|
|
|
case reflect.Uint8:
|
|
|
|
|
_, err = w.Write(value.Bytes())
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
var conv []interface{}
|
|
|
|
|
for i := 0; i < value.Len(); i++ {
|
|
|
|
|
conv = append(conv, value.Index(i).Interface())
|
|
|
|
|
}
|
|
|
|
|
if len(conv) == 0 {
|
|
|
|
|
_, err = w.Write([]byte("[]"))
|
|
|
|
|
} else {
|
|
|
|
|
err = encoder.Encode(conv)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case reflect.Interface, reflect.Struct, reflect.Map:
|
|
|
|
|
if value.Kind() == reflect.Struct {
|
|
|
|
|
err = encoder.Encode(value.Interface())
|
|
|
|
|
} else if !value.IsNil() {
|
|
|
|
|
err = encoder.Encode(value.Interface())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case reflect.Ptr:
|
|
|
|
|
if !value.IsNil() {
|
|
|
|
|
if wro, ok := value.Interface().(io.WriterTo); ok {
|
|
|
|
|
_, err = wro.WriteTo(w)
|
|
|
|
|
} else {
|
|
|
|
|
err = json.NewEncoder(w).Encode(value.Interface())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return
|
|
|
|
|
}
|
2023-12-01 19:34:49 +09:00
|
|
|
|
2023-12-02 20:30:43 +09:00
|
|
|
func ShrinkSliceAt[T any](in []T, from int) []T {
|
|
|
|
|
if len(in) == 0 {
|
|
|
|
|
return in
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cursor := from
|
|
|
|
|
for i := from + 1; i < len(in); i++ {
|
|
|
|
|
in[cursor] = in[i]
|
|
|
|
|
cursor++
|
|
|
|
|
}
|
|
|
|
|
return in[:len(in)-1]
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-01 19:34:49 +09:00
|
|
|
func ShrinkSlice[T any](in []T, compare func(elem T) bool) []T {
|
2023-12-02 20:09:52 +09:00
|
|
|
if len(in) == 0 {
|
|
|
|
|
return in
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-01 19:34:49 +09:00
|
|
|
cursor := 0
|
|
|
|
|
for i := 0; i < len(in); i++ {
|
|
|
|
|
if compare(in[i]) {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
in[cursor] = in[i]
|
|
|
|
|
cursor++
|
|
|
|
|
}
|
|
|
|
|
return in[:cursor]
|
|
|
|
|
}
|
2023-12-02 01:25:12 +09:00
|
|
|
|
2023-12-02 19:56:37 +09:00
|
|
|
func FindOneInSlice[T any](in []T, compare func(elem *T) bool) (int, bool) {
|
2023-12-02 01:25:12 +09:00
|
|
|
for i, e := range in {
|
|
|
|
|
if compare(&e) {
|
2023-12-02 19:56:37 +09:00
|
|
|
return i, true
|
2023-12-02 01:25:12 +09:00
|
|
|
}
|
|
|
|
|
}
|
2023-12-02 19:56:37 +09:00
|
|
|
return -1, false
|
2023-12-02 01:25:12 +09:00
|
|
|
}
|
2024-07-18 17:06:51 +09:00
|
|
|
|
|
|
|
|
// RotateRight rotates the bits in the byte array to the right by n positions
|
|
|
|
|
func rotateBitsRight(data []byte, n int) {
|
|
|
|
|
// Normalize n to avoid unnecessary rotations
|
|
|
|
|
n = n % (len(data) * 8)
|
|
|
|
|
if n == 0 {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// To hold the final rotated result
|
|
|
|
|
inlen := len(data)
|
|
|
|
|
for k := 0; k < n/8; k++ {
|
|
|
|
|
last := data[inlen-1]
|
|
|
|
|
for i := 0; i < inlen-1; i++ {
|
|
|
|
|
data[inlen-1-i] = data[inlen-2-i]
|
|
|
|
|
}
|
|
|
|
|
data[0] = last
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
n = n % 8
|
|
|
|
|
if n == 0 {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mask := byte(1<<n) - 1
|
|
|
|
|
carry := data[0] & mask
|
|
|
|
|
for i := 1; i < inlen; i++ {
|
|
|
|
|
nextcarry := data[i] & mask
|
|
|
|
|
data[i] = (data[i] >> n) | (carry << (8 - n))
|
|
|
|
|
carry = nextcarry
|
|
|
|
|
}
|
|
|
|
|
data[0] = (data[0] >> n) | (carry << (8 - n))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func rotateBitsLeft(data []byte, n int) {
|
|
|
|
|
// Normalize n to avoid unnecessary rotations
|
|
|
|
|
n = n % (len(data) * 8)
|
|
|
|
|
if n == 0 {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// To hold the final rotated result
|
|
|
|
|
inlen := len(data)
|
|
|
|
|
for k := 0; k < n/8; k++ {
|
|
|
|
|
last := data[0]
|
|
|
|
|
for i := 0; i < inlen-1; i++ {
|
|
|
|
|
data[i] = data[i+1]
|
|
|
|
|
}
|
|
|
|
|
data[inlen-1] = last
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
n = n % 8
|
|
|
|
|
if n == 0 {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mask := (byte(1<<n) - 1) << (8 - n)
|
|
|
|
|
carry := data[0] & mask
|
|
|
|
|
for i := inlen - 1; i >= 0; i-- {
|
|
|
|
|
nextcarry := data[i] & mask
|
|
|
|
|
data[i] = (data[i] << n) | (carry >> (8 - n))
|
|
|
|
|
carry = nextcarry
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func RotateBits(data []byte, n int) {
|
|
|
|
|
if n > 0 {
|
|
|
|
|
rotateBitsRight(data, n)
|
|
|
|
|
} else {
|
|
|
|
|
rotateBitsLeft(data, -n)
|
|
|
|
|
}
|
|
|
|
|
}
|