Advanced literals for Visual Studio
As soon as I learned that Microsoft had opened a channel at uservoice.com so that we (developers) could suggest new/improved features for the upcoming Visual Studio 11 (now known as Visual Studio 2012), the first thing I wanted to suggest was the ability to easily handle numbers of different bases, natively.
Regardless of the language, which in this case is VB, consider the beauty and simplicity of the following code:
Dim decNum = 726d Dim binNum = 1001b Dim hexNum = f7a1h Dim octNum = 167o
Here we are initializing several numeric variables which obtain their value based on a compiler automated procedure that converts the number into an unsigned integer from a base predefined by a suffix letter that conditions the conversion to the appropriate base type.
Then we would require simple ToXXX() functions (as well as “CType “, “DirectCast” or “as”, in C#, support) in order to easily and specifically convert from one type to another without requiring a string intermediate, as we do now… which, frankly, sucks!
For this to work, the Framework should implement distinct types for each base (of course, only for the most common ones) and derive them all from UInt (and make UInt inheritable) so that it’s easy to perform simple type castings between them and allows us to extend it to support any custom base.
In an attempt to overcome the limitations of the Framework in regards to its support for different bases I’ve been working on a class that should ease the process of working with binary values inside Visual Studio.
Nothing fancy… and nothing even close to what I’m proposing here but it definitely helps.
Here’s the code for the class:
Public Class Binary Public Enum Sizes Bit = 1 Nibble = 4 [Byte] = 8 Word = 16 DoubleWord = 32 QuadWord = 64 'DoubleQuadWord = 128 Undefined = -1 End Enum Private binaryValue As Long Private mSize As Sizes Public Sub New() mSize = Sizes.Word End Sub Public Sub New(value As Long, Optional size As Sizes = Sizes.Undefined) Me.New() binaryValue = Math.Abs(value) If size = Sizes.Undefined Then CalculateMinimumSize() Else mSize = size binaryValue = binaryValue And Mask(size) End If End Sub Public Sub New(value As String, Optional size As Sizes = Sizes.Undefined) Dim binValue As Binary = 0 TryParse(value, binValue) binaryValue = binValue If size = Sizes.Undefined Then mSize = binValue.Size Else mSize = Sizes.Word End If End Sub Public Shared Function TryParse(value As String, ByRef result As Long) As Boolean Try Select Case value.Last() Case "d" result = Long.Parse(value.TrimEnd("d")) Return True Case "h" result = Convert.ToInt32(value.TrimEnd("h"), 16) Return True Case "b" result = Convert.ToInt32(value.TrimEnd("b"), 2) Return True Case "o" result = Convert.ToInt32(value.TrimEnd("o"), 8) Return True Case Else Dim base As Integer = 2 For Each c In value If c <> "0" AndAlso c <> "1" Then If c >= "A" AndAlso c <= "F" Then base = 16 ElseIf c < "0" OrElse c > "F" Then base = -1 Exit For ElseIf base <> 16 Then base = 10 End If End If Next If base = -1 Then Return False Else result = Convert.ToInt32(value, base) Return True End If End Select Catch Return False End Try End Function Public Property Size As Sizes Get Return mSize End Get Set(value As Sizes) mSize = value End Set End Property Public Shared Narrowing Operator CType(value As Long) As Binary Return New Binary(value) End Operator Public Shared Narrowing Operator CType(value As Int32) As Binary Return New Binary(CUInt(Math.Abs(value))) End Operator Public Shared Narrowing Operator CType(value As String) As Binary Dim result As Binary = 0 Binary.TryParse(value, result) Return result End Operator Public Shared Widening Operator CType(value As Binary) As Long Return value.ToLong() End Operator Public Shared Operator =(value1 As Binary, value2 As Binary) As Boolean Return value1.ToLong() = value2.ToLong() End Operator Public Shared Operator <>(value1 As Binary, value2 As Binary) As Boolean Return Not value1 = value2 End Operator Public Shared Operator >(value1 As Binary, value2 As Binary) As Boolean Return value1.ToLong() > value2.ToLong() End Operator Public Shared Operator value2 End Operator Public Shared Operator >=(value1 As Binary, value2 As Binary) As Boolean Return value1.ToLong() >= value2.ToLong() End Operator Public Shared Operator = value2 End Operator Public Shared Operator +(value1 As Binary, value2 As Binary) As Binary Return AdjustSize(value1.ToLong() + value2.ToLong(), value1.Size) End Operator Public Shared Operator -(value1 As Binary, value2 As Binary) As Binary Return AdjustSize(value1.ToLong() - value2.ToLong(), value1.Size) End Operator Public Shared Operator *(value1 As Binary, value2 As Binary) As Binary Return AdjustSize(value1.ToLong() * value2.ToLong(), value1.Size) End Operator Public Shared Operator /(value1 As Binary, value2 As Binary) As Binary Return AdjustSize(value1.ToLong() \ value2.ToLong(), value1.Size) End Operator Public Shared Operator \(value1 As Binary, value2 As Binary) As Binary Return value1 / value2 End Operator Public Shared Operator ^(value1 As Binary, value2 As Binary) As Binary Return AdjustSize(value1.ToLong() ^ value2.ToLong(), value1.Size) End Operator Public Shared Operator Mod(value1 As Binary, value2 As Binary) As Binary Return AdjustSize(value1.ToLong() Mod value2.ToLong(), value1.Size) End Operator Public Shared Operator And(value1 As Binary, value2 As Binary) As Binary Return value1.ToLong() And value2.ToLong() End Operator Public Shared Operator Or(value1 As Binary, value2 As Binary) As Binary Return value1.ToLong() Or value2.ToLong() End Operator Public Shared Operator Xor(value1 As Binary, value2 As Binary) As Binary Return value1.ToLong() Xor value2.ToLong() End Operator Public Shared Operator Not(value1 As Binary) As Binary Return AdjustSize(Not value1.ToLong(), value1.Size) End Operator Public Shared Operator <>(value1 As Binary, value2 As Integer) As Binary Return AdjustSize(value1.ToLong() >> value2, value1.Size) End Operator Public Shared Function From(value As String, Optional size As Sizes = Sizes.Undefined) As Binary Return New Binary(value, size) End Function Public Shared Function From(value As Long, Optional size As Sizes = Sizes.Undefined) As Binary Return New Binary(value, size) End Function Public Shared Function From(value As Int32, Optional size As Sizes = Sizes.Undefined) As Binary Return Binary.From(CUInt(Math.Abs(value)), size) End Function Private Shared Function AdjustSize(value As Long, size As Sizes) As Binary Return New Binary(value And Mask(size), size) End Function Private Shared Function Mask(size As Sizes) As Long Return (2 ^ size) - 1 End Function Public Function ToLong() As Long Return binaryValue End Function Public Overrides Function ToString() As String Return ConvertToBase(2).PadLeft(mSize, "0") End Function Public Function ToHex() As String Return ConvertToBase(16) End Function Public Function ToOctal() As String Return ConvertToBase(8) End Function Private Sub CalculateMinimumSize() If binaryValue 0 Return result End If End If End Function End Class
The class is very basic and allows for the easy initialization of values of different bases.
It also provides a rudimentary support for basic arithmetic and logic operations between values instantiated with the class against native numerical data types.
It won’t server of any use in regards to performance or functionality. The whole and only purpose of the class is to let you write less awkward looking code so that it is easier to understand and maintain.
Attached is a ZIP file containing the Binary Class along with a simple test module.
Hope you find it useful!
UPDATE (2012/Sept/9): I’ve changed the original Parse() function into a TryParse() function to easily detect when the parser is not able to identify the correct base for the value being passed.
BinaryClass (1936 downloads )
Recent Comments