新增工具库

This commit is contained in:
boyce
2019-02-28 09:25:13 +08:00
parent a831db0a4e
commit d021127a77
5 changed files with 375 additions and 0 deletions

76
util/deepcopy.go Normal file
View File

@@ -0,0 +1,76 @@
package util
// reference: https://github.com/mohae/deepcopy
import (
"reflect"
)
func deepCopy(dst, src reflect.Value) {
switch src.Kind() {
case reflect.Interface:
value := src.Elem()
if !value.IsValid() {
return
}
newValue := reflect.New(value.Type()).Elem()
deepCopy(newValue, value)
dst.Set(newValue)
case reflect.Ptr:
value := src.Elem()
if !value.IsValid() {
return
}
dst.Set(reflect.New(value.Type()))
deepCopy(dst.Elem(), value)
case reflect.Map:
dst.Set(reflect.MakeMap(src.Type()))
keys := src.MapKeys()
for _, key := range keys {
value := src.MapIndex(key)
newValue := reflect.New(value.Type()).Elem()
deepCopy(newValue, value)
dst.SetMapIndex(key, newValue)
}
case reflect.Slice:
dst.Set(reflect.MakeSlice(src.Type(), src.Len(), src.Cap()))
for i := 0; i < src.Len(); i++ {
deepCopy(dst.Index(i), src.Index(i))
}
case reflect.Struct:
typeSrc := src.Type()
for i := 0; i < src.NumField(); i++ {
value := src.Field(i)
tag := typeSrc.Field(i).Tag
if value.CanSet() && tag.Get("deepcopy") != "-" {
deepCopy(dst.Field(i), value)
}
}
default:
dst.Set(src)
}
}
func DeepCopy(dst, src interface{}) {
typeDst := reflect.TypeOf(dst)
typeSrc := reflect.TypeOf(src)
if typeDst != typeSrc {
panic("DeepCopy: " + typeDst.String() + " != " + typeSrc.String())
}
if typeSrc.Kind() != reflect.Ptr {
panic("DeepCopy: pass arguments by address")
}
valueDst := reflect.ValueOf(dst).Elem()
valueSrc := reflect.ValueOf(src).Elem()
if !valueDst.IsValid() || !valueSrc.IsValid() {
panic("DeepCopy: invalid arguments")
}
deepCopy(valueDst, valueSrc)
}
func DeepClone(v interface{}) interface{} {
dst := reflect.New(reflect.TypeOf(v)).Elem()
deepCopy(dst, reflect.ValueOf(v))
return dst.Interface()
}

92
util/example_test.go Normal file
View File

@@ -0,0 +1,92 @@
package util_test
import (
"fmt"
"github.com/name5566/leaf/util"
)
func ExampleMap() {
m := new(util.Map)
fmt.Println(m.Get("key"))
m.Set("key", "value")
fmt.Println(m.Get("key"))
m.Del("key")
fmt.Println(m.Get("key"))
m.Set(1, "1")
m.Set(2, 2)
m.Set("3", 3)
fmt.Println(m.Len())
// Output:
// <nil>
// value
// <nil>
// 3
}
func ExampleRandGroup() {
i := util.RandGroup(0, 0, 50, 50)
switch i {
case 2, 3:
fmt.Println("ok")
}
// Output:
// ok
}
func ExampleRandInterval() {
v := util.RandInterval(-1, 1)
switch v {
case -1, 0, 1:
fmt.Println("ok")
}
// Output:
// ok
}
func ExampleRandIntervalN() {
r := util.RandIntervalN(-1, 0, 2)
if r[0] == -1 && r[1] == 0 ||
r[0] == 0 && r[1] == -1 {
fmt.Println("ok")
}
// Output:
// ok
}
func ExampleDeepCopy() {
src := []int{1, 2, 3}
var dst []int
util.DeepCopy(&dst, &src)
for _, v := range dst {
fmt.Println(v)
}
// Output:
// 1
// 2
// 3
}
func ExampleDeepClone() {
src := []int{1, 2, 3}
dst := util.DeepClone(src).([]int)
for _, v := range dst {
fmt.Println(v)
}
// Output:
// 1
// 2
// 3
}

