github.com/mithrandie/csvq@v1.18.1/lib/query/utils.go (about) 1 package query 2 3 import ( 4 "bytes" 5 "fmt" 6 "strings" 7 "sync" 8 "time" 9 10 "github.com/mithrandie/csvq/lib/option" 11 "github.com/mithrandie/csvq/lib/value" 12 13 "github.com/mithrandie/ternary" 14 ) 15 16 const LimitToUseUintSlicePool = 20 17 18 type UintPool struct { 19 limitToUseSlice int 20 m map[uint]bool 21 values []uint 22 } 23 24 func NewUintPool(initCap int, limitToUseSlice int) *UintPool { 25 return &UintPool{ 26 limitToUseSlice: limitToUseSlice, 27 m: make(map[uint]bool, initCap), 28 values: make([]uint, 0, initCap), 29 } 30 } 31 32 func (c *UintPool) Exists(val uint) bool { 33 if c.limitToUseSlice <= len(c.values) { 34 _, ok := c.m[val] 35 return ok 36 } 37 38 for i := range c.values { 39 if val == c.values[i] { 40 return true 41 } 42 } 43 return false 44 } 45 46 func (c *UintPool) Add(val uint) { 47 c.m[val] = true 48 c.values = append(c.values, val) 49 } 50 51 func (c *UintPool) Range(fn func(idx int, value uint) error) error { 52 var err error 53 for i := range c.values { 54 if err = fn(i, c.values[i]); err != nil { 55 break 56 } 57 } 58 return err 59 } 60 61 func (c *UintPool) Len() int { 62 return len(c.values) 63 } 64 65 func InStrSliceWithCaseInsensitive(s string, list []string) bool { 66 for _, v := range list { 67 if strings.EqualFold(s, v) { 68 return true 69 } 70 } 71 return false 72 } 73 74 func Distinguish(list []value.Primary, flags *option.Flags) []value.Primary { 75 values := make(map[string]int, 40) 76 valueKeys := make([]string, 0, 40) 77 78 buf := GetComparisonKeysBuf() 79 80 for i, v := range list { 81 buf.Reset() 82 SerializeComparisonKeys(buf, []value.Primary{v}, flags) 83 key := buf.String() 84 if _, ok := values[key]; !ok { 85 values[key] = i 86 valueKeys = append(valueKeys, key) 87 } 88 } 89 90 PutComparisonkeysBuf(buf) 91 92 distinguished := make([]value.Primary, len(valueKeys)) 93 for i, key := range valueKeys { 94 distinguished[i] = list[values[key]] 95 } 96 97 return distinguished 98 } 99 100 func FormatCount(i int, obj string) string { 101 var s string 102 if i == 0 { 103 s = fmt.Sprintf("no %s", obj) 104 } else if i == 1 { 105 s = fmt.Sprintf("%d %s", i, obj) 106 } else { 107 s = fmt.Sprintf("%d %ss", i, obj) 108 } 109 return s 110 } 111 112 var comparisonKeysBufPool = &sync.Pool{ 113 New: func() interface{} { 114 return &bytes.Buffer{} 115 }, 116 } 117 118 func GetComparisonKeysBuf() *bytes.Buffer { 119 buf := comparisonKeysBufPool.Get().(*bytes.Buffer) 120 return buf 121 } 122 123 func PutComparisonkeysBuf(buf *bytes.Buffer) { 124 buf.Reset() 125 comparisonKeysBufPool.Put(buf) 126 } 127 128 func SerializeComparisonKeys(buf *bytes.Buffer, values []value.Primary, flags *option.Flags) { 129 for i, val := range values { 130 if 0 < i { 131 buf.WriteByte(58) 132 } 133 134 if flags.StrictEqual { 135 SerializeIdenticalKey(buf, val) 136 } else { 137 SerializeKey(buf, val, flags) 138 } 139 } 140 } 141 142 func SerializeKey(buf *bytes.Buffer, val value.Primary, flags *option.Flags) { 143 if value.IsNull(val) { 144 serializeNull(buf) 145 } else if in := value.ToIntegerStrictly(val); !value.IsNull(in) { 146 serializeInteger(buf, in.(*value.Integer).String()) 147 value.Discard(in) 148 } else if f := value.ToFloat(val); !value.IsNull(f) { 149 serializeFloat(buf, f.(*value.Float).String()) 150 value.Discard(f) 151 } else if dt := value.ToDatetime(val, flags.DatetimeFormat, flags.GetTimeLocation()); !value.IsNull(dt) { 152 serializeDatetime(buf, dt.(*value.Datetime).Raw()) 153 value.Discard(dt) 154 } else if b := value.ToBoolean(val); !value.IsNull(b) { 155 if b.(*value.Boolean).Raw() { 156 serializeInteger(buf, "1") 157 } else { 158 serializeInteger(buf, "0") 159 } 160 } else if s, ok := val.(*value.String); ok { 161 serializeString(buf, s.Raw()) 162 } else { 163 serializeNull(buf) 164 } 165 } 166 167 func SerializeIdenticalKey(buf *bytes.Buffer, val value.Primary) { 168 switch val.(type) { 169 case *value.String: 170 serializeCaseSensitiveString(buf, val.(*value.String).Raw()) 171 case *value.Integer: 172 serializeInteger(buf, val.(*value.Integer).String()) 173 case *value.Float: 174 serializeFloat(buf, val.(*value.Float).String()) 175 case *value.Boolean: 176 serializeBoolean(buf, val.(*value.Boolean).Raw()) 177 case *value.Ternary: 178 serializeTernary(buf, val.(*value.Ternary).Ternary()) 179 case *value.Datetime: 180 serializeDatetime(buf, val.(*value.Datetime).Raw()) 181 default: 182 serializeNull(buf) 183 } 184 } 185 186 func serializeNull(buf *bytes.Buffer) { 187 buf.Write([]byte{91, 78, 93}) 188 } 189 190 func serializeInteger(buf *bytes.Buffer, s string) { 191 buf.Write([]byte{91, 73, 93}) 192 buf.WriteString(s) 193 } 194 195 func serializeFloat(buf *bytes.Buffer, s string) { 196 buf.Write([]byte{91, 70, 93}) 197 buf.WriteString(s) 198 } 199 200 func serializeDatetime(buf *bytes.Buffer, t time.Time) { 201 serializeDatetimeFromUnixNano(buf, t.UnixNano()) 202 } 203 204 func serializeDatetimeFromUnixNano(buf *bytes.Buffer, t int64) { 205 buf.Write([]byte{91, 68, 93}) 206 buf.WriteString(value.Int64ToStr(t)) 207 } 208 209 func serializeString(buf *bytes.Buffer, s string) { 210 buf.Write([]byte{91, 83, 93}) 211 buf.WriteString(strings.ToUpper(option.TrimSpace(s))) 212 } 213 214 func serializeCaseSensitiveString(buf *bytes.Buffer, s string) { 215 buf.Write([]byte{91, 83, 93}) 216 buf.WriteString(option.TrimSpace(s)) 217 } 218 219 func serializeBoolean(buf *bytes.Buffer, b bool) { 220 buf.Write([]byte{91, 66, 93}) 221 if b { 222 buf.WriteString("T") 223 } else { 224 buf.WriteString("F") 225 } 226 } 227 228 func serializeTernary(buf *bytes.Buffer, t ternary.Value) { 229 buf.Write([]byte{91, 84, 93}) 230 if t == ternary.TRUE { 231 buf.WriteString("T") 232 } else if t == ternary.FALSE { 233 buf.WriteString("F") 234 } else { 235 buf.WriteString("U") 236 } 237 }