Mercurial > dovecot > original-hg > dovecot-1.2
diff src/lib/seq-range-array.c @ 3716:821035fdc9f6 HEAD
Moved seq_range_*() functions to more generic ones in lib/.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Fri, 25 Nov 2005 17:16:46 +0200 |
parents | |
children | 55df57c028d4 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib/seq-range-array.c Fri Nov 25 17:16:46 2005 +0200 @@ -0,0 +1,175 @@ +/* Copyright (c) 2005 Timo Sirainen */ + +#include "lib.h" +#include "array.h" +#include "seq-range-array.h" + +static int seq_range_lookup(array_t *array, uint32_t seq, unsigned int *idx_r) +{ + ARRAY_SET_TYPE(array, struct seq_range); + struct seq_range *data; + unsigned int idx, left_idx, right_idx, count; + + data = array_get_modifyable(array, &count); + + idx = 0; left_idx = 0; right_idx = count; + while (left_idx < right_idx) { + idx = (left_idx + right_idx) / 2; + + if (data[idx].seq1 <= seq) { + if (data[idx].seq2 >= seq) { + /* it's already in the range */ + *idx_r = idx; + return TRUE; + } + left_idx = idx+1; + } else { + right_idx = idx; + } + } + *idx_r = idx; + return FALSE; +} + +void seq_range_array_add(array_t *array, unsigned int init_count, uint32_t seq) +{ + ARRAY_SET_TYPE(array, struct seq_range); + struct seq_range *data, value; + unsigned int idx, count; + + value.seq1 = value.seq2 = seq; + + if (!array_is_created(array)) { + array_create(array, default_pool, + sizeof(struct seq_range), init_count); + } + + data = array_get_modifyable(array, &count); + if (count == 0) { + array_append(array, &value, 1); + return; + } + + /* quick checks */ + if (data[count-1].seq2 == seq-1) { + /* grow last range */ + data[count-1].seq2 = seq; + return; + } + if (data[count-1].seq2 < seq) { + array_append(array, &value, 1); + return; + } + if (data[0].seq1 == seq+1) { + /* grow down first range */ + data[0].seq1 = seq; + return; + } + if (data[0].seq1 > seq) { + array_insert(array, 0, &value, 1); + return; + } + + /* somewhere in the middle, array is sorted so find it with + binary search */ + if (seq_range_lookup(array, seq, &idx)) + return; + + if (data[idx].seq2 < seq) + idx++; + + /* idx == count couldn't happen because we already handle it above */ + i_assert(idx < count && data[idx].seq1 >= seq); + i_assert(data[idx].seq1 > seq || data[idx].seq2 < seq); + + if (data[idx].seq1 == seq+1) { + data[idx].seq1 = seq; + if (idx > 0 && data[idx-1].seq2 == seq-1) { + /* merge */ + data[idx-1].seq2 = data[idx].seq2; + array_delete(array, idx, 1); + } + } else if (data[idx].seq2 == seq-1) { + i_assert(idx+1 < count); /* already handled above */ + data[idx].seq2 = seq; + if (data[idx+1].seq1 == seq+1) { + /* merge */ + data[idx+1].seq1 = data[idx].seq1; + array_delete(array, idx, 1); + } + } else { + array_insert(array, idx, &value, 1); + } +} + +void seq_range_array_remove(array_t *array, uint32_t seq) +{ + ARRAY_SET_TYPE(array, struct seq_range); + struct seq_range *data, value; + unsigned int idx, left_idx, right_idx, count; + + if (!array_is_created(array)) + return; + + data = array_get_modifyable(array, &count); + i_assert(count > 0); + + /* quick checks */ + if (seq > data[count-1].seq2 || seq < data[0].seq1) { + /* outside the range */ + return; + } + if (data[count-1].seq2 == seq) { + /* shrink last range */ + data[count-1].seq2--; + return; + } + if (data[0].seq1 == seq) { + /* shrink up first range */ + data[0].seq1++; + return; + } + + /* somewhere in the middle, array is sorted so find it with + binary search */ + idx = 0; left_idx = 0; right_idx = count; + while (left_idx < right_idx) { + idx = (left_idx + right_idx) / 2; + + if (data[idx].seq1 > seq) + right_idx = idx; + else if (data[idx].seq2 < seq) + left_idx = idx+1; + else { + /* found it */ + if (data[idx].seq1 == seq) { + if (data[idx].seq1 == data[idx].seq2) { + /* a single sequence range. + remove it entirely */ + array_delete(array, idx, 1); + } else { + /* shrink the range */ + data[idx].seq1++; + } + } else if (data[idx].seq2 == seq) { + /* shrink the range */ + data[idx].seq2--; + } else { + /* split the sequence range */ + value.seq1 = seq + 1; + value.seq2 = data[idx].seq2; + data[idx].seq2 = seq - 1; + + array_insert(array, idx, &value, 1); + } + break; + } + } +} + +int seq_range_exists(array_t *array, uint32_t seq) +{ + unsigned int idx; + + return seq_range_lookup(array, seq, &idx); +}