[fpc-pascal] Can you knock my socks off ? Can you mimic Skybuck's/Delphi's Major Breakthrough for code path and memory structure selection ?

Skybuck Flying skybuck2000 at hotmail.com
Sat Feb 9 22:53:45 CET 2008


Hello,

This usenet posting discussess what I consider to be a major breakthrough 
for me and Delphi coding in general.

It explains what I need and want to do and how I solved it.

So instead of typing the whole idea again I simply copy and paste what I 
posted back then on this mailing list plus the features the code uses:

New Delphi 2007 Features used:

"methods in records"

"properties in records"

Later I even used "class method in records" but not discussed below.

Old features used:

"variant types/records or whatever"

"case statements used to switch code paths"

"pointers used to switch memory structures/layouts"

"typecasts used to access fields from raw/untyped pointer"

None the less very interesting example.

Problem is ofcourse FPC does not support the new Delphi 2007 features.

And the big question is how would you port this code to FPC ?

My bet is it would drive you crazy because you can't get it to work.

And if you can your code will probably be ugly and huge ?

Can you prove me wrong ? and knock my socks off ?

Original posting from meeeee:

"
Hello,

Seperating record storage from record handling was a good and nice idea (I
knew it all along lol)

This garantuees:

1. Compactness of the record/storages.

2. No gaps

3. Adding "handling" fields can be done to the handling records... so these
fields aren't transmitted to save bandwidth which is good.

4. Nice seperation of handling code.

5. Flexiblity, selecting structure based on bitmode is now possible.

6. Internal handling of largest supported type is possible and includes ZERO
PERFORMANCE HIT to program... especially once delphi goes 64 bit.
(For now there is a small performance hit because uint64 type is emulated)

7. Finally only a little performance hit by reading and writing finally.
Which is neglectiable.

8. Also bitmode can be set once and is remember. Isn't transmitted...
ofcourse for a protocol a "info" packet could be sent once to inform the
other side of the bitmode ;)

9. And finally as already mentioned... the program can now write code pretty
much just once, high performant by simply using the natives types as
provided by the handling code.

10. No stupid properties... Actually those properties causes some weird
const/compiler problems... so that wasn't even possible.

(So fields need to be direct not via properties.)

11. And most important: Internal number can be passed to var parameters !
EXCELLENT

See code for example which might be more clear then this wacky explanation
above LOL.

Brilliant piece of code if I say so myself.

This is definetly usuable and actually will increase the performance of my
code !

NEAR ZERO PERFORMANCE HIT...

Just need a read once and write once... LOVELY

And can code it just once LOL LOVELY !

MAXIMUM COMPACTNESS

NO GAPS

LOVELY ;)

// *** Begin of Code ***

program ProjectSelectingStructureV6;

{$APPTYPE CONSOLE}

{

Selecting a Structure Idea

Version 0.01 created on 10 oktober 2007 by Skybuck Flying

I wish I could select a structure based on a variable.

Example code below.

There must be no compiler generated gaps in the structures, that would cost
space !
That's why the structures are "packed" to save space !

See *** below for feature idea.

Some success with code below

No gaps, A nice property, modest code overhead.

Probably still can't be passed as var parameters..

But this solves 50% of the problem.

My comments from the usenet:

The following code solves 50% of the problem.

Internally the program can work with the largest integer type available.

When the programs needs to read or write to the packet it can specify the
bit mode.

Only those bits will be read or written to/from the packet no ovewrites
should occur.

Only problem remains is the property Number can not be passed to var
parameters.

At least now the programmer can write single lines of code and not used case
statements anymore in maybe 50% of the time ;)

}


{

version 0.06 created on 11 oktober 2007 by Skybuck Flying !

One might call this a major breakthrough ! ;)

All problems now solved.

Selecting structures based on bit mode is now possible...

It's even done only once, only when bitmode is set/changed.

By using NumberRead, NumberWrite... the internal storage Number can be read
or written
to the real package.

The internal storage number simply called "Number : Uint64"... can be used
to do internal program coding.

The storage/internal/temp 64 bit number can be passed as a var parameter so
this solves that problem as well !

All problems now 100% solved and performance further increased ;) especially
when bit mode only has to be set a few times or so ;)

Also the storage structures and the handling code is nicely seperated.

Some extra fields in the handling code requires a little bit more memory...
but the storage
remains compact and gap free ! ;)

Simply call NumberWrite... if the number is to be written to the package...

This could be done at a final stage right before sending the package.

