github.com/tobgu/qframe@v0.4.0/internal/fcolumn/column.go (about) 1 package fcolumn 2 3 import ( 4 "github.com/tobgu/qframe/internal/ryu" 5 "math" 6 "math/rand" 7 "reflect" 8 "strconv" 9 "unsafe" 10 11 "github.com/tobgu/qframe/internal/column" 12 "github.com/tobgu/qframe/internal/hash" 13 "github.com/tobgu/qframe/internal/index" 14 "github.com/tobgu/qframe/qerrors" 15 "github.com/tobgu/qframe/types" 16 ) 17 18 func (c Column) DataType() types.DataType { 19 return types.Float 20 } 21 22 func (c Column) StringAt(i uint32, naRep string) string { 23 value := c.data[i] 24 if math.IsNaN(value) { 25 return naRep 26 } 27 return strconv.FormatFloat(c.data[i], 'f', -1, 64) 28 } 29 30 func (c Column) AppendByteStringAt(buf []byte, i uint32) []byte { 31 value := c.data[i] 32 if math.IsNaN(value) { 33 return append(buf, "null"...) 34 } 35 36 return ryu.AppendFloat64f(buf, value) 37 } 38 39 func (c Column) ByteSize() int { 40 // Slice header + data 41 return 2*8 + 8*cap(c.data) 42 } 43 44 func (c Column) Equals(index index.Int, other column.Column, otherIndex index.Int) bool { 45 otherI, ok := other.(Column) 46 if !ok { 47 return false 48 } 49 50 for ix, x := range index { 51 v1, v2 := c.data[x], otherI.data[otherIndex[ix]] 52 if v1 != v2 { 53 // NaN != NaN but for our purposes they are the same 54 if !(math.IsNaN(v1) && math.IsNaN(v2)) { 55 return false 56 } 57 } 58 } 59 60 return true 61 } 62 63 func (c Comparable) Compare(i, j uint32) column.CompareResult { 64 x, y := c.data[i], c.data[j] 65 if x < y { 66 return c.ltValue 67 } 68 69 if x > y { 70 return c.gtValue 71 } 72 73 if math.IsNaN(x) || math.IsNaN(y) { 74 if !math.IsNaN(x) { 75 return c.nullGtValue 76 } 77 78 if !math.IsNaN(y) { 79 return c.nullLtValue 80 } 81 82 return c.equalNullValue 83 } 84 85 return column.Equal 86 } 87 88 func (c Comparable) Hash(i uint32, seed uint64) uint64 { 89 f := c.data[i] 90 if math.IsNaN(f) && c.equalNullValue == column.NotEqual { 91 // Use a random value here to avoid hash collisions when 92 // we don't consider null to equal null. 93 return rand.Uint64() 94 } 95 96 bits := math.Float64bits(c.data[i]) 97 b := (*[8]byte)(unsafe.Pointer(&bits))[:] 98 return hash.HashBytes(b, seed) 99 } 100 101 func (c Column) filterBuiltIn(index index.Int, comparator string, comparatee interface{}, bIndex index.Bool) error { 102 switch t := comparatee.(type) { 103 case float64: 104 if math.IsNaN(t) { 105 return qerrors.New("filter float", "NaN not allowed as filter argument") 106 } 107 108 compFunc, ok := filterFuncs1[comparator] 109 if !ok { 110 return qerrors.New("filter float", "invalid comparison operator to single argument filter, %v", comparator) 111 } 112 compFunc(index, c.data, t, bIndex) 113 case Column: 114 compFunc, ok := filterFuncs2[comparator] 115 if !ok { 116 return qerrors.New("filter float", "invalid comparison operator to column - column filter, %v", comparator) 117 } 118 compFunc(index, c.data, t.data, bIndex) 119 case nil: 120 compFunc, ok := filterFuncs0[comparator] 121 if !ok { 122 return qerrors.New("filter float", "invalid comparison operator to zero argument filter, %v", comparator) 123 } 124 compFunc(index, c.data, bIndex) 125 default: 126 return qerrors.New("filter float", "invalid comparison value type %v", reflect.TypeOf(comparatee)) 127 } 128 return nil 129 } 130 131 func (c Column) filterCustom1(index index.Int, fn func(float64) bool, bIndex index.Bool) { 132 for i, x := range bIndex { 133 if !x { 134 bIndex[i] = fn(c.data[index[i]]) 135 } 136 } 137 } 138 139 func (c Column) filterCustom2(index index.Int, fn func(float64, float64) bool, comparatee interface{}, bIndex index.Bool) error { 140 otherC, ok := comparatee.(Column) 141 if !ok { 142 return qerrors.New("filter float", "expected comparatee to be float column, was %v", reflect.TypeOf(comparatee)) 143 } 144 145 for i, x := range bIndex { 146 if !x { 147 bIndex[i] = fn(c.data[index[i]], otherC.data[index[i]]) 148 } 149 } 150 151 return nil 152 } 153 154 func (c Column) Filter(index index.Int, comparator interface{}, comparatee interface{}, bIndex index.Bool) error { 155 var err error 156 switch t := comparator.(type) { 157 case string: 158 err = c.filterBuiltIn(index, t, comparatee, bIndex) 159 case func(float64) bool: 160 c.filterCustom1(index, t, bIndex) 161 case func(float64, float64) bool: 162 err = c.filterCustom2(index, t, comparatee, bIndex) 163 default: 164 err = qerrors.New("filter float", "invalid filter type %v", reflect.TypeOf(comparator)) 165 } 166 return err 167 } 168 169 func (c Column) FunctionType() types.FunctionType { 170 return types.FunctionTypeFloat 171 } 172 173 func (c Column) Append(cols ...column.Column) (column.Column, error) { 174 // TODO Append 175 return nil, qerrors.New("Append", "Not implemented yet") 176 }