1 | // non-pub versions of array functions |
2 | // that allocale new memory using `GC_MALLOC_ATOMIC()` |
3 | // when `-gc boehm_*_opt` is used. These memory areas are not |
4 | // scanned for pointers. |
5 | |
6 | module builtin |
7 | |
8 | fn __new_array_noscan(mylen int, cap int, elm_size int) array { |
9 | cap_ := if cap < mylen { mylen } else { cap } |
10 | arr := array{ |
11 | element_size: elm_size |
12 | data: vcalloc_noscan(u64(cap_) * u64(elm_size)) |
13 | len: mylen |
14 | cap: cap_ |
15 | } |
16 | return arr |
17 | } |
18 | |
19 | fn __new_array_with_default_noscan(mylen int, cap int, elm_size int, val voidptr) array { |
20 | cap_ := if cap < mylen { mylen } else { cap } |
21 | mut arr := array{ |
22 | element_size: elm_size |
23 | data: vcalloc_noscan(u64(cap_) * u64(elm_size)) |
24 | len: mylen |
25 | cap: cap_ |
26 | } |
27 | if val != 0 && arr.data != unsafe { nil } { |
28 | if elm_size == 1 { |
29 | byte_value := *(&u8(val)) |
30 | dptr := &u8(arr.data) |
31 | for i in 0 .. arr.len { |
32 | unsafe { |
33 | dptr[i] = byte_value |
34 | } |
35 | } |
36 | } else { |
37 | for i in 0 .. arr.len { |
38 | unsafe { arr.set_unsafe(i, val) } |
39 | } |
40 | } |
41 | } |
42 | return arr |
43 | } |
44 | |
45 | fn __new_array_with_multi_default_noscan(mylen int, cap int, elm_size int, val voidptr) array { |
46 | cap_ := if cap < mylen { mylen } else { cap } |
47 | mut arr := array{ |
48 | element_size: elm_size |
49 | data: vcalloc_noscan(u64(cap_) * u64(elm_size)) |
50 | len: mylen |
51 | cap: cap_ |
52 | } |
53 | if val != 0 && arr.data != unsafe { nil } { |
54 | for i in 0 .. arr.len { |
55 | unsafe { arr.set_unsafe(i, charptr(val) + i * elm_size) } |
56 | } |
57 | } |
58 | return arr |
59 | } |
60 | |
61 | fn __new_array_with_array_default_noscan(mylen int, cap int, elm_size int, val array) array { |
62 | cap_ := if cap < mylen { mylen } else { cap } |
63 | mut arr := array{ |
64 | element_size: elm_size |
65 | data: vcalloc_noscan(u64(cap_) * u64(elm_size)) |
66 | len: mylen |
67 | cap: cap_ |
68 | } |
69 | for i in 0 .. arr.len { |
70 | val_clone := val.clone() |
71 | unsafe { arr.set_unsafe(i, &val_clone) } |
72 | } |
73 | return arr |
74 | } |
75 | |
76 | // Private function, used by V (`nums := [1, 2, 3]`) |
77 | fn new_array_from_c_array_noscan(len int, cap int, elm_size int, c_array voidptr) array { |
78 | cap_ := if cap < len { len } else { cap } |
79 | arr := array{ |
80 | element_size: elm_size |
81 | data: vcalloc_noscan(u64(cap_) * u64(elm_size)) |
82 | len: len |
83 | cap: cap_ |
84 | } |
85 | // TODO Write all memory functions (like memcpy) in V |
86 | unsafe { vmemcpy(arr.data, c_array, u64(len) * u64(elm_size)) } |
87 | return arr |
88 | } |
89 | |
90 | // Private function. Doubles array capacity if needed. |
91 | fn (mut a array) ensure_cap_noscan(required int) { |
92 | if required <= a.cap { |
93 | return |
94 | } |
95 | if a.flags.has(.nogrow) { |
96 | panic('array.ensure_cap_noscan: array with the flag `.nogrow` cannot grow in size, array required new size: ${required}') |
97 | } |
98 | mut cap := if a.cap > 0 { a.cap } else { 2 } |
99 | for required > cap { |
100 | cap *= 2 |
101 | } |
102 | new_size := u64(cap) * u64(a.element_size) |
103 | new_data := vcalloc_noscan(new_size) |
104 | if a.data != unsafe { nil } { |
105 | unsafe { vmemcpy(new_data, a.data, u64(a.len) * u64(a.element_size)) } |
106 | // TODO: the old data may be leaked when no GC is used (ref-counting?) |
107 | } |
108 | a.data = new_data |
109 | a.offset = 0 |
110 | a.cap = cap |
111 | } |
112 | |
113 | // repeat returns a new array with the given array elements repeated given times. |
114 | // `cgen` will replace this with an apropriate call to `repeat_to_depth()` |
115 | |
116 | // version of `repeat()` that handles multi dimensional arrays |
117 | // `unsafe` to call directly because `depth` is not checked |
118 | [unsafe] |
119 | fn (a array) repeat_to_depth_noscan(count int, depth int) array { |
120 | if count < 0 { |
121 | panic('array.repeat: count is negative: ${count}') |
122 | } |
123 | mut size := u64(count) * u64(a.len) * u64(a.element_size) |
124 | if size == 0 { |
125 | size = u64(a.element_size) |
126 | } |
127 | arr := array{ |
128 | element_size: a.element_size |
129 | data: if depth > 0 { vcalloc(size) } else { vcalloc_noscan(size) } |
130 | len: count * a.len |
131 | cap: count * a.len |
132 | } |
133 | if a.len > 0 { |
134 | a_total_size := u64(a.len) * u64(a.element_size) |
135 | arr_step_size := u64(a.len) * u64(arr.element_size) |
136 | mut eptr := &u8(arr.data) |
137 | unsafe { |
138 | for _ in 0 .. count { |
139 | if depth > 0 { |
140 | ary_clone := a.clone_to_depth_noscan(depth) |
141 | vmemcpy(eptr, &u8(ary_clone.data), a_total_size) |
142 | } else { |
143 | vmemcpy(eptr, &u8(a.data), a_total_size) |
144 | } |
145 | eptr += arr_step_size |
146 | } |
147 | } |
148 | } |
149 | return arr |
150 | } |
151 | |
152 | // insert inserts a value in the array at index `i` |
153 | fn (mut a array) insert_noscan(i int, val voidptr) { |
154 | $if !no_bounds_checking { |
155 | if i < 0 || i > a.len { |
156 | panic('array.insert: index out of range (i == ${i}, a.len == ${a.len})') |
157 | } |
158 | } |
159 | a.ensure_cap_noscan(a.len + 1) |
160 | unsafe { |
161 | vmemmove(a.get_unsafe(i + 1), a.get_unsafe(i), u64(a.len - i) * u64(a.element_size)) |
162 | a.set_unsafe(i, val) |
163 | } |
164 | a.len++ |
165 | } |
166 | |
167 | // insert_many inserts many values into the array from index `i`. |
168 | [unsafe] |
169 | fn (mut a array) insert_many_noscan(i int, val voidptr, size int) { |
170 | $if !no_bounds_checking { |
171 | if i < 0 || i > a.len { |
172 | panic('array.insert_many: index out of range (i == ${i}, a.len == ${a.len})') |
173 | } |
174 | } |
175 | a.ensure_cap_noscan(a.len + size) |
176 | elem_size := a.element_size |
177 | unsafe { |
178 | iptr := a.get_unsafe(i) |
179 | vmemmove(a.get_unsafe(i + size), iptr, u64(a.len - i) * u64(elem_size)) |
180 | vmemcpy(iptr, val, u64(size) * u64(elem_size)) |
181 | } |
182 | a.len += size |
183 | } |
184 | |
185 | // prepend prepends one value to the array. |
186 | fn (mut a array) prepend_noscan(val voidptr) { |
187 | a.insert_noscan(0, val) |
188 | } |
189 | |
190 | // prepend_many prepends another array to this array. |
191 | [unsafe] |
192 | fn (mut a array) prepend_many_noscan(val voidptr, size int) { |
193 | unsafe { a.insert_many_noscan(0, val, size) } |
194 | } |
195 | |
196 | // pop returns the last element of the array, and removes it. |
197 | fn (mut a array) pop_noscan() voidptr { |
198 | // in a sense, this is the opposite of `a << x` |
199 | $if !no_bounds_checking { |
200 | if a.len == 0 { |
201 | panic('array.pop: array is empty') |
202 | } |
203 | } |
204 | new_len := a.len - 1 |
205 | last_elem := unsafe { &u8(a.data) + u64(new_len) * u64(a.element_size) } |
206 | a.len = new_len |
207 | // Note: a.cap is not changed here *on purpose*, so that |
208 | // further << ops on that array will be more efficient. |
209 | return unsafe { memdup_noscan(last_elem, a.element_size) } |
210 | } |
211 | |
212 | // `clone_static_to_depth_noscan()` returns an independent copy of a given array. |
213 | // Unlike `clone_to_depth_noscan()` it has a value receiver and is used internally |
214 | // for slice-clone expressions like `a[2..4].clone()` and in -autofree generated code. |
215 | fn (a array) clone_static_to_depth_noscan(depth int) array { |
216 | return unsafe { a.clone_to_depth_noscan(depth) } |
217 | } |
218 | |
219 | // recursively clone given array - `unsafe` when called directly because depth is not checked |
220 | [unsafe] |
221 | fn (a &array) clone_to_depth_noscan(depth int) array { |
222 | mut size := u64(a.cap) * u64(a.element_size) |
223 | if size == 0 { |
224 | size++ |
225 | } |
226 | mut arr := array{ |
227 | element_size: a.element_size |
228 | data: if depth == 0 { vcalloc_noscan(size) } else { vcalloc(size) } |
229 | len: a.len |
230 | cap: a.cap |
231 | } |
232 | // Recursively clone-generated elements if array element is array type |
233 | if depth > 0 { |
234 | for i in 0 .. a.len { |
235 | ar := array{} |
236 | unsafe { vmemcpy(&ar, a.get_unsafe(i), int(sizeof(array))) } |
237 | ar_clone := unsafe { ar.clone_to_depth_noscan(depth - 1) } |
238 | unsafe { arr.set_unsafe(i, &ar_clone) } |
239 | } |
240 | return arr |
241 | } else { |
242 | if a.data != 0 { |
243 | unsafe { vmemcpy(&u8(arr.data), a.data, u64(a.cap) * u64(a.element_size)) } |
244 | } |
245 | return arr |
246 | } |
247 | } |
248 | |
249 | fn (mut a array) push_noscan(val voidptr) { |
250 | a.ensure_cap_noscan(a.len + 1) |
251 | unsafe { vmemcpy(&u8(a.data) + u64(a.element_size) * u64(a.len), val, a.element_size) } |
252 | a.len++ |
253 | } |
254 | |
255 | // push_many implements the functionality for pushing another array. |
256 | // `val` is array.data and user facing usage is `a << [1,2,3]` |
257 | [unsafe] |
258 | fn (mut a3 array) push_many_noscan(val voidptr, size int) { |
259 | if size <= 0 || val == unsafe { nil } { |
260 | return |
261 | } |
262 | if a3.data == val && a3.data != 0 { |
263 | // handle `arr << arr` |
264 | copy := a3.clone() |
265 | a3.ensure_cap_noscan(a3.len + size) |
266 | unsafe { |
267 | vmemcpy(a3.get_unsafe(a3.len), copy.data, u64(a3.element_size) * u64(size)) |
268 | } |
269 | } else { |
270 | a3.ensure_cap_noscan(a3.len + size) |
271 | if a3.data != 0 && val != 0 { |
272 | unsafe { vmemcpy(a3.get_unsafe(a3.len), val, u64(a3.element_size) * u64(size)) } |
273 | } |
274 | } |
275 | a3.len += size |
276 | } |
277 | |
278 | // reverse returns a new array with the elements of the original array in reverse order. |
279 | fn (a array) reverse_noscan() array { |
280 | if a.len < 2 { |
281 | return a |
282 | } |
283 | mut arr := array{ |
284 | element_size: a.element_size |
285 | data: vcalloc_noscan(u64(a.cap) * u64(a.element_size)) |
286 | len: a.len |
287 | cap: a.cap |
288 | } |
289 | for i in 0 .. a.len { |
290 | unsafe { arr.set_unsafe(i, a.get_unsafe(a.len - 1 - i)) } |
291 | } |
292 | return arr |
293 | } |
294 | |
295 | // grow_cap grows the array's capacity by `amount` elements. |
296 | fn (mut a array) grow_cap_noscan(amount int) { |
297 | a.ensure_cap_noscan(a.cap + amount) |
298 | } |
299 | |
300 | // grow_len ensures that an array has a.len + amount of length |
301 | [unsafe] |
302 | fn (mut a array) grow_len_noscan(amount int) { |
303 | a.ensure_cap_noscan(a.len + amount) |
304 | a.len += amount |
305 | } |