From 73cf84ba00020b9e78d75a8e1001d90f75b45e7a Mon Sep 17 00:00:00 2001 From: Rene Rivera Date: Thu, 17 Aug 2023 10:49:01 -0500 Subject: [PATCH] Add concurrent guarded hash map wrapper. --- src/engine/hash.h | 108 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 85 insertions(+), 23 deletions(-) diff --git a/src/engine/hash.h b/src/engine/hash.h index 4088894e3c..c478a14dfd 100644 --- a/src/engine/hash.h +++ b/src/engine/hash.h @@ -7,7 +7,8 @@ /* This file is ALSO: * Copyright 2022 René Ferdinand Rivera Morell * Distributed under the Boost Software License, Version 1.0. - * (See accompanying file LICENSE.txt or https://www.bfgroup.xyz/b2/LICENSE.txt) + * (See accompanying file LICENSE.txt or + * https://www.bfgroup.xyz/b2/LICENSE.txt) */ /* @@ -18,8 +19,12 @@ #define BOOST_JAM_HASH_H #include "config.h" + +#include "mem.h" #include "object.h" +#include + /* * An opaque struct representing an item in the hash table. The first element of * every struct stored in the table must be an OBJECT * which is treated as the @@ -34,31 +39,31 @@ typedef struct hashdata HASHDATA; * datalen - item size * name - used for debugging */ -struct hash * hashinit( int32_t datalen, char const * name ); +struct hash * hashinit(int32_t datalen, char const * name); /* * hash_free() - free a hash table, given its handle */ -void hash_free( struct hash * ); -void hashdone( struct hash * ); +void hash_free(struct hash *); +void hashdone(struct hash *); -typedef void (* hashenumerate_f)( void *, void * ); +typedef void (*hashenumerate_f)(void *, void *); /* * hashenumerate() - call f(i, data) on each item, i in the hash table. The * enumeration order is unspecified. */ -void hashenumerate( struct hash *, void (* f)( void *, void * ), void * data ); +void hashenumerate(struct hash *, void (*f)(void *, void *), void * data); template -void hash_enumerate( struct hash * h, void (* f)(T *, D *), D * data) +void hash_enumerate(struct hash * h, void (*f)(T *, D *), D * data) { - hashenumerate(h, reinterpret_cast(f), data); + hashenumerate(h, reinterpret_cast(f), data); } template -void hash_enumerate( struct hash * h, void (* f)(T *, D *)) +void hash_enumerate(struct hash * h, void (*f)(T *, D *)) { - hashenumerate(h, reinterpret_cast(f), nullptr); + hashenumerate(h, reinterpret_cast(f), nullptr); } /* @@ -76,24 +81,81 @@ void hash_enumerate( struct hash * h, void (* f)(T *, D *)) * - if the key is present then *found == 1 and the result is a pointer to the * existing record. */ -HASHDATA * hash_insert( struct hash *, OBJECT * key, int32_t * found ); +HASHDATA * hash_insert(struct hash *, OBJECT * key, int32_t * found); /* * hash_find() - find a record in the table or NULL if none exists */ -HASHDATA * hash_find( struct hash *, OBJECT * key ); - -struct hashstats { - int count; - int num_items; - int tab_size; - int item_size; - int sets; - int num_hashes; +HASHDATA * hash_find(struct hash *, OBJECT * key); + +struct hashstats +{ + int count; + int num_items; + int tab_size; + int item_size; + int sets; + int num_hashes; +}; + +void hashstats_init(struct hashstats * stats); +void hashstats_add(struct hashstats * stats, struct hash *); +void hashstats_print(struct hashstats * stats, char const * name); + +namespace b2 { namespace core { + +template +struct concurrent_hash +{ + using key_type = b2::value_ptr; + using value_type = T; + + concurrent_hash(const char * debug_name) + { + table = hashinit(sizeof(value_type), debug_name); + } + + ~concurrent_hash() { reset(); } + + void reset() + { + std::lock_guard guard(mutex); + if (table != nullptr) + { + hashenumerate(table, concurrent_hash::destroy_at, nullptr); + hashdone(table); + table = nullptr; + } + } + + template + std::pair get(b2::value_ptr key, Args... args) + { + int found = 0; + std::lock_guard guard(mutex); + value_type * val + = reinterpret_cast(hash_insert(table, key, &found)); + if (found == 0) b2::jam::ctor_ptr(val, args...); + return std::make_pair(val, found != 0); + } + + template + void guarded(F f) + { + std::lock_guard guard(mutex); + f(); + } + + private: + std::mutex mutex; + hash * table = nullptr; + + static void destroy_at(void * p, void * _) + { + b2::jam::dtor_ptr(static_cast(p)); + } }; -void hashstats_init( struct hashstats * stats ); -void hashstats_add( struct hashstats * stats, struct hash * ); -void hashstats_print( struct hashstats * stats, char const * name ); +}} // namespace b2::core #endif