Re: Structures not behaving as value types

Richard Kucia <[email protected]> Mon, 25 Feb 2008 18:56:06 +0000
Newsgroups gmane.comp.windows.devel.dotnet.clr
Message-ID <022520081856.25086.47C30F460009C48B000061FE22230682329B0A02D29B9B0EBF0E070C9A05069D@att.net>
Option Explicit On
Option Strict On
Public Structure strFieldMask
Private Const K_BITS As Integer = 128
Private Const K_BITS_PER_ITEM As Integer = 32 '     32 bits per Integer
Private Const UBOUND As Integer = (K_BITS - 1) \ 32 '    Number of items required
Private Const HIGH_ORDER As Integer = 1 << 31 '      High order bit of an integer
Private mMask() As Integer '          Array of words with the bits
#Region "Accessors"
Private Property Mask(ByVal I As Integer) As Integer
 Get
  If mMask Is Nothing OrElse mMask.Length = 0 Then ReDim mMask(UBOUND)
  Return mMask(I)
 End Get
 Set(ByVal value As Integer)
  If mMask Is Nothing OrElse mMask.Length = 0 Then ReDim mMask(UBOUND)
  mMask(I) = value
 End Set
End Property
Public ReadOnly Property AsString() As String
Get
 Return Me.ToString()
End Get
End Property
#End Region
#Region "Operators"
Public Shared Operator =(ByVal Operand1 As strFieldMask, ByVal Operand2 As strFieldMask) As Boolean
For I As Integer = 0 To UBOUND
 If Operand1.Mask(I) <> Operand2.Mask(I) Then Return False
Next
Return True
End Operator
Public Shared Operator <>(ByVal Operand1 As strFieldMask, ByVal Operand2 As strFieldMask) As Boolean
Return Not (Operand1 = Operand2)
End Operator
Public Shared Operator And(ByVal Operand1 As strFieldMask, ByVal Operand2 As strFieldMask) As strFieldMask
Dim Result As New strFieldMask
For I As Integer = 0 To UBOUND
 Result.Mask(I) = Operand1.Mask(I) And Operand2.Mask(I)
Next
Return Result
End Operator
Public Shared Operator Or(ByVal Operand1 As strFieldMask, ByVal Operand2 As strFieldMask) As strFieldMask
Dim Result As New strFieldMask
For I As Integer = 0 To UBOUND
 Result.Mask(I) = Operand1.Mask(I) Or Operand2.Mask(I)
Next
Return Result
End Operator
Public Shared Operator Not(ByVal Operand As strFieldMask) As strFieldMask
Dim Result As New strFieldMask
For I As Integer = 0 To UBOUND
 Result.Mask(I) = Not Operand.Mask(I)
Next
Return Result
End Operator
Public Shared Operator <<(ByVal Operand As strFieldMask, ByVal Bits As Integer) As strFieldMask
Dim Result As strFieldMask
Dim BitCrossing As Integer
' Brute force method: shift one bit at a time
Result = Operand
For Bit As Integer = 1 To Bits
 For I As Integer = UBOUND To 0 Step -1 '      From MS to LS
  If I > 0 Then '            If a lower bit could be promoted...
   If (Operand.Mask(I - 1) And HIGH_ORDER) <> 0 Then '  ...then capture the bit that crosses the word
    BitCrossing = 1
   Else
    BitCrossing = 0
   End If
  Else
   BitCrossing = 0 '          ...else this is the LSW -- shift-in a 0
  End If
  Result.Mask(I) = (Result.Mask(I) << 1) Or BitCrossing
 Next
Next
Return Result
End Operator
#End Region
#Region "Other Functions and Methods"
Public Property Bit(ByVal BitNumber As Integer) As Boolean
Get
 Const One As Integer = 1
 Dim I As Integer
 Dim TheBit As Integer
 I = BitNumber \ K_BITS_PER_ITEM
 TheBit = Mask(I) And (One << (BitNumber Mod K_BITS_PER_ITEM))
 Return (TheBit <> 0)
End Get
Set(ByVal State As Boolean)
 If State Then
  SetBit(BitNumber)
 Else
  ResetBit(BitNumber)
 End If
End Set
End Property
Public Sub SetBit(ByVal BitNumber As Integer)
Const One As Integer = 1
Dim I As Integer
I = BitNumber \ K_BITS_PER_ITEM
Mask(I) = Mask(I) Or (One << (BitNumber Mod K_BITS_PER_ITEM))
End Sub
Public Sub ResetBit(ByVal BitNumber As Integer)
Const One As Integer = 1
Dim I As Integer
I = BitNumber \ K_BITS_PER_ITEM
Mask(I) = Mask(I) And Not (One << (BitNumber Mod K_BITS_PER_ITEM))
End Sub
Public Sub Zero()
For I As Integer = 0 To UBOUND
 Mask(I) = 0
Next
End Sub
Public ReadOnly Property IsZero() As Boolean
Get
 For I As Integer = 0 To UBOUND
  If Mask(I) <> 0 Then Return False
 Next
 Return True
