1 /* Copyright (c) 2005-2018 Dovecot authors, see the included COPYING file */
2
3 #include "lib.h"
4 #include "array.h"
5 #include "seq-range-array.h"
6
seq_range_is_overflowed(const ARRAY_TYPE (seq_range)* array)7 static bool seq_range_is_overflowed(const ARRAY_TYPE(seq_range) *array)
8 {
9 const struct seq_range *range;
10 unsigned int count;
11
12 range = array_get(array, &count);
13 return count == 1 && range[0].seq1 == 0 &&
14 range[0].seq2 == (uint32_t)-1;
15 }
16
17 static bool ATTR_NOWARN_UNUSED_RESULT
seq_range_lookup(const ARRAY_TYPE (seq_range)* array,uint32_t seq,unsigned int * idx_r)18 seq_range_lookup(const ARRAY_TYPE(seq_range) *array,
19 uint32_t seq, unsigned int *idx_r)
20 {
21 const struct seq_range *data;
22 unsigned int idx, left_idx, right_idx, count;
23
24 data = array_get(array, &count);
25 i_assert(count < INT_MAX);
26
27 idx = 0; left_idx = 0; right_idx = count;
28 while (left_idx < right_idx) {
29 idx = (left_idx + right_idx) / 2;
30
31 if (data[idx].seq1 <= seq) {
32 if (data[idx].seq2 >= seq) {
33 /* it's already in the range */
34 *idx_r = idx;
35 return TRUE;
36 }
37 left_idx = idx+1;
38 } else {
39 right_idx = idx;
40 }
41 }
42 if (left_idx > idx)
43 idx++;
44 *idx_r = idx;
45 return FALSE;
46 }
47
48 static bool
seq_range_array_add_slow_path(ARRAY_TYPE (seq_range)* array,uint32_t seq)49 seq_range_array_add_slow_path(ARRAY_TYPE(seq_range) *array, uint32_t seq)
50 {
51 struct seq_range *data, value;
52 unsigned int idx, count;
53
54 value.seq1 = value.seq2 = seq;
55 data = array_get_modifiable(array, &count);
56
57 /* somewhere in the middle, array is sorted so find it with
58 binary search */
59 if (seq_range_lookup(array, seq, &idx))
60 return TRUE;
61
62 /* idx == count couldn't happen because we already handle it above */
63 i_assert(idx < count && data[idx].seq1 >= seq);
64 i_assert(data[idx].seq1 > seq || data[idx].seq2 < seq);
65
66 if (data[idx].seq1 == seq+1) {
67 data[idx].seq1 = seq;
68 if (idx > 0 && data[idx-1].seq2 == seq-1) {
69 /* merge */
70 data[idx-1].seq2 = data[idx].seq2;
71 array_delete(array, idx, 1);
72 }
73 } else {
74 if (idx > 0 && data[idx-1].seq2 == seq-1)
75 idx--;
76 if (data[idx].seq2 == seq-1) {
77 i_assert(idx+1 < count); /* already handled above */
78 data[idx].seq2 = seq;
79 if (data[idx+1].seq1 == seq+1) {
80 /* merge */
81 data[idx+1].seq1 = data[idx].seq1;
82 array_delete(array, idx, 1);
83 }
84 } else {
85 array_insert(array, idx, &value, 1);
86 }
87 }
88 return FALSE;
89 }
90
seq_range_array_add(ARRAY_TYPE (seq_range)* array,uint32_t seq)91 bool seq_range_array_add(ARRAY_TYPE(seq_range) *array, uint32_t seq)
92 {
93 struct seq_range *data, value;
94 unsigned int count;
95 bool exists = FALSE;
96
97 value.seq1 = value.seq2 = seq;
98
99 data = array_get_modifiable(array, &count);
100 /* quick checks */
101 if (count == 0)
102 array_push_back(array, &value);
103 else if (data[count-1].seq2 < seq) {
104 if (data[count-1].seq2 == seq-1) {
105 /* grow last range */
106 data[count-1].seq2 = seq;
107 } else {
108 array_push_back(array, &value);
109 }
110 } else if (data[0].seq1 > seq) {
111 if (data[0].seq1-1 == seq) {
112 /* grow down first range */
113 data[0].seq1 = seq;
114 } else {
115 array_push_front(array, &value);
116 }
117 } else {
118 exists = seq_range_array_add_slow_path(array, seq);
119 }
120 i_assert(!seq_range_is_overflowed(array));
121 return exists;
122 }
123
seq_range_array_add_with_init(ARRAY_TYPE (seq_range)* array,unsigned int init_count,uint32_t seq)124 void seq_range_array_add_with_init(ARRAY_TYPE(seq_range) *array,
125 unsigned int init_count, uint32_t seq)
126 {
127 if (!array_is_created(array))
128 i_array_init(array, init_count);
129 seq_range_array_add(array, seq);
130 }
131
132 static void
seq_range_array_add_range_internal(ARRAY_TYPE (seq_range)* array,uint32_t seq1,uint32_t seq2,unsigned int * r_count)133 seq_range_array_add_range_internal(ARRAY_TYPE(seq_range) *array,
134 uint32_t seq1, uint32_t seq2,
135 unsigned int *r_count)
136 {
137 struct seq_range *data, value;
138 unsigned int idx1, idx2, count;
139
140 seq_range_lookup(array, seq1, &idx1);
141 seq_range_lookup(array, seq2, &idx2);
142
143 data = array_get_modifiable(array, &count);
144 if (r_count != NULL) {
145 /* Find number we're adding by counting the number we're
146 not adding, and subtracting that from the nominal range. */
147 unsigned int added = seq2+1 - seq1;
148 unsigned int countidx2 = idx2;
149 unsigned int overcounted = 0u, notadded = 0u;
150 unsigned int i;
151
152 if (idx1 == count) {
153 /* not in a range as too far right */
154 } else if (seq1 < data[idx1].seq1) {
155 /* not in a range, to the left of a real range */
156 } else {
157 /* count the whole of this range, which is an overcount */
158 overcounted += seq1 - data[idx1].seq1;
159 /* fencepost check: equality means the whole range is valid,
160 therefore there's no overcounting. Result = 0 overcount */
161 }
162 if (idx2 == count) {
163 /* not in a range as too far right */
164 } else if (seq2 < data[idx2].seq1) {
165 /* not in a range, to the left of a real range */
166 } else {
167 /* count the whole of this range, which is an overcount */
168 overcounted += data[idx2].seq2 - seq2;
169 countidx2++; /* may become == count i.e. past the end */
170 /* fencepost check: equality means the whole range is valid,
171 therefore there's no overcounting. Result = 0 overcount. */
172 }
173 /* Now count how many we're not adding */
174 for (i = idx1; i < countidx2; i++)
175 notadded += data[i].seq2+1 - data[i].seq1;
176 /* Maybe the not added tally included some over-counting too */
177 added -= (notadded - overcounted);
178 *r_count = added;
179 }
180
181 if (idx1 > 0 && data[idx1-1].seq2+1 == seq1)
182 idx1--;
183
184 if (idx1 == idx2 &&
185 (idx2 == count || (seq2 < (uint32_t)-1 && data[idx2].seq1 > seq2+1)) &&
186 (idx1 == 0 || data[idx1-1].seq2 < seq1-1)) {
187 /* no overlapping */
188 value.seq1 = seq1;
189 value.seq2 = seq2;
190 array_insert(array, idx1, &value, 1);
191 } else {
192 i_assert(idx1 < count);
193 if (seq1 < data[idx1].seq1)
194 data[idx1].seq1 = seq1;
195 if (seq2 > data[idx1].seq2) {
196 /* merge */
197 if (idx2 == count ||
198 data[idx2].seq1 > seq2+1)
199 idx2--;
200 if (seq2 >= data[idx2].seq2) {
201 data[idx1].seq2 = seq2;
202 } else {
203 data[idx1].seq2 = data[idx2].seq2;
204 }
205 array_delete(array, idx1 + 1, idx2 - idx1);
206 }
207 }
208 i_assert(!seq_range_is_overflowed(array));
209 }
210
seq_range_array_add_range(ARRAY_TYPE (seq_range)* array,uint32_t seq1,uint32_t seq2)211 void seq_range_array_add_range(ARRAY_TYPE(seq_range) *array,
212 uint32_t seq1, uint32_t seq2)
213 {
214 seq_range_array_add_range_internal(array, seq1, seq2, NULL);
215 }
seq_range_array_add_range_count(ARRAY_TYPE (seq_range)* array,uint32_t seq1,uint32_t seq2)216 unsigned int seq_range_array_add_range_count(ARRAY_TYPE(seq_range) *array,
217 uint32_t seq1, uint32_t seq2)
218 {
219 unsigned int count;
220 seq_range_array_add_range_internal(array, seq1, seq2, &count);
221 return count;
222 }
223
seq_range_array_merge(ARRAY_TYPE (seq_range)* dest,const ARRAY_TYPE (seq_range)* src)224 void seq_range_array_merge(ARRAY_TYPE(seq_range) *dest,
225 const ARRAY_TYPE(seq_range) *src)
226 {
227 const struct seq_range *range;
228
229 if (array_count(dest) == 0) {
230 array_append_array(dest, src);
231 return;
232 }
233
234 array_foreach(src, range)
235 seq_range_array_add_range(dest, range->seq1, range->seq2);
236 }
237
seq_range_array_merge_n(ARRAY_TYPE (seq_range)* dest,const ARRAY_TYPE (seq_range)* src,unsigned int count)238 void seq_range_array_merge_n(ARRAY_TYPE(seq_range) *dest,
239 const ARRAY_TYPE(seq_range) *src,
240 unsigned int count)
241 {
242 const struct seq_range *src_range;
243 unsigned int src_idx, src_count;
244 unsigned int merge_count = count;
245
246 src_range = array_get(src, &src_count);
247 for (src_idx = 0; src_idx < src_count && merge_count > 0; src_idx++) {
248 uint32_t first_seq = src_range[src_idx].seq1;
249 uint32_t last_seq = src_range[src_idx].seq2;
250 unsigned int idx_count = last_seq - first_seq + 1;
251
252 if (idx_count > merge_count) {
253 last_seq = first_seq + merge_count - 1;
254 merge_count = 0;
255 } else {
256 merge_count -= idx_count;
257 }
258 seq_range_array_add_range(dest, first_seq, last_seq);
259 }
260 }
261
seq_range_array_remove(ARRAY_TYPE (seq_range)* array,uint32_t seq)262 bool seq_range_array_remove(ARRAY_TYPE(seq_range) *array, uint32_t seq)
263 {
264 struct seq_range *data, value;
265 unsigned int idx, left_idx, right_idx, count;
266
267 if (!array_is_created(array))
268 return FALSE;
269
270 data = array_get_modifiable(array, &count);
271 if (count == 0)
272 return FALSE;
273
274 /* quick checks */
275 if (seq > data[count-1].seq2 || seq < data[0].seq1) {
276 /* outside the range */
277 return FALSE;
278 }
279 if (data[count-1].seq2 == seq) {
280 /* shrink last range */
281 if (data[count-1].seq1 != data[count-1].seq2)
282 data[count-1].seq2--;
283 else
284 array_delete(array, count-1, 1);
285 return TRUE;
286 }
287 if (data[0].seq1 == seq) {
288 /* shrink up first range */
289 if (data[0].seq1 != data[0].seq2)
290 data[0].seq1++;
291 else
292 array_pop_front(array);
293 return TRUE;
294 }
295
296 /* somewhere in the middle, array is sorted so find it with
297 binary search */
298 i_assert(count < INT_MAX);
299 left_idx = 0; right_idx = count;
300 while (left_idx < right_idx) {
301 idx = (left_idx + right_idx) / 2;
302
303 if (data[idx].seq1 > seq)
304 right_idx = idx;
305 else if (data[idx].seq2 < seq)
306 left_idx = idx+1;
307 else {
308 /* found it */
309 if (data[idx].seq1 == seq) {
310 if (data[idx].seq1 == data[idx].seq2) {
311 /* a single sequence range.
312 remove it entirely */
313 array_delete(array, idx, 1);
314 } else {
315 /* shrink the range */
316 data[idx].seq1++;
317 }
318 } else if (data[idx].seq2 == seq) {
319 /* shrink the range */
320 data[idx].seq2--;
321 } else {
322 /* split the sequence range */
323 value.seq1 = seq + 1;
324 value.seq2 = data[idx].seq2;
325 data[idx].seq2 = seq - 1;
326
327 array_insert(array, idx + 1, &value, 1);
328 }
329 return TRUE;
330 }
331 }
332 return FALSE;
333 }
334
seq_range_array_remove_range(ARRAY_TYPE (seq_range)* array,uint32_t seq1,uint32_t seq2)335 unsigned int seq_range_array_remove_range(ARRAY_TYPE(seq_range) *array,
336 uint32_t seq1, uint32_t seq2)
337 {
338 const struct seq_range *data;
339 unsigned int idx, idx2, count, remove_count = 0;
340
341 /* remove first and last. this makes sure that everything between
342 can simply be deleted with array_delete().
343
344 FIXME: it would be faster if we did only one binary lookup here
345 and handled the splitting ourself.. */
346 if (seq_range_array_remove(array, seq1))
347 remove_count++;
348 if (seq1 == seq2)
349 return remove_count;
350 seq1++;
351
352 if (seq_range_array_remove(array, seq2--))
353 remove_count++;
354 if (seq1 > seq2)
355 return remove_count;
356
357 /* find the beginning */
358 data = array_get(array, &count);
359 seq_range_lookup(array, seq1, &idx);
360
361 if (idx == count)
362 return remove_count;
363
364 i_assert(data[idx].seq1 >= seq1);
365 for (idx2 = idx; idx2 < count; idx2++) {
366 if (data[idx2].seq1 > seq2)
367 break;
368 i_assert(UINT_MAX - remove_count >= seq_range_length(&data[idx2]));
369 remove_count += seq_range_length(&data[idx2]);
370 }
371 array_delete(array, idx, idx2-idx);
372 return remove_count;
373 }
374
seq_range_array_remove_seq_range(ARRAY_TYPE (seq_range)* dest,const ARRAY_TYPE (seq_range)* src)375 unsigned int seq_range_array_remove_seq_range(ARRAY_TYPE(seq_range) *dest,
376 const ARRAY_TYPE(seq_range) *src)
377 {
378 unsigned int count, full_count = 0;
379 const struct seq_range *src_range;
380
381 array_foreach(src, src_range) {
382 count = seq_range_array_remove_range(dest, src_range->seq1,
383 src_range->seq2);
384 i_assert(UINT_MAX - full_count >= count);
385 full_count += count;
386 }
387 return full_count;
388 }
389
seq_range_array_remove_nth(ARRAY_TYPE (seq_range)* array,uint32_t n,uint32_t count)390 void seq_range_array_remove_nth(ARRAY_TYPE(seq_range) *array,
391 uint32_t n, uint32_t count)
392 {
393 struct seq_range_iter iter;
394 uint32_t seq1, seq2;
395
396 if (count == 0)
397 return;
398
399 seq_range_array_iter_init(&iter, array);
400 if (!seq_range_array_iter_nth(&iter, n, &seq1)) {
401 /* n points beyond array */
402 return;
403 }
404 if (count-1 >= (uint32_t)-1 - n ||
405 !seq_range_array_iter_nth(&iter, n + (count-1), &seq2)) {
406 /* count points beyond array */
407 seq2 = (uint32_t)-1;
408 }
409 seq_range_array_remove_range(array, seq1, seq2);
410 }
411
seq_range_array_intersect(ARRAY_TYPE (seq_range)* dest,const ARRAY_TYPE (seq_range)* src)412 unsigned int seq_range_array_intersect(ARRAY_TYPE(seq_range) *dest,
413 const ARRAY_TYPE(seq_range) *src)
414 {
415 const struct seq_range *src_range;
416 unsigned int i, count, remove_count, full_count = 0;
417 uint32_t last_seq = 0;
418
419 src_range = array_get(src, &count);
420 for (i = 0; i < count; i++) {
421 if (last_seq + 1 < src_range[i].seq1) {
422 remove_count = seq_range_array_remove_range(dest,
423 last_seq + 1, src_range[i].seq1 - 1);
424 i_assert(UINT_MAX - full_count >= remove_count);
425 full_count += remove_count;
426 }
427 last_seq = src_range[i].seq2;
428 }
429 if (last_seq != (uint32_t)-1) {
430 remove_count = seq_range_array_remove_range(dest, last_seq + 1,
431 (uint32_t)-1);
432 i_assert(UINT_MAX - full_count >= remove_count);
433 full_count += remove_count;
434 }
435 return full_count;
436 }
437
seq_range_exists(const ARRAY_TYPE (seq_range)* array,uint32_t seq)438 bool seq_range_exists(const ARRAY_TYPE(seq_range) *array, uint32_t seq)
439 {
440 unsigned int idx;
441
442 return seq_range_lookup(array, seq, &idx);
443 }
444
seq_range_array_have_common(const ARRAY_TYPE (seq_range)* array1,const ARRAY_TYPE (seq_range)* array2)445 bool seq_range_array_have_common(const ARRAY_TYPE(seq_range) *array1,
446 const ARRAY_TYPE(seq_range) *array2)
447 {
448 const struct seq_range *range1, *range2;
449 unsigned int i1, i2, count1, count2;
450
451 range1 = array_get(array1, &count1);
452 range2 = array_get(array2, &count2);
453 for (i1 = i2 = 0; i1 < count1 && i2 < count2; ) {
454 if (range1[i1].seq1 <= range2[i2].seq2 &&
455 range1[i1].seq2 >= range2[i2].seq1)
456 return TRUE;
457
458 if (range1[i1].seq1 < range2[i2].seq1)
459 i1++;
460 else
461 i2++;
462 }
463 return FALSE;
464 }
465
seq_range_count(const ARRAY_TYPE (seq_range)* array)466 unsigned int seq_range_count(const ARRAY_TYPE(seq_range) *array)
467 {
468 const struct seq_range *range;
469 unsigned int seq_count = 0;
470
471 array_foreach(array, range) {
472 i_assert(UINT_MAX - seq_count >= seq_range_length(range));
473 seq_count += seq_range_length(range);
474 }
475 return seq_count;
476 }
477
seq_range_array_invert(ARRAY_TYPE (seq_range)* array,uint32_t min_seq,uint32_t max_seq)478 void seq_range_array_invert(ARRAY_TYPE(seq_range) *array,
479 uint32_t min_seq, uint32_t max_seq)
480 {
481 struct seq_range *range, value;
482 unsigned int i, count;
483 uint32_t prev_min_seq;
484
485 if (array_is_created(array))
486 range = array_get_modifiable(array, &count);
487 else {
488 range = NULL;
489 count = 0;
490 }
491 if (count == 0) {
492 /* empty -> full */
493 if (!array_is_created(array))
494 i_array_init(array, 4);
495 value.seq1 = min_seq;
496 value.seq2 = max_seq;
497 array_push_back(array, &value);
498 return;
499 }
500 i_assert(range[0].seq1 >= min_seq);
501 i_assert(range[count-1].seq2 <= max_seq);
502
503 if (range[0].seq1 == min_seq && range[0].seq2 == max_seq) {
504 /* full -> empty */
505 array_clear(array);
506 return;
507 }
508
509 for (i = 0; i < count; ) {
510 prev_min_seq = min_seq;
511 min_seq = range[i].seq2;
512 if (range[i].seq1 == prev_min_seq) {
513 array_delete(array, i, 1);
514 range = array_get_modifiable(array, &count);
515 } else {
516 range[i].seq2 = range[i].seq1 - 1;
517 range[i].seq1 = prev_min_seq;
518 i++;
519 }
520 if (min_seq >= max_seq) {
521 /* max_seq is reached. the rest of the array should be
522 empty. we'll return here, because min_seq++ may
523 wrap to 0. */
524 i_assert(min_seq == max_seq);
525 i_assert(i == count);
526 return;
527 }
528 min_seq++;
529 }
530 if (min_seq <= max_seq) {
531 value.seq1 = min_seq;
532 value.seq2 = max_seq;
533 array_push_back(array, &value);
534 }
535 }
536
seq_range_array_iter_init(struct seq_range_iter * iter_r,const ARRAY_TYPE (seq_range)* array)537 void seq_range_array_iter_init(struct seq_range_iter *iter_r,
538 const ARRAY_TYPE(seq_range) *array)
539 {
540 i_zero(iter_r);
541 iter_r->array = array;
542 }
543
seq_range_array_iter_nth(struct seq_range_iter * iter,unsigned int n,uint32_t * seq_r)544 bool seq_range_array_iter_nth(struct seq_range_iter *iter, unsigned int n,
545 uint32_t *seq_r)
546 {
547 const struct seq_range *range;
548 unsigned int i, count, diff;
549
550 if (n < iter->prev_n) {
551 /* iterating backwards, don't bother optimizing */
552 iter->prev_n = 0;
553 iter->prev_idx = 0;
554 }
555
556 range = array_get(iter->array, &count);
557 for (i = iter->prev_idx; i < count; i++) {
558 diff = range[i].seq2 - range[i].seq1;
559 if (n <= iter->prev_n + diff) {
560 i_assert(n >= iter->prev_n);
561 *seq_r = range[i].seq1 + (n - iter->prev_n);
562 iter->prev_idx = i;
563 return TRUE;
564 }
565 iter->prev_n += diff + 1;
566 }
567 iter->prev_idx = i;
568 return FALSE;
569 }
570