diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..721442b
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,6 @@
+{
+ "sonarlint.connectedMode.project": {
+ "connectionId": "dgmjr-io",
+ "projectKey": "dgmjr-io_Primitives"
+ }
+}
diff --git a/Tests/Dgmjr.Primitives.Tests.csproj b/Tests/Dgmjr.Primitives.Tests.csproj
index 1e675b1..04c4e48 100644
--- a/Tests/Dgmjr.Primitives.Tests.csproj
+++ b/Tests/Dgmjr.Primitives.Tests.csproj
@@ -22,7 +22,7 @@
-
+
diff --git a/Tests/Dgmjr.Primitives.Tests.sln b/Tests/Dgmjr.Primitives.Tests.sln
index 6cba4f4..3088077 100644
--- a/Tests/Dgmjr.Primitives.Tests.sln
+++ b/Tests/Dgmjr.Primitives.Tests.sln
@@ -8,9 +8,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
..\..\..\..\Packages\Versions.Local.props = ..\..\..\..\Packages\Versions.Local.props
EndProjectSection
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dgmjr.Primitives", "..\src\Dgmjr.Primitives.csproj", "{4E1F4A52-7F97-43E1-AAA6-2EEEE07326E6}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dgmjr.Primitives.Tests", "Dgmjr.Primitives.Tests.csproj", "{366CE85C-81D5-438D-B208-FC32FF29AB5A}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dgmjr.Primitives.Tests", "Dgmjr.Primitives.Tests.csproj", "{7B428690-5BC1-48AE-BE92-795E8E67A8E5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -22,30 +20,18 @@ Global
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {4E1F4A52-7F97-43E1-AAA6-2EEEE07326E6}.Local|Any CPU.ActiveCfg = Local|Any CPU
- {4E1F4A52-7F97-43E1-AAA6-2EEEE07326E6}.Local|Any CPU.Build.0 = Local|Any CPU
- {4E1F4A52-7F97-43E1-AAA6-2EEEE07326E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {4E1F4A52-7F97-43E1-AAA6-2EEEE07326E6}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {4E1F4A52-7F97-43E1-AAA6-2EEEE07326E6}.Testing|Any CPU.ActiveCfg = Testing|Any CPU
- {4E1F4A52-7F97-43E1-AAA6-2EEEE07326E6}.Testing|Any CPU.Build.0 = Testing|Any CPU
- {4E1F4A52-7F97-43E1-AAA6-2EEEE07326E6}.Staging|Any CPU.ActiveCfg = Staging|Any CPU
- {4E1F4A52-7F97-43E1-AAA6-2EEEE07326E6}.Staging|Any CPU.Build.0 = Staging|Any CPU
- {4E1F4A52-7F97-43E1-AAA6-2EEEE07326E6}.Production|Any CPU.ActiveCfg = Local|Any CPU
- {4E1F4A52-7F97-43E1-AAA6-2EEEE07326E6}.Production|Any CPU.Build.0 = Local|Any CPU
- {4E1F4A52-7F97-43E1-AAA6-2EEEE07326E6}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {4E1F4A52-7F97-43E1-AAA6-2EEEE07326E6}.Release|Any CPU.Build.0 = Release|Any CPU
- {366CE85C-81D5-438D-B208-FC32FF29AB5A}.Local|Any CPU.ActiveCfg = Local|Any CPU
- {366CE85C-81D5-438D-B208-FC32FF29AB5A}.Local|Any CPU.Build.0 = Local|Any CPU
- {366CE85C-81D5-438D-B208-FC32FF29AB5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {366CE85C-81D5-438D-B208-FC32FF29AB5A}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {366CE85C-81D5-438D-B208-FC32FF29AB5A}.Testing|Any CPU.ActiveCfg = Testing|Any CPU
- {366CE85C-81D5-438D-B208-FC32FF29AB5A}.Testing|Any CPU.Build.0 = Testing|Any CPU
- {366CE85C-81D5-438D-B208-FC32FF29AB5A}.Staging|Any CPU.ActiveCfg = Staging|Any CPU
- {366CE85C-81D5-438D-B208-FC32FF29AB5A}.Staging|Any CPU.Build.0 = Staging|Any CPU
- {366CE85C-81D5-438D-B208-FC32FF29AB5A}.Production|Any CPU.ActiveCfg = Local|Any CPU
- {366CE85C-81D5-438D-B208-FC32FF29AB5A}.Production|Any CPU.Build.0 = Local|Any CPU
- {366CE85C-81D5-438D-B208-FC32FF29AB5A}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {366CE85C-81D5-438D-B208-FC32FF29AB5A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7B428690-5BC1-48AE-BE92-795E8E67A8E5}.Local|Any CPU.ActiveCfg = Local|Any CPU
+ {7B428690-5BC1-48AE-BE92-795E8E67A8E5}.Local|Any CPU.Build.0 = Local|Any CPU
+ {7B428690-5BC1-48AE-BE92-795E8E67A8E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7B428690-5BC1-48AE-BE92-795E8E67A8E5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7B428690-5BC1-48AE-BE92-795E8E67A8E5}.Testing|Any CPU.ActiveCfg = Testing|Any CPU
+ {7B428690-5BC1-48AE-BE92-795E8E67A8E5}.Testing|Any CPU.Build.0 = Testing|Any CPU
+ {7B428690-5BC1-48AE-BE92-795E8E67A8E5}.Staging|Any CPU.ActiveCfg = Staging|Any CPU
+ {7B428690-5BC1-48AE-BE92-795E8E67A8E5}.Staging|Any CPU.Build.0 = Staging|Any CPU
+ {7B428690-5BC1-48AE-BE92-795E8E67A8E5}.Production|Any CPU.ActiveCfg = Local|Any CPU
+ {7B428690-5BC1-48AE-BE92-795E8E67A8E5}.Production|Any CPU.Build.0 = Local|Any CPU
+ {7B428690-5BC1-48AE-BE92-795E8E67A8E5}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7B428690-5BC1-48AE-BE92-795E8E67A8E5}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/src/Int24.cs b/src/Int24.cs
index 539522d..335e21a 100644
--- a/src/Int24.cs
+++ b/src/Int24.cs
@@ -1,393 +1,1539 @@
+//******************************************************************************************************
+// Int24.cs - Gbtc
+//
+// Copyright © 2012, 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://www.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:
+// ----------------------------------------------------------------------------------------------------
+// 11/12/2004 - J. Ritchie Carroll
+// Initial version of source generated.
+// 08/3/2009 - Josh L. Patterson
+// Updated comments.
+// 08/11/2009 - Josh L. Patterson
+// Updated comments.
+// 09/14/2009 - Stephen C. Wills
+// Added new header and license agreement.
+// 12/14/2012 - Starlynn Danyelle Gilliam
+// Modified Header.
+//
+//******************************************************************************************************
+
+#region [ Contributor License Agreements ]
+
+/**************************************************************************\
+ Copyright © 2009 - J. Ritchie Carroll
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
+ EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+\**************************************************************************/
+
+#endregion
+
using System;
+using System.ComponentModel;
+using System.Globalization;
using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
namespace System
{
- ///
- /// Represents a 24-bit integer.
- ///
- [StructLayout(LayoutKind.Explicit, Size = 3)]
- public readonly struct Int24 : IEquatable, IComparable, IFormattable, IConvertible
-#if NE7_0_OR_GREATER
- ,
- IAdditionOperators,
- ISubtractionOperators,
- IMultiplicationOperators,
- IDivisionOperators,
- IUnaryNegationOperators,
- IBinaryIntegerOperators,
- IComparisonOperators,
- IMinMaxValue,
- IIncrementOperators,
- IDecrementOperators
-#endif
+ /// Represents a 3-byte, 24-bit signed integer.
+ ///
+ ///
+ /// This class behaves like most other intrinsic signed integers but allows a 3-byte, 24-bit integer implementation
+ /// that is often found in many digital-signal processing arenas and different kinds of protocol parsing. A signed
+ /// 24-bit integer is typically used to save storage space on disk where its value range of -8388608 to 8388607 is
+ /// sufficient, but the signed Int16 value range of -32768 to 32767 is too small.
+ ///
+ ///
+ /// This structure uses an Int32 internally for storage and most other common expected integer functionality, so using
+ /// a 24-bit integer will not save memory. However, if the 24-bit signed integer range (-8388608 to 8388607) suits your
+ /// data needs you can save disk space by only storing the three bytes that this integer actually consumes. You can do
+ /// this by calling the Int24.GetBytes function to return a three byte binary array that can be serialized to the desired
+ /// destination and then calling the Int24.GetValue function to restore the Int24 value from those three bytes.
+ ///
+ ///
+ /// All the standard operators for the Int24 have been fully defined for use with both Int24 and Int32 signed integers;
+ /// you should find that without the exception Int24 can be compared and numerically calculated with an Int24 or Int32.
+ /// Necessary casting should be minimal and typical use should be very simple - just as if you are using any other native
+ /// signed integer.
+ ///
+ ///
+ [Serializable]
+ public struct Int24
+ : IComparable,
+ IFormattable,
+ IConvertible,
+ IComparable,
+ IComparable,
+ IEquatable,
+ IEquatable
{
+ #region [ Members ]
+
+ // Constants
+ private const int MaxValue32 = 8388607; // Represents the largest possible value of an Int24 as an Int32.
+ private const int MinValue32 = -8388608; // Represents the smallest possible value of an Int24 as an Int32.
+
+ /// High byte bit-mask used when a 24-bit integer is stored within a 32-bit integer. This field is constant.
+ public const int BitMask = -16777216;
+
+ // Fields
+ private readonly int m_value; // We internally store the Int24 value in a 4-byte integer for convenience
+ #endregion
+
+ #region [ Constructors ]
+
+ /// Creates 24-bit signed integer from an existing 24-bit signed integer.
+ /// 24-but signed integer to create new Int24 from.
+ public Int24(Int24 value)
+ {
+ m_value = ApplyBitMask((int)value);
+ }
+
+ /// Creates 24-bit signed integer from a 32-bit signed integer.
+ /// 32-bit signed integer to use as new 24-bit signed integer value.
+ /// Source values outside 24-bit min/max range will cause an overflow exception.
+ public Int24(int value)
+ {
+ ValidateNumericRange(value);
+ m_value = ApplyBitMask(value);
+ }
+
+ /// Creates 24-bit signed integer from three bytes at a specified position in a byte array.
+ /// An array of bytes.
+ /// The starting position within .
+ ///
+ /// You can use this constructor in-lieu of a System.BitConverter.ToInt24 function.
+ /// Bytes endian order assumed to match that of currently executing process architecture (little-endian on Intel platforms).
+ ///
+ /// cannot be null.
+ /// is greater than length.
+ /// length from is too small to represent a .
+ public Int24(byte[] value, int startIndex)
+ {
+ m_value = GetValue(value, startIndex).m_value;
+ }
+
+ #endregion
+
+ #region [ Methods ]
+
+ /// Returns the Int24 value as an array of three bytes.
+ /// An array of bytes with length 3.
+ ///
+ /// You can use this function in-lieu of a System.BitConverter.GetBytes function.
+ /// Bytes will be returned in endian order of currently executing process architecture (little-endian on Intel platforms).
+ ///
+ public byte[] GetBytes()
+ {
+ // Return serialized 3-byte representation of Int24
+ return GetBytes(this);
+ }
+
///
- /// The bit offset of the integer.
+ /// Compares this instance to a specified object and returns an indication of their relative values.
///
- private const int BitOffset = 8;
+ /// An object to compare, or null.
+ ///
+ /// A signed number indicating the relative values of this instance and value. Returns less than zero
+ /// if this instance is less than value, zero if this instance is equal to value, or greater than zero
+ /// if this instance is greater than value.
+ ///
+ /// value is not an Int32 or Int24.
+ public int CompareTo(object value)
+ {
+ if ((object)value == null)
+ return 1;
+
+ if (!(value is int) && !(value is Int24))
+ throw new ArgumentException("Argument must be an Int32 or an Int24");
+
+ int num = (int)value;
+ return (m_value < num ? -1 : (m_value > num ? 1 : 0));
+ }
///
- /// The size of the bits in the integer.
+ /// Compares this instance to a specified 24-bit signed integer and returns an indication of their
+ /// relative values.
///
- public const int Size = 24;
+ /// An integer to compare.
+ ///
+ /// A signed number indicating the relative values of this instance and value. Returns less than zero
+ /// if this instance is less than value, zero if this instance is equal to value, or greater than zero
+ /// if this instance is greater than value.
+ ///
+ public int CompareTo(Int24 value)
+ {
+ return CompareTo((int)value);
+ }
///
- /// The zero mask for the integer.
+ /// Compares this instance to a specified 32-bit signed integer and returns an indication of their
+ /// relative values.
///
- public const uint Zero = 0x00800000;
+ /// An integer to compare.
+ ///
+ /// A signed number indicating the relative values of this instance and value. Returns less than zero
+ /// if this instance is less than value, zero if this instance is equal to value, or greater than zero
+ /// if this instance is greater than value.
+ ///
+ public int CompareTo(int value)
+ {
+ return (m_value < value ? -1 : (m_value > value ? 1 : 0));
+ }
///
- /// The mask for negative sign.
+ /// Returns a value indicating whether this instance is equal to a specified object.
///
- private const uint NegativeSignMask = 0xFF000000;
+ /// An object to compare, or null.
+ ///
+ /// True if obj is an instance of Int32 or Int24 and equals the value of this instance;
+ /// otherwise, False.
+ ///
+ public override bool Equals(object obj)
+ {
+ if (obj is int || obj is Int24)
+ return Equals((int)obj);
+ return false;
+ }
///
- /// The mask for positive sign.
- ///
- private const uint PositiveSignMask = 0x00FFFFFF;
-
- [FieldOffset(0)]
- private readonly byte _b0;
-
- [FieldOffset(1)]
- private readonly byte _b1;
+ /// Returns a value indicating whether this instance is equal to a specified Int24 value.
+ ///
+ /// An Int24 value to compare to this instance.
+ ///
+ /// True if obj has the same value as this instance; otherwise, False.
+ ///
+ public bool Equals(Int24 obj)
+ {
+ return Equals((int)obj);
+ }
- [FieldOffset(2)]
- private readonly byte _b2;
+ ///
+ /// Returns a value indicating whether this instance is equal to a specified Int32 value.
+ ///
+ /// An Int32 value to compare to this instance.
+ ///
+ /// True if obj has the same value as this instance; otherwise, False.
+ ///
+ public bool Equals(int obj)
+ {
+ return (m_value == obj);
+ }
- private readonly byte[] Bytes => [_b0, _b1, _b2];
+ ///
+ /// Returns the hash code for this instance.
+ ///
+ ///
+ /// A 32-bit signed integer hash code.
+ ///
+ public override int GetHashCode()
+ {
+ return m_value;
+ }
- public static implicit operator uint(i24 value) =>
- (uint)value._b0 | (uint)(value._b1 >> BitOffset) | (uint)(value._b2 >> BitOffset * 2);
+ ///
+ /// Converts the numeric value of this instance to its equivalent string representation.
+ ///
+ ///
+ /// The string representation of the value of this instance, consisting of a minus sign if
+ /// the value is negative, and a sequence of digits ranging from 0 to 9 with no leading zeroes.
+ ///
+ public override string ToString()
+ {
+ return m_value.ToString();
+ }
- public static implicit operator int(i24 value) =>
- (int)value._b0 | ((int)value._b1 >> BitOffset) | ((int)value._b2 >> BitOffset * 2);
+ ///
+ /// Converts the numeric value of this instance to its equivalent string representation, using
+ /// the specified format.
+ ///
+ /// A format string.
+ ///
+ /// The string representation of the value of this instance as specified by format.
+ ///
+ public string ToString(string format)
+ {
+ return m_value.ToString(format);
+ }
- // ///
- // /// Gets the value of the integer.
- // ///
- // public i24 Value => this;
+ ///
+ /// Converts the numeric value of this instance to its equivalent string representation using the
+ /// specified culture-specific format information.
+ ///
+ ///
+ /// A that supplies culture-specific formatting information.
+ ///
+ ///
+ /// The string representation of the value of this instance as specified by provider.
+ ///
+ public string ToString(IFormatProvider provider)
+ {
+ return m_value.ToString(provider);
+ }
///
- /// Initializes a new instance of the i24 struct with three bytes.
+ /// Converts the numeric value of this instance to its equivalent string representation using the
+ /// specified format and culture-specific format information.
///
- /// The first byte.
- /// The second byte.
- /// The third byte.
- public Int24(byte b0, byte b1, byte b2)
+ /// A format specification.
+ ///
+ /// A that supplies culture-specific formatting information.
+ ///
+ ///
+ /// The string representation of the value of this instance as specified by format and provider.
+ ///
+ public string ToString(string format, IFormatProvider provider)
{
- _b0 = b0;
- _b1 = b1;
- _b2 = b2;
+ return m_value.ToString(format, provider);
}
+
///
- /// Initializes a new instance of the i24 struct with three bytes.
+ /// Converts the string representation of a number to its 24-bit signed integer equivalent.
///
- /// The array of three bytes holding the int24 value.
- public Int24(byte[] bytes) : this(bytes[0], bytes[1], bytes[2]) { }
+ /// A string containing a number to convert.
+ ///
+ /// A 24-bit signed integer equivalent to the number contained in s.
+ ///
+ /// s is null.
+ ///
+ /// s represents a number less than Int24.MinValue or greater than Int24.MaxValue.
+ ///
+ /// s is not in the correct format.
+ public static Int24 Parse(string s)
+ {
+ return (Int24)int.Parse(s);
+ }
///
- /// Initializes a new instance of the i24 struct with a signed byte value.
+ /// Converts the string representation of a number in a specified style to its 24-bit signed integer equivalent.
///
- /// The signed byte value.
- public Int24(sbyte value) : this((byte)value, 0x0, 0x0) { }
+ /// A string containing a number to convert.
+ ///
+ /// A bitwise combination of System.Globalization.NumberStyles values that indicates the permitted format of s.
+ /// A typical value to specify is System.Globalization.NumberStyles.Integer.
+ ///
+ ///
+ /// A 24-bit signed integer equivalent to the number contained in s.
+ ///
+ ///
+ /// style is not a System.Globalization.NumberStyles value. -or- style is not a combination of
+ /// System.Globalization.NumberStyles.AllowHexSpecifier and System.Globalization.NumberStyles.HexNumber values.
+ ///
+ /// s is null.
+ ///
+ /// s represents a number less than Int24.MinValue or greater than Int24.MaxValue.
+ ///
+ /// s is not in a format compliant with style.
+ public static Int24 Parse(string s, NumberStyles style)
+ {
+ return (Int24)int.Parse(s, style);
+ }
///
- /// Initializes a new instance of the i24 struct with a short integer value.
+ /// Converts the string representation of a number in a specified culture-specific format to its 24-bit
+ /// signed integer equivalent.
///
- ///The short integer value.
- public Int24(short value) : this((byte)(value & 0xFF), (byte)(value >> BitOffset), 0x0) { }
+ /// A string containing a number to convert.
+ ///
+ /// A that supplies culture-specific formatting information about s.
+ ///
+ ///
+ /// A 24-bit signed integer equivalent to the number contained in s.
+ ///
+ /// s is null.
+ ///
+ /// s represents a number less than Int24.MinValue or greater than Int24.MaxValue.
+ ///
+ /// s is not in the correct format.
+ public static Int24 Parse(string s, IFormatProvider provider)
+ {
+ return (Int24)int.Parse(s, provider);
+ }
///
- /// Initializes a new instance of the i24 struct with an integer value.
+ /// Converts the string representation of a number in a specified style and culture-specific format to its 24-bit
+ /// signed integer equivalent.
///
- ///The integer value.
- public Int24(int value) : this((byte)(value & 0xFF), (byte)(value >> BitOffset), (byte)(value >> BitOffset * 2)) { }
+ /// A string containing a number to convert.
+ ///
+ /// A bitwise combination of System.Globalization.NumberStyles values that indicates the permitted format of s.
+ /// A typical value to specify is System.Globalization.NumberStyles.Integer.
+ ///
+ ///
+ /// A that supplies culture-specific formatting information about s.
+ ///
+ ///
+ /// A 24-bit signed integer equivalent to the number contained in s.
+ ///
+ ///
+ /// style is not a System.Globalization.NumberStyles value. -or- style is not a combination of
+ /// System.Globalization.NumberStyles.AllowHexSpecifier and System.Globalization.NumberStyles.HexNumber values.
+ ///
+ /// s is null.
+ ///
+ /// s represents a number less than Int24.MinValue or greater than Int24.MaxValue.
+ ///
+ /// s is not in a format compliant with style.
+ public static Int24 Parse(string s, NumberStyles style, IFormatProvider provider)
+ {
+ return (Int24)int.Parse(s, style, provider);
+ }
///
- /// Initializes a new instance of the i24 struct with an unsigned integer value.
+ /// Converts the string representation of a number to its 24-bit signed integer equivalent. A return value
+ /// indicates whether the conversion succeeded or failed.
///
- /// The unsigned integer value.
- public Int24(uint value)
+ /// A string containing a number to convert.
+ ///
+ /// When this method returns, contains the 24-bit signed integer value equivalent to the number contained in s,
+ /// if the conversion succeeded, or zero if the conversion failed. The conversion fails if the s parameter is null,
+ /// is not of the correct format, or represents a number less than Int24.MinValue or greater than Int24.MaxValue.
+ /// This parameter is passed uninitialized.
+ ///
+ /// true if s was converted successfully; otherwise, false.
+ public static bool TryParse(string s, out Int24 result)
{
- if (value > (1 << Size - 1) - 1)
+ int parseResult;
+ bool parseResponse;
+
+ parseResponse = int.TryParse(s, out parseResult);
+
+ try
+ {
+ result = (Int24)parseResult;
+ }
+ catch
{
- throw new ArgumentOutOfRangeException(nameof(value), "Value too large for i24");
+ result = (Int24)0;
+ parseResponse = false;
}
- _b0 = (byte)(value & 0xFF);
- _b1 = (byte)(value >> BitOffset);
- _b2 = (byte)(value >> BitOffset * 2);
+ return parseResponse;
}
///
- /// Initializes a new instance of the i24 struct with a read-only span of bytes.
+ /// Converts the string representation of a number in a specified style and culture-specific format to its
+ /// 24-bit signed integer equivalent. A return value indicates whether the conversion succeeded or failed.
///
- /// The read-only span of bytes.
- public Int24(ReadOnlySpan bytes)
+ /// A string containing a number to convert.
+ ///
+ /// A bitwise combination of System.Globalization.NumberStyles values that indicates the permitted format of s.
+ /// A typical value to specify is System.Globalization.NumberStyles.Integer.
+ ///
+ ///
+ /// When this method returns, contains the 24-bit signed integer value equivalent to the number contained in s,
+ /// if the conversion succeeded, or zero if the conversion failed. The conversion fails if the s parameter is null,
+ /// is not in a format compliant with style, or represents a number less than Int24.MinValue or greater than
+ /// Int24.MaxValue. This parameter is passed uninitialized.
+ ///
+ ///
+ /// A object that supplies culture-specific formatting information about s.
+ ///
+ /// true if s was converted successfully; otherwise, false.
+ ///
+ /// style is not a System.Globalization.NumberStyles value. -or- style is not a combination of
+ /// System.Globalization.NumberStyles.AllowHexSpecifier and System.Globalization.NumberStyles.HexNumber values.
+ ///
+ public static bool TryParse(
+ string s,
+ NumberStyles style,
+ IFormatProvider provider,
+ out Int24 result
+ )
{
- if (bytes.Length != 3)
+ int parseResult;
+ bool parseResponse;
+
+ parseResponse = int.TryParse(s, style, provider, out parseResult);
+
+ try
{
- throw new ArgumentException(
- "Bytes span must be exactly 3 bytes long",
- nameof(bytes)
- );
+ result = (Int24)parseResult;
+ }
+ catch
+ {
+ result = (Int24)0;
+ parseResponse = false;
}
- _b0 = bytes[0];
- _b1 = bytes[1];
- _b2 = bytes[2];
+ return parseResponse;
}
///
- /// Gets or sets the byte at the specified index.
+ /// Returns the System.TypeCode for value type System.Int32 (there is no defined type code for an Int24).
///
- /// The zero-based index of the byte to get or set.
- public byte this[int index]
+ /// The enumerated constant, System.TypeCode.Int32.
+ ///
+ /// There is no defined Int24 type code and since an Int24 will easily fit inside an Int32, the
+ /// Int32 type code is returned.
+ ///
+ public TypeCode GetTypeCode()
{
- get
- {
- return index switch
- {
- 0 => _b0,
- 1 => _b1,
- 2 => _b2,
- _ => throw new IndexOutOfRangeException()
- };
- }
+ return TypeCode.Int32;
+ }
+
+ #region [ Explicit IConvertible Implementation ]
+
+ // These are explicitly implemented on the native integer implementations, so we do the same...
+
+ bool IConvertible.ToBoolean(IFormatProvider provider)
+ {
+ return Convert.ToBoolean(m_value, provider);
+ }
+
+ char IConvertible.ToChar(IFormatProvider provider)
+ {
+ return Convert.ToChar(m_value, provider);
+ }
+
+ sbyte IConvertible.ToSByte(IFormatProvider provider)
+ {
+ return Convert.ToSByte(m_value, provider);
+ }
+
+ byte IConvertible.ToByte(IFormatProvider provider)
+ {
+ return Convert.ToByte(m_value, provider);
+ }
+
+ short IConvertible.ToInt16(IFormatProvider provider)
+ {
+ return Convert.ToInt16(m_value, provider);
+ }
+
+ ushort IConvertible.ToUInt16(IFormatProvider provider)
+ {
+ return Convert.ToUInt16(m_value, provider);
+ }
+
+ int IConvertible.ToInt32(IFormatProvider provider)
+ {
+ return m_value;
+ }
+
+ uint IConvertible.ToUInt32(IFormatProvider provider)
+ {
+ return Convert.ToUInt32(m_value, provider);
+ }
+
+ long IConvertible.ToInt64(IFormatProvider provider)
+ {
+ return Convert.ToInt64(m_value, provider);
+ }
+
+ ulong IConvertible.ToUInt64(IFormatProvider provider)
+ {
+ return Convert.ToUInt64(m_value, provider);
+ }
+
+ float IConvertible.ToSingle(IFormatProvider provider)
+ {
+ return Convert.ToSingle(m_value, provider);
+ }
+
+ double IConvertible.ToDouble(IFormatProvider provider)
+ {
+ return Convert.ToDouble(m_value, provider);
}
+ decimal IConvertible.ToDecimal(IFormatProvider provider)
+ {
+ return Convert.ToDecimal(m_value, provider);
+ }
+
+ DateTime IConvertible.ToDateTime(IFormatProvider provider)
+ {
+ return Convert.ToDateTime(m_value, provider);
+ }
+
+ object IConvertible.ToType(Type type, IFormatProvider provider)
+ {
+ return Convert.ChangeType(m_value, type, provider);
+ }
+
+ #endregion
+
+ #endregion
+
+ #region [ Operators ]
+
+ // Every effort has been made to make Int24 as cleanly interoperable with Int32 as possible...
+
+ #region [ Comparison Operators ]
+
///
- /// Compares this instance to another i24 instance and returns an indication of their relative values.
+ /// Compares the two values for equality.
///
- /// An object to compare with this instance.
- public int CompareTo(i24 other)
+ /// Left hand operand.
+ /// Right hand operand.
+ /// Boolean value indicating equality.
+ public static bool operator ==(Int24 value1, Int24 value2)
{
- int thisValue = SignExtend();
- int otherValue = other.SignExtend();
- return thisValue.CompareTo(otherValue);
+ return value1.Equals(value2);
}
///
- /// Determines whether this instance and another specified i24 object have the same value.
+ /// Compares the two values for equality.
///
- /// The i24 to compare to this instance.
- /// true if the value of the other parameter is the same as the value of this instance; otherwise, false.
- public bool Equals(i24 other)
+ /// Left hand operand.
+ /// Right hand operand.
+ /// Boolean value indicating equality.
+ public static bool operator ==(int value1, Int24 value2)
{
- return SignExtend() == other.SignExtend();
+ return value1.Equals((int)value2);
}
///
- /// Determines whether this instance and a specified object, which must also be an i24 object, have the same value.
+ /// Compares the two values for equality.
///
- /// The object to compare to this instance.
- /// true if obj is an i24 and its value is the same as this instance; otherwise, false. If obj is null, the method returns false.
- public override bool Equals(object? obj)
+ /// Left hand operand.
+ /// Right hand operand.
+ /// Boolean value indicating equality.
+ public static bool operator ==(Int24 value1, int value2)
{
- return obj is i24 other && Equals(other);
+ return ((int)value1).Equals(value2);
}
///
- /// Sign extends the current i24 struct.
+ /// Compares the two values for inequality.
///
- /// A new i24 struct with sign extension applied.
- public i24 SignExtend()
+ /// Left hand operand.
+ /// Right hand operand.
+ /// Boolean indicating the result of the inequality.
+ public static bool operator !=(Int24 value1, Int24 value2)
{
- if ((this & Zero) != 0)
- {
- // Negative number: fill upper 8 bits with 1's
- return unchecked ((i24)(int)(this | NegativeSignMask));
- }
- // Positive number: fill upper 8 bits with 0's
- return (i24)(int)(this & PositiveSignMask);
+ return !value1.Equals(value2);
}
///
- /// Returns a hash code for this instance.
+ /// Compares the two values for inequality.
///
- ///A hash code for the current object.
- public override int GetHashCode()
+ /// Left hand operand.
+ /// Right hand operand.
+ /// Boolean indicating the result of the inequality.
+ public static bool operator !=(int value1, Int24 value2)
{
- return SignExtend().GetHashCode();
+ return !value1.Equals((int)value2);
}
///
- /// Converts the numeric value of this instance to its equivalent string representation.
+ /// Compares the two values for inequality.
///
- ///The string representation of the value of this instance.
- public override string ToString()
+ /// Left hand operand.
+ /// Right hand operand.
+ /// Boolean indicating the result of the inequality.
+ public static bool operator !=(Int24 value1, int value2)
{
- return SignExtend().ToString();
+ return !((int)value1).Equals(value2);
}
///
- /// Converts the numeric value of this instance to its equivalent string representation using specified format and culture-specific format information.
- ///
- ///A standard or custom numeric format string.
- ///An object that supplies culture-specific formatting information.
- ///The string representation of the value of this instance as specified by format and provider parameters.
- public string ToString(string? format, IFormatProvider? formatProvider)
+ /// Returns true if left value is less than right value.
+ ///
+ /// Left hand operand.
+ /// Right hand operand.
+ /// Boolean indicating whether the left value was less than the right value.
+ public static bool operator <(Int24 value1, Int24 value2)
{
- return SignExtend().ToString(format, formatProvider);
+ return (value1.CompareTo(value2) < 0);
}
- private const int Int32MinValue = -8388608;
- private const int Int32MaxValue = 8388607;
+ ///
+ /// Returns true if left value is less than right value.
+ ///
+ /// Left hand operand.
+ /// Right hand operand.
+ /// Boolean indicating whether the left value was less than the right value.
+ public static bool operator <(int value1, Int24 value2)
+ {
+ return (value1.CompareTo((int)value2) < 0);
+ }
- // Implementations of IComparable, IComparable, IEquatable, and IConvertible
- // ...
+ ///
+ /// Returns true if left value is less than right value.
+ ///
+ /// Left hand operand.
+ /// Right hand operand.
+ /// Boolean indicating whether the left value was less than the right value.
+ public static bool operator <(Int24 value1, int value2)
+ {
+ return (value1.CompareTo(value2) < 0);
+ }
///
- /// Converts the value of this instance to a 32-bit signed integer.
+ /// Returns true if left value is less or equal to than right value.
///
- ///A 32-bit signed integer equal to the value of this instance.
- public int ToInt32()
+ /// Left hand operand.
+ /// Right hand operand.
+ /// Boolean indicating whether the left value was less than the right value.
+ public static bool operator <=(Int24 value1, Int24 value2)
{
- int result = _b0;
- result |= _b1 << 8;
- result |= (_b2 & 0x7F) << 16;
+ return (value1.CompareTo(value2) <= 0);
+ }
- if ((_b2 & 0x80) == 0x80)
- {
- result |= 0xFF << 23;
- }
+ ///
+ /// Returns true if left value is less or equal to than right value.
+ ///
+ /// Left hand operand.
+ /// Right hand operand.
+ /// Boolean indicating whether the left value was less than the right value.
+ public static bool operator <=(int value1, Int24 value2)
+ {
+ return (value1.CompareTo((int)value2) <= 0);
+ }
- return result;
+ ///
+ /// Returns true if left value is less or equal to than right value.
+ ///
+ /// Left hand operand.
+ /// Right hand operand.
+ /// Boolean indicating whether the left value was less than the right value.
+ public static bool operator <=(Int24 value1, int value2)
+ {
+ return (value1.CompareTo(value2) <= 0);
}
- private const int Bits = 24;
- private const int SignBit = 1 << (Bits - 1);
- private const int MaxValueWithoutSignBit = SignBit - 1;
+ ///
+ /// Returns true if left value is greater than right value.
+ ///
+ /// Left hand operand.
+ /// Right hand operand.
+ /// Boolean indicating whether the left value was greater than the right value.
+ public static bool operator >(Int24 value1, Int24 value2)
+ {
+ return (value1.CompareTo(value2) > 0);
+ }
///
- /// Implicitly converts an i24 struct to an integer.
+ /// Returns true if left value is greater than right value.
///
- ///The i24 struct to convert.
- public static implicit operator i24(int value) => new(value);
+ /// Left hand operand.
+ /// Right hand operand.
+ /// Boolean indicating whether the left value was greater than the right value.
+ public static bool operator >(int value1, Int24 value2)
+ {
+ return (value1.CompareTo((int)value2) > 0);
+ }
///
- /// Determines whether two specified i24 objects have the same value.
+ /// Returns true if left value is greater than right value.
///
- /// The first i24 to compare.
- /// The second i24 to compare.
- /// true if the value of left is the same as the value of right; otherwise, false.
- public static bool operator ==(i24 left, i24 right) => left.Equals(right);
+ /// Left hand operand.
+ /// Right hand operand.
+ /// Boolean indicating whether the left value was greater than the right value.
+ public static bool operator >(Int24 value1, int value2)
+ {
+ return (value1.CompareTo(value2) > 0);
+ }
///
- /// Determines whether two specified i24 objects have different values.
+ /// Returns true if left value is greater than or equal to right value.
///
- /// The first i24 to compare.
- /// The second i24 to compare.
- /// true if the value of left is different from the value of right; otherwise, false.
- public static bool operator !=(i24 left, i24 right) => !left.Equals(right);
+ /// Left hand operand.
+ /// Right hand operand.
+ /// Boolean indicating whether the left value was greater than or equal to the right value.
+ public static bool operator >=(Int24 value1, Int24 value2)
+ {
+ return (value1.CompareTo(value2) >= 0);
+ }
///
- /// Determines whether one specified i24 is less than another specified i24.
+ /// Returns true if left value is greater than or equal to right value.
///
- ///The first object to compare.
- ///The second object to compare.
- ///true if left is less than right; otherwise, false.
- public static bool operator <(i24 left, i24 right) => left.CompareTo(right) < 0;
+ /// Left hand operand.
+ /// Right hand operand.
+ /// Boolean indicating whether the left value was greater than or equal to the right value.
+ public static bool operator >=(int value1, Int24 value2)
+ {
+ return (value1.CompareTo((int)value2) >= 0);
+ }
///
- /// Determines whether one specified i24 is greater than another specified i24.
+ /// Returns true if left value is greater than or equal to right value.
///
- ///The first object to compare.
- ///The second object to compare.
- ///true if left is greater than right; otherwise, false.
- public static bool operator >(i24 left, i24 right) => left.CompareTo(right) > 0;
+ /// Left hand operand.
+ /// Right hand operand.
+ /// Boolean indicating whether the left value was greater than or equal to the right value.
+ public static bool operator >=(Int24 value1, int value2)
+ {
+ return (value1.CompareTo(value2) >= 0);
+ }
+
+ #endregion
+
+ #region [ Type Conversion Operators ]
+
+ #region [ Explicit Narrowing Conversions ]
///
- /// Determines whether one specified i24 is less than or equal to another specified int.
- ///
- ///The first object to compare.
- ///The second object to compare.
- ///true if left is less than or equal to right; otherwise, false.
- public static bool operator <=(i24 left, i24? right)
+ /// Explicitly converts value to an .
+ ///
+ /// Enum value that is converted.
+ /// Int24
+ public static explicit operator Int24(Enum value)
{
- return !(left > right);
+ return new Int24(Convert.ToInt32(value));
}
///
- /// Determines whether one specified i24 is greater than or equal to another specified int.
- ///
- ///The first object to compare.
- ///The second object to compare.
- ///true if left is greater than or equal to right; otherwise, false.
- public static bool operator >=(i24 left, i24? right)
+ /// Explicitly converts value to an .
+ ///
+ /// String value that is converted.
+ /// Int24
+ public static explicit operator Int24(string value)
{
- return !(left < right);
+ return new Int24(Convert.ToInt32(value));
}
///
- /// Returns the TypeCode for this instance.
+ /// Explicitly converts value to an .
///
- ///The enumerated constant that is the TypeCode of the class or value type that implements this interface.
- public TypeCode GetTypeCode() => TypeCode.Int32;
+ /// Decimal value that is converted.
+ /// Int24
+ public static explicit operator Int24(decimal value)
+ {
+ return new Int24(Convert.ToInt32(value));
+ }
- /// The maximum value that can be assigned to an instance of this type.
- /// A constant equal to 8388607.
- /// 8388607
- public static readonly i24 MaxValue = new(Int32MinValue);
+ ///
+ /// Explicitly converts value to an .
+ ///
+ /// Double value that is converted.
+ /// Int24
+ public static explicit operator Int24(double value)
+ {
+ return new Int24(Convert.ToInt32(value));
+ }
///
- /// The minimum value that can be assigned to an instance of this type.
+ /// Explicitly converts value to an .
///
- /// A constant equal to -8388608.
- /// -8388608
- public static readonly i24 MinValue = new(Int32MaxValue);
+ /// Float value that is converted.
+ /// Int24
+ public static explicit operator Int24(float value)
+ {
+ return new Int24(Convert.ToInt32(value));
+ }
- public static explicit operator i24(sbyte value) => new(value);
+ ///
+ /// Explicitly converts value to an .
+ ///
+ /// Long value that is converted.
+ /// Int24
+ public static explicit operator Int24(long value)
+ {
+ return new Int24(Convert.ToInt32(value));
+ }
- public int ToInt32(IFormatProvider? formatProvider) => ToInt32();
+ ///
+ /// Explicitly converts value to an .
+ ///
+ /// Integer value that is converted.
+ /// Int24
+ public static explicit operator Int24(int value)
+ {
+ return new Int24(value);
+ }
- public uint ToUInt32(IFormatProvider? formatProvider) => (uint)ToInt32();
+ ///
+ /// Explicitly converts to .
+ ///
+ /// Int24 value that is converted.
+ /// Short
+ public static explicit operator short(Int24 value)
+ {
+ return (short)((int)value);
+ }
- public long ToInt64(IFormatProvider? formatProvider) => (long)ToInt32();
+ ///
+ /// Explicitly converts to .
+ ///
+ /// Int24 value that is converted.
+ /// Unsigned Short
+ public static explicit operator ushort(Int24 value)
+ {
+ return (ushort)((uint)value);
+ }
- public ulong ToUInt64(IFormatProvider? formatProvider) => (ulong)ToInt32();
+ ///
+ /// Explicitly converts to .
+ ///
+ /// Int24 value that is converted.
+ /// Byte
+ public static explicit operator byte(Int24 value)
+ {
+ return (byte)((int)value);
+ }
- public short ToInt16(IFormatProvider? formatProvider) => (short)ToInt32();
+ #endregion
- public ushort ToUInt16(IFormatProvider? formatProvider) => (ushort)ToInt32();
+ #region [ Implicit Widening Conversions ]
-#if NET7_0_OR_GREATER
- public Int128 ToInt128(IFormatProvider? formatProvider) => (Int128)ToInt32();
+ ///
+ /// Implicitly converts value to an .
+ ///
+ /// Byte value that is converted to an .
+ /// An value.
+ public static implicit operator Int24(byte value)
+ {
+ return new Int24((int)value);
+ }
- public UInt128 ToUInt128(IFormatProvider? formatProvider) => (UInt128)ToInt32();
-#endif
+ ///
+ /// Implicitly converts value to an .
+ ///
+ /// Char value that is converted to an .
+ /// An value.
+ public static implicit operator Int24(char value)
+ {
+ return new Int24((int)value);
+ }
- public byte ToByte(IFormatProvider? formatProvider) => (byte)ToInt32();
+ ///
+ /// Implicitly converts value to an .
+ ///
+ /// Short value that is converted to an .
+ /// An value.
+ public static implicit operator Int24(short value)
+ {
+ return new Int24((int)value);
+ }
- public sbyte ToSByte(IFormatProvider? formatProvider) => (sbyte)ToInt32();
+ ///
+ /// Implicitly converts to .
+ ///
+ /// value that is converted to an .
+ /// An value.
+ public static implicit operator int(Int24 value)
+ {
+ return ((IConvertible)value).ToInt32(null);
+ }
- public Single ToSingle(IFormatProvider? formatProvider) => (Single)ToInt32();
+ ///
+ /// Implicitly converts to .
+ ///
+ /// value that is converted to an unsigned integer.
+ /// Unsigned integer
+ public static implicit operator uint(Int24 value)
+ {
+ return ((IConvertible)value).ToUInt32(null);
+ }
- public double ToDouble(IFormatProvider? formatProvider) => (double)ToInt32();
+ ///
+ /// Implicitly converts to .
+ ///
+ /// value that is converted to an .
+ /// An value.
+ public static implicit operator long(Int24 value)
+ {
+ return ((IConvertible)value).ToInt64(null);
+ }
- public decimal ToDecimal(IFormatProvider? formatProvider) => (decimal)ToInt32();
+ ///
+ /// Implicitly converts to .
+ ///
+ /// value that is converted to an .
+ /// An value.
+ public static implicit operator ulong(Int24 value)
+ {
+ return ((IConvertible)value).ToUInt64(null);
+ }
- public char ToChar(IFormatProvider? formatProvider) => (char)ToInt32();
+ ///
+ /// Implicitly converts to .
+ ///
+ /// value that is converted to an .
+ /// A value.
+ public static implicit operator double(Int24 value)
+ {
+ return ((IConvertible)value).ToDouble(null);
+ }
- public DateTime ToDateTime(IFormatProvider? formatProvider) =>
- DateTime.FromBinary((long)ToInt32());
+ ///
+ /// Implicitly converts to .
+ ///
+ /// value that is converted to an .
+ /// A value.
+ public static implicit operator float(Int24 value)
+ {
+ return ((IConvertible)value).ToSingle(null);
+ }
- public bool ToBoolean(IFormatProvider? formatProvider) => ToInt32() > 0;
+ ///
+ /// Implicitly converts to .
+ ///
+ /// value that is converted to an .
+ /// A value.
+ public static implicit operator decimal(Int24 value)
+ {
+ return ((IConvertible)value).ToDecimal(null);
+ }
- public object ToType(Type conversionType, IFormatProvider? formatProvider) =>
- Convert.ChangeType(ToInt32(), conversionType, formatProvider);
+ ///
+ /// Implicitly converts to .
+ ///
+ /// value that is converted to an .
+ /// A value.
+ public static implicit operator string(Int24 value)
+ {
+ return value.ToString();
+ }
- public string ToString(IFormatProvider? formatProvider) =>
- ((int)ToInt32()).ToString(formatProvider);
+ #endregion
- public static i24 Parse(string s, Globalization.NumberStyles style = 0) =>
- new(int.Parse(s, style));
- }
+ #endregion
+
+ #region [ Boolean and Bitwise Operators ]
+
+ ///
+ /// Returns true if value is not zero.
+ ///
+ /// Int24 value to test.
+ /// Boolean to indicate whether the value was not equal to zero.
+ public static bool operator true(Int24 value)
+ {
+ return (value != 0);
+ }
+
+ ///
+ /// Returns true if value is equal to zero.
+ ///
+ /// Int24 value to test.
+ /// Boolean to indicate whether the value was equal to zero.
+ public static bool operator false(Int24 value)
+ {
+ return (value == 0);
+ }
+
+ ///
+ /// Returns bitwise complement of value.
+ ///
+ /// value as operand.
+ /// as result.
+ public static Int24 operator ~(Int24 value)
+ {
+ return (Int24)ApplyBitMask(~(int)value);
+ }
+
+ ///
+ /// Returns logical bitwise AND of values.
+ ///
+ /// Left hand operand.
+ /// Right hand operand.
+ /// Int24 as result of operation.
+ public static Int24 operator &(Int24 value1, Int24 value2)
+ {
+ return (Int24)ApplyBitMask((int)value1 & (int)value2);
+ }
+
+ ///
+ /// Returns logical bitwise AND of values.
+ ///
+ /// Left hand operand.
+ /// Right hand operand.
+ /// Integer as result of operation.
+ public static int operator &(int value1, Int24 value2)
+ {
+ return (value1 & (int)value2);
+ }
+
+ ///
+ /// Returns logical bitwise AND of values.
+ ///
+ /// Left hand operand.
+ /// Right hand operand.
+ /// Integer as result of operation.
+ public static int operator &(Int24 value1, int value2)
+ {
+ return ((int)value1 & value2);
+ }
+
+ ///
+ /// Returns logical bitwise OR of values.
+ ///
+ /// Left hand operand.
+ /// Right hand operand.
+ /// Int24 as result of operation.
+ public static Int24 operator |(Int24 value1, Int24 value2)
+ {
+ return (Int24)ApplyBitMask((int)value1 | (int)value2);
+ }
+
+ ///
+ /// Returns logical bitwise OR of values.
+ ///
+ /// Left hand operand.
+ /// Right hand operand.
+ /// Integer as result of operation.
+ public static int operator |(int value1, Int24 value2)
+ {
+ return (value1 | (int)value2);
+ }
+
+ ///
+ /// Returns logical bitwise OR of values.
+ ///
+ /// Left hand operand.
+ /// Right hand operand.
+ /// Integer as result of operation.
+ public static int operator |(Int24 value1, int value2)
+ {
+ return ((int)value1 | value2);
+ }
+
+ ///
+ /// Returns logical bitwise exclusive-OR of values.
+ ///
+ /// Left hand operand.
+ /// Right hand operand.
+ /// Integer value of the resulting exclusive-OR operation.
+ public static Int24 operator ^(Int24 value1, Int24 value2)
+ {
+ return (Int24)ApplyBitMask((int)value1 ^ (int)value2);
+ }
+
+ ///
+ /// Returns logical bitwise exclusive-OR of values.
+ ///
+ /// Left hand operand.
+ /// Right hand operand.
+ /// Integer value of the resulting exclusive-OR operation.
+ public static int operator ^(int value1, Int24 value2)
+ {
+ return (value1 ^ (int)value2);
+ }
+
+ ///
+ /// Returns logical bitwise exclusive-OR of values.
+ ///
+ /// Left hand operand.
+ /// Right hand operand.
+ /// Integer value of the resulting exclusive-OR operation.
+ public static int operator ^(Int24 value1, int value2)
+ {
+ return ((int)value1 ^ value2);
+ }
+
+ ///
+ /// Returns value after right shifts of first value by the number of bits specified by second value.
+ ///
+ /// value to shift.
+ /// shifts indicates how many places to shift.
+ /// An value.
+ public static Int24 operator >>(Int24 value, int shifts)
+ {
+ return (Int24)(ApplyBitMask((int)value >> shifts));
+ }
+
+ ///
+ /// Returns value after left shifts of first value by the number of bits specified by second value.
+ ///
+ /// value to shift.
+ /// shifts indicates how many places to shift.
+ /// An value.
+ public static Int24 operator <<(Int24 value, int shifts)
+ {
+ return (Int24)(ApplyBitMask((int)value << shifts));
+ }
+
+ #endregion
+
+ #region [ Arithmetic Operators ]
+
+ ///
+ /// Returns computed remainder after dividing first value by the second.
+ ///
+ /// value as numerator.
+ /// value as denominator.
+ /// as remainder
+ public static Int24 operator %(Int24 value1, Int24 value2)
+ {
+ return (Int24)((int)value1 % (int)value2);
+ }
+
+ ///
+ /// Returns computed remainder after dividing first value by the second.
+ ///
+ /// value as numerator.
+ /// value as denominator.
+ /// as remainder
+ public static int operator %(int value1, Int24 value2)
+ {
+ return (value1 % (int)value2);
+ }
+
+ ///
+ /// Returns computed remainder after dividing first value by the second.
+ ///
+ /// value as numerator.
+ /// value as denominator.
+ /// as remainder
+ public static int operator %(Int24 value1, int value2)
+ {
+ return ((int)value1 % value2);
+ }
+
+ ///
+ /// Returns computed sum of values.
+ ///
+ /// Left hand operand.
+ /// Right hand operand.
+ /// Int24 result of addition.
+ public static Int24 operator +(Int24 value1, Int24 value2)
+ {
+ return (Int24)((int)value1 + (int)value2);
+ }
+
+ ///
+ /// Returns computed sum of values.
+ ///
+ /// Left hand operand.
+ /// Right hand operand.
+ /// Integer result of addition.
+ public static int operator +(int value1, Int24 value2)
+ {
+ return (value1 + (int)value2);
+ }
+
+ ///
+ /// Returns computed sum of values.
+ ///
+ /// Left hand operand.
+ /// Right hand operand.
+ /// Integer result of addition.
+ public static int operator +(Int24 value1, int value2)
+ {
+ return ((int)value1 + value2);
+ }
+
+ ///
+ /// Returns computed difference of values.
+ ///
+ /// Left hand operand.
+ /// Right hand operand.
+ /// Int24 result of subtraction.
+ public static Int24 operator -(Int24 value1, Int24 value2)
+ {
+ return (Int24)((int)value1 - (int)value2);
+ }
+
+ ///
+ /// Returns computed difference of values.
+ ///
+ /// Left hand operand.
+ /// Right hand operand.
+ /// Integer result of subtraction.
+ public static int operator -(int value1, Int24 value2)
+ {
+ return (value1 - (int)value2);
+ }
+
+ ///
+ /// Returns computed difference of values.
+ ///
+ /// Left hand operand.
+ /// Right hand operand.
+ /// Integer result of subtraction.
+ public static int operator -(Int24 value1, int value2)
+ {
+ return ((int)value1 - value2);
+ }
+
+ ///
+ /// Returns incremented value.
+ ///
+ /// The operand.
+ /// Int24 result of increment.
+ public static Int24 operator ++(Int24 value)
+ {
+ return (Int24)(value + 1);
+ }
+
+ ///
+ /// Returns decremented value.
+ ///
+ /// The operand.
+ /// Int24 result of decrement.
+ public static Int24 operator --(Int24 value)
+ {
+ return (Int24)(value - 1);
+ }
+
+ ///
+ /// Returns computed product of values.
+ ///
+ /// value as left hand operand.
+ /// value as right hand operand.
+ /// as result
+ public static Int24 operator *(Int24 value1, Int24 value2)
+ {
+ return (Int24)((int)value1 * (int)value2);
+ }
+
+ ///
+ /// Returns computed product of values.
+ ///
+ /// value as left hand operand.
+ /// value as right hand operand.
+ /// as result
+ public static int operator *(int value1, Int24 value2)
+ {
+ return (value1 * (int)value2);
+ }
+
+ ///
+ /// Returns computed product of values.
+ ///
+ /// value as left hand operand.
+ /// value as right hand operand.
+ /// as result
+ public static int operator *(Int24 value1, int value2)
+ {
+ return ((int)value1 * value2);
+ }
+
+ // Integer division operators
+
+ ///
+ /// Returns computed division of values.
+ ///
+ /// Left hand operand.
+ /// Right hand operand.
+ /// Int24 result of operation.
+ public static Int24 operator /(Int24 value1, Int24 value2)
+ {
+ return (Int24)((int)value1 / (int)value2);
+ }
+
+ ///
+ /// Returns computed division of values.
+ ///
+ /// Left hand operand.
+ /// Right hand operand.
+ /// Integer result of operation.
+ public static int operator /(int value1, Int24 value2)
+ {
+ return (value1 / (int)value2);
+ }
+
+ ///
+ /// Returns computed division of values.
+ ///
+ /// Left hand operand.
+ /// Right hand operand.
+ /// Integer result of operation.
+ public static int operator /(Int24 value1, int value2)
+ {
+ return ((int)value1 / value2);
+ }
+
+ //// Standard division operators
+ //public static double operator /(Int24 value1, Int24 value2)
+ //{
+ // return ((double)value1 / (double)value2);
+ //}
-#if NETSTANDARD2_0_OR_GREATER
+ //public static double operator /(int value1, Int24 value2)
+ //{
+ // return ((double)value1 / (double)value2);
+ //}
-#endif
+ //public static double operator /(Int24 value1, int value2)
+ //{
+ // return ((double)value1 / (double)value2);
+ //}
+
+ // C# doesn't expose an exponent operator but some other .NET languages do,
+ // so we expose the operator via its native special IL function name
+
+ ///
+ /// Returns result of first value raised to power of second value.
+ ///
+ /// Left hand operand.
+ /// Right hand operand.
+ /// Double that is the result of the operation.
+ [EditorBrowsable(EditorBrowsableState.Advanced), SpecialName]
+ public static double op_Exponent(Int24 value1, Int24 value2)
+ {
+ return Math.Pow((double)value1, (double)value2);
+ }
+
+ ///
+ /// Returns result of first value raised to power of second value.
+ ///
+ /// Left hand operand.
+ /// Right hand operand.
+ /// Double that is the result of the operation.
+ [EditorBrowsable(EditorBrowsableState.Advanced), SpecialName]
+ public static double op_Exponent(int value1, Int24 value2)
+ {
+ return Math.Pow((double)value1, (double)value2);
+ }
+
+ ///
+ /// Returns result of first value raised to power of second value.
+ ///
+ /// Left hand operand.
+ /// Right hand operand.
+ /// Double that is the result of the operation.
+ [EditorBrowsable(EditorBrowsableState.Advanced), SpecialName]
+ public static double op_Exponent(Int24 value1, int value2)
+ {
+ return Math.Pow((double)value1, (double)value2);
+ }
+
+ #endregion
+
+ #endregion
+
+ #region [ Static ]
+
+ ///
+ /// Represents the largest possible value of an Int24. This field is constant.
+ ///
+ public static readonly Int24 MaxValue = (Int24)MaxValue32;
+
+ ///
+ /// Represents the smallest possible value of an Int24. This field is constant.
+ ///
+ public static readonly Int24 MinValue = (Int24)MinValue32;
+
+ /// Returns the specified Int24 value as an array of three bytes.
+ /// Int24 value to convert to bytes.
+ /// An array of bytes with length 3.
+ ///
+ /// You can use this function in-lieu of a System.BitConverter.GetBytes(Int24) function.
+ /// Bytes will be returned in endian order of currently executing process architecture (little-endian on Intel platforms).
+ ///
+ public static byte[] GetBytes(Int24 value)
+ {
+ // We use a 32-bit integer to store 24-bit integer internally
+ byte[] data = new byte[3];
+ int valueInt = value;
+ if (BitConverter.IsLittleEndian)
+ {
+ data[0] = (byte)valueInt;
+ data[1] = (byte)(valueInt >> 8);
+ data[2] = (byte)(valueInt >> 16);
+ }
+ else
+ {
+ data[0] = (byte)(valueInt >> 16);
+ data[1] = (byte)(valueInt >> 8);
+ data[2] = (byte)(valueInt);
+ }
+
+ // Return serialized 3-byte representation of Int24
+ return data;
+ }
+
+ /// Returns a 24-bit signed integer from three bytes at a specified position in a byte array.
+ /// An array of bytes.
+ /// The starting position within value.
+ /// A 24-bit signed integer formed by three bytes beginning at startIndex.
+ ///
+ /// You can use this function in-lieu of a System.BitConverter.ToInt24 function.
+ /// Bytes endian order assumed to match that of currently executing process architecture (little-endian on Intel platforms).
+ ///
+ /// cannot be null.
+ /// is greater than length.
+ /// length from is too small to represent an .
+ public static Int24 GetValue(byte[] value, int startIndex)
+ {
+ if (value == null)
+ throw new ArgumentNullException(nameof(value), "Cannot be null");
+ if (startIndex > value.Length)
+ throw new ArgumentOutOfRangeException(
+ nameof(startIndex),
+ "Cannot be greater than length of value"
+ );
+ if (value.Length - startIndex < 3)
+ throw new ArgumentException(
+ "Array length from startIndex must be at least 3",
+ nameof(value)
+ );
+ if (value.Length - startIndex > 3)
+ throw new ArgumentException(
+ "Array length from startIndex must be no more than 3",
+ nameof(value)
+ );
+ if (value.Length == 0)
+ return 0;
+ int valueInt;
+ if (BitConverter.IsLittleEndian)
+ {
+ valueInt =
+ value[startIndex] | value[startIndex + 1] << 8 | value[startIndex + 2] << 16;
+ }
+ else
+ {
+ valueInt =
+ value[startIndex] << 16 | value[startIndex + 1] << 8 | value[startIndex + 2];
+ }
+ // Deserialize value
+ return (Int24)ApplyBitMask(valueInt);
+ }
+
+ private static void ValidateNumericRange(int value)
+ {
+ if (value > (MaxValue32 + 1) || value < MinValue32)
+ throw new OverflowException(
+ string.Format("Value of {0} will not fit in a 24-bit signed integer", value)
+ );
+ }
+
+ private static int ApplyBitMask(int value)
+ {
+ // Check bit 23, the sign bit in a signed 24-bit integer
+ if ((value & 0x00800000) > 0)
+ {
+ // If the sign-bit is set, this number will be negative - set all high-byte bits (keeps 32-bit number in 24-bit range)
+ value |= BitMask;
+ }
+ else
+ {
+ // If the sign-bit is not set, this number will be positive - clear all high-byte bits (keeps 32-bit number in 24-bit range)
+ value &= ~BitMask;
+ }
+
+ return value;
+ }
+
+ #endregion
+ }
}
diff --git a/src/ObjectId.cs b/src/ObjectId.cs
index 9790d4c..2e204c6 100644
--- a/src/ObjectId.cs
+++ b/src/ObjectId.cs
@@ -223,13 +223,13 @@ public static bool TryParse(string? s, IFormatProvider? provider, out ObjectId r
? BitConverter.GetBytes(((IObjectId)this).MachineId).Reverse().ToArray()
: BitConverter.GetBytes(((IObjectId)this).MachineId);
- public readonly int Counter => int.Parse(Value.Substring(17, 6), NumberStyles.HexNumber);
+ public readonly i24 Counter => i24.Parse(Value.Substring(17, 6), NumberStyles.HexNumber);
public readonly byte[] CounterBytes =>
BitConverter.IsLittleEndian
? BitConverter.GetBytes(((IObjectId)this).Counter).Reverse().ToArray()
: BitConverter.GetBytes(((IObjectId)this).Counter);
- private static int _counter = Random.NextInt32(0, i24.MaxValue);
+ private static i24 _counter = (i24)Random.NextInt32(0, i24.MaxValue);
public static int NextCounter() => _counter++;
@@ -243,7 +243,7 @@ public interface IObjectId
{
int Timestamp { get; }
long MachineId { get; }
- int Counter { get; }
+ i24 Counter { get; }
DateTimeOffset TimestampAsDateTimeOffset { get; }
#if NET6_0_OR_GREATER
static abstract ObjectId NewId();