Solved

Porting a packed variant record with bit fields

Posted on 2006-11-09
5
635 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
Comment Utility
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
Comment Utility
(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
Comment Utility
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
Comment Utility
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
Comment Utility
The Delphi2006 option seems easiest - thanks.

Geoff M.
0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
In this seventh video of the Xpdf series, we discuss and demonstrate the PDFfonts utility, which lists all the fonts used in a PDF file. It does this via a command line interface, making it suitable for use in programs, scripts, batch files — any pl…
Access reports are powerful and flexible. Learn how to create a query and then a grouped report using the wizard. Modify the report design after the wizard is done to make it look better. There will be another video to explain how to put the final p…

771 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

16 Experts available now in Live!

Get 1:1 Help Now