8787#define SH_INITIAL_BUCKET SH_MAKE_NAME(initial_bucket)
8888#define SH_ENTRY_HASH SH_MAKE_NAME(entry_hash)
8989
90+ /* Allocation function for hash table elements */
91+ typedef void * (* simplehash_allocate ) (Size size ,void * args );
92+ typedef void (* simplehash_free ) (void * pointer ,void * args );
93+
9094/* generate forward declarations necessary to use the hash table */
9195#ifdef SH_DECLARE
9296
@@ -112,6 +116,11 @@ typedef struct SH_TYPE
112116/* hash buckets */
113117SH_ELEMENT_TYPE * data ;
114118
119+ /* Allocation and free functions, and the associated context. */
120+ simplehash_allocate element_alloc ;
121+ simplehash_free element_free ;
122+ void * element_args ;
123+
115124/* memory context to use for allocations */
116125MemoryContext ctx ;
117126
@@ -133,7 +142,8 @@ typedef struct SH_ITERATOR
133142}SH_ITERATOR ;
134143
135144/* externally visible function prototypes */
136- SH_SCOPE SH_TYPE * SH_CREATE (MemoryContext ctx ,uint32 nelements );
145+ SH_SCOPE SH_TYPE * SH_CREATE (MemoryContext ctx ,uint32 nelements ,
146+ simplehash_allocate allocfunc ,simplehash_free freefunc ,void * args );
137147SH_SCOPE void SH_DESTROY (SH_TYPE * tb );
138148SH_SCOPE void SH_GROW (SH_TYPE * tb ,uint32 newsize );
139149SH_SCOPE SH_ELEMENT_TYPE * SH_INSERT (SH_TYPE * tb ,SH_KEY_TYPE key ,bool * found );
@@ -276,12 +286,35 @@ SH_ENTRY_HASH(SH_TYPE *tb, SH_ELEMENT_TYPE * entry)
276286#endif
277287}
278288
289+ /* default memory allocator function */
290+ static void *
291+ SH_DEFAULT_ALLOC (Size size ,void * args )
292+ {
293+ MemoryContext context = (MemoryContext )args ;
294+
295+ return MemoryContextAllocExtended (context ,size ,
296+ MCXT_ALLOC_HUGE |MCXT_ALLOC_ZERO );
297+ }
298+
299+ /* default memory free function */
300+ static void
301+ SH_DEFAULT_FREE (void * pointer ,void * args )
302+ {
303+ pfree (pointer );
304+ }
305+
279306/*
280- * Create a hash table with enough space for `nelements` distinct members,
281- * allocating required memory in the passed-in context.
307+ * Create a hash table with enough space for `nelements` distinct members.
308+ * Memory for the hash table is allocated from the passed-in context. If
309+ * desired, the array of elements can be allocated using a passed-in allocator;
310+ * this could be useful in order to place the array of elements in a shared
311+ * memory, or in a context that will outlive the rest of the hash table.
312+ * Memory other than for the array of elements will still be allocated from
313+ * the passed-in context.
282314 */
283315SH_SCOPE SH_TYPE *
284- SH_CREATE (MemoryContext ctx ,uint32 nelements )
316+ SH_CREATE (MemoryContext ctx ,uint32 nelements ,simplehash_allocate allocfunc ,
317+ simplehash_free freefunc ,void * args )
285318{
286319SH_TYPE * tb ;
287320uint64 size ;
@@ -294,9 +327,22 @@ SH_CREATE(MemoryContext ctx, uint32 nelements)
294327
295328SH_COMPUTE_PARAMETERS (tb ,size );
296329
297- tb -> data = MemoryContextAllocExtended (tb -> ctx ,
298- sizeof (SH_ELEMENT_TYPE )* tb -> size ,
299- MCXT_ALLOC_HUGE |MCXT_ALLOC_ZERO );
330+ if (allocfunc == NULL )
331+ {
332+ tb -> element_alloc = SH_DEFAULT_ALLOC ;
333+ tb -> element_free = SH_DEFAULT_FREE ;
334+ tb -> element_args = ctx ;
335+ }
336+ else
337+ {
338+ tb -> element_alloc = allocfunc ;
339+ tb -> element_free = freefunc ;
340+
341+ tb -> element_args = args ;
342+ }
343+
344+ tb -> data = tb -> element_alloc (sizeof (SH_ELEMENT_TYPE )* tb -> size ,
345+ tb -> element_args );
300346
301347return tb ;
302348}
@@ -305,7 +351,7 @@ SH_CREATE(MemoryContext ctx, uint32 nelements)
305351SH_SCOPE void
306352SH_DESTROY (SH_TYPE * tb )
307353{
308- pfree (tb -> data );
354+ tb -> element_free (tb -> data , tb -> element_args );
309355pfree (tb );
310356}
311357
@@ -333,9 +379,8 @@ SH_GROW(SH_TYPE *tb, uint32 newsize)
333379/* compute parameters for new table */
334380SH_COMPUTE_PARAMETERS (tb ,newsize );
335381
336- tb -> data = MemoryContextAllocExtended (
337- tb -> ctx ,sizeof (SH_ELEMENT_TYPE )* tb -> size ,
338- MCXT_ALLOC_HUGE |MCXT_ALLOC_ZERO );
382+ tb -> data = tb -> element_alloc (sizeof (SH_ELEMENT_TYPE )* tb -> size ,
383+ tb -> element_args );
339384
340385newdata = tb -> data ;
341386
@@ -421,7 +466,7 @@ SH_GROW(SH_TYPE *tb, uint32 newsize)
421466}
422467}
423468
424- pfree (olddata );
469+ tb -> element_free (olddata , tb -> element_args );
425470}
426471
427472/*