• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

f2calv / CasCap.Common / 22972729257

11 Mar 2026 08:22PM UTC coverage: 3.947% (-0.1%) from 4.045%
22972729257

push

github

web-flow
Merge pull request #248 from f2calv/f2calv/2026-03-updates

F2calv/2026 03 updates

4 of 342 branches covered (1.17%)

Branch coverage included in aggregate %.

0 of 29 new or added lines in 5 files covered. (0.0%)

24 existing lines in 3 files now uncovered.

32 of 570 relevant lines covered (5.61%)

0.37 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/CasCap.Common.Extensions/Extensions/ParseExtensions.cs
1
namespace CasCap.Common.Extensions;
2

3
/// <summary>
4
/// Extension methods for parsing strings and numeric types.
5
/// </summary>
6
public static class ParseExtensions
7
{
8
    /// <summary>
9
    /// Returns the number of decimal places in the specified <see cref="double"/> value.
10
    /// </summary>
11
    /// <param name="val">The value to inspect.</param>
12
    /// <returns>The number of decimal places.</returns>
13
    public static int GetDecimalCount(this double val)
14
    {
15
        var i = 0;
×
16
        //Doubles can be rounded to 15 digits max. ref: https://stackoverflow.com/a/33714700/1266873
17
        while (i < 16 && Math.Round(val, i) != val)
×
18
            i++;
×
19
        return i;
×
20
    }
21

22
    /// <summary>
23
    /// Returns the number of decimal places in the specified <see cref="decimal"/> value.
24
    /// </summary>
25
    /// <param name="val">The value to inspect.</param>
26
    /// <returns>The number of decimal places.</returns>
27
    public static int GetDecimalCount(this decimal val)
28
    {
29
        var i = 0;
×
30
        while (Math.Round(val, i) != val)
×
31
            i++;
×
32
        return i;
×
33
    }
34

35
    /// <summary>
36
    /// Returns the number of decimal places in the specified string representation of a number.
37
    /// </summary>
38
    /// <param name="val">The string value to inspect.</param>
39
    /// <returns>The number of decimal places.</returns>
40
    public static int GetDecimalCount(this string val)
41
    {
42
        var s = val.ToString();
×
43
        var dot = s.IndexOf('.');
×
44
        if (dot == -1)
×
45
            return 0;
×
46
        else
47
            return s.Length - dot;
×
48
    }
49

50
#if NET8_0_OR_GREATER
51
    /// <summary>
52
    /// Returns the number of decimal places in the specified <see cref="System.Numerics.INumber{T}"/> value.
53
    /// </summary>
54
    /// <typeparam name="T">A numeric type implementing <see cref="System.Numerics.INumber{T}"/>.</typeparam>
55
    /// <param name="val">The value to inspect.</param>
56
    /// <returns>The number of decimal places.</returns>
57
    public static int GetDecimalCount<T>(this T val)
58
        where T : INumber<T>
59
    {
60
        return val.ToString()!.GetDecimalCount();
×
61
    }
62
#endif
63

64
    /// <summary>
65
    /// Use when converting a DateTime value from a string to an actual DateTime.
66
    /// </summary>
67
    /// <param name="f">supports 1) Ticks, 2) ISO 8601 &amp; 3) Time without the Date</param>
68
    /// <param name="date">Pass in the DateOnly here when Ticks string dosn't contain it for brevity.</param>
69
    /// <param name="kind">The <see cref="DateTimeKind"/> to assign to the resulting <see cref="DateTime"/>.</param>
70
    public static DateTime CsvStr2Date(this string f, DateTime? date = null, DateTimeKind kind = DateTimeKind.Utc)
71
    {
72
        DateTime dt;
73
        if (f.Length == 18)//"635990653080800000".Length
×
NEW
74
            dt = new DateTime(f.Decimal2Long(), kind);
×
75
        else if (f.Length == 23 && DateTime.TryParse(f, out var _dt1))//"yyyy-MM-dd HH:mm:ss.fff".Length
×
76
            dt = _dt1;
×
77
        else if (f.Length == 14)//"63599065308080".Length
×
NEW
78
            dt = new DateTime(f.Decimal2Long(4), kind);
×
79
        else if (f.Length == 12 && date.HasValue && DateTime.TryParse(date.Value.To_yyyy_MM_dd() + " " + f, out var _dt2))//"HH:mm:ss.fff".Length
×
80
            dt = _dt2;
×
81
        else
82
            throw new NotSupportedException("invalid date format string");
×
83
        return dt;
×
84
    }
85

86
    /// <summary>
87
    /// Converts a <see cref="DateTime"/> to its tick count string representation.
88
    /// </summary>
89
    /// <param name="date">The date to convert.</param>
90
    /// <returns>The tick count as a string.</returns>
NEW
91
    public static string CsvDate2Str(this DateTime date) => date.Ticks.ToString();
×
92

93
    private const char _zero = '0';
94

95
    /// <summary>
96
    /// When you know the input value is a string-ified decimal this is the fastest way to parse
97
    /// that string into the equivalent number.
98
    /// </summary>
99
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
100
    public static int Decimal2Int(this string input, int exp = 0)
101
    {
102
        //Debug.WriteLine($"input={input}, input.Length={input.Length}, dp={dp}");
103
        var decimalExists = false;
×
104
        var output = 0;
×
105
        for (var i = 0; i < input.Length; i++)
×
106
        {
107
            var digit = input[i];
×
108
            if (digit != 46)
×
109
            {
110
                output = output * 10 + (digit - _zero);
×
111
                if (decimalExists)
×
112
                {
113
                    //there are decimal places so reduce the dp value accordingly
114
                    exp--;
×
115
                    if (exp == 0) break;
×
116
                }
117
            }
118
            else
119
            {
120
                decimalExists = true;
×
121
                if (exp == 0) break;//we don't care about anything after the decimal point
×
122
                                    //var strLenRemaining = input.Length - 1 - i;
123
                                    //Debug.WriteLine($"decimalPos={decimalPos}, strLenRemaining={strLenRemaining}");
124
            }
125
            //Debug.WriteLine($"index i={i}, output={output}");
126
        }
127
        output = exp switch
×
128
        {
×
129
            0 => output,
×
130
            1 => output *= 10,
×
131
            2 => output *= 100,
×
132
            3 => output *= 1000,
×
133
            4 => output *= 10000,
×
134
            _ => output *= Pow(exp)
×
135
        };
×
136
        //Debug.WriteLine($"output={output}");
137
        return output;
×
138
    }
139

140
    /// <summary>
141
    /// Parses the input string as a <see cref="decimal"/>.
142
    /// </summary>
143
    /// <param name="input">The string to parse.</param>
144
    /// <returns>The parsed decimal value.</returns>
145
    public static decimal String2Decimal(this string input)//TODO: make this fast and not just a bog standard decimal.TryParse
146
    {
147
        if (decimal.TryParse(input, out decimal val))
×
148
            return val;
×
149
        else
NEW
150
            throw new GenericException($"{nameof(String2Decimal)} issue! :/");
×
151
    }
152

153
    /// <summary>
154
    /// Fast parser that converts a string-ified decimal to its <see cref="long"/> equivalent.
155
    /// </summary>
156
    /// <param name="input">The string to parse.</param>
157
    /// <param name="exp">The exponent (number of decimal places to shift).</param>
158
    /// <returns>The parsed long value.</returns>
159
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
160
    public static long Decimal2Long(this string input, int exp = 0)
161
    {
162
        //Debug.WriteLine($"input={input}, input.Length={input.Length}, dp={dp}");
163
        var decimalExists = false;
×
164
        var output = 0L;
×
165
        for (var i = 0; i < input.Length; i++)
×
166
        {
167
            var digit = input[i];
×
168
            if (digit != 46)
×
169
            {
170
                output = output * 10 + (digit - _zero);
×
171
                if (decimalExists)
×
172
                {
173
                    //there are decimal places so reduce the dp value accordingly
174
                    exp--;
×
175
                    if (exp == 0) break;
×
176
                }
177
            }
178
            else
179
            {
180
                decimalExists = true;
×
181
                if (exp == 0) break;//we don't care about anything after the decimal point
×
182
                                    //var strLenRemaining = input.Length - 1 - i;
183
                                    //Debug.WriteLine($"decimalPos={decimalPos}, strLenRemaining={strLenRemaining}");
184
            }
185
            //Debug.WriteLine($"index i={i}, output={output}");
186
        }
187
        output = exp switch
×
188
        {
×
189
            0 => output,
×
190
            1 => output *= 10,
×
191
            2 => output *= 100,
×
192
            3 => output *= 1000,
×
193
            4 => output *= 10000,
×
194
            _ => output *= Pow(exp)
×
195
        };
×
196
        //Debug.WriteLine($"output={output}");
197
        return output;
×
198
    }
199

200
    /// <summary>
201
    /// Converts an <see cref="int"/> to a <see cref="decimal"/> by dividing by 10^exp.
202
    /// </summary>
203
    /// <param name="input">The integer input.</param>
204
    /// <param name="exp">The exponent to divide by.</param>
205
    /// <returns>The resulting decimal value.</returns>
206
    public static decimal Int2Decimal(this int input, int exp = 0)//uses of this should be *very* limited
207
    {
208
        if (exp > 0)
×
209
            return input / (decimal)Pow(exp);
×
210
        else
211
            return input;
×
212
    }
213

214
    /// <summary>
215
    /// Converts an <see cref="int"/> to a <see cref="double"/> by dividing by 10^exp.
216
    /// </summary>
217
    /// <param name="input">The integer input.</param>
218
    /// <param name="exp">The exponent to divide by.</param>
219
    /// <returns>The resulting double value.</returns>
220
    public static double Int2Double(this int input, int exp = 0)
221
    {
222
        if (exp > 0)
×
223
            return input / (double)Pow(exp);
×
224
        else
225
            return input;
×
226
    }
227

228
    //this will be faster than the bitmask variant below
229
    private static int Pow(int exp) => exp switch
×
230
    {
×
231
        0 => exp,
×
232
        1 => exp *= 10,
×
233
        2 => exp *= 100,
×
234
        3 => exp *= 1000,
×
235
        4 => exp *= 10000,
×
236
        _ => exp *= Pow(exp)
×
237
    };
×
238

239
    //https://stackoverflow.com/questions/2065249/c-sharp-efficient-algorithm-integer-based-power-function
240
    //https://stackoverflow.com/questions/936541/math-pow-vs-multiply-operator-performance (slightly wrong)
241
    private static int Pow(int exp, int num/* = 10*/)
242
    {
243
        var result = 1;
×
244
        while (exp > 0)
×
245
        {
246
            if ((exp & 1) != 0)
×
247
                result *= num;
×
248
            exp >>= 1;
×
249
            num *= num;
×
250
        }
251
        return result;
×
252
    }
253
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc