github.com/siglens/siglens@v0.0.0-20240328180423-f7ce9ae441ed/pkg/segment/utils/aggutils.go (about) 1 /* 2 Copyright 2023. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package utils 18 19 import ( 20 "fmt" 21 "math" 22 ) 23 24 func Reduce(e1 CValueEnclosure, e2 CValueEnclosure, fun AggregateFunctions) (CValueEnclosure, error) { 25 26 if e1.Dtype == SS_INVALID { 27 return e2, nil 28 } else if e2.Dtype == SS_INVALID { 29 return e1, nil 30 } else if e2.Dtype == SS_DT_BACKFILL { 31 return e1, nil 32 } else if e1.Dtype == SS_DT_BACKFILL { 33 return e2, nil 34 } 35 36 // cannot reduce with incoming as string 37 if e2.Dtype == SS_DT_STRING { 38 return e1, nil 39 } 40 41 // Convert to float if needed 42 if e1.Dtype == SS_DT_FLOAT && e2.Dtype != SS_DT_FLOAT { 43 switch e2.Dtype { 44 case SS_DT_UNSIGNED_NUM: 45 e2 = CValueEnclosure{Dtype: SS_DT_FLOAT, CVal: float64(e2.CVal.(uint64))} 46 case SS_DT_SIGNED_NUM: 47 e2 = CValueEnclosure{Dtype: SS_DT_FLOAT, CVal: float64(e2.CVal.(int64))} 48 } 49 } 50 51 if e2.Dtype == SS_DT_FLOAT && e1.Dtype != SS_DT_FLOAT { 52 switch e1.Dtype { 53 case SS_DT_UNSIGNED_NUM: 54 e1 = CValueEnclosure{Dtype: SS_DT_FLOAT, CVal: float64(e1.CVal.(uint64))} 55 case SS_DT_SIGNED_NUM: 56 e1 = CValueEnclosure{Dtype: SS_DT_FLOAT, CVal: float64(e1.CVal.(int64))} 57 } 58 } 59 60 // TODO: what if one is int64 and the other is uint64? Is there any way to avoid annoying conversions? 61 62 switch e1.Dtype { 63 case SS_DT_UNSIGNED_NUM: 64 switch fun { 65 case Sum: 66 return CValueEnclosure{Dtype: e1.Dtype, CVal: e1.CVal.(uint64) + e2.CVal.(uint64)}, nil 67 case Min: 68 return CValueEnclosure{Dtype: e1.Dtype, CVal: MinUint64(e1.CVal.(uint64), e2.CVal.(uint64))}, nil 69 case Max: 70 return CValueEnclosure{Dtype: e1.Dtype, CVal: MaxUint64(e1.CVal.(uint64), e2.CVal.(uint64))}, nil 71 case Count: 72 return CValueEnclosure{Dtype: e1.Dtype, CVal: e1.CVal.(uint64) + e2.CVal.(uint64)}, nil 73 } 74 case SS_DT_SIGNED_NUM: 75 switch fun { 76 case Sum: 77 return CValueEnclosure{Dtype: e1.Dtype, CVal: e1.CVal.(int64) + e2.CVal.(int64)}, nil 78 case Min: 79 return CValueEnclosure{Dtype: e1.Dtype, CVal: MinInt64(e1.CVal.(int64), e2.CVal.(int64))}, nil 80 case Max: 81 return CValueEnclosure{Dtype: e1.Dtype, CVal: MaxInt64(e1.CVal.(int64), e2.CVal.(int64))}, nil 82 case Count: 83 return CValueEnclosure{Dtype: e1.Dtype, CVal: e1.CVal.(int64) + e2.CVal.(int64)}, nil 84 } 85 case SS_DT_FLOAT: 86 switch fun { 87 case Sum: 88 return CValueEnclosure{Dtype: e1.Dtype, CVal: e1.CVal.(float64) + e2.CVal.(float64)}, nil 89 case Min: 90 return CValueEnclosure{Dtype: e1.Dtype, CVal: math.Min(e1.CVal.(float64), e2.CVal.(float64))}, nil 91 case Max: 92 return CValueEnclosure{Dtype: e1.Dtype, CVal: math.Max(e1.CVal.(float64), e2.CVal.(float64))}, nil 93 case Count: 94 return CValueEnclosure{Dtype: e1.Dtype, CVal: e1.CVal.(float64) + e2.CVal.(float64)}, nil 95 } 96 case SS_DT_STRING_SET: 97 { 98 switch fun { 99 case Cardinality: 100 fallthrough 101 case Values: 102 set1 := e1.CVal.(map[string]struct{}) 103 set2 := e2.CVal.(map[string]struct{}) 104 for str := range set2 { 105 set1[str] = struct{}{} 106 } 107 return CValueEnclosure{Dtype: e1.Dtype, CVal: set1}, nil 108 } 109 return e1, fmt.Errorf("Reduce: unsupported CVal Dtype: %v", e1.Dtype) 110 } 111 default: 112 return e1, fmt.Errorf("Reduce: unsupported CVal Dtype: %v", e1.Dtype) 113 } 114 return e1, fmt.Errorf("Reduce: unsupported reduce function: %v", fun) 115 } 116 117 func (self *NumTypeEnclosure) ReduceFast(e2Dtype SS_DTYPE, e2int64 int64, 118 e2float64 float64, fun AggregateFunctions) error { 119 120 if self.Ntype == SS_INVALID { // on first node we hit this, and we just use whatever is e2 121 self.Ntype = e2Dtype 122 switch e2Dtype { 123 case SS_DT_UNSIGNED_NUM, SS_DT_SIGNED_NUM: 124 self.IntgrVal = e2int64 125 case SS_DT_FLOAT: 126 self.FloatVal = e2float64 127 } 128 return nil 129 } else if e2Dtype == SS_INVALID { // if e2 is invalid, we live with whats in self 130 return nil 131 } else if e2Dtype == SS_DT_BACKFILL { // cant use e2 so return 132 return nil 133 } else if self.Ntype == SS_DT_BACKFILL { // if the first node happened to be backfill, then we use e2 134 self.Ntype = e2Dtype 135 switch e2Dtype { 136 case SS_DT_UNSIGNED_NUM, SS_DT_SIGNED_NUM: 137 self.IntgrVal = e2int64 138 case SS_DT_FLOAT: 139 self.FloatVal = e2float64 140 } 141 return nil 142 } 143 144 // cannot reduce with incoming as string 145 if e2Dtype == SS_DT_STRING { 146 return nil 147 } 148 149 // if self is float and e2 is not, then convert e2 150 if self.Ntype == SS_DT_FLOAT && e2Dtype != SS_DT_FLOAT { 151 switch e2Dtype { 152 case SS_DT_UNSIGNED_NUM, SS_DT_SIGNED_NUM: 153 e2float64 = float64(e2int64) 154 } 155 } 156 157 // if e2 is float and self is not, then convert self 158 if e2Dtype == SS_DT_FLOAT && self.Ntype != SS_DT_FLOAT { 159 switch self.Ntype { 160 case SS_DT_UNSIGNED_NUM, SS_DT_SIGNED_NUM: 161 self.Ntype = SS_DT_FLOAT 162 self.FloatVal = float64(self.IntgrVal) 163 } 164 } 165 166 // TODO: what if one is int64 and the other is uint64? Is there any way to avoid annoying conversions? 167 // by now both sides are of same type 168 switch self.Ntype { 169 case SS_DT_SIGNED_NUM, SS_DT_UNSIGNED_NUM: 170 switch fun { 171 case Sum: 172 self.IntgrVal = self.IntgrVal + e2int64 173 return nil 174 case Min: 175 self.IntgrVal = MinInt64(self.IntgrVal, e2int64) 176 return nil 177 case Max: 178 self.IntgrVal = MaxInt64(self.IntgrVal, e2int64) 179 return nil 180 case Count: 181 self.IntgrVal = self.IntgrVal + e2int64 182 return nil 183 } 184 case SS_DT_FLOAT: 185 switch fun { 186 case Sum: 187 self.FloatVal = self.FloatVal + e2float64 188 return nil 189 case Min: 190 self.FloatVal = math.Min(self.FloatVal, e2float64) 191 return nil 192 case Max: 193 self.FloatVal = math.Max(self.FloatVal, e2float64) 194 return nil 195 case Count: 196 self.FloatVal = self.FloatVal + e2float64 197 return nil 198 } 199 default: 200 return fmt.Errorf("Reduce: unsupported self CVal Dtype: %v", self.Ntype) 201 } 202 return fmt.Errorf("Reduce: unsupported reduce function: %v", fun) 203 }