It turns out that having three "low-level" pointers per "high-level" pointer is not actually necessary in ravioli memory - two is enough.
The reason for this is that all the entries in the linked list are actually the same, so we don't need to store the pointer value in every element of the list. What we can instead do is to have two types of node:
- A node containing the pointer to the target and a pointer to the next node in the linked list.
- A node containing a pointer to the next node in the linked list and a pointer that points back in the linked list either 2 or 3 entries.
To find the target pointer if you have a node that doesn't contain it, just advance through the linked list until you do. To add a pointer to the linked list, add a forward pointer if that would cause the next backward pointer to point back 3 entries, otherwise add new backwards pointer so there are two "back 2" entries and the invariants are maintained. To remove a pointer, do the opposite to adding it.
If we want to make each raviolo a power of 2 bytes in size, we can then have 3 "high-level" pointers per raviolo (it doesn't allow us to make the ravioli smaller, since we still need a pointer for the vtable and to the first entry in that node's reference list).
However, I've since moved on to a more conceptually clean version of ravioli, which I'll talk about tomorrow.