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