101
util/map.go Normal file
View File

@@ -0,0 +1,101 @@
package util
import (
"sync"
)
type Map struct {
sync.RWMutex
m map[interface{}]interface{}
}
func (m *Map) init() {
if m.m == nil {
m.m = make(map[interface{}]interface{})
}
}
func (m *Map) UnsafeGet(key interface{}) interface{} {
if m.m == nil {
return nil
} else {
return m.m[key]
}
}
func (m *Map) Get(key interface{}) interface{} {
m.RLock()
defer m.RUnlock()
return m.UnsafeGet(key)
}
func (m *Map) UnsafeSet(key interface{}, value interface{}) {
m.init()
m.m[key] = value
}
func (m *Map) Set(key interface{}, value interface{}) {
m.Lock()
defer m.Unlock()
m.UnsafeSet(key, value)
}
func (m *Map) TestAndSet(key interface{}, value interface{}) interface{} {
m.Lock()
defer m.Unlock()
m.init()
if v, ok := m.m[key]; ok {
return v
} else {
m.m[key] = value
return nil
}
}
func (m *Map) UnsafeDel(key interface{}) {
m.init()
delete(m.m, key)
}
func (m *Map) Del(key interface{}) {
m.Lock()
defer m.Unlock()
m.UnsafeDel(key)
}
func (m *Map) UnsafeLen() int {
if m.m == nil {
return 0
} else {
return len(m.m)
}
}
func (m *Map) Len() int {
m.RLock()
defer m.RUnlock()
return m.UnsafeLen()
}
func (m *Map) UnsafeRange(f func(interface{}, interface{})) {
if m.m == nil {
return
}
for k, v := range m.m {
f(k, v)
}
}
func (m *Map) RLockRange(f func(interface{}, interface{})) {
m.RLock()
defer m.RUnlock()
m.UnsafeRange(f)
}
func (m *Map) LockRange(f func(interface{}, interface{})) {
m.Lock()
defer m.Unlock()
m.UnsafeRange(f)
}

91
util/rand.go Normal file
View File

@@ -0,0 +1,91 @@
package util
import (
"math/rand"
"time"
)
func init() {
rand.Seed(time.Now().UnixNano())
}
func RandGroup(p ...uint32) int {
if p == nil {
panic("args not found")
}
r := make([]uint32, len(p))
for i := 0; i < len(p); i++ {
if i == 0 {
r[0] = p[0]
} else {
r[i] = r[i-1] + p[i]
}
}
rl := r[len(r)-1]
if rl == 0 {
return 0
}
rn := uint32(rand.Int63n(int64(rl)))
for i := 0; i < len(r); i++ {
if rn < r[i] {
return i
}
}
panic("bug")
}
func RandInterval(b1, b2 int32) int32 {
if b1 == b2 {
return b1
}
min, max := int64(b1), int64(b2)
if min > max {
min, max = max, min
}
return int32(rand.Int63n(max-min+1) + min)
}
func RandIntervalN(b1, b2 int32, n uint32) []int32 {
if b1 == b2 {
return []int32{b1}
}
min, max := int64(b1), int64(b2)
if min > max {
min, max = max, min
}
l := max - min + 1
if int64(n) > l {
n = uint32(l)
}
r := make([]int32, n)
m := make(map[int32]int32)
for i := uint32(0); i < n; i++ {
v := int32(rand.Int63n(l) + min)
if mv, ok := m[v]; ok {
r[i] = mv
} else {
r[i] = v
}
lv := int32(l - 1 + min)
if v != lv {
if mv, ok := m[lv]; ok {
m[v] = mv
} else {
m[v] = lv
}
}
l--
}
return r
}

15
util/semaphore.go Normal file
View File

@@ -0,0 +1,15 @@
package util
type Semaphore chan struct{}
func MakeSemaphore(n int) Semaphore {
return make(Semaphore, n)
}
func (s Semaphore) Acquire() {
s <- struct{}{}
}
func (s Semaphore) Release() {
<-s
}