mirror of
				https://gitlab.labs.nic.cz/labs/bird.git
				synced 2024-05-11 16:54:54 +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:
		
							
								
								
									
										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(); | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user