-
Notifications
You must be signed in to change notification settings - Fork 2
/
empty.go
206 lines (188 loc) · 4.29 KB
/
empty.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
package reflecthelper
import (
"math"
"reflect"
"time"
"github.com/fairyhunter13/task/v2"
"github.com/panjf2000/ants"
)
// Zeroable is a contract to specifies the Zero attribute of a custom type.
type Zeroable interface {
IsZero() bool
}
var nilTime *time.Time
// IsZero returns false if k is nil or has a zero value.
func IsZero(k interface{}) bool {
if k == nil {
return true
}
switch val := k.(type) {
case bool:
return !val
case int:
return val == 0
case int8:
return val == 0
case int16:
return val == 0
case int32:
return val == 0
case int64:
return val == 0
case uint:
return val == 0
case uint8:
return val == 0
case uint16:
return val == 0
case uint32:
return val == 0
case uint64:
return val == 0
case uintptr:
return val == 0
case float32:
return val == 0
case float64:
return val == 0
case complex64:
return val == 0
case complex128:
return val == 0
case string:
return val == ""
case *time.Time:
return val == nilTime || IsTimeZero(*val)
case time.Time:
return IsTimeZero(val)
case Zeroable:
if IsNil(val) {
return true
}
return val == nil || val.IsZero()
case reflect.Value: // for go version less than 1.13 because reflect.Value has no method IsZero
return IsValueZero(val)
}
return IsValueZero(reflect.ValueOf(k))
}
var zeroType = reflect.TypeOf((*Zeroable)(nil)).Elem()
// IsValueZero check the reflect.Value if it is zero based on it's kind.
func IsValueZero(v reflect.Value) bool {
switch GetKind(v) {
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:
complexNum := v.Complex()
return math.Float64bits(real(complexNum)) == 0 && math.Float64bits(imag(complexNum)) == 0
case reflect.Array, reflect.Slice:
return IsArrayZero(v)
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.UnsafePointer:
return v.IsNil()
case reflect.Ptr:
if v.IsNil() {
return true
}
return IsValueZero(v.Elem())
case reflect.String:
return v.Len() == 0
case reflect.Struct:
return IsStructZero(v)
case reflect.Invalid:
return true
}
return false
}
// IsStructZero checks if the struct is zero.
func IsStructZero(v reflect.Value) bool {
if !v.IsValid() || !IsKindStruct(GetKind(v)) || v.NumField() == 0 {
return true
}
if v.Type().Implements(zeroType) {
f := v.MethodByName("IsZero")
if f.IsValid() {
res := f.Call(nil)
return len(res) == 1 && res[0].Bool()
}
}
var (
numField = v.NumField()
boolChan = make(chan bool, numField)
tm = task.NewManager()
)
for i := 0; i < numField; i++ {
field := v.Field(i)
tm.Run(func() {
if !field.IsValid() {
return
}
if field.CanInterface() && !IsZero(field.Interface()) {
boolChan <- false
}
})
}
_ = ants.Submit(func() {
tm.Wait()
close(boolChan)
})
for boolVal := range boolChan {
if !boolVal {
return boolVal
}
}
return true
}
// IsArrayZero checks if the array is empty.
func IsArrayZero(v reflect.Value) bool {
if !v.IsValid() || !IsKindList(GetKind(v)) || v.Len() == 0 {
return true
}
var (
length = v.Len()
boolChan = make(chan bool, length)
tm = task.NewManager()
)
for i := 0; i < length; i++ {
elem := v.Index(i)
tm.Run(func() {
if !elem.IsValid() {
return
}
if elem.CanInterface() && !IsZero(elem.Interface()) {
boolChan <- false
}
})
}
_ = ants.Submit(func() {
tm.Wait()
close(boolChan)
})
for boolVal := range boolChan {
if !boolVal {
return boolVal
}
}
return true
}
// List of constants for the zero time.
const (
ZeroTime0 = "0000-00-00 00:00:00"
ZeroTime1 = "0001-01-01 00:00:00"
)
// IsTimeZero checks if the time is zero.
func IsTimeZero(t time.Time) bool {
return t.IsZero() || t.Format("2006-01-02 15:04:05") == ZeroTime0 ||
t.Format("2006-01-02 15:04:05") == ZeroTime1
}
// IsPtrValueZero overrides the default behavior for the reflect.Ptr case in the IsValueZero method.
func IsPtrValueZero(val reflect.Value) bool {
if val.Kind() != reflect.Ptr {
return IsValueZero(val)
}
return val.IsNil()
}