Skip to content

Commit 4bb23e5

Browse files
committed
Adding comments.
1 parent b36a210 commit 4bb23e5

File tree

1 file changed

+60
-0
lines changed

1 file changed

+60
-0
lines changed

src/containers/mixed_union.c

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,36 @@ bool array_array_container_inplace_union(
206206
return false; // not a bitset
207207
} else {
208208
memmove(src_1->array + src_2->cardinality, src_1->array, src_1->cardinality * sizeof(uint16_t));
209+
/*
210+
Next line is safe:
211+
212+
We just need to focus on the reading and writing performed on array1. In `union_vector16`, both vectorized and scalar code still obey the basic rule: read from two inputs, do the union, and then write the output.
213+
214+
Let's say the length(cardinality) of input2 is L2:
215+
```
216+
|<- L2 ->|
217+
array1: [output--- |input 1---|---]
218+
array2: [input 2---]
219+
```
220+
Let's define 3 __m128i pointers, `pos1` starts from `input1`, `pos2` starts from `input2`, these 2 point at the next byte to read, `out` starts from `output`, pointing at the next byte to overwrite.
221+
```
222+
array1: [output--- |input 1---|---]
223+
^ ^
224+
out pos1
225+
array2: [input 2---]
226+
^
227+
pos2
228+
```
229+
The union output always contains less or equal number of elements than all inputs added, so we have:
230+
```
231+
out <= pos1 + pos2
232+
```
233+
therefore:
234+
```
235+
out <= pos1 + L2
236+
```
237+
which means you will not overwrite data beyond pos1, so the data haven't read is safe, and we don't care the data already read.
238+
*/
209239
src_1->cardinality = (int32_t)fast_union_uint16(src_1->array + src_2->cardinality, src_1->cardinality,
210240
src_2->array, src_2->cardinality, src_1->array);
211241
return false; // not a bitset
@@ -302,6 +332,36 @@ bool array_array_container_lazy_inplace_union(
302332
return false; // not a bitset
303333
} else {
304334
memmove(src_1->array + src_2->cardinality, src_1->array, src_1->cardinality * sizeof(uint16_t));
335+
/*
336+
Next line is safe:
337+
338+
We just need to focus on the reading and writing performed on array1. In `union_vector16`, both vectorized and scalar code still obey the basic rule: read from two inputs, do the union, and then write the output.
339+
340+
Let's say the length(cardinality) of input2 is L2:
341+
```
342+
|<- L2 ->|
343+
array1: [output--- |input 1---|---]
344+
array2: [input 2---]
345+
```
346+
Let's define 3 __m128i pointers, `pos1` starts from `input1`, `pos2` starts from `input2`, these 2 point at the next byte to read, `out` starts from `output`, pointing at the next byte to overwrite.
347+
```
348+
array1: [output--- |input 1---|---]
349+
^ ^
350+
out pos1
351+
array2: [input 2---]
352+
^
353+
pos2
354+
```
355+
The union output always contains less or equal number of elements than all inputs added, so we have:
356+
```
357+
out <= pos1 + pos2
358+
```
359+
therefore:
360+
```
361+
out <= pos1 + L2
362+
```
363+
which means you will not overwrite data beyond pos1, so the data haven't read is safe, and we don't care the data already read.
364+
*/
305365
src_1->cardinality = (int32_t)fast_union_uint16(src_1->array + src_2->cardinality, src_1->cardinality,
306366
src_2->array, src_2->cardinality, src_1->array);
307367
return false; // not a bitset

0 commit comments

Comments
 (0)