It all started with the need to write an extremely fast and flexible algorithm to search for patterns in a large block of memory.
I need it for hacking the firmware of the rb532a router; patterns are hex-blocks, and the search key needs to use wildcards.
hex_search_ans_t hex_search
(
p_o_lineadv_t p_o_blk,
p_o_lineadv_t p_o_key,
p_o_lineadv_t p_o_msk
)
since the search key must also work with wildcards, I combined three algorithms
- evaluates the shortest subkey that does not contain wildcards: f(key, msk) -> toe
- quickly searches for the position of the first occurrence of toe, which is presumably assumed as a candidate for the solution
- classic pattern matching that uses the original search { key, msk } to confirm/reject the candidate
typedef struct
{
p_char_t p; /* point to the body */
uint32_t i0; /* starting position */
uint32_t i1; /* ending position */
uint32_t size; /* body size */
} o_lineadv_t;
All the algorithms uses a special type, which is a superset of safestring and can also handle array of hex chars
I decided to split the searching key into two things, an array containing all the hex values of key and a mask containing nothing but the wildcards.
This way, it's super clean and flexible, but these two arrays must be of the same lenght, and use the same offset.
o_lineadv_copy(p_o_key, p_o_toe); /* source -> target */
l0_key_toe0_get(p_o_toe, p_o_msk); /* case toe begins with a wildcard */
l0_key_toe1_get(p_o_toe, p_o_msk); /* case toe first char after a wildcard */
toe is dynamically created as (field-by-field) copy of o_key, then it's modified.
/*
* key and msk must be intertwined
* in practice their structures must have the same values
* except the field which points to two different bodies
*/
is_ok = o_lineadv_is_comparable(p_o_key, p_o_msk);
if (is_ok isEqualTo True)
{
...
}
else
{
panic(module, fid, "key and msk must be intertwined");
ans.i0 = p_o_msg->i0;
ans.is_valid = False;
}
In practice their structures must have the same values except the field which points to two different bodies!
The first version of the library was full of these checkpoints, then... I asked myself if they could be avoided!
And ...
... and that's how I got the idea to create a new language-feauture.
Something that I don't even know if anyone has already thought of or if it's useful... but experimenting it seems to be!
entanglement o_lineadv_t
{
p: no; /* will not be shared */
i0: yes; /* will be shared */
i1: yes; /* will be shared */
size: yes; /* will be shared */
} o_key, o_msk;
p_o_lineadv_t p_o_key;
p_o_lineadv_t p_o_msk;
p_o_key = get_address(o_key);
p_o_msk = get_address(o_msk);
with this weird variable definition, these two variables won't be implemented as independent structs, for a total of 2x(4x4) = 32 bytes,
but rather with an unique struct that shares most of the fields, for a total of 2x4+(3x4)=20bytes.
So, not only do you no longer have to worry about whether key and mask are perfectly compatible, but they also consume less memory!
Ok, not too much here, but in my opinion, the real advantages come with polymorphic programming!
With this feature you save a lot of code and RAM, making two objects share a large part of the methods and structures that are common.
Ummm, too crazy?

(already implemented as alpha version, it's working!)