Skip to content

Commit 46bd266

Browse files
JelteFCommitfest Bot
authored andcommitted
Add foreach_hash macro
For lists we've had a new foreach style macros since 14dd0f2. This adds a similar macro for hash tables. This new foreach_hash macro makes iterating over the items in an HTAB as simple as iterating over the items in a List. The only additional thing to keep in mind is that when exiting the loop early you need to call foreach_hash_term.
1 parent ba2680d commit 46bd266

File tree

2 files changed

+60
-1
lines changed

2 files changed

+60
-1
lines changed

src/backend/utils/hash/dynahash.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1462,7 +1462,7 @@ hash_get_num_entries(HTAB *hashp)
14621462
}
14631463

14641464
/*
1465-
* hash_seq_init/_search/_term
1465+
* hash_seq_init/_new/_search/_term
14661466
* Sequentially search through hash table and return
14671467
* all the elements one by one, return NULL when no more.
14681468
*
@@ -1496,6 +1496,19 @@ hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
14961496
register_seq_scan(hashp);
14971497
}
14981498

1499+
/*
1500+
* Same as hash_seq_init(), but returns the status struct instead of taking a
1501+
* pointer.
1502+
*/
1503+
HASH_SEQ_STATUS
1504+
hash_seq_new(HTAB *hashp)
1505+
{
1506+
HASH_SEQ_STATUS status;
1507+
1508+
hash_seq_init(&status, hashp);
1509+
return status;
1510+
}
1511+
14991512
/*
15001513
* Same as above but scan by the given hash value.
15011514
* See also hash_seq_search().

src/include/utils/hsearch.h

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,51 @@ typedef struct
273273
uint32 hashvalue; /* hashvalue to start seqscan over hash */
274274
} HASH_SEQ_STATUS;
275275

276+
/*
277+
* foreach_hash - iterate over all entries in a hash table
278+
*
279+
* This macro simplifies hash table iteration by combining hash_seq_init
280+
* and hash_seq_search into a single for-loop construct.
281+
*
282+
* Usage:
283+
* foreach_hash(MyEntry, entry, my_hashtable)
284+
* {
285+
* // use entry
286+
* }
287+
*
288+
* This replaces the more verbose pattern:
289+
* HASH_SEQ_STATUS status;
290+
* MyEntry *entry;
291+
* hash_seq_init(&status, my_hashtable);
292+
* while ((entry = (MyEntry *) hash_seq_search(&status)) != NULL)
293+
* {
294+
* // use entry
295+
* }
296+
*
297+
* For early termination, use foreach_hash_term() before break:
298+
* foreach_hash(MyEntry, entry, my_hashtable)
299+
* {
300+
* if (found_it)
301+
* {
302+
* foreach_hash_term(entry);
303+
* break;
304+
* }
305+
* }
306+
*/
307+
#define foreach_hash(type, var, htab) \
308+
for (type *var = 0, *var##__outerloop = (type *) 1; \
309+
var##__outerloop; \
310+
var##__outerloop = 0) \
311+
for (HASH_SEQ_STATUS var##__status = hash_seq_new(htab); \
312+
(var = (type *) hash_seq_search(&var##__status)) != NULL; )
313+
314+
/*
315+
* foreach_hash_term - terminate a foreach_hash loop early
316+
*
317+
* Call this before 'break' to properly clean up the hash scan.
318+
*/
319+
#define foreach_hash_term(var) hash_seq_term(&var##__status)
320+
276321
/*
277322
* prototypes for functions in dynahash.c
278323
*/
@@ -293,6 +338,7 @@ extern bool hash_update_hash_key(HTAB *hashp, void *existingEntry,
293338
const void *newKeyPtr);
294339
extern int64 hash_get_num_entries(HTAB *hashp);
295340
extern void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp);
341+
extern HASH_SEQ_STATUS hash_seq_new(HTAB *hashp);
296342
extern void hash_seq_init_with_hash_value(HASH_SEQ_STATUS *status,
297343
HTAB *hashp,
298344
uint32 hashvalue);

0 commit comments

Comments
 (0)