henriqueprj / BrTypes

Estruturas de dados comumente utilizados no Brasil
MIT License
3 stars 2 forks source link

Implementar 'UF' considerando códigos IBGE #11

Open henriqueprj opened 4 years ago

henriqueprj commented 4 years ago

Este é uma idéia de implementação. O que acham?

    [Serializable]
    public readonly struct UF : IEquatable<UF>
    {
        private readonly byte _uf;

        /// <summary>
        /// Representa uma UF vazia.
        /// </summary>
        public static readonly UF Empty = new UF();

        private UF(byte uf)
        {
            _uf = uf;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private static byte GetCodigoIbge(int value) =>
            value switch
            {
                // MT
                7784 => (byte)CodigoIbge.MT,
                _ => 0
            };

        public static bool TryParse(string s, out UF result)
        {
            if (s == null || s.Length != 2)
            {
                result = default;
                return false;
            }

            var b1 = ToUpperOrZero(s[0]);
            var b2 = ToUpperOrZero(s[1]);
            var r = b1 * 100 + b2;

            var codigoIbge = GetCodigoIbge(r);
            if (codigoIbge == 0)
            {
                result = default;
                return false;
            }

            result = new UF(codigoIbge);
            return true;
        }

        public static UF Parse(string s)
        {
            if (!TryParse(s, out var uf))
                throw new UFInvalidaException(s);
            return uf;
        }

        private static char ToUpperOrZero(char c)
        {
            if (c >= 'a' && c <= 'z')
                return (char) (c - 32);

            if (c >= 'A' && c <= 'Z')
                return c;

            return '\0';
        }

        public override int GetHashCode()
        {
            return _uf.GetHashCode();
        }

        public override string ToString()
        {
            return ((CodigoIbge) _uf).ToString();
        }

        public bool Equals(UF other)
        {
            return _uf == other._uf;
        }

        public override bool Equals(object obj)
        {
            return obj is UF other && Equals(other);
        }

        public static bool operator ==(UF left, UF right)
        {
            return left.Equals(right);
        }

        public static bool operator !=(UF left, UF right)
        {
            return !left.Equals(right);
        }

        public static implicit operator UF(string uf) => Parse(uf);
    }

Sem alocações! ~36 ms para 1M de iterações.