Also reading would have to be done only once etc...

And working with uint64 directly is pretty fast... SO NO PERFORMANCE HIT
what so ever !

EXCELLENT

}


uses
  SysUtils;

type
 TbitMode = ( bm_8, bm_16, bm_32, bm_64 );

type
 // storage
 Pheader8bit = ^Theader8bit;
 Theader8bit = packed record
  mNumber : byte;
  mLength : word;
 end;

 Pheader16bit = ^Theader16bit;
 Theader16bit = packed record
  mNumber : word;
  mLength : word;
 end;

 Pheader32bit = ^Theader32bit;
 Theader32bit = packed record
  mNumber : longword;
  mLength : word;
 end;

 Pheader64bit = ^Theader64bit;
 Theader64bit = packed record
  mNumber : uint64;
  mLength : word;
 end;

 TpacketStorage = packed record
  case TbitMode of
   bm_8 : ( Header_8_bit : Theader8bit; ); // must use different names for
header
   bm_16 : ( Header_16_bit : Theader16bit; );
   bm_32 : ( Header_32_bit : Theader32bit; );
   bm_64 : ( Header_64_bit : Theader64bit; );
 end;

 // handling code:

 TheaderHandling = record
 private
  mBitMode : TbitMode;
  mHeaderPointer : pointer;
 public
  Number : uint64;

  procedure NumberWrite;
  procedure NumberRead;
 end;

 // handling
 TpacketHandling = record
 private
  mBitMode : TbitMode;
  mPacketStorage : TpacketStorage;

  procedure SetBitMode( ParaBitMode : TbitMode );
 public
  Header : TheaderHandling;
  property BitMode : TbitMode read mBitMode write SetBitMode;
 end;

// set header pointer just once :) for further use ;)
procedure TpacketHandling.SetBitMode( ParaBitMode : TbitMode );
begin
 mBitMode := ParaBitMode;
 Header.mBitMode := ParaBitMode;

 case ParaBitMode of
  bm_8 :
  begin
   Header.mHeaderPointer := @mPacketStorage.Header_8_bit;
  end;

  bm_16:
  begin
   Header.mHeaderPointer := @mPacketStorage.header_16_bit;
  end;

  bm_32:
  begin
   Header.mHeaderPointer := @mPacketStorage.header_32_bit;
  end;

  bm_64:
  begin
   Header.mHeaderPointer := @mPacketStorage.header_64_bit;
  end;
 end;
end;

procedure THeaderHandling.NumberWrite;
begin
 case mBitMode of
  bm_8:
  begin
   Pheader8bit(mHeaderPointer).mNumber := byte(Number);
  end;

  bm_16:
  begin
   Pheader16bit(mHeaderPointer)^.mNumber := word(Number);
  end;

  bm_32:
  begin
   Pheader32bit(mHeaderPointer)^.mNumber := longword(Number);
  end;

  bm_64:
  begin
   Pheader64bit(mHeaderPointer)^.mNumber := uint64(Number);
  end;
 end;
end;

procedure THeaderHandling.NumberRead;
begin
 case mBitMode of
  bm_8:
  begin
   Number := Pheader8bit(mHeaderPointer).mNumber;
  end;

  bm_16:
  begin
   Number := Pheader16bit(mHeaderPointer).mNumber;
  end;

  bm_32:
  begin
   Number := Pheader32bit(mHeaderPointer).mNumber;
  end;

  bm_64:
  begin
   Number := Pheader64bit(mHeaderPointer).mNumber;
  end;
 end;
end;

procedure Test( var ModifyMe : Uint64 );
begin
 ModifyMe := 258;
end;

var
 vPacket : TpacketHandling;
begin
 try
  // set packet mode just once ;)
  vPacket.BitMode := bm_8;

  // write a number to the packet in it's bit mode ;)
  vPacket.Header.Number := 257;
  vPacket.Header.NumberWrite;

  // read what was stored ;)
  vPacket.Header.NumberRead;
  writeln( vPacket.Header.Number );

  // read number
  vPacket.Header.NumberRead; // not really necessary but let's do it anyway
;)
  Test( vPacket.Header.Number );
  vPacket.Header.NumberWrite;

  // read number and show it
  vPacket.Header.NumberRead;
  writeln( vPacket.Header.Number );

 except
  on E : Exception do
  begin
   writeln( e.Message );
  end;

 end;

 readln;
end.

// *** End of Code ***

Bye,
  Skybuck. 




More information about the fpc-pascal mailing list