Next: , Previous: , Up: Structuring Data   [Contents][Index]


4.6 Poking Structs

4.6.1 Heterogeneous Related Data

Let’s recap the structure of the header of a Stupid BitMap:

                SBM header
+-------+-------+-------+-------+-------+
|  'S'  |  'B'  |  'M'  |  ppl  | lines |
+-------+-------+-------+-------+-------+
  byte0   byte1   byte2   byte3   byte4

The header is composed of five fields, which actually compose three different logical fields: a magic number, the number of pixels per line, and the number of lines.

We could of course abstract the header using an array of five bytes, like this:

type SBM_Header = byte[5];

However, this would not capture the properties of the fields themselves, which would need to be remembered by the user: which of these five bytes correspond to the magic number? Is the pixels per line number signed or unsigned? etc.

Poke provides a much better way to abstract collections of heterogeneous data: struct types. Using a struct type we can abstract the SBM header like this:

type SBM_Header =
 struct
 {
   byte[3] magic;
   uint<8> ppl;
   uint<8> lines;
 }

Note how the struct has three named fields: magic, ppl and lines. magic is an array of three bytes, while ppl and lines are both unsigned integers.

4.6.2 Mapping Structs

Once defined, struct types can be referred by name. For example, we can map the SBM header at the beginning of our file p.sbm like this:

(poke) SBM_Header @ 0#B
SBM_Header {
  magic=[0x53UB,0x42UB,0x4dUB],
  ppl=0x5UB,
  lines=0x7UB
}

The value resulting from the mapping is a struct value. The fields of struct values are accessed using the familiar dot-notation:

(poke) var header = SBM_Header @ 0#B
(poke) header.ppl * header.lines
35UB

The total number of pixels in the image is 35. Note how both header.ppl and header.lines are indeed unsigned byte values, and thus the result of the multiplication is also an unsigned byte. This could be problematic if the image contained more than 255 pixels, but this can be prevented by using a cast:

(poke) header.ppl as uint * header.lines
35U

Now the second operand header.lines is promoted to a 32-bit unsigned value before the multiplication is performed. Consequently, the result of the operation is also 32-bit wide (note the suffix of the result.)

4.6.3 Modifying Mapped Structs

Remember when we wanted to crop a SBM image by removing the first and last row? We updated the header in a byte by byte manner, like this:

(poke) byte @ 3#B = 3
(poke) byte @ 4#B = 7

Now that we have the header mapped in a variable, updating it is much more easy and convenient. The dot-notation is used to update the contents of a struct field, by placing it at the left hand side of an assignment:

(poke) header.ppl = 3
(poke) header.lines = 7

This updates the pixel per line and the number of lines, in the IO space:

(poke) dump :size 5#B
76543210  0011 2233 4455 6677 8899 aabb ccdd eeff  0123456789ABCDEF
00000000: 5342 4d03 07                             SBM..

Next: , Previous: , Up: Structuring Data   [Contents][Index]