v / vlib / builtin / array_push_element_sizes_test.v
243 lines · 220 sloc · 4.84 KB · 4a6645fd15543b5295ca56a658240f47341aa049
Raw
1// Guards the single element push fast path in `array.push`/`push_noscan`.
2// Single element pushes dispatch the common small element sizes (1/2/4/8/16 bytes) to
3// `vmemcpy` with a constant size, and fall back to a runtime sized `vmemcpy` otherwise.
4// These tests make sure every size copies the right bytes for awkward element types too:
5// low alignment size 8/16 structs, structs with padding, and floats - i.e. types where a
6// typed integer copy would impose alignment it does not have or read padding through the
7// wrong type. They also check that pushing to a slice view clones the backing buffer
8// instead of corrupting the parent array.
9
10struct S16 {
11 a u64
12 b u64
13}
14
15struct S3 {
16 a u8
17 b u8
18 c u8
19}
20
21struct S24 {
22 a u64
23 b u64
24 c u64
25}
26
27// Pair8 is 8 bytes with only 4 byte alignment (no field needs 8 byte alignment).
28struct Pair8 {
29 a int
30 b int
31}
32
33// Padded8 is 8 bytes and contains padding: a u8 followed by 3 padding bytes, then a u32.
34struct Padded8 {
35 a u8
36 b u32
37}
38
39// LowAlign16 is a 16 byte element with only 1 byte alignment (a fixed byte array field).
40// This is the case a 16 byte typed (two u64) copy would mishandle on strict alignment targets.
41struct LowAlign16 {
42mut:
43 data [16]u8
44}
45
46// Padded16 is 16 bytes and contains padding: a u8 followed by 3 padding bytes, then three
47// u32s. It avoids u64 fields so its size is exactly 16 on every ABI (u64 alignment can be 4
48// on some 32-bit targets, which would make a u8+u64 struct 12 bytes instead of 16).
49struct Padded16 {
50 a u8
51 b u32
52 c u32
53 d u32
54}
55
56fn test_push_u8() {
57 mut a := []u8{cap: 4}
58 for i in 0 .. 300 {
59 a << u8(i & 0xff)
60 }
61 assert a.len == 300
62 for i in 0 .. 300 {
63 assert a[i] == u8(i & 0xff)
64 }
65}
66
67fn test_push_u16() {
68 mut a := []u16{}
69 for i in 0 .. 300 {
70 a << u16(i * 7)
71 }
72 for i in 0 .. 300 {
73 assert a[i] == u16(i * 7)
74 }
75}
76
77fn test_push_int() {
78 mut a := []int{}
79 for i in 0 .. 300 {
80 a << i * 12345
81 }
82 for i in 0 .. 300 {
83 assert a[i] == i * 12345
84 }
85}
86
87fn test_push_i64() {
88 mut a := []i64{}
89 for i in 0 .. 300 {
90 a << i64(i) * 9876543210
91 }
92 for i in 0 .. 300 {
93 assert a[i] == i64(i) * 9876543210
94 }
95}
96
97fn test_push_f64() {
98 mut a := []f64{}
99 for i in 0 .. 100 {
100 a << f64(i) + 0.5
101 }
102 for i in 0 .. 100 {
103 assert a[i] == f64(i) + 0.5
104 }
105}
106
107fn test_push_string() {
108 // string is a 16 byte element
109 mut a := []string{}
110 for i in 0 .. 200 {
111 a << 'item_${i}'
112 }
113 for i in 0 .. 200 {
114 assert a[i] == 'item_${i}'
115 }
116}
117
118fn test_push_struct_16() {
119 mut a := []S16{}
120 for i in 0 .. 200 {
121 a << S16{u64(i), u64(i) * 2}
122 }
123 for i in 0 .. 200 {
124 assert a[i].a == u64(i)
125 assert a[i].b == u64(i) * 2
126 }
127}
128
129fn test_push_struct_odd_size() {
130 // 3 byte element exercises the vmemcpy fallback path
131 mut a := []S3{}
132 for i in 0 .. 200 {
133 a << S3{u8(i), u8(i + 1), u8(i + 2)}
134 }
135 for i in 0 .. 200 {
136 assert a[i].a == u8(i)
137 assert a[i].b == u8(i + 1)
138 assert a[i].c == u8(i + 2)
139 }
140}
141
142fn test_push_struct_large() {
143 // 24 byte element exercises the vmemcpy fallback path
144 mut a := []S24{}
145 for i in 0 .. 200 {
146 a << S24{u64(i), u64(i) * 2, u64(i) * 3}
147 }
148 for i in 0 .. 200 {
149 assert a[i].a == u64(i)
150 assert a[i].b == u64(i) * 2
151 assert a[i].c == u64(i) * 3
152 }
153}
154
155fn test_push_to_slice_view_clones() {
156 mut a := []int{cap: 10}
157 for i in 0 .. 5 {
158 a << i
159 }
160 // a real slice view into a's buffer, with spare capacity after it
161 mut s := unsafe { a[1..3] }
162 // pushing to a slice view must clone first, not overwrite a[3]
163 s << 999
164 assert a == [0, 1, 2, 3, 4]
165 assert s == [1, 2, 999]
166}
167
168fn test_push_to_byte_slice_view_clones() {
169 mut a := []u8{cap: 10}
170 for i in 0 .. 5 {
171 a << u8(i)
172 }
173 mut s := unsafe { a[1..3] }
174 s << u8(200)
175 assert a == [u8(0), 1, 2, 3, 4]
176 assert s == [u8(1), 2, 200]
177}
178
179fn test_push_f32() {
180 // f32 is a 4 byte element; the copy must not route it through an integer type
181 mut a := []f32{}
182 for i in 0 .. 100 {
183 a << f32(i) + 0.25
184 }
185 for i in 0 .. 100 {
186 assert a[i] == f32(i) + 0.25
187 }
188}
189
190fn test_push_pair8_low_alignment() {
191 assert sizeof(Pair8) == 8
192 mut a := []Pair8{}
193 for i in 0 .. 200 {
194 a << Pair8{i, i * 3}
195 }
196 for i in 0 .. 200 {
197 assert a[i].a == i
198 assert a[i].b == i * 3
199 }
200}
201
202fn test_push_padded8() {
203 assert sizeof(Padded8) == 8
204 mut a := []Padded8{}
205 for i in 0 .. 200 {
206 a << Padded8{u8(i), u32(i) * 7}
207 }
208 for i in 0 .. 200 {
209 assert a[i].a == u8(i)
210 assert a[i].b == u32(i) * 7
211 }
212}
213
214fn test_push_low_alignment_16() {
215 assert sizeof(LowAlign16) == 16
216 mut a := []LowAlign16{}
217 for i in 0 .. 200 {
218 mut e := LowAlign16{}
219 for j in 0 .. 16 {
220 e.data[j] = u8(i + j)
221 }
222 a << e
223 }
224 for i in 0 .. 200 {
225 for j in 0 .. 16 {
226 assert a[i].data[j] == u8(i + j)
227 }
228 }
229}
230
231fn test_push_padded16() {
232 assert sizeof(Padded16) == 16
233 mut a := []Padded16{}
234 for i in 0 .. 200 {
235 a << Padded16{u8(i), u32(i) * 99, u32(i) * 7, u32(i) * 13}
236 }
237 for i in 0 .. 200 {
238 assert a[i].a == u8(i)
239 assert a[i].b == u32(i) * 99
240 assert a[i].c == u32(i) * 7
241 assert a[i].d == u32(i) * 13
242 }
243}
244