idxset: Add reverse iteration functions

Add complementary functions to the existing idxset iterate(),
steal_first(), first(), next() functions that work in the reverse
direction: reverse_iterate(), steal_last(), last() and previous().

Signed-off-by: Alper Nebi Yasak <alpernebiyasak@gmail.com>
Part-of: <https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/merge_requests/596>
This commit is contained in:
Alper Nebi Yasak 2021-06-23 17:58:37 +03:00
parent ec668ac44b
commit 97d9c28579
2 changed files with 123 additions and 6 deletions

View file

@ -381,6 +381,39 @@ at_end:
return NULL;
}
void *pa_idxset_reverse_iterate(pa_idxset *s, void **state, uint32_t *idx) {
struct idxset_entry *e;
pa_assert(s);
pa_assert(state);
if (*state == (void*) -1)
goto at_end;
if ((!*state && !s->iterate_list_tail))
goto at_end;
e = *state ? *state : s->iterate_list_tail;
if (e->iterate_previous)
*state = e->iterate_previous;
else
*state = (void*) -1;
if (idx)
*idx = e->idx;
return e->data;
at_end:
*state = (void *) -1;
if (idx)
*idx = PA_IDXSET_INVALID;
return NULL;
}
void* pa_idxset_steal_first(pa_idxset *s, uint32_t *idx) {
void *data;
@ -399,6 +432,24 @@ void* pa_idxset_steal_first(pa_idxset *s, uint32_t *idx) {
return data;
}
void* pa_idxset_steal_last(pa_idxset *s, uint32_t *idx) {
void *data;
pa_assert(s);
if (!s->iterate_list_tail)
return NULL;
data = s->iterate_list_tail->data;
if (idx)
*idx = s->iterate_list_tail->idx;
remove_entry(s, s->iterate_list_tail);
return data;
}
void* pa_idxset_first(pa_idxset *s, uint32_t *idx) {
pa_assert(s);
@ -414,6 +465,21 @@ void* pa_idxset_first(pa_idxset *s, uint32_t *idx) {
return s->iterate_list_head->data;
}
void* pa_idxset_last(pa_idxset *s, uint32_t *idx) {
pa_assert(s);
if (!s->iterate_list_tail) {
if (idx)
*idx = PA_IDXSET_INVALID;
return NULL;
}
if (idx)
*idx = s->iterate_list_tail->idx;
return s->iterate_list_tail->data;
}
void *pa_idxset_next(pa_idxset *s, uint32_t *idx) {
struct idxset_entry *e;
unsigned hash;
@ -458,6 +524,50 @@ void *pa_idxset_next(pa_idxset *s, uint32_t *idx) {
}
}
void *pa_idxset_previous(pa_idxset *s, uint32_t *idx) {
struct idxset_entry *e;
unsigned hash;
pa_assert(s);
pa_assert(idx);
if (*idx == PA_IDXSET_INVALID)
return NULL;
hash = *idx % NBUCKETS;
if ((e = index_scan(s, hash, *idx))) {
e = e->iterate_previous;
if (e) {
*idx = e->idx;
return e->data;
} else {
*idx = PA_IDXSET_INVALID;
return NULL;
}
} else {
/* If the entry passed doesn't exist anymore we try to find
* the preceding one. */
for ((*idx)--; *idx < s->current_index; (*idx)--) {
hash = *idx % NBUCKETS;
if ((e = index_scan(s, hash, *idx))) {
*idx = e->idx;
return e->data;
}
}
*idx = PA_IDXSET_INVALID;
return NULL;
}
}
unsigned pa_idxset_size(pa_idxset*s) {
pa_assert(s);

View file

@ -88,18 +88,25 @@ void* pa_idxset_rrobin(pa_idxset *s, uint32_t *idx);
/* Iterate through the idxset. At first iteration state should be NULL */
void *pa_idxset_iterate(pa_idxset *s, void **state, uint32_t *idx);
void *pa_idxset_reverse_iterate(pa_idxset *s, void **state, uint32_t *idx);
/* Return the oldest entry in the idxset and remove it. If idx is not NULL fill in its index in *idx */
/* Return the oldest or newest entry in the idxset and remove it.
* If idx is not NULL fill in its index in *idx */
void* pa_idxset_steal_first(pa_idxset *s, uint32_t *idx);
void* pa_idxset_steal_last(pa_idxset *s, uint32_t *idx);
/* Return the oldest entry in the idxset. Fill in its index in *idx. */
/* Return the oldest or newest entry in the idxset.
* Fill in its index in *idx. */
void* pa_idxset_first(pa_idxset *s, uint32_t *idx);
void* pa_idxset_last(pa_idxset *s, uint32_t *idx);
/* Return the entry following the entry indexed by *idx. After the
* call *index contains the index of the returned
* object. pa_idxset_first() and pa_idxset_next() may be used to
* iterate through the set.*/
/* Return the entry following or preceding the entry indexed by *idx.
* After the call *index contains the index of the returned object.
* pa_idxset_first() and pa_idxset_next() may be used to iterate through
* the set. pa_idxset_last() and pa_idxset_previous() may be used to
* iterate through the set in reverse. */
void *pa_idxset_next(pa_idxset *s, uint32_t *idx);
void *pa_idxset_previous(pa_idxset *s, uint32_t *idx);
/* Return the current number of entries in the idxset */
unsigned pa_idxset_size(pa_idxset*s);