lib/std/vec.rad 4.8 KiB raw
1
//! Raw vector: type-unsafe dynamic array backed by static storage.
2
//!
3
//! Users provide their own arena (static array) and the vector manages
4
//! element count within that arena. The arena should be aligned according
5
//! to the element type's requirements.
6
7
/// Raw vector metadata structure.
8
///
9
/// Does not own storage, points to user-provided arena.
10
export record RawVec {
11
    /// Pointer to user-provided byte arena.
12
    data: *mut [u8],
13
    /// Current number of elements stored.
14
    len: u32,
15
    /// Size of each element in bytes (stride between elements).
16
    stride: u32,
17
    /// Alignment in bytes required by element type (>= 1).
18
    alignment: u32,
19
}
20
21
/// Create a new raw vector with external arena.
22
///
23
/// * `arena` is a pointer to static array backing storage.
24
/// * `stride` is the size of each element.
25
/// * `alignment` is the required alignment for elements.
26
export fn new(arena: *mut [u8], stride: u32, alignment: u32) -> RawVec {
27
    assert stride > 0;
28
    assert alignment > 0;
29
    assert (arena.ptr as u32) % alignment == 0;
30
    assert (arena.len % stride) == 0;
31
32
    return RawVec { data: arena, len: 0, stride, alignment };
33
}
34
35
/// Get the current number of elements in the vector.
36
export fn len(vec: *RawVec) -> u32 {
37
    return vec.len;
38
}
39
40
/// Get the maximum capacity of the vector.
41
export fn capacity(vec: *RawVec) -> u32 {
42
    return vec.data.len / vec.stride;
43
}
44
45
/// Reset the vector to empty (does not clear memory).
46
export fn reset(vec: *mut RawVec) {
47
    set vec.len = 0;
48
}
49
50
/// Get a pointer to the element at the given index.
51
///
52
/// Returns nil if index is out of bounds.
53
export fn get(vec: *RawVec, index: u32) -> ?*opaque {
54
    if index >= vec.len {
55
        return nil;
56
    }
57
    let offset: u32 = index * vec.stride;
58
    let ptr: *u8 = &vec.data[offset];
59
60
    return ptr as *opaque;
61
}
62
63
/// Push an element onto the end of the vector.
64
///
65
/// Returns false if the vector is at capacity.
66
///
67
/// The caller must preserve the metadata invariants established by [`new`],
68
/// including `vec.stride > 0` and `vec.len <= capacity(vec)`. When the vector
69
/// has spare capacity, `elem` must point to at least `vec.stride` readable,
70
/// initialized bytes, and the destination range beginning at
71
/// `vec.len * vec.stride` in `vec.data` must be writable for `vec.stride`
72
/// bytes. The copy is byte-wise, so `elem` has no alignment requirement and
73
/// the destination need not already be initialized.
74
export unsafe fn push(vec: *mut RawVec, elem: *opaque) -> bool {
75
    if vec.len >= capacity(vec) {
76
        return false;
77
    }
78
    let off: u32 = vec.len * vec.stride;
79
    let dst: *mut u8 = &mut vec.data[off];
80
    let src: *u8 = elem as *u8;
81
82
    copyBytes(dst, src, vec.stride);
83
    set vec.len += 1;
84
85
    return true;
86
}
87
88
/// Pop an element from the end of the vector.
89
///
90
/// Copies the element into the provided output pointer.
91
/// Returns false if the vector is empty.
92
///
93
/// The caller must preserve the metadata invariants established by [`new`],
94
/// including `vec.stride > 0` and `vec.len <= capacity(vec)`. When the vector
95
/// is non-empty, `out` must point to at least `vec.stride` writable bytes, and
96
/// the source range for the last logical element in `vec.data` must contain
97
/// `vec.stride` initialized bytes. The copy is byte-wise, so `out` has no
98
/// alignment requirement and its previous contents need not be initialized.
99
export unsafe fn pop(vec: *mut RawVec, out: *mut opaque) -> bool {
100
    if vec.len == 0 {
101
        return false;
102
    }
103
    set vec.len -= 1;
104
105
    let off: u32 = vec.len * vec.stride;
106
    let src: *u8 = &vec.data[off];
107
    let dst: *mut u8 = out as *mut u8;
108
109
    copyBytes(dst, src, vec.stride);
110
111
    return true;
112
}
113
114
/// Set the element at the given index.
115
///
116
/// Returns false if index is out of bounds.
117
///
118
/// The caller must preserve the metadata invariants established by [`new`],
119
/// including `vec.stride > 0` and `vec.len <= capacity(vec)`. When `index` is
120
/// in bounds, `elem` must point to at least `vec.stride` readable, initialized
121
/// bytes, and the destination range beginning at `index * vec.stride` in
122
/// `vec.data` must be writable for `vec.stride` bytes. The copy is byte-wise,
123
/// so `elem` has no alignment requirement.
124
export unsafe fn put(vec: *mut RawVec, index: u32, elem: *opaque) -> bool {
125
    if index >= vec.len {
126
        return false;
127
    }
128
    let off: u32 = index * vec.stride;
129
    let dst: *mut u8 = &mut vec.data[off];
130
    let src: *u8 = elem as *u8;
131
132
    copyBytes(dst, src, vec.stride);
133
134
    return true;
135
}
136
137
/// Copy `count` initialized bytes from `src` into writable storage at `dst`.
138
///
139
/// The caller must ensure both pointers are valid for `count` bytes. No
140
/// alignment is required because the copy operates one byte at a time.
141
unsafe fn copyBytes(dst: *mut u8, src: *u8, count: u32) {
142
    for i in 0..count {
143
        set *(dst + i) = *(src + i);
144
    }
145
}