Solved

Porting a packed variant record with bit fields

Posted on 2006-11-09
5
642 Views
Last Modified: 2010-04-05
We've got a program to port which heavily uses a record with variant parts looking something like this:
 TData = packed record
    case integer of
      1: (sword : word);
      2: (byte0 : byte; byte1: byte);
      3: (bits10_0 : 0..1023; bits 6_10 : 0..63);
    etc.

In other words, the record is supposed to store a single word, but there are different methods of accessing that word - or parts of that word. Delphi creates this record as a word for each entry (SizeOf returns 16). Setting mydata.sword to $1234 and then reading mydata.byte0 returns 0 instead of $34.

My immediate reaction was to create a class with properties called bits10_0 and Getbits10_0 and Setbits10_0 as that would involve the minimum of changes. But, of course, classes are not variables like records are.

The only thing I can think of is to change every single read and write of these data items with a function or procedure instead. There are potentially 1000 of these - and a find/replace won't work. Is there a better and easier solution?

Thanks
0
Comment
Question by:gmayo
  • 2
  • 2
5 Comments
 
LVL 17

Accepted Solution

by:
Wim ten Brink earned 125 total points
ID: 17905341
If it's supposed to store a single word, it SizeOf would return the size of a word, thus 2 bytes. You're having 16 bytes here...

The solution would be to use operators like AND/OR/XOR and SHL/SHR on this. For example,
if you want to get the right-most 3 bits, use: MyData and $0007
If you want the 4 bits to the left, use: (MyData AND $F000) SHR 12
if you want to set the 8 bytes in the middle, use: MyData := MyData or ((Value SHL 4) and $0FF)

Yeah, I know... C++ does this easier since C++ allows you to manipulate data at the bit-level. Delphi only supports the byte level.

Btw, this part: (bits10_0 : 0..1023; bits 6_10 : 0..63);
That will already make your record 3 bytes in size. First two bytes for the range 0..1023 and then one byte for the range 0..63. So your overhead comes from this construction.

In Delphi 2006 it is possible to write record methods so that would allow you to do something like this:

type
  TData = packed record
    Data: Word;
    function GetBits10_0: Word;
    procedure SetBits10_0(Value: Word);
    property Bits10_0: Word read GetBits10_0 write SetBits10_0;
  end;

And of course you would have to write code that will AND/OR/XOR/SHL/SHR the data in it's proper place. And it's still just a record so no inheritance here. Or overriding methods. Or virtual methods. The SizeOf would just return 2 in this case.
0
 
LVL 8

Author Comment

by:gmayo
ID: 17905386
(bits10_0 : 0..1023; bits 6_10 : 0..63); is actually 16 bits, ie 2 bytes.

The reason Delphi reports 16 bytes insteaf of 2 is because there is another Case with 16 "bits" which Delphi treats as bytes, hence 16 bytes. It will always return the *largest* possible size of the variant record.

I know how I can solve this by changing all the access routines that do the bit manipulation, but as I say, there are around 1000 of them and I don't want to change each one by hand. Obviously these would involve and/or/shl/shr etc.

Interesting that D2006 supports methods in records. I have a copy of that somewhere.

The annoying thing is, I did exactly the same thing about 10 years ago - but I can't remember how I solved it then!

Thanks.
0
 
LVL 17

Expert Comment

by:Wim ten Brink
ID: 17905509
As an alternative option, you might want to use a set.

type
  TData = packed record
    case integer of
      1: (Data: Word);
      2: (Byte1, Byte2: Byte);
      3: (DataSet: set of 0..15);
    end;

This is exactly two bytes and allows you to manipulate every bit and also the whole package. And the lower and higher byte. And of course you could use set operators to check and modify the contents. (For example, multiplying or adding two sets...)
0
 
LVL 9

Expert Comment

by:alkisg
ID: 17917452
Put properties in your struct. I tried this in Delphi 2006 and worked fine:

type
  TenBits = 0..1023;
  TData = packed record
    function GetBits0_9: TenBits;
    procedure SetBits0_9(value: TenBits);
    property Bits0_9: TenBits read GetBits0_9 write SetBits0_9;
    case byte of
      1: (sword : word);
      2: (byte0 : byte; byte1: byte);
    end;

function TData.GetBits0_9: TenBits;
begin
  Result := sword and $3FF;
end;

procedure TData.SetBits0_9(value: TenBits);
begin
  sword := sword and $FC00 or value;
end;
0
 
LVL 8

Author Comment

by:gmayo
ID: 18043792
The Delphi2006 option seems easiest - thanks.

Geoff M.
0

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Objective: - This article will help user in how to convert their numeric value become words. How to use 1. You can copy this code in your Unit as function 2. than you can perform your function by type this code The Code   (CODE) The Im…
In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
This Micro Tutorial hows how you can integrate  Mac OSX to a Windows Active Directory Domain. Apple has made it easy to allow users to bind their macs to a windows domain with relative ease. The following video show how to bind OSX Mavericks to …
Many functions in Excel can make decisions. The most simple of these is the IF function: it returns a value depending on whether a condition you describe is true or false. Once you get the hang of using the IF function, you will find it easier to us…

911 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

17 Experts available now in Live!

Get 1:1 Help Now