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