unsigned int num_elements; //!< Number of elements in the LST
size_t offset; //!< Offset of heap index in element structure.
void **p; //!< Array of elements.
- pivot_stack_t *s; //!< Stack of pivots, always with depth >= 1.
+ pivot_stack_t s; //!< Stack of pivots, always with depth >= 1.
fr_fast_rand_t rand_ctx; //!< Seed for random choices.
char const *type; //!< Type of elements.
fr_lst_cmp_t cmp; //!< Comparator function.
static inline CC_HINT(always_inline, nonnull) void *pivot_item(fr_lst_t *lst, stack_index_t idx)
{
- return item(lst, stack_item(lst->s, idx));
+ return item(lst, stack_item(&lst->s, idx));
}
/*
return lst_length(lst, idx) == 1;
}
-/*
- * First, the canonical stack implementation, customized for LST usage:
- * 1. pop doesn't return a stack value, and even lets you discard multiple
- * stack items at a time
- * 2. one can fetch and modify arbitrary stack items; when array elements must be
- * moved to keep them contiguous, the pivot stack entries must change to match.
- */
-static inline CC_HINT(always_inline, nonnull) pivot_stack_t *stack_alloc(TALLOC_CTX *ctx)
-{
- pivot_stack_t *s;
-
- s = talloc_zero(ctx, pivot_stack_t);
- if (unlikely(!s)) return NULL;
-
- s->data = talloc_array(s, fr_lst_index_t, INITIAL_STACK_CAPACITY);
- if (unlikely(!s->data)) {
- talloc_free(s);
- return NULL;
- }
- s->depth = 0;
- s->size = INITIAL_STACK_CAPACITY;
- return s;
-}
-
-static bool stack_expand(pivot_stack_t *s)
+static bool stack_expand(fr_lst_t *lst, pivot_stack_t *s)
{
fr_lst_index_t *n;
unsigned int n_size;
}
#endif
- n = talloc_realloc(s, s->data, fr_lst_index_t, n_size);
+ n = talloc_realloc(lst, s->data, fr_lst_index_t, n_size);
if (unlikely(!n)) {
fr_strerror_printf("Failed expanding lst stack to %u elements (%u bytes)",
n_size, n_size * (unsigned int)sizeof(fr_lst_index_t));
return true;
}
-static inline CC_HINT(always_inline, nonnull) int stack_push(pivot_stack_t *s, fr_lst_index_t pivot)
+static inline CC_HINT(always_inline, nonnull) int stack_push(fr_lst_t *lst, pivot_stack_t *s, fr_lst_index_t pivot)
{
- if (unlikely(s->depth == s->size && !stack_expand(s))) return -1;
+ if (unlikely(s->depth == s->size && !stack_expand(lst, s))) return -1;
s->data[s->depth++] = pivot;
return 0;
fr_lst_t *_fr_lst_alloc(TALLOC_CTX *ctx, fr_lst_cmp_t cmp, char const *type, size_t offset)
{
fr_lst_t *lst;
+ pivot_stack_t *s;
/*
* Pre-allocate stack memory as it is
* we'd end up wasting that memory as soon as
* we needed to expand the array.
*/
- lst = talloc_zero_pooled_object(ctx, fr_lst_t, 2,
- sizeof(pivot_stack_t) + (INITIAL_STACK_CAPACITY * sizeof(fr_lst_index_t)));
+ lst = talloc_zero_pooled_object(ctx, fr_lst_t, 2, (INITIAL_STACK_CAPACITY * sizeof(fr_lst_index_t)));
if (unlikely(!lst)) return NULL;
lst->capacity = INITIAL_CAPACITY;
return NULL;
}
- lst->s = stack_alloc(lst);
- if (unlikely(!lst->s)) goto cleanup;
+ /*
+ * Allocate the initial stack
+ */
+ s = &lst->s;
+ s->data = talloc_array(lst, fr_lst_index_t, INITIAL_STACK_CAPACITY);
+ if (unlikely(!s->data)) goto cleanup;
+ s->depth = 0;
+ s->size = INITIAL_STACK_CAPACITY;
/* Initially the LST is empty and we start at the beginning of the array */
- stack_push(lst->s, 0);
+ stack_push(lst, &lst->s, 0);
+
lst->idx = 0;
/* Prepare for random choices */
*/
static inline stack_index_t lst_length(fr_lst_t *lst, stack_index_t stack_index)
{
- return stack_depth(lst->s) - stack_index;
+ return stack_depth(&lst->s) - stack_index;
}
/** The size function for LSTs (number of items a (sub)tree contains)
if (stack_index == 0) return lst->num_elements;
- reduced_right = index_reduce(lst, stack_item(lst->s, stack_index));
+ reduced_right = index_reduce(lst, stack_item(&lst->s, stack_index));
reduced_idx = index_reduce(lst, lst->idx);
if (reduced_idx <= reduced_right) return reduced_right - reduced_idx; /* No wraparound--easy. */
*/
static inline CC_HINT(always_inline, nonnull) void lst_flatten(fr_lst_t *lst, stack_index_t stack_index)
{
- stack_pop(lst->s, stack_depth(lst->s) - stack_index);
+ stack_pop(&lst->s, stack_depth(&lst->s) - stack_index);
}
/** Move data to a specific location in an LST's array.
* so we save pivot moving for the end of the loop.
*/
for (ridx = 0; ridx < stack_index; ridx++) {
- fr_lst_index_t prev_pivot_index = stack_item(lst->s, ridx + 1);
+ fr_lst_index_t prev_pivot_index = stack_item(&lst->s, ridx + 1);
bool empty_bucket;
- new_space = stack_item(lst->s, ridx);
+ new_space = stack_item(&lst->s, ridx);
empty_bucket = (new_space - prev_pivot_index) == 1;
- stack_set(lst->s, ridx, new_space + 1);
+ stack_set(&lst->s, ridx, new_space + 1);
if (!empty_bucket) lst_move(lst, new_space, item(lst, prev_pivot_index + 1));
* If it is the leftmost, the loop wasn't executed, but the fictitious
* pivot isn't there, which is just as good.
*/
- new_space = stack_item(lst->s, stack_index);
- stack_set(lst->s, stack_index, new_space + 1);
+ new_space = stack_item(&lst->s, stack_index);
+ stack_set(&lst->s, stack_index, new_space + 1);
lst_move(lst, new_space, data);
lst->num_elements++;
static void lst_indices_reduce(fr_lst_t *lst)
{
fr_lst_index_t reduced_idx = index_reduce(lst, lst->idx);
- stack_index_t depth = stack_depth(lst->s), i;
+ stack_index_t depth = stack_depth(&lst->s), i;
- for (i = 0; i < depth; i++) stack_set(lst->s, i, reduced_idx + stack_item(lst->s, i) - lst->idx);
+ for (i = 0; i < depth; i++) stack_set(&lst->s, i, reduced_idx + stack_item(&lst->s, i) - lst->idx);
lst->idx = reduced_idx;
}
{
if (is_bucket(lst, stack_index)) return lst->idx;
- return stack_item(lst->s, stack_index + 1) + 1;
+ return stack_item(&lst->s, stack_index + 1) + 1;
}
/*
*/
static inline CC_HINT(always_inline, nonnull) fr_lst_index_t bucket_upb(fr_lst_t *lst, stack_index_t stack_index)
{
- return stack_item(lst->s, stack_index) - 1;
+ return stack_item(&lst->s, stack_index) - 1;
}
/*
* Hoare partition doesn't do the trivial case, so catch it here.
*/
if (is_equivalent(lst, low, high)) {
- stack_push(lst->s, low);
+ stack_push(lst, &lst->s, low);
return;
}
lst_move(lst, h, pivot);
}
- stack_push(lst->s, h);
+ stack_push(lst, &lst->s, h);
}
/*
for (;;) {
top = bucket_upb(lst, stack_index);
if (!is_equivalent(lst, location, top)) lst_move(lst, location, item(lst, top));
- stack_set(lst->s, stack_index, top);
+ stack_set(&lst->s, stack_index, top);
if (stack_index == 0) break;
lst_move(lst, top, item(lst, top + 1));
stack_index--;
*/
void *fr_lst_iter_next(fr_lst_t *lst, fr_lst_iter_t *iter)
{
- if ((*iter + 1) >= stack_item(lst->s, 0)) return NULL;
+ if ((*iter + 1) >= stack_item(&lst->s, 0)) return NULL;
*iter += 1;
return item(lst, *iter);