Skip to content

Commit

Permalink
Add concurrent guarded hash map wrapper.
Browse files Browse the repository at this point in the history
  • Loading branch information
grafikrobot committed Aug 17, 2023
1 parent bddc4c0 commit 73cf84b
Showing 1 changed file with 85 additions and 23 deletions.
108 changes: 85 additions & 23 deletions src/engine/hash.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
*/

/*
Expand All @@ -18,8 +19,12 @@
#define BOOST_JAM_HASH_H

#include "config.h"

#include "mem.h"
#include "object.h"

#include <mutex>

/*
* 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
Expand All @@ -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 <typename T, typename D>
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<hashenumerate_f>(f), data);
hashenumerate(h, reinterpret_cast<hashenumerate_f>(f), data);
}
template <typename T, typename D>
void hash_enumerate( struct hash * h, void (* f)(T *, D *))
void hash_enumerate(struct hash * h, void (*f)(T *, D *))
{
hashenumerate(h, reinterpret_cast<hashenumerate_f>(f), nullptr);
hashenumerate(h, reinterpret_cast<hashenumerate_f>(f), nullptr);
}

/*
Expand All @@ -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 <typename T>
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<std::mutex> guard(mutex);
if (table != nullptr)
{
hashenumerate(table, concurrent_hash::destroy_at, nullptr);
hashdone(table);
table = nullptr;
}
}

template <typename... Args>
std::pair<value_type *, bool> get(b2::value_ptr key, Args... args)
{
int found = 0;
std::lock_guard<std::mutex> guard(mutex);
value_type * val
= reinterpret_cast<value_type *>(hash_insert(table, key, &found));
if (found == 0) b2::jam::ctor_ptr<value_type>(val, args...);
return std::make_pair(val, found != 0);
}

template <typename F>
void guarded(F f)
{
std::lock_guard<std::mutex> guard(mutex);
f();
}

private:
std::mutex mutex;
hash * table = nullptr;

static void destroy_at(void * p, void * _)
{
b2::jam::dtor_ptr(static_cast<value_type *>(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

0 comments on commit 73cf84b

Please sign in to comment.