mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-12-22 17:51:53 +00:00
Hash: iterable now per partes by an iterator
It's now possible to pause iteration through hash. This requires struct hash_iterator to be allocated somewhere handy. The iteration itself is surrounded by HASH_WALK_ITER and HASH_WALK_ITER_END. Call HASH_WALK_ITER_PUT to ask for pausing; it may still do some more iterations until it comes to a suitable pausing point. The iterator must be initalized to an empty structure. No cleanup is needed if iteration is abandoned inbetween.
This commit is contained in:
parent
b06911f6ef
commit
d5e3272f3d
24
lib/hash.h
24
lib/hash.h
@ -10,7 +10,7 @@
|
|||||||
#ifndef _BIRD_HASH_H_
|
#ifndef _BIRD_HASH_H_
|
||||||
#define _BIRD_HASH_H_
|
#define _BIRD_HASH_H_
|
||||||
|
|
||||||
#define HASH(type) struct { type **data; uint count, order; }
|
#define HASH(type) struct { type **data; uint count; u16 iterators; u8 order; u8 down_requested:1; }
|
||||||
#define HASH_TYPE(v) typeof(** (v).data)
|
#define HASH_TYPE(v) typeof(** (v).data)
|
||||||
#define HASH_SIZE(v) (1U << (v).order)
|
#define HASH_SIZE(v) (1U << (v).order)
|
||||||
|
|
||||||
@ -125,19 +125,25 @@
|
|||||||
|
|
||||||
#define HASH_MAY_STEP_DOWN_(v,pool,rehash_fn,args) \
|
#define HASH_MAY_STEP_DOWN_(v,pool,rehash_fn,args) \
|
||||||
({ \
|
({ \
|
||||||
if (((v).count < (HASH_SIZE(v) REHASH_LO_MARK(args))) && \
|
if ((v).iterators) \
|
||||||
|
(v).down_requested = 1; \
|
||||||
|
else if (((v).count < (HASH_SIZE(v) REHASH_LO_MARK(args))) && \
|
||||||
((v).order > (REHASH_LO_BOUND(args)))) \
|
((v).order > (REHASH_LO_BOUND(args)))) \
|
||||||
rehash_fn(&(v), pool, -(REHASH_LO_STEP(args))); \
|
rehash_fn(&(v), pool, -(REHASH_LO_STEP(args))); \
|
||||||
})
|
})
|
||||||
|
|
||||||
#define HASH_MAY_RESIZE_DOWN_(v,pool,rehash_fn,args) \
|
#define HASH_MAY_RESIZE_DOWN_(v,pool,rehash_fn,args) \
|
||||||
({ \
|
({ \
|
||||||
|
if ((v).iterators) \
|
||||||
|
(v).down_requested = 1; \
|
||||||
|
else { \
|
||||||
uint _o = (v).order; \
|
uint _o = (v).order; \
|
||||||
while (((v).count < ((1U << _o) REHASH_LO_MARK(args))) && \
|
while (((v).count < ((1U << _o) REHASH_LO_MARK(args))) && \
|
||||||
(_o > (REHASH_LO_BOUND(args)))) \
|
(_o > (REHASH_LO_BOUND(args)))) \
|
||||||
_o -= (REHASH_LO_STEP(args)); \
|
_o -= (REHASH_LO_STEP(args)); \
|
||||||
if (_o < (v).order) \
|
if (_o < (v).order) \
|
||||||
rehash_fn(&(v), pool, _o - (v).order); \
|
rehash_fn(&(v), pool, _o - (v).order); \
|
||||||
|
} \
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
@ -195,6 +201,20 @@
|
|||||||
#define HASH_WALK_FILTER_END } while (0)
|
#define HASH_WALK_FILTER_END } while (0)
|
||||||
|
|
||||||
|
|
||||||
|
#define HASH_WALK_ITER(v, id, n, iter) \
|
||||||
|
do { \
|
||||||
|
uint _hash_walk_iter_put = 0; \
|
||||||
|
uint _shift = 32 - (v).order; \
|
||||||
|
for ( ; !_hash_walk_iter_put; (iter) += (1U << _shift)) { \
|
||||||
|
_hash_walk_iter_put = ((iter) + (1U << _shift) == 0); \
|
||||||
|
for (HASH_TYPE(v) *n = (v).data[(iter) >> _shift]; n; n = id##_NEXT((n)))\
|
||||||
|
if (HASH_FN(v, id, id##_KEY(n)) >= ((iter) >> _shift)) \
|
||||||
|
|
||||||
|
#define HASH_WALK_ITER_PUT (_hash_walk_iter_put = 1)
|
||||||
|
|
||||||
|
#define HASH_WALK_ITER_END } } while (0)
|
||||||
|
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
mem_hash_init(u64 *h)
|
mem_hash_init(u64 *h)
|
||||||
{
|
{
|
||||||
|
@ -285,6 +285,46 @@ t_walk_filter(void)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
t_walk_iter(void)
|
||||||
|
{
|
||||||
|
init_hash();
|
||||||
|
fill_hash();
|
||||||
|
|
||||||
|
u32 hit = 0;
|
||||||
|
|
||||||
|
u32 prev_hash = ~0;
|
||||||
|
for (uint cnt = 0; cnt < MAX_NUM; )
|
||||||
|
{
|
||||||
|
u32 last_hash = ~0;
|
||||||
|
// printf("PUT!\n");
|
||||||
|
HASH_WALK_ITER(hash, TEST, n, hit)
|
||||||
|
{
|
||||||
|
cnt++;
|
||||||
|
u32 cur_hash = HASH_FN(hash, TEST, n->key);
|
||||||
|
/*
|
||||||
|
printf("C%08x L%08x P%08x K%08x H%08x N%p S%d I%ld\n",
|
||||||
|
cur_hash, last_hash, prev_hash, n->key, hit, n, _shift, n - &nodes[0]);
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (last_hash == ~0U)
|
||||||
|
{
|
||||||
|
if (prev_hash != ~0U)
|
||||||
|
bt_assert(prev_hash < cur_hash);
|
||||||
|
last_hash = prev_hash = cur_hash;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
bt_assert(last_hash == cur_hash);
|
||||||
|
|
||||||
|
if (cnt < MAX_NUM)
|
||||||
|
HASH_WALK_ITER_PUT;
|
||||||
|
}
|
||||||
|
HASH_WALK_ITER_END;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char *argv[])
|
main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
@ -299,6 +339,7 @@ main(int argc, char *argv[])
|
|||||||
bt_test_suite(t_walk_delsafe_remove, "HASH_WALK_DELSAFE and HASH_REMOVE");
|
bt_test_suite(t_walk_delsafe_remove, "HASH_WALK_DELSAFE and HASH_REMOVE");
|
||||||
bt_test_suite(t_walk_delsafe_remove2, "HASH_WALK_DELSAFE and HASH_REMOVE2. HASH_REMOVE2 is HASH_REMOVE and smart auto-resize function");
|
bt_test_suite(t_walk_delsafe_remove2, "HASH_WALK_DELSAFE and HASH_REMOVE2. HASH_REMOVE2 is HASH_REMOVE and smart auto-resize function");
|
||||||
bt_test_suite(t_walk_filter, "HASH_WALK_FILTER");
|
bt_test_suite(t_walk_filter, "HASH_WALK_FILTER");
|
||||||
|
bt_test_suite(t_walk_iter, "HASH_WALK_ITER");
|
||||||
|
|
||||||
return bt_exit_value();
|
return bt_exit_value();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user