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 SByteStorage : DataStorage
11     {
12         private const sbyte defaultValue = 0;
13 
14         private sbyte[] _values;
15 
SByteStorage(DataColumn column)16         public SByteStorage(DataColumn column)
17         : base(column, typeof(sbyte), defaultValue, StorageType.SByte)
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                         long 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                         long 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                             sbyte mean;
57                             checked { mean = (sbyte)(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                     case AggregateType.Min:
102                         sbyte min = sbyte.MaxValue;
103                         for (int i = 0; i < records.Length; i++)
104                         {
105                             int record = records[i];
106                             if (IsNull(record))
107                                 continue;
108                             min = Math.Min(_values[record], min);
109                             hasData = true;
110                         }
111                         if (hasData)
112                         {
113                             return min;
114                         }
115                         return _nullValue;
116 
117                     case AggregateType.Max:
118                         sbyte max = sbyte.MinValue;
119                         for (int i = 0; i < records.Length; i++)
120                         {
121                             int record = records[i];
122                             if (IsNull(record))
123                                 continue;
124                             max = Math.Max(_values[record], max);
125                             hasData = true;
126                         }
127                         if (hasData)
128                         {
129                             return max;
130                         }
131                         return _nullValue;
132 
133                     case AggregateType.First:
134                         if (records.Length > 0)
135                         {
136                             return _values[records[0]];
137                         }
138                         return null;
139 
140                     case AggregateType.Count:
141                         return base.Aggregate(records, kind);
142                 }
143             }
144             catch (OverflowException)
145             {
146                 throw ExprException.Overflow(typeof(sbyte));
147             }
148             throw ExceptionBuilder.AggregateException(kind, _dataType);
149         }
150 
Compare(int recordNo1, int recordNo2)151         public override int Compare(int recordNo1, int recordNo2)
152         {
153             sbyte valueNo1 = _values[recordNo1];
154             sbyte valueNo2 = _values[recordNo2];
155 
156             if (valueNo1.Equals(defaultValue) || valueNo2.Equals(defaultValue))
157             {
158                 int bitCheck = CompareBits(recordNo1, recordNo2);
159                 if (0 != bitCheck)
160                     return bitCheck;
161             }
162             return valueNo1.CompareTo(valueNo2);
163             //return(valueNo1 - valueNo2); // copied from SByte.CompareTo(SByte)
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             sbyte valueNo1 = _values[recordNo];
181             if ((defaultValue == valueNo1) && IsNull(recordNo))
182             {
183                 return -1;
184             }
185             return valueNo1.CompareTo((sbyte)value);
186             //return(valueNo1 - valueNo2); // copied from SByte.CompareTo(SByte)
187         }
188 
ConvertValue(object value)189         public override object ConvertValue(object value)
190         {
191             if (_nullValue != value)
192             {
193                 if (null != value)
194                 {
195                     value = ((IConvertible)value).ToSByte(FormatProvider);
196                 }
197                 else
198                 {
199                     value = _nullValue;
200                 }
201             }
202             return value;
203         }
204 
Copy(int recordNo1, int recordNo2)205         public override void Copy(int recordNo1, int recordNo2)
206         {
207             CopyBits(recordNo1, recordNo2);
208             _values[recordNo2] = _values[recordNo1];
209         }
210 
Get(int record)211         public override object Get(int record)
212         {
213             sbyte value = _values[record];
214             if (!value.Equals(defaultValue))
215             {
216                 return value;
217             }
218             return GetBits(record);
219         }
220 
Set(int record, object value)221         public override void Set(int record, object value)
222         {
223             System.Diagnostics.Debug.Assert(null != value, "null value");
224             if (_nullValue == value)
225             {
226                 _values[record] = defaultValue;
227                 SetNullBit(record, true);
228             }
229             else
230             {
231                 _values[record] = ((IConvertible)value).ToSByte(FormatProvider);
232                 SetNullBit(record, false);
233             }
234         }
235 
SetCapacity(int capacity)236         public override void SetCapacity(int capacity)
237         {
238             sbyte[] newValues = new sbyte[capacity];
239             if (null != _values)
240             {
241                 Array.Copy(_values, 0, newValues, 0, Math.Min(capacity, _values.Length));
242             }
243             _values = newValues;
244             base.SetCapacity(capacity);
245         }
246 
ConvertXmlToObject(string s)247         public override object ConvertXmlToObject(string s)
248         {
249             return XmlConvert.ToSByte(s);
250         }
251 
ConvertObjectToXml(object value)252         public override string ConvertObjectToXml(object value)
253         {
254             return XmlConvert.ToString((sbyte)value);
255         }
256 
GetEmptyStorage(int recordCount)257         protected override object GetEmptyStorage(int recordCount)
258         {
259             return new sbyte[recordCount];
260         }
261 
CopyValue(int record, object store, BitArray nullbits, int storeIndex)262         protected override void CopyValue(int record, object store, BitArray nullbits, int storeIndex)
263         {
264             sbyte[] typedStore = (sbyte[])store;
265             typedStore[storeIndex] = _values[record];
266             nullbits.Set(storeIndex, IsNull(record));
267         }
268 
SetStorage(object store, BitArray nullbits)269         protected override void SetStorage(object store, BitArray nullbits)
270         {
271             _values = (sbyte[])store;
272             SetNullStorage(nullbits);
273         }
274     }
275 }
276