Pointer slicing
Indexing a pointer with a range turns raw memory into a slice: a view with a length, whose indexing and iteration are checked from then on. Because a pointer has no length of its own, the range must say where the view ends.
| Expression | Elements, counting from p | Length |
|---|---|---|
p[..n] | 0 up to, not including, n | n |
p[..=n] | 0 to n inclusive | n + 1 |
p[a..b] | a up to, not including, b | b - a |
p[a..=b] | a to b inclusive | b - a + 1 |
The view's type follows the pointer's writability: a *var T gives a var T[..], and a *T gives a T[..]. A view of a null pointer with a length of zero is an empty view.
import Memory::{ Alloc, Free };
func Fill(values: var int[..], start: int) {
for i in 0..values.length {
values[i] = start + i as int;
}
}
func Total(values: int[..]) -> int {
var sum = 0;
for value in values {
sum += value;
}
return sum;
}
func Main() -> int {
let count: uint = 4;
let block = Alloc(count * sizeof(int)) as *var int;
if block == null {
return 1;
}
defer Free(block);
let all = block[..count]; // var int[..], four elements
Fill(all, 10); // 10, 11, 12, 13
let total = Total(block[1..3]); // 11 + 12
return 0;
}
The end is required
A pointer does not know how far its memory extends, so a range with no end — p[..] or p[a..] — is rejected:
error: cannot slice pointer '*var int' without an end bound
help: write 'p[..n]' or 'p[a..b]' to give the slice a length
Once built, the view checks every index against the length it was given. That length is the program's promise, and nothing checks it against the memory: block[..100] over a four-element block compiles, and its indexes are then checked against 100, not 4. Build every view from the count the memory was allocated with.
Precedence
@ is a prefix operator and indexing is postfix, so postfix binds first: @a[0][..2] means @(a[0][..2]) — a slice of the element a[0], which is not a sequence:
error: cannot slice value of type 'int'
help: declare 'func []' taking a range on 'int'
Parenthesise the address to slice the memory it points at:
var numbers: int[6] = [1, 2, 3, 4, 5, 6];
let window = (@numbers[2])[..3]; // var int[..]: 3, 4, 5
A view of an array is more simply numbers[2..5]; slicing a pointer is for memory that arrives as an address, such as an allocation, a buffer from a foreign function, or a flexible tail.
Views of literal text
The .data of a string literal is a *char8, and slicing it gives back a read-only view, as any read-only pointer does: "abc".data[..2] is a char8[..] of a and b.
See also
- Pointers —
*T,*var Tand@ - Pointer arithmetic — unchecked offsets and indexing
- Slices — what a view can do once it has a length
- Learn: Pointer slice, Fixed buffer