-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathinferred_number.go
167 lines (147 loc) · 3.52 KB
/
inferred_number.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
package jtdinfer
import (
"math"
jtd "github.com./jsontypedef/json-typedef-go"
)
// NumType represents the type of number a number should be represented in the
// JTD.
type NumType uint8
// Available number types.
const (
NumTypeUint8 NumType = iota
NumTypeInt8
NumTypeUint16
NumTypeInt16
NumTypeUint32
NumTypeInt32
NumTypeFloat32
NumTypeFloat64
)
// IsFloat returns true if the `NumType` is a float.
func (n NumType) IsFloat() bool {
return n == NumTypeFloat32 || n == NumTypeFloat64
}
// AsRange returns the maximum and minimum value for a `NumType`.
func (n NumType) AsRange() (float64, float64) {
switch n {
case NumTypeUint8:
return 0, math.MaxUint8
case NumTypeInt8:
return math.MinInt8, math.MaxInt8
case NumTypeUint16:
return 0, math.MaxUint16
case NumTypeInt16:
return math.MinInt16, math.MaxInt16
case NumTypeUint32:
return 0, math.MaxUint32
case NumTypeInt32:
return math.MinInt32, math.MaxInt32
case NumTypeFloat32, NumTypeFloat64:
return -math.MaxFloat64, math.MaxFloat64
}
return 0, 0
}
// IntoType will convert a `NumType` to a `jtd.Type`.
func (n NumType) IntoType() jtd.Type {
switch n {
case NumTypeUint8:
return jtd.TypeUint8
case NumTypeInt8:
return jtd.TypeInt8
case NumTypeUint16:
return jtd.TypeUint16
case NumTypeInt16:
return jtd.TypeInt16
case NumTypeUint32:
return jtd.TypeUint32
case NumTypeInt32:
return jtd.TypeInt32
case NumTypeFloat32:
return jtd.TypeFloat32
case NumTypeFloat64:
return jtd.TypeFloat64
}
return jtd.TypeUint8
}
// InferredNumber represents the state for a column that is a number. It holds
// the seen maximum and minimum value together with information about if all
// seen numbers are integers.
type InferredNumber struct {
Min float64
Max float64
IsInteger bool
}
// NewNumber will return a new `InferredNumber`.
func NewNumber() *InferredNumber {
return &InferredNumber{
IsInteger: true,
}
}
// Infer will infer a value, updating the state for the `InferredNumber`.
func (i *InferredNumber) Infer(n float64) *InferredNumber {
return &InferredNumber{
Min: math.Min(i.Min, n),
Max: math.Max(i.Max, n),
IsInteger: i.IsInteger && float64(int(n)) == n,
}
}
// IntoType will convert an `InferredNumber` to a `jtd.Type`.
func (i *InferredNumber) IntoType(defaultType NumType) jtd.Type {
if i.ContainedBy(defaultType) {
return defaultType.IntoType()
}
numTypes := []NumType{
NumTypeUint8,
NumTypeInt8,
NumTypeUint16,
NumTypeInt16,
NumTypeUint32,
NumTypeInt32,
}
for _, v := range numTypes {
if i.ContainedBy(v) {
return v.IntoType()
}
}
return jtd.TypeFloat64
}
// ContainedBy checks if an inferred number column can be contained within the
// passed `NumType`, meaning it is above the minimum and below the maximum value
// for the number type.
func (i *InferredNumber) ContainedBy(nt NumType) bool {
if !i.IsInteger && !nt.IsFloat() {
return false
}
minValue, maxValue := nt.AsRange()
return minValue <= i.Min && maxValue >= i.Max
}
func anyAsNumber(value any) (float64, bool) {
switch v := value.(type) {
case float64:
return v, true
case float32:
return float64(v), true
case uint:
return float64(v), true
case uint8:
return float64(v), true
case uint16:
return float64(v), true
case uint32:
return float64(v), true
case uint64:
return float64(v), true
case int:
return float64(v), true
case int8:
return float64(v), true
case int16:
return float64(v), true
case int32:
return float64(v), true
case int64:
return float64(v), true
default:
return 0.0, false
}
}