1 // Licensed to the .NET Foundation under one or more agreements. 2 // The .NET Foundation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System.Xml; 6 using System.Collections; 7 8 namespace System.Data.Common 9 { 10 internal sealed class SingleStorage : DataStorage 11 { 12 private const float defaultValue = 0.0f; 13 14 private float[] _values; 15 SingleStorage(DataColumn column)16 public SingleStorage(DataColumn column) 17 : base(column, typeof(float), defaultValue, StorageType.Single) 18 { 19 } 20 Aggregate(int[] records, AggregateType kind)21 public override object Aggregate(int[] records, AggregateType kind) 22 { 23 bool hasData = false; 24 try 25 { 26 switch (kind) 27 { 28 case AggregateType.Sum: 29 float sum = defaultValue; 30 foreach (int record in records) 31 { 32 if (IsNull(record)) 33 continue; 34 checked { sum += _values[record]; } 35 hasData = true; 36 } 37 if (hasData) 38 { 39 return sum; 40 } 41 return _nullValue; 42 43 case AggregateType.Mean: 44 double meanSum = defaultValue; 45 int meanCount = 0; 46 foreach (int record in records) 47 { 48 if (IsNull(record)) 49 continue; 50 checked { meanSum += _values[record]; } 51 meanCount++; 52 hasData = true; 53 } 54 if (hasData) 55 { 56 float mean; 57 checked { mean = (float)(meanSum / meanCount); } 58 return mean; 59 } 60 return _nullValue; 61 62 case AggregateType.Var: 63 case AggregateType.StDev: 64 int count = 0; 65 double var = defaultValue; 66 double prec = defaultValue; 67 double dsum = defaultValue; 68 double sqrsum = defaultValue; 69 70 foreach (int record in records) 71 { 72 if (IsNull(record)) 73 continue; 74 dsum += _values[record]; 75 sqrsum += _values[record] * (double)_values[record]; 76 count++; 77 } 78 79 if (count > 1) 80 { 81 var = count * sqrsum - (dsum * dsum); 82 prec = var / (dsum * dsum); 83 84 // we are dealing with the risk of a cancellation error 85 // double is guaranteed only for 15 digits so a difference 86 // with a result less than 1e-15 should be considered as zero 87 88 if ((prec < 1e-15) || (var < 0)) 89 var = 0; 90 else 91 var = var / (count * (count - 1)); 92 93 if (kind == AggregateType.StDev) 94 { 95 return Math.Sqrt(var); 96 } 97 return var; 98 } 99 return _nullValue; 100 101 102 case AggregateType.Min: 103 float min = float.MaxValue; 104 for (int i = 0; i < records.Length; i++) 105 { 106 int record = records[i]; 107 if (IsNull(record)) 108 continue; 109 min = Math.Min(_values[record], min); 110 hasData = true; 111 } 112 if (hasData) 113 { 114 return min; 115 } 116 return _nullValue; 117 118 case AggregateType.Max: 119 float max = float.MinValue; 120 for (int i = 0; i < records.Length; i++) 121 { 122 int record = records[i]; 123 if (IsNull(record)) 124 continue; 125 max = Math.Max(_values[record], max); 126 hasData = true; 127 } 128 if (hasData) 129 { 130 return max; 131 } 132 return _nullValue; 133 134 case AggregateType.First: 135 if (records.Length > 0) 136 { 137 return _values[records[0]]; 138 } 139 return null; 140 141 case AggregateType.Count: 142 return base.Aggregate(records, kind); 143 } 144 } 145 catch (OverflowException) 146 { 147 throw ExprException.Overflow(typeof(float)); 148 } 149 throw ExceptionBuilder.AggregateException(kind, _dataType); 150 } 151 Compare(int recordNo1, int recordNo2)152 public override int Compare(int recordNo1, int recordNo2) 153 { 154 float valueNo1 = _values[recordNo1]; 155 float valueNo2 = _values[recordNo2]; 156 157 if (valueNo1 == defaultValue || valueNo2 == defaultValue) 158 { 159 int bitCheck = CompareBits(recordNo1, recordNo2); 160 if (0 != bitCheck) 161 return bitCheck; 162 } 163 return valueNo1.CompareTo(valueNo2); // not simple, checks Nan 164 } 165 CompareValueTo(int recordNo, object value)166 public override int CompareValueTo(int recordNo, object value) 167 { 168 System.Diagnostics.Debug.Assert(0 <= recordNo, "Invalid record"); 169 System.Diagnostics.Debug.Assert(null != value, "null value"); 170 171 if (_nullValue == value) 172 { 173 if (IsNull(recordNo)) 174 { 175 return 0; 176 } 177 return 1; 178 } 179 180 float valueNo1 = _values[recordNo]; 181 if ((defaultValue == valueNo1) && IsNull(recordNo)) 182 { 183 return -1; 184 } 185 return valueNo1.CompareTo((float)value); 186 } 187 ConvertValue(object value)188 public override object ConvertValue(object value) 189 { 190 if (_nullValue != value) 191 { 192 if (null != value) 193 { 194 value = ((IConvertible)value).ToSingle(FormatProvider); 195 } 196 else 197 { 198 value = _nullValue; 199 } 200 } 201 return value; 202 } 203 Copy(int recordNo1, int recordNo2)204 public override void Copy(int recordNo1, int recordNo2) 205 { 206 CopyBits(recordNo1, recordNo2); 207 _values[recordNo2] = _values[recordNo1]; 208 } 209 Get(int record)210 public override object Get(int record) 211 { 212 float value = _values[record]; 213 if (value != defaultValue) 214 { 215 return value; 216 } 217 return GetBits(record); 218 } 219 Set(int record, object value)220 public override void Set(int record, object value) 221 { 222 System.Diagnostics.Debug.Assert(null != value, "null value"); 223 if (_nullValue == value) 224 { 225 _values[record] = defaultValue; 226 SetNullBit(record, true); 227 } 228 else 229 { 230 _values[record] = ((IConvertible)value).ToSingle(FormatProvider); 231 SetNullBit(record, false); 232 } 233 } 234 SetCapacity(int capacity)235 public override void SetCapacity(int capacity) 236 { 237 float[] newValues = new float[capacity]; 238 if (null != _values) 239 { 240 Array.Copy(_values, 0, newValues, 0, Math.Min(capacity, _values.Length)); 241 } 242 _values = newValues; 243 base.SetCapacity(capacity); 244 } 245 ConvertXmlToObject(string s)246 public override object ConvertXmlToObject(string s) 247 { 248 return XmlConvert.ToSingle(s); 249 } 250 ConvertObjectToXml(object value)251 public override string ConvertObjectToXml(object value) 252 { 253 return XmlConvert.ToString((float)value); 254 } 255 GetEmptyStorage(int recordCount)256 protected override object GetEmptyStorage(int recordCount) 257 { 258 return new float[recordCount]; 259 } 260 CopyValue(int record, object store, BitArray nullbits, int storeIndex)261 protected override void CopyValue(int record, object store, BitArray nullbits, int storeIndex) 262 { 263 float[] typedStore = (float[])store; 264 typedStore[storeIndex] = _values[record]; 265 nullbits.Set(storeIndex, IsNull(record)); 266 } 267 SetStorage(object store, BitArray nullbits)268 protected override void SetStorage(object store, BitArray nullbits) 269 { 270 _values = (float[])store; 271 SetNullStorage(nullbits); 272 } 273 } 274 } 275