Stephen JenksFix warnings91cf67c8 years agoHistory
566 lines · 24.5 KB · C#
RawDownload
//******************************************************************************************************//  RadixCodec.cs - Gbtc////  Copyright © 2017, Grid Protection Alliance.  All Rights Reserved.////  Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See//  the NOTICE file distributed with this work for additional information regarding copyright ownership.//  The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this//  file except in compliance with the License. You may obtain a copy of the License at:////      http://opensource.org/licenses/MIT////  Unless agreed to in writing, the subject software distributed under the License is distributed on an//  "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the//  License for the specific language governing permissions and limitations.////  Code Modification History://  ----------------------------------------------------------------------------------------------------//  08/11/2017 - Ritchie Carroll//       Generated original version of source code.////****************************************************************************************************** using System;using System.Diagnostics.CodeAnalysis; namespace GSF{    /// <summary>    /// Represents a radix value codec for conversion of base-10 integer values to and from other base values.    /// </summary>    /// <remarks>    /// The primary use case of this class is to provide compact string encodings of integer values.    /// The encodings produced by this class do not manage arbitrary sized bytes arrays, nor do they    /// include padding - as a result, encodings are not intended to comply with RFC 3548.    /// </remarks>    public class RadixCodec    {        #region [ Members ]         // Nested Types        private class RadixIntegerCodec<T> where T : IComparable<T>, IEquatable<T>        {            #region [ Members ]             private readonly RadixCodec m_parent;            private readonly bool m_caseSensitive;            private readonly int m_bitSize;            private readonly T m_minValue;            private readonly T m_zeroValue;            private readonly Func<T, T> m_abs;            private readonly Func<T, int, int> m_mod;            private readonly Func<T, int, T> m_divide;            private readonly Func<long, bool, T> m_convert;            private readonly string m_minRadix;             #endregion             #region [ Constructors ]             public RadixIntegerCodec(RadixCodec parent, bool caseSensitive, int bitSize, T minValue, T zeroValue, Func<T, T> abs, Func<T, int, int> mod, Func<T, int, T> divide, Func<long, bool, T> convert, string minRadix = null)            {                m_parent = parent;                m_caseSensitive = caseSensitive;                m_bitSize = bitSize;                m_minValue = minValue;                m_zeroValue = zeroValue;                m_abs = abs;                m_mod = mod;                m_divide = divide;                m_convert = convert;                m_minRadix = minRadix ?? Encode(minValue);            }             #endregion             #region [ Methods ]             public T Decode(string value)            {                if (string.IsNullOrWhiteSpace(value))                    throw new ArgumentNullException(nameof(value));                 bool isNegative = false;                long result = 0;                long multiplier = 1;                int radix = m_parent.Digits.Length;                 value = value.Trim();                 if (!m_caseSensitive)                    value = value.ToUpperInvariant();                 for (int i = value.Length - 1; i >= 0; i--)                {                    if (i == 0 && value[i] == '-')                    {                        isNegative = true;                        break;                    }                     int digit = m_parent.Digits.IndexOf(value[i]);                     if (digit == -1)                        throw new ArgumentException($"Invalid characters in radix-{m_parent.Digits.Length} value: \"{value}\".", nameof(value));                     result += digit * multiplier;                    multiplier *= radix;                }                 return m_convert(result, isNegative);            }             public string Encode(T value)            {                // Check for minimum T value, this avoids a Math.Abs exception:                // "Negating the minimum value of a twos complement number is invalid."                if (value.Equals(m_minValue) && m_minValue.CompareTo(m_zeroValue) < 0)                    return m_minRadix;                 bool isNegative = value.CompareTo(m_zeroValue) < 0;                char[] buffer = new char[m_bitSize];                int index = m_bitSize - 1;                int radix = m_parent.Digits.Length;                 value = m_abs(value);                 do                    buffer[index--] = m_parent.Digits[m_mod(value, radix)];                while ((value = m_divide(value, radix)).CompareTo(m_zeroValue) != 0);                 string result = new string(buffer, index + 1, m_bitSize - index - 1);                 if (isNegative)                    result = $"-{result}";                 return result;            }             #endregion        }         // Fields         /// <summary>        /// Defines the available digits for a radix value codec.        /// </summary>        public readonly string Digits;         private readonly RadixIntegerCodec<short> m_int16;        private readonly RadixIntegerCodec<ushort> m_uint16;        private readonly RadixIntegerCodec<Int24> m_int24;        private readonly RadixIntegerCodec<UInt24> m_uint24;        private readonly RadixIntegerCodec<int> m_int32;        private readonly RadixIntegerCodec<uint> m_uint32;        private readonly RadixIntegerCodec<long> m_int64;        private readonly RadixIntegerCodec<ulong> m_uint64;         #endregion         #region [ Constructors ]         /// <summary>        /// Creates a new <see cref="RadixCodec"/>.        /// </summary>        /// <param name="digits">Digits to use for radix values.</param>        /// <param name="caseSensitive">Determines if alphabetic radix characters are case sensitive.</param>        [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]        public RadixCodec(string digits, bool caseSensitive)        {            if (string.IsNullOrWhiteSpace(digits))                throw new ArgumentNullException(nameof(digits));             if (digits.Length < 2)                throw new ArgumentOutOfRangeException(nameof(digits), "Minimum of 2 characters required for radix value digits.");             Digits = digits;             // ReSharper disable once PossibleLossOfFraction            RadixIntegerCodec<decimal> int96 = new RadixIntegerCodec<decimal>(this, caseSensitive, 64, decimal.MinValue, 0, Math.Abs, (i, d) => (int)(i % d), (i, d) => (ulong)i / (ulong)d, (v, n) => n ? -v : v);            m_int64 = new RadixIntegerCodec<long>(this, caseSensitive, 64, long.MinValue, 0L, Math.Abs, (i, d) => (int)(i % d), (i, d) => i / d, (v, n) => n ? -v : v, int96.Encode(long.MinValue));            m_uint64 = new RadixIntegerCodec<ulong>(this, caseSensitive, 64, ulong.MinValue, 0UL, i => i, (i, d) => (int)(i % (ulong)d), (i, d) => i / (ulong)d, (v, n) => (ulong)(n ? -v : v));            m_int32 = new RadixIntegerCodec<int>(this, caseSensitive, 32, int.MinValue, 0, Math.Abs, (i, d) => i % d, (i, d) => i / d, (v, n) => (int)(n ? -v : v), m_int64.Encode(int.MinValue));            m_uint32 = new RadixIntegerCodec<uint>(this, caseSensitive, 32, uint.MinValue, 0U, i => i, (i, d) => (int)(i % (uint)d), (i, d) => i / (uint)d, (v, n) => (uint)(n ? -v : v));            m_int24 = new RadixIntegerCodec<Int24>(this, caseSensitive, 24, Int24.MinValue, 0, i => (Int24)Math.Abs(i), (i, d) => i % d, (i, d) => (Int24)(i / d), (v, n) => (Int24)(n ? -v : v), m_int32.Encode(Int24.MinValue));            m_uint24 = new RadixIntegerCodec<UInt24>(this, caseSensitive, 24, UInt24.MinValue, 0, i => i, (i, d) => (int)(i % (uint)d), (i, d) => (UInt24)(i / (uint)d), (v, n) => (UInt24)(uint)(n ? -v : v));            m_int16 = new RadixIntegerCodec<short>(this, caseSensitive, 16, short.MinValue, 0, Math.Abs, (i, d) => i % d, (i, d) => (short)(i / d), (v, n) => (short)(n ? -v : v), m_int32.Encode(short.MinValue));            m_uint16 = new RadixIntegerCodec<ushort>(this, caseSensitive, 16, ushort.MinValue, 0, i => i, (i, d) => i % (ushort)d, (i, d) => (ushort)(i / d), (v, n) => (ushort)(n ? -v : v));        }         #endregion         #region [ Methods ]         /// <summary>        /// Converts integer value to a radix value.        /// </summary>        /// <param name="value">Integer value to convert.</param>        /// <returns>Radix value string.</returns>        public string Encode(short value) => m_int16.Encode(value);         /// <summary>        /// Converts integer value to a radix value.        /// </summary>        /// <param name="value">Integer value to convert.</param>        /// <returns>Radix value string.</returns>        public string Encode(ushort value) => m_uint16.Encode(value);         /// <summary>        /// Converts integer value to a radix value.        /// </summary>        /// <param name="value">Integer value to convert.</param>        /// <returns>Radix value string.</returns>        public string Encode(Int24 value) => m_int24.Encode(value);         /// <summary>        /// Converts integer value to a radix value.        /// </summary>        /// <param name="value">Integer value to convert.</param>        /// <returns>Radix value string.</returns>        public string Encode(UInt24 value) => m_uint24.Encode(value);         /// <summary>        /// Converts integer value to a radix value.        /// </summary>        /// <param name="value">Integer value to convert.</param>        /// <returns>Radix value string.</returns>        public string Encode(int value) => m_int32.Encode(value);         /// <summary>        /// Converts integer value to a radix value.        /// </summary>        /// <param name="value">Integer value to convert.</param>        /// <returns>Radix value string.</returns>        public string Encode(uint value) => m_uint32.Encode(value);         /// <summary>        /// Converts integer value to a radix value.        /// </summary>        /// <param name="value">Integer value to convert.</param>        /// <returns>Radix value string.</returns>        public string Encode(long value) => m_int64.Encode(value);         /// <summary>        /// Converts integer value to a radix value.        /// </summary>        /// <param name="value">Integer value to convert.</param>        /// <returns>Radix value string.</returns>        public string Encode(ulong value) => m_uint64.Encode(value);         /// <summary>        /// Attempts to convert a radix value to an integer value.        /// </summary>        /// <param name="radixValue">Radix value to convert.</param>        /// <param name="value">Decoded integer value.</param>        /// <returns><c>true</c> if decode succeeds; otherwise, <c>false</c>.</returns>        public bool TryDecode(string radixValue, out short value)        {            try            {                value = m_int16.Decode(radixValue);                return true;            }            catch            {                value = 0;                return false;            }        }         /// <summary>        /// Attempts to convert a radix value to an integer value.        /// </summary>        /// <param name="radixValue">Radix value to convert.</param>        /// <param name="value">Decoded integer value.</param>        /// <returns><c>true</c> if decode succeeds; otherwise, <c>false</c>.</returns>        public bool TryDecode(string radixValue, out ushort value)        {            try            {                value = m_uint16.Decode(radixValue);                return true;            }            catch            {                value = 0;                return false;            }        }         /// <summary>        /// Attempts to convert a radix value to an integer value.        /// </summary>        /// <param name="radixValue">Radix value to convert.</param>        /// <param name="value">Decoded integer value.</param>        /// <returns><c>true</c> if decode succeeds; otherwise, <c>false</c>.</returns>        public bool TryDecode(string radixValue, out Int24 value)        {            try            {                value = m_int24.Decode(radixValue);                return true;            }            catch            {                value = 0;                return false;            }        }         /// <summary>        /// Attempts to convert a radix value to an integer value.        /// </summary>        /// <param name="radixValue">Radix value to convert.</param>        /// <param name="value">Decoded integer value.</param>        /// <returns><c>true</c> if decode succeeds; otherwise, <c>false</c>.</returns>        public bool TryDecode(string radixValue, out UInt24 value)        {            try            {                value = m_uint24.Decode(radixValue);                return true;            }            catch            {                value = 0;                return false;            }        }         /// <summary>        /// Attempts to convert a radix value to an integer value.        /// </summary>        /// <param name="radixValue">Radix value to convert.</param>        /// <param name="value">Decoded integer value.</param>        /// <returns><c>true</c> if decode succeeds; otherwise, <c>false</c>.</returns>        public bool TryDecode(string radixValue, out int value)        {            try            {                value = m_int32.Decode(radixValue);                return true;            }            catch            {                value = 0;                return false;            }        }         /// <summary>        /// Attempts to convert a radix value to an integer value.        /// </summary>        /// <param name="radixValue">Radix value to convert.</param>        /// <param name="value">Decoded integer value.</param>        /// <returns><c>true</c> if decode succeeds; otherwise, <c>false</c>.</returns>        public bool TryDecode(string radixValue, out uint value)        {            try            {                value = m_uint32.Decode(radixValue);                return true;            }            catch            {                value = 0;                return false;            }        }         /// <summary>        /// Attempts to convert a radix value to an integer value.        /// </summary>        /// <param name="radixValue">Radix value to convert.</param>        /// <param name="value">Decoded integer value.</param>        /// <returns><c>true</c> if decode succeeds; otherwise, <c>false</c>.</returns>        public bool TryDecode(string radixValue, out long value)        {            try            {                value = m_int64.Decode(radixValue);                return true;            }            catch            {                value = 0;                return false;            }        }         /// <summary>        /// Attempts to convert a radix value to an integer value.        /// </summary>        /// <param name="radixValue">Radix value to convert.</param>        /// <param name="value">Decoded integer value.</param>        /// <returns><c>true</c> if decode succeeds; otherwise, <c>false</c>.</returns>        public bool TryDecode(string radixValue, out ulong value)        {            try            {                value = m_uint64.Decode(radixValue);                return true;            }            catch            {                value = 0;                return false;            }        }         /// <summary>        /// Converts a radix value to an integer value.        /// </summary>        /// <typeparam name="T">Integer type to convert</typeparam>        /// <param name="radixValue">Radix value to convert.</param>        /// <returns>Decoded integer value.</returns>        /// <exception cref="ArgumentNullException">Radix value is <c>null</c>.</exception>        /// <exception cref="ArgumentException">Invalid radix value character.</exception>        /// <exception cref="OverflowException">Decoded radix value overflowed integer type.</exception>        /// <exception cref="ArgumentOutOfRangeException">Only integer types Int16, UInt16, Int24, UInt24, Int32, UInt32, Int64 and UInt64 are supported.</exception>        public T Decode<T>(string radixValue) => (T)Decode(typeof(T), radixValue);         /// <summary>        /// Converts a radix value to an integer value.        /// </summary>        /// <param name="type">Integer type to convert.</param>        /// <param name="radixValue">Radix value to convert.</param>        /// <returns>Decoded integer value.</returns>        /// <exception cref="ArgumentNullException">Radix value is <c>null</c>.</exception>        /// <exception cref="ArgumentException">Invalid radix value character.</exception>        /// <exception cref="OverflowException">Decoded radix value overflowed integer type.</exception>        /// <exception cref="ArgumentOutOfRangeException">Only integer types Int16, UInt16, Int24, UInt24, Int32, UInt32, Int64 and UInt64 are supported.</exception>        public object Decode(Type type, string radixValue)        {            switch (Type.GetTypeCode(type))            {                case TypeCode.Int16:                    return m_int16.Decode(radixValue);                case TypeCode.UInt16:                    return m_uint16.Decode(radixValue);                case TypeCode.Int32:                    if (type == typeof(Int24))                        return m_int24.Decode(radixValue);                    return m_int32.Decode(radixValue);                case TypeCode.UInt32:                    if (type == typeof(UInt24))                        return m_uint24.Decode(radixValue);                    return m_uint32.Decode(radixValue);                case TypeCode.Int64:                    return m_int64.Decode(radixValue);                case TypeCode.UInt64:                    return m_uint64.Decode(radixValue);                default:                    throw new ArgumentOutOfRangeException(nameof(type), "Only integer types Int16, UInt16, Int24, UInt24, Int32, UInt32, Int64 and UInt64 are supported.");            }        }         #endregion         #region [ Static ]         // Static Fields        private static RadixCodec s_radix2;        private static RadixCodec s_radix8;        private static RadixCodec s_radix16;        private static RadixCodec s_radix32;        private static RadixCodec s_radix36;        private static RadixCodec s_radix64;        private static RadixCodec s_radix86;         // Static Properties         /// <summary>        /// Gets a radix-2 value (binary) encoding.        /// </summary>        /// <remarks>        /// int.MaxValue encodes to "1111111111111111111111111111111", 31 characters        /// int.MinValue encodes to "-10000000000000000000000000000000", 33 characters        /// uint.MaxValue encodes to "11111111111111111111111111111111", 32 characters        /// long.MaxValue encodes to "111111111111111111111111111111111111111111111111111111111111111", 63 characters        /// long.MinValue encodes to "-1000000000000000000000000000000000000000000000000000000000000000", 65 characters        /// ulong.MaxValue encodes to "1111111111111111111111111111111111111111111111111111111111111111", 64 characters        /// </remarks>                                                            12        public static RadixCodec Radix2 = s_radix2 ?? (s_radix2 = new RadixCodec("01", false));         /// <summary>        /// Gets a radix-8 value (octal) encoding.        /// </summary>        /// <remarks>        /// int.MaxValue encodes to "17777777777", 11 characters        /// int.MinValue encodes to "-20000000000", 12 characters        /// uint.MaxValue encodes to "37777777777", 11 characters        /// long.MaxValue encodes to "777777777777777777777", 21 characters        /// long.MinValue encodes to "-1000000000000000000000", 23 characters        /// ulong.MaxValue encodes to "1777777777777777777777", 22 characters        /// </remarks>                                                            12345678        public static RadixCodec Radix8 = s_radix8 ?? (s_radix8 = new RadixCodec("01234567", false));         /// <summary>        /// Gets a radix-16 value (hex) encoding.

Lines 1–500 of 566.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t