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 (3214 downloads )
Recent Comments