Up to now all the examples of padding we have shown are in the category of esoteric or internal padding, i.e. it was intended to add space between fields of some particular entity.
However, sometimes we want to specify some padding between the elements of a sequence of entities. In Poke this basically means an array.
Suppose we have a simple file system that is conformed by a sequence of inodes. The contents of the file system have the following form:
+-----------------+ | inode | +-----------------+ : : : data : : : +-----------------+ | inode | +-----------------+ : : : data : : : +-----------------+ | ... |
That’s it, each inode describes a block of data of variable size that immediately follows. Then more pairs of inode-data follow until the end of the device. However, a requirement is that each inode has to be aligned to 128 bytes.
Let’s start by writing a simple type definition for the inodes:
type Inode = struct { string filename; int perms; offset<uint<32>,B> data_size; };
This definition is simple enough, but it doesn’t allow us to just map an array of inodes like this:
(poke) Inode[] 0#B
We could of course add the data and padding explicitly to the inode structure:
type Inode = struct { string filename; int perms; offset<uint<32>,B> data_size; byte[data_size] data; byte[alignto (data_size, 128#B)] padding; };
Then we could just map Inode[] @ 0#B
and we would the get expected
result.
But this is not a good idea. On one hand because, as we know, this would imply mapping the full file system data byte by byte, and that would be very very slow. On the other hand, because the data is not part of the inode, conceptually speaking.
A better solution is to use this idiom:
type Inode = struct { string filename; int perms; offset<uint<32>,B> data_size; byte[0] @ OFFSET + data_size + alignto (data_size, 128#B); };
This uses an anonymous field at the end of the struct type, of size zero, located at exactly the offset where the data plus padding would end in the version with explicit fields.
This later solution is fast and still allows us to get an array of inodes reflecting the whole file system with:
(poke) var inodes = Inode[] @ 0#B
Like in the previous sections, a method =get_data_offset= can be added to the struct type in order to allow accessing the data blocks corresponding to a given inode.