< Summary

Information
Class: ArturRios.Util.Math.PrimeGenerator<T>
Assembly: ArturRios.Util
File(s): D:\Repositories\dotnet-util\src\Math\PrimeGenerator.cs
Line coverage
59%
Covered lines: 134
Uncovered lines: 92
Coverable lines: 226
Total lines: 353
Line coverage: 59.2%
Branch coverage
65%
Covered branches: 82
Total branches: 126
Branch coverage: 65%
Method coverage
100%
Covered methods: 7
Fully covered methods: 0
Total methods: 7
Method coverage: 100%
Full method coverage: 0%

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor()100%11100%
Next()100%22100%
ValidateSupportedType()100%1818100%
GetStartValue()72.22%271870%
Increment(...)52.94%1723450.79%
EnsureAtLeastTwo(...)50%2903641.89%
IsPrime(...)72.22%271870%

File(s)

D:\Repositories\dotnet-util\src\Math\PrimeGenerator.cs

#LineLine coverage
 1using System.Numerics;
 2
 3namespace ArturRios.Util.Math;
 4
 5/// <summary>
 6/// A generic prime number generator that generates primes of a specified integer type.
 7/// Create an instance to get an independent sequence of primes.
 8/// </summary>
 9/// <typeparam name="T">The integer type to generate primes for. Supported types: sbyte, byte, short, ushort, int, uint,
 10public class PrimeGenerator<T> where T : struct
 11{
 12    private T _current;
 913    private readonly Lock _lock = new();
 14
 15    /// <summary>
 16    /// Initializes a new instance of the <see cref="PrimeGenerator{T}"/> class.
 17    /// </summary>
 18    /// <exception cref="ArgumentException">Thrown if T is not a supported integer type.</exception>
 919    public PrimeGenerator()
 920    {
 921        ValidateSupportedType();
 822        _current = GetStartValue();
 823    }
 24
 25    /// <summary>
 26    /// Returns the next prime in the sequence (2, 3, 5, 7, ...).
 27    /// Thread-safe.
 28    /// </summary>
 29    /// <returns>The next prime number of type T.</returns>
 30    /// <exception cref="OverflowException">Thrown when the next prime exceeds the maximum value for type T.</exception>
 31    public T Next()
 7832    {
 33        lock (_lock)
 7834        {
 7835            var candidate = Increment(_current);
 7736            EnsureAtLeastTwo(ref candidate);
 37
 24538            while (!IsPrime(candidate))
 16839            {
 16840                candidate = Increment(candidate);
 16841            }
 42
 7743            _current = candidate;
 7744            return candidate;
 45        }
 7746    }
 47
 48    /// <summary>
 49    /// Validates that T is one of the supported integer types.
 50    /// </summary>
 51    /// <exception cref="ArgumentException">Thrown if T is not a supported type.</exception>
 52    private static void ValidateSupportedType()
 953    {
 954        var typeOfT = typeof(T);
 955        if (typeOfT != typeof(sbyte) && typeOfT != typeof(byte) &&
 956            typeOfT != typeof(short) && typeOfT != typeof(ushort) &&
 957            typeOfT != typeof(int) && typeOfT != typeof(uint) &&
 958            typeOfT != typeof(long) && typeOfT != typeof(ulong) &&
 959            typeOfT != typeof(BigInteger))
 160        {
 161            throw new ArgumentException(
 162                $"Type '{typeof(T).Name}' is not supported for PrimeGenerator. " +
 163                $"Supported types are: sbyte, byte, short, ushort, int, uint, long, ulong, and BigInteger.");
 64        }
 865    }
 66
 67    /// <summary>
 68    /// Gets the starting value (one less than the first prime).
 69    /// </summary>
 70    private static T GetStartValue()
 871    {
 872        if (typeof(T) == typeof(sbyte))
 173        {
 174            return (T)(object)(sbyte)1;
 75        }
 76
 777        if (typeof(T) == typeof(byte))
 178        {
 179            return (T)(object)(byte)1;
 80        }
 81
 682        if (typeof(T) == typeof(short))
 083        {
 084            return (T)(object)(short)1;
 85        }
 86
 687        if (typeof(T) == typeof(ushort))
 088        {
 089            return (T)(object)(ushort)1;
 90        }
 91
 692        if (typeof(T) == typeof(int))
 493        {
 494            return (T)(object)1;
 95        }
 96
 297        if (typeof(T) == typeof(uint))
 098        {
 099            return (T)(object)1U;
 100        }
 101
 2102        if (typeof(T) == typeof(long))
 1103        {
 1104            return (T)(object)1L;
 105        }
 106
 1107        if (typeof(T) == typeof(ulong))
 0108        {
 0109            return (T)(object)1UL;
 110        }
 111
 1112        if (typeof(T) == typeof(BigInteger))
 1113        {
 1114            return (T)(object)BigInteger.One;
 115        }
 116
 0117        throw new InvalidOperationException("Unexpected type in GetStartValue");
 8118    }
 119
 120    /// <summary>
 121    /// Increments the given value by one, throwing on overflow.
 122    /// </summary>
 123    private static T Increment(T value)
 246124    {
 246125        if (typeof(T) == typeof(sbyte))
 127126        {
 127127            var sbyteValue = (sbyte)(object)value;
 127128            if (sbyteValue == sbyte.MaxValue)
 1129            {
 1130                throw new OverflowException($"Cannot increment beyond maximum value for {typeof(T).Name}");
 131            }
 132
 126133            return (T)(object)(sbyte)(sbyteValue + 1);
 134        }
 135
 119136        if (typeof(T) == typeof(byte))
 28137        {
 28138            var byteValue = (byte)(object)value;
 28139            if (byteValue == byte.MaxValue)
 0140            {
 0141                throw new OverflowException($"Cannot increment beyond maximum value for {typeof(T).Name}");
 142            }
 143
 28144            return (T)(object)(byte)(byteValue + 1);
 145        }
 146
 91147        if (typeof(T) == typeof(short))
 0148        {
 0149            var shortValue = (short)(object)value;
 0150            if (shortValue == short.MaxValue)
 0151            {
 0152                throw new OverflowException($"Cannot increment beyond maximum value for {typeof(T).Name}");
 153            }
 154
 0155            return (T)(object)(short)(shortValue + 1);
 156        }
 157
 91158        if (typeof(T) == typeof(ushort))
 0159        {
 0160            var ushortValue = (ushort)(object)value;
 0161            if (ushortValue == ushort.MaxValue)
 0162            {
 0163                throw new OverflowException($"Cannot increment beyond maximum value for {typeof(T).Name}");
 164            }
 165
 0166            return (T)(object)(ushort)(ushortValue + 1);
 167        }
 168
 91169        if (typeof(T) == typeof(int))
 35170        {
 35171            var intValue = (int)(object)value;
 35172            if (intValue == int.MaxValue)
 0173            {
 0174                throw new OverflowException($"Cannot increment beyond maximum value for {typeof(T).Name}");
 175            }
 176
 35177            return (T)(object)(intValue + 1);
 178        }
 179
 56180        if (typeof(T) == typeof(uint))
 0181        {
 0182            var uintValue = (uint)(object)value;
 0183            if (uintValue == uint.MaxValue)
 0184            {
 0185                throw new OverflowException($"Cannot increment beyond maximum value for {typeof(T).Name}");
 186            }
 187
 0188            return (T)(object)(uintValue + 1U);
 189        }
 190
 56191        if (typeof(T) == typeof(long))
 28192        {
 28193            var longValue = (long)(object)value;
 28194            if (longValue == long.MaxValue)
 0195            {
 0196                throw new OverflowException($"Cannot increment beyond maximum value for {typeof(T).Name}");
 197            }
 198
 28199            return (T)(object)(longValue + 1L);
 200        }
 201
 28202        if (typeof(T) == typeof(ulong))
 0203        {
 0204            var ulongValue = (ulong)(object)value;
 0205            if (ulongValue == ulong.MaxValue)
 0206            {
 0207                throw new OverflowException($"Cannot increment beyond maximum value for {typeof(T).Name}");
 208            }
 209
 0210            return (T)(object)(ulongValue + 1UL);
 211        }
 212
 28213        if (typeof(T) == typeof(BigInteger))
 28214        {
 28215            var bigIntegerValue = (BigInteger)(object)value;
 28216            return (T)(object)(bigIntegerValue + BigInteger.One);
 217        }
 218
 0219        throw new InvalidOperationException("Unexpected type in Increment");
 245220    }
 221
 222    /// <summary>
 223    /// Ensures the candidate is at least 2 (the first prime).
 224    /// </summary>
 225    private static void EnsureAtLeastTwo(ref T candidate)
 77226    {
 77227        if (typeof(T) == typeof(sbyte))
 31228        {
 31229            var sbyteValue = (sbyte)(object)candidate;
 31230            if (sbyteValue < 2)
 0231            {
 0232                candidate = (T)(object)(sbyte)2;
 0233            }
 31234        }
 46235        else if (typeof(T) == typeof(byte))
 10236        {
 10237            var byteValue = (byte)(object)candidate;
 10238            if (byteValue < 2)
 0239            {
 0240                candidate = (T)(object)(byte)2;
 0241            }
 10242        }
 36243        else if (typeof(T) == typeof(short))
 0244        {
 0245            var shortValue = (short)(object)candidate;
 0246            if (shortValue < 2)
 0247            {
 0248                candidate = (T)(object)(short)2;
 0249            }
 0250        }
 36251        else if (typeof(T) == typeof(ushort))
 0252        {
 0253            var ushortValue = (ushort)(object)candidate;
 0254            if (ushortValue < 2)
 0255            {
 0256                candidate = (T)(object)(ushort)2;
 0257            }
 0258        }
 36259        else if (typeof(T) == typeof(int))
 16260        {
 16261            var intValue = (int)(object)candidate;
 16262            if (intValue < 2)
 0263            {
 0264                candidate = (T)(object)2;
 0265            }
 16266        }
 20267        else if (typeof(T) == typeof(uint))
 0268        {
 0269            var uintValue = (uint)(object)candidate;
 0270            if (uintValue < 2)
 0271            {
 0272                candidate = (T)(object)2U;
 0273            }
 0274        }
 20275        else if (typeof(T) == typeof(long))
 10276        {
 10277            var longValue = (long)(object)candidate;
 10278            if (longValue < 2)
 0279            {
 0280                candidate = (T)(object)2L;
 0281            }
 10282        }
 10283        else if (typeof(T) == typeof(ulong))
 0284        {
 0285            var ulongValue = (ulong)(object)candidate;
 0286            if (ulongValue < 2)
 0287            {
 0288                candidate = (T)(object)2UL;
 0289            }
 0290        }
 10291        else if (typeof(T) == typeof(BigInteger))
 10292        {
 10293            var bigIntegerValue = (BigInteger)(object)candidate;
 10294            if (bigIntegerValue < BigInteger.One + BigInteger.One)
 0295            {
 0296                candidate = (T)(object)(BigInteger.One + BigInteger.One);
 0297            }
 10298        }
 77299    }
 300
 301    /// <summary>
 302    /// Tests if the candidate is prime using PrimeUtils.IsPrimeNumber.
 303    /// </summary>
 304    private static bool IsPrime(T candidate)
 245305    {
 245306        if (typeof(T) == typeof(sbyte))
 126307        {
 126308            return PrimeUtils.IsPrimeNumber((sbyte)(object)candidate);
 309        }
 310
 119311        if (typeof(T) == typeof(byte))
 28312        {
 28313            return PrimeUtils.IsPrimeNumber((byte)(object)candidate);
 314        }
 315
 91316        if (typeof(T) == typeof(short))
 0317        {
 0318            return PrimeUtils.IsPrimeNumber((short)(object)candidate);
 319        }
 320
 91321        if (typeof(T) == typeof(ushort))
 0322        {
 0323            return PrimeUtils.IsPrimeNumber((ushort)(object)candidate);
 324        }
 325
 91326        if (typeof(T) == typeof(int))
 35327        {
 35328            return PrimeUtils.IsPrimeNumber((int)(object)candidate);
 329        }
 330
 56331        if (typeof(T) == typeof(uint))
 0332        {
 0333            return PrimeUtils.IsPrimeNumber((uint)(object)candidate);
 334        }
 335
 56336        if (typeof(T) == typeof(long))
 28337        {
 28338            return PrimeUtils.IsPrimeNumber((long)(object)candidate);
 339        }
 340
 28341        if (typeof(T) == typeof(ulong))
 0342        {
 0343            return PrimeUtils.IsPrimeNumber((ulong)(object)candidate);
 344        }
 345
 28346        if (typeof(T) == typeof(BigInteger))
 28347        {
 28348            return PrimeUtils.IsPrimeNumber((BigInteger)(object)candidate);
 349        }
 350
 0351        throw new InvalidOperationException("Unexpected type in IsPrime");
 245352    }
 353}