From 2f7d4cd80daecfeba387f464a06c1a8d6e9e2723 Mon Sep 17 00:00:00 2001 From: John Date: Mon, 15 Apr 2019 22:55:12 +0800 Subject: [PATCH] fix issue in Add function for gtype.Float32/Float64 --- TODO.MD | 1 + g/container/gtype/bool.go | 18 +++++++----- g/container/gtype/byte.go | 21 +++++++++----- g/container/gtype/bytes.go | 14 +++++++--- g/container/gtype/float32.go | 50 +++++++++++++++++++--------------- g/container/gtype/float64.go | 50 +++++++++++++++++++--------------- g/container/gtype/gtype.go | 3 +- g/container/gtype/int.go | 22 +++++++++------ g/container/gtype/int32.go | 20 ++++++++++---- g/container/gtype/int64.go | 18 ++++++++---- g/container/gtype/interface.go | 18 ++++++------ g/container/gtype/string.go | 13 ++++++--- g/container/gtype/uint.go | 20 ++++++++++---- g/container/gtype/uint32.go | 20 ++++++++++---- g/container/gtype/uint64.go | 20 ++++++++++---- geg/other/test.go | 19 +++++++++---- 16 files changed, 209 insertions(+), 118 deletions(-) diff --git a/TODO.MD b/TODO.MD index e456a8c6c..6ac97bca3 100644 --- a/TODO.MD +++ b/TODO.MD @@ -44,6 +44,7 @@ 1. 添加sqlite数据库的单元测试用例; 1. gredis增加cluster支持; 1. gset.Add/Remove/Contains方法增加批量操作支持; +1. gmlock增加手动清理机制:当内存锁不再使用时,由调用端决定是否清理内存锁; # DONE 1. gconv完善针对不同类型的判断,例如:尽量减少sprintf("%v", xxx)来执行string类型的转换; diff --git a/g/container/gtype/bool.go b/g/container/gtype/bool.go index 9ae7db583..e919ce9de 100644 --- a/g/container/gtype/bool.go +++ b/g/container/gtype/bool.go @@ -11,35 +11,39 @@ import ( ) type Bool struct { - val int32 + value int32 } +// NewBool returns a concurrent-safe object for bool type, +// with given initial value . func NewBool(value...bool) *Bool { t := &Bool{} if len(value) > 0 { if value[0] { - t.val = 1 + t.value = 1 } else { - t.val = 0 + t.value = 0 } } return t } +// Clone clones and returns a new concurrent-safe object for bool type. func (t *Bool) Clone() *Bool { return NewBool(t.Val()) } -// 并发安全设置变量值,返回之前的旧值 +// Set atomically stores value into t.valueue and returns the previous t.value value. func (t *Bool) Set(value bool) (old bool) { if value { - old = atomic.SwapInt32(&t.val, 1) == 1 + old = atomic.SwapInt32(&t.value, 1) == 1 } else { - old = atomic.SwapInt32(&t.val, 0) == 1 + old = atomic.SwapInt32(&t.value, 0) == 1 } return } +// Val atomically loads t.valueue. func (t *Bool) Val() bool { - return atomic.LoadInt32(&t.val) > 0 + return atomic.LoadInt32(&t.value) > 0 } diff --git a/g/container/gtype/byte.go b/g/container/gtype/byte.go index 104df712c..e6acc2e2a 100644 --- a/g/container/gtype/byte.go +++ b/g/container/gtype/byte.go @@ -11,29 +11,36 @@ import ( ) type Byte struct { - val int32 + value int32 } +// NewByte returns a concurrent-safe object for byte type, +// with given initial value . func NewByte(value...byte) *Byte { if len(value) > 0 { - return &Byte{val : int32(value[0])} + return &Byte{ + value : int32(value[0]), + } } return &Byte{} } +// Clone clones and returns a new concurrent-safe object for byte type. func (t *Byte) Clone() *Byte { return NewByte(t.Val()) } -// 并发安全设置变量值,返回之前的旧值 +// Set atomically stores value into t.value and returns the previous t.value value. func (t *Byte) Set(value byte) (old byte) { - return byte(atomic.SwapInt32(&t.val, int32(value))) + return byte(atomic.SwapInt32(&t.value, int32(value))) } +// Val atomically loads t.value. func (t *Byte) Val() byte { - return byte(atomic.LoadInt32(&t.val)) + return byte(atomic.LoadInt32(&t.value)) } -func (t *Byte) Add(delta int) byte { - return byte(atomic.AddInt32(&t.val, int32(delta))) +// Add atomically adds delta to t.value and returns the new value. +func (t *Byte) Add(delta int) (new byte) { + return byte(atomic.AddInt32(&t.value, int32(delta))) } diff --git a/g/container/gtype/bytes.go b/g/container/gtype/bytes.go index 125c92632..909b8f41d 100644 --- a/g/container/gtype/bytes.go +++ b/g/container/gtype/bytes.go @@ -9,29 +9,35 @@ package gtype import "sync/atomic" type Bytes struct { - val atomic.Value + value atomic.Value } +// NewBytes returns a concurrent-safe object for []byte type, +// with given initial value . func NewBytes(value...[]byte) *Bytes { t := &Bytes{} if len(value) > 0 { - t.val.Store(value[0]) + t.value.Store(value[0]) } return t } +// Clone clones and returns a new concurrent-safe object for []byte type. func (t *Bytes) Clone() *Bytes { return NewBytes(t.Val()) } +// Set atomically stores value into t.value and returns the previous t.value value. +// Note: The parameter cannot be nil. func (t *Bytes) Set(value []byte) (old []byte) { old = t.Val() - t.val.Store(value) + t.value.Store(value) return } +// Val atomically loads t.value. func (t *Bytes) Val() []byte { - if s := t.val.Load(); s != nil { + if s := t.value.Load(); s != nil { return s.([]byte) } return nil diff --git a/g/container/gtype/float32.go b/g/container/gtype/float32.go index 26a5d50b2..680910770 100644 --- a/g/container/gtype/float32.go +++ b/g/container/gtype/float32.go @@ -7,47 +7,53 @@ package gtype import ( - "sync/atomic" - "github.com/gogf/gf/g/encoding/gbinary" + "math" + "sync/atomic" + "unsafe" ) type Float32 struct { - val uint32 + value uint32 } +// NewFloat32 returns a concurrent-safe object for float32 type, +// with given initial value . func NewFloat32(value...float32) *Float32 { if len(value) > 0 { - return &Float32{ val : float32ToUint32InBits(value[0]) } + return &Float32{ + value : math.Float32bits(value[0]), + } } return &Float32{} } +// Clone clones and returns a new concurrent-safe object for float32 type. func (t *Float32) Clone() *Float32 { return NewFloat32(t.Val()) } +// Set atomically stores value into t.value and returns the previous t.value value. func (t *Float32) Set(value float32) (old float32) { - return uint32ToFloat32InBits(atomic.SwapUint32(&t.val, float32ToUint32InBits(value))) + return math.Float32frombits(atomic.SwapUint32(&t.value, math.Float32bits(value))) } +// Val atomically loads t.value. func (t *Float32) Val() float32 { - return uint32ToFloat32InBits(atomic.LoadUint32(&t.val)) + return math.Float32frombits(atomic.LoadUint32(&t.value)) } -func (t *Float32) Add(delta float32) float32 { - return uint32ToFloat32InBits(atomic.AddUint32(&t.val, float32ToUint32InBits(delta))) -} - -// 通过二进制的方式将float32转换为uint32(都是32bits) -func float32ToUint32InBits(value float32) uint32 { - b := gbinary.Encode(value) - i := gbinary.DecodeToUint32(b) - return i -} - -// 通过二进制的方式将uint32转换为float32(都是32bits) -func uint32ToFloat32InBits(value uint32) float32 { - b := gbinary.Encode(value) - f := gbinary.DecodeToFloat32(b) - return f +// Add atomically adds delta to t.value and returns the new value. +func (t *Float32) Add(delta float32) (new float32) { + for { + old := math.Float32frombits(t.value) + new = old + delta + if atomic.CompareAndSwapUint32( + (*uint32)(unsafe.Pointer(&t.value)), + math.Float32bits(old), + math.Float32bits(new), + ) { + break + } + } + return } \ No newline at end of file diff --git a/g/container/gtype/float64.go b/g/container/gtype/float64.go index 59896e7fe..1ffb6a03f 100644 --- a/g/container/gtype/float64.go +++ b/g/container/gtype/float64.go @@ -7,47 +7,53 @@ package gtype import ( - "sync/atomic" - "github.com/gogf/gf/g/encoding/gbinary" + "math" + "sync/atomic" + "unsafe" ) type Float64 struct { - val uint64 + value uint64 } +// NewFloat64 returns a concurrent-safe object for float64 type, +// with given initial value . func NewFloat64(value...float64) *Float64 { if len(value) > 0 { - return &Float64{ val : float64ToUint64InBits(value[0]) } + return &Float64{ + value : math.Float64bits(value[0]), + } } return &Float64{} } +// Clone clones and returns a new concurrent-safe object for float64 type. func (t *Float64) Clone() *Float64 { return NewFloat64(t.Val()) } +// Set atomically stores value into t.value and returns the previous t.value value. func (t *Float64) Set(value float64) (old float64) { - return uint64ToFloat64InBits(atomic.SwapUint64(&t.val, float64ToUint64InBits(value))) + return math.Float64frombits(atomic.SwapUint64(&t.value, math.Float64bits(value))) } +// Val atomically loads t.value. func (t *Float64) Val() float64 { - return uint64ToFloat64InBits(atomic.LoadUint64(&t.val)) + return math.Float64frombits(atomic.LoadUint64(&t.value)) } -func (t *Float64) Add(delta float64) float64 { - return uint64ToFloat64InBits(atomic.AddUint64(&t.val, float64ToUint64InBits(delta))) +// Add atomically adds delta to t.value and returns the new value. +func (t *Float64) Add(delta float64) (new float64) { + for { + old := math.Float64frombits(t.value) + new = old + delta + if atomic.CompareAndSwapUint64( + (*uint64)(unsafe.Pointer(&t.value)), + math.Float64bits(old), + math.Float64bits(new), + ) { + break + } + } + return } - -// 通过二进制的方式将float64转换为uint64(都是64bits) -func float64ToUint64InBits(value float64) uint64 { - b := gbinary.Encode(value) - i := gbinary.DecodeToUint64(b) - return i -} - -// 通过二进制的方式将uint64转换为float64(都是64bits) -func uint64ToFloat64InBits(value uint64) float64 { - b := gbinary.Encode(value) - f := gbinary.DecodeToFloat64(b) - return f -} \ No newline at end of file diff --git a/g/container/gtype/gtype.go b/g/container/gtype/gtype.go index d23d509bb..a1bcf92f8 100644 --- a/g/container/gtype/gtype.go +++ b/g/container/gtype/gtype.go @@ -4,11 +4,12 @@ // If a copy of the MIT was not distributed with this file, // You can obtain one at https://github.com/gogf/gf. -// Package gtype provides kinds of high performance, concurrent-safe/unsafe basic variable types. +// Package gtype provides kinds of high performance and concurrent-safe basic variable types. package gtype type Type = Interface +// See NewInterface. func New(value ... interface{}) *Type { return NewInterface(value...) } \ No newline at end of file diff --git a/g/container/gtype/int.go b/g/container/gtype/int.go index d8b2f6a4a..6e240a873 100644 --- a/g/container/gtype/int.go +++ b/g/container/gtype/int.go @@ -11,30 +11,36 @@ import ( ) type Int struct { - val int64 + value int64 } +// NewInt returns a concurrent-safe object for int type, +// with given initial value . func NewInt(value...int) *Int { if len(value) > 0 { - return &Int{val:int64(value[0])} + return &Int{ + value : int64(value[0]), + } } return &Int{} } +// Clone clones and returns a new concurrent-safe object for int type. func (t *Int) Clone() *Int { return NewInt(t.Val()) } -// 并发安全设置变量值,返回之前的旧值 +// Set atomically stores value into t.value and returns the previous t.value value. func (t *Int) Set(value int) (old int) { - return int(atomic.SwapInt64(&t.val, int64(value))) + return int(atomic.SwapInt64(&t.value, int64(value))) } +// Val atomically loads t.value. func (t *Int) Val() int { - return int(atomic.LoadInt64(&t.val)) + return int(atomic.LoadInt64(&t.value)) } -// 数值增加delta,并返回**新**的数值 -func (t *Int) Add(delta int) int { - return int(atomic.AddInt64(&t.val, int64(delta))) +// Add atomically adds delta to t.value and returns the new value. +func (t *Int) Add(delta int) (new int) { + return int(atomic.AddInt64(&t.value, int64(delta))) } \ No newline at end of file diff --git a/g/container/gtype/int32.go b/g/container/gtype/int32.go index c98caa817..7802ebb0d 100644 --- a/g/container/gtype/int32.go +++ b/g/container/gtype/int32.go @@ -11,28 +11,36 @@ import ( ) type Int32 struct { - val int32 + value int32 } +// NewInt32 returns a concurrent-safe object for int32 type, +// with given initial value . func NewInt32(value...int32) *Int32 { if len(value) > 0 { - return &Int32{val: value[0]} + return &Int32{ + value : value[0], + } } return &Int32{} } +// Clone clones and returns a new concurrent-safe object for int32 type. func (t *Int32) Clone() *Int32 { return NewInt32(t.Val()) } +// Set atomically stores value into t.value and returns the previous t.value value. func (t *Int32) Set(value int32) (old int32) { - return atomic.SwapInt32(&t.val, value) + return atomic.SwapInt32(&t.value, value) } +// Val atomically loads t.value. func (t *Int32) Val() int32 { - return atomic.LoadInt32(&t.val) + return atomic.LoadInt32(&t.value) } -func (t *Int32) Add(delta int32) int32 { - return atomic.AddInt32(&t.val, delta) +// Add atomically adds delta to t.value and returns the new value. +func (t *Int32) Add(delta int32) (new int32) { + return atomic.AddInt32(&t.value, delta) } \ No newline at end of file diff --git a/g/container/gtype/int64.go b/g/container/gtype/int64.go index 77f4a37d9..9758be4a8 100644 --- a/g/container/gtype/int64.go +++ b/g/container/gtype/int64.go @@ -11,28 +11,36 @@ import ( ) type Int64 struct { - val int64 + value int64 } +// NewInt64 returns a concurrent-safe object for int64 type, +// with given initial value . func NewInt64(value...int64) *Int64 { if len(value) > 0 { - return &Int64{val:value[0]} + return &Int64{ + value : value[0], + } } return &Int64{} } +// Clone clones and returns a new concurrent-safe object for int64 type. func (t *Int64) Clone() *Int64 { return NewInt64(t.Val()) } +// Set atomically stores value into t.value and returns the previous t.value value. func (t *Int64) Set(value int64) (old int64) { - return atomic.SwapInt64(&t.val, value) + return atomic.SwapInt64(&t.value, value) } +// Val atomically loads t.value. func (t *Int64) Val() int64 { - return atomic.LoadInt64(&t.val) + return atomic.LoadInt64(&t.value) } +// Add atomically adds delta to t.value and returns the new value. func (t *Int64) Add(delta int64) int64 { - return atomic.AddInt64(&t.val, delta) + return atomic.AddInt64(&t.value, delta) } \ No newline at end of file diff --git a/g/container/gtype/interface.go b/g/container/gtype/interface.go index fd606656d..3dd1b1507 100644 --- a/g/container/gtype/interface.go +++ b/g/container/gtype/interface.go @@ -10,32 +10,34 @@ import ( "sync/atomic" ) -// 比较通用的并发安全数据类型 type Interface struct { - val atomic.Value + value atomic.Value } +// NewInterface returns a concurrent-safe object for interface{} type, +// with given initial value . func NewInterface(value...interface{}) *Interface { t := &Interface{} if len(value) > 0 && value[0] != nil { - t.val.Store(value[0]) + t.value.Store(value[0]) } return t } +// Clone clones and returns a new concurrent-safe object for interface{} type. func (t *Interface) Clone() *Interface { return NewInterface(t.Val()) } +// Set atomically stores value into t.value and returns the previous t.value value. +// Note: The parameter cannot be nil. func (t *Interface) Set(value interface{}) (old interface{}) { - if value == nil { - return - } old = t.Val() - t.val.Store(value) + t.value.Store(value) return } +// Val atomically loads t.value. func (t *Interface) Val() interface{} { - return t.val.Load() + return t.value.Load() } \ No newline at end of file diff --git a/g/container/gtype/string.go b/g/container/gtype/string.go index 70b8c8959..f524d20bb 100644 --- a/g/container/gtype/string.go +++ b/g/container/gtype/string.go @@ -11,29 +11,34 @@ import ( ) type String struct { - val atomic.Value + value atomic.Value } +// NewString returns a concurrent-safe object for string type, +// with given initial value . func NewString(value...string) *String { t := &String{} if len(value) > 0 { - t.val.Store(value[0]) + t.value.Store(value[0]) } return t } +// Clone clones and returns a new concurrent-safe object for string type. func (t *String) Clone() *String { return NewString(t.Val()) } +// Set atomically stores value into t.value and returns the previous t.value value. func (t *String) Set(value string) (old string) { old = t.Val() - t.val.Store(value) + t.value.Store(value) return } +// Val atomically loads t.value. func (t *String) Val() string { - s := t.val.Load() + s := t.value.Load() if s != nil { return s.(string) } diff --git a/g/container/gtype/uint.go b/g/container/gtype/uint.go index 4c8286df5..c9b5ad3d8 100644 --- a/g/container/gtype/uint.go +++ b/g/container/gtype/uint.go @@ -11,28 +11,36 @@ import ( ) type Uint struct { - val uint64 + value uint64 } +// NewUint returns a concurrent-safe object for uint type, +// with given initial value . func NewUint(value...uint) *Uint { if len(value) > 0 { - return &Uint{val:uint64(value[0])} + return &Uint{ + value : uint64(value[0]), + } } return &Uint{} } +// Clone clones and returns a new concurrent-safe object for uint type. func (t *Uint) Clone() *Uint { return NewUint(t.Val()) } +// Set atomically stores value into t.value and returns the previous t.value value. func (t *Uint) Set(value uint) (old uint) { - return uint(atomic.SwapUint64(&t.val, uint64(value))) + return uint(atomic.SwapUint64(&t.value, uint64(value))) } +// Val atomically loads t.value. func (t *Uint) Val() uint { - return uint(atomic.LoadUint64(&t.val)) + return uint(atomic.LoadUint64(&t.value)) } -func (t *Uint) Add(delta uint) int { - return int(atomic.AddUint64(&t.val, uint64(delta))) +// Add atomically adds delta to t.value and returns the new value. +func (t *Uint) Add(delta uint) (new uint) { + return uint(atomic.AddUint64(&t.value, uint64(delta))) } \ No newline at end of file diff --git a/g/container/gtype/uint32.go b/g/container/gtype/uint32.go index 6596e3467..c3a18c904 100644 --- a/g/container/gtype/uint32.go +++ b/g/container/gtype/uint32.go @@ -11,28 +11,36 @@ import ( ) type Uint32 struct { - val uint32 + value uint32 } +// NewUint32 returns a concurrent-safe object for uint32 type, +// with given initial value . func NewUint32(value...uint32) *Uint32 { if len(value) > 0 { - return &Uint32{val:value[0]} + return &Uint32{ + value : value[0], + } } return &Uint32{} } +// Clone clones and returns a new concurrent-safe object for uint32 type. func (t *Uint32) Clone() *Uint32 { return NewUint32(t.Val()) } +// Set atomically stores value into t.value and returns the previous t.value value. func (t *Uint32) Set(value uint32) (old uint32) { - return atomic.SwapUint32(&t.val, value) + return atomic.SwapUint32(&t.value, value) } +// Val atomically loads t.value. func (t *Uint32) Val() uint32 { - return atomic.LoadUint32(&t.val) + return atomic.LoadUint32(&t.value) } -func (t *Uint32) Add(delta uint32) uint32 { - return atomic.AddUint32(&t.val, delta) +// Add atomically adds delta to t.value and returns the new value. +func (t *Uint32) Add(delta uint32) (new uint32) { + return atomic.AddUint32(&t.value, delta) } \ No newline at end of file diff --git a/g/container/gtype/uint64.go b/g/container/gtype/uint64.go index 79d185312..9e63234e0 100644 --- a/g/container/gtype/uint64.go +++ b/g/container/gtype/uint64.go @@ -11,28 +11,36 @@ import ( ) type Uint64 struct { - val uint64 + value uint64 } +// NewUint64 returns a concurrent-safe object for uint64 type, +// with given initial value . func NewUint64(value...uint64) *Uint64 { if len(value) > 0 { - return &Uint64{val:value[0]} + return &Uint64{ + value : value[0], + } } return &Uint64{} } +// Clone clones and returns a new concurrent-safe object for uint64 type. func (t *Uint64) Clone() *Uint64 { return NewUint64(t.Val()) } +// Set atomically stores value into t.value and returns the previous t.value value. func (t *Uint64) Set(value uint64) (old uint64) { - return atomic.SwapUint64(&t.val, value) + return atomic.SwapUint64(&t.value, value) } +// Val atomically loads t.value. func (t *Uint64) Val() uint64 { - return atomic.LoadUint64(&t.val) + return atomic.LoadUint64(&t.value) } -func (t *Uint64) Add(delta uint64) uint64 { - return atomic.AddUint64(&t.val, delta) +// Add atomically adds delta to t.value and returns the new value. +func (t *Uint64) Add(delta uint64) (new uint64) { + return atomic.AddUint64(&t.value, delta) } \ No newline at end of file diff --git a/geg/other/test.go b/geg/other/test.go index 63996a987..8de0ca94a 100644 --- a/geg/other/test.go +++ b/geg/other/test.go @@ -2,14 +2,21 @@ package main import ( "fmt" - "github.com/gogf/gf/g/util/grand" + "github.com/gogf/gf/g/container/gtype" + "github.com/gogf/gf/g/test/gtest" ) - - func main() { - for { - fmt.Println(grand.Intn(100)) - } + + var add float32 + add = 3.1415926 + + myF32 := gtype.NewFloat32(add) + myAdd := myF32.Add(float32(6.2951413)) + + add += float32(6.2951413) + + fmt.Println(myF32.Val()) + gtest.AssertEQ(myAdd, add) } \ No newline at end of file