End Get
End Property
#End Region
#Region "ToString"
Public Overrides Function ToString() As String
Const BYTEMASK As Integer = &HFF
Dim str As System.Text.StringBuilder
Dim B(K_BITS \ 8 - 1) As Byte
Dim N As Integer
Dim Word As Integer
N = 0
For I As Integer = 0 To UBOUND
 Word = Mask(I)
 For ByteNumber As Integer = 0 To K_BITS_PER_ITEM \ 8 - 1
  B(N) = Convert.ToByte(Word And BYTEMASK)
  Word = Word >> 8 '           Put the next byte into the low-order position
  N += 1
 Next
Next
str = New System.Text.StringBuilder
For N = B.Length - 1 To 0 Step -1
 str.AppendFormat("{0:X2} ", B(N))
Next
Return str.ToString
End Function
#End Region
End Structure



-------------- Original message from Greg Young <[email protected]>: --------------


> Can you put up your code?
>
> On Mon, Feb 25, 2008 at 10:44 AM, Richard Kucia wrote:
> > Well, in fact it does. The mask structure contains one array of N 32-bit
> integers to hold the bits. Each time any function or property of the mask is
> invoked, that code tests the array to see if it is (nothing), and Redim's it.
> >
> > So that explains it. The formula mentioned below takes the most recently used
> mask structure and shifts it left 1 bit. So each request for another mask is
> obviously getting the same object reference, and when the bit-shift occurs, it
> effectively occurs in every mask structure, since they are all referencing the
> same array.
> >
> > So what is the correct way to handle this? I want each structure to have its
> own independent array of N 32-bit integers.
> >
> > Rick
> > -------------- Original message from Matthew Wills
> : --------------
> >
> >
> >
> > > Richard,
> > >
> > > Show us the code for strFieldMask. I would bet you are using some reference
> > > types in it.
> > >
> > > Seeya
> > > Matthew Wills | Solution Designer | Adviser Tools and Services | Financial
> > > Planning and Third Party | NAB Technology
> > >
> > > Phone: 02 9376 4029 | Mobile: 0435 002 520 | Email:
> > > [email protected]
> > >
> > >
> > >
> > >
> > > Richard Kucia
> > >
> >
> >
> > > To
> > > [email protected]
> > > cc
> > >
> > > Subject
> > > [DOTNET-CLR] Structures not
> > > behaving as value types
> > >
> > > I have a VB.Net declaration of a structure strFieldMask. The intended
> > > purpose is to store a bunch of bits, like a bit vector. The structure also
> > > has operator declarations for =, <>, And, Or, Not and <<, plus some other
> > > methods for bit manipulation.
> > >
> > > The problem is that variables of type strFieldMask seem to behave as
> > > though there was a singleton strFieldMask and all instances shared it.
> > >
> > > Consider this:
> > >
> > > Dim Mask1 as strFieldMask
> > > Dim Mask2 as strFieldMask
> > >
> > > Mask1 = (formula for computing the next unused mask value)
> > > Debug.WriteLine(Mask1.ToString))
> > > Mask2 = (same formula)
> > > Debug.WriteLine(Mask1.ToString)) ' Yes, Mask1, not Mask2
> > >
> > > The result from the first WriteLine might be "0x10" and the result from
> > > the second WriteLine might be "0x20".
> > >
> > > I've successfully used structures before, but this is the first time I've
> > > tried overloading the operators. Has that caused the behavior I'm seeing?
> > >
> > > Thanks.
> > >
> > >
> > >
> > > National Australia Bank Ltd - ABN 12 004 044 937
> > > This email may contain confidential information. If you are not the
> intended
> > > recipient, please immediately notify us at [email protected] or by
> replying
> > > to
> > > the sender, and then destroy all copies of this email. Except where this
> email
> > > indicates otherwise, views expressed in this email are those of the sender
> and
> > > not
> > > of National Australia Bank Ltd. Advice in this email does not take account
> of
> > > your
> > > objectives, financial situation, or needs. It is important for you to
> consider
> > > these
> > > matters and, if the e-mail refers to a product(s), you should read the
> relevant
> > > Product Disclosure Statement(s)/other disclosure document(s) before making
> any
> > > decisions. If you do not want email marketing from us in future, forward
> this
> > > email
> > > with "unsubscribe" in the subject line to [email protected] in
> order to
> > > stop marketing emails from this sender. National Australia Bank Ltd does
> not
> > > represent that this email is free of errors, viruses or interference.
> > >
> > > ===================================
> > > This list is hosted by DevelopMentor(R) http://www.develop.com
> > >
> > > View archives and manage your subscription(s) at http://discuss.develop.com
> >
> > ===================================
> > This list is hosted by DevelopMentor(R) http://www.develop.com
> >
> > View archives and manage your subscription(s) at http://discuss.develop.com
> >
>
>
>
> --
> Studying for the Turing test
>
> ===================================
> This list is hosted by DevelopMentorĀ® http://www.develop.com
>
> View archives and manage your subscription(s) at http://discuss.develop.com

===================================
This list is hosted by DevelopMentorĀ®  http://www.develop.com

View archives and manage your subscription(s) at http://discuss.develop.com