Add slice support
This PR implements slices as part of my thesis. Slices are intended to provide views onto arrays, which provides the possibility to avoid unnecessary copies. I.e. we can write things like: b = _slice_VxA_(idx, a), where b is a slice and a is a sliced array (or source). This will lead to the creation of a new descriptor for b, but we do not allocate a new data vector. Instead, the pointer to the data vector of b points to some memory (at the correct offset) within the data vector of a.
A good starting point when reviewing is src/runtime/essentials_h/std.h. Here, I have included a visual representation of what slices do. I also extend the descriptor with 2 fields:
- INDIRECTION: This is a field that is set in the descriptor of a slice (
b) and points to the descriptor of the sliced array (a). - DATA: this is a field that is only set in arrays that have not been created using slices and points towards the data vector. This is required to free the data vector from a slice.
Additionally, I introduce these invariants:
- INDIRECTION is always NULL for non-slice arrays; it is never NULL for slices
- DATA is always set for non-sliced arrays; for slices it is always NULL
- Slices always represent a single reference to the sliced array (even if we have multiple aliases of a slice).
Freeing becomes a bit more complicated, as we must now also make sure that INDIRECTION is null. If it is not, we must follow the INDIRECTION pointer and perform a dec_rc_free on the source. We no longer have the named tuple, so I have created a free version that operates using only a descriptor.
Crucially, if we have b = _slice_VxA_(idx, a), then we do NOT consume a reference of a! This ensures that we do not accidentally free a when creating a slice. Instead, if b is freed, then we will encounter a set INDIRECTION, at which point we perform a dec_rc_free on a, and consume the reference that way.