1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
|
#include <stdlib.h>
#include <string.h>
#include "apop_internal.h" //just for OMP_critical
#ifdef _OPENMP
#include <omp.h>
#define lock omp_set_lock(&v->mutex);
#define unlock omp_unset_lock(&v->mutex);
#else
#define lock
#define unlock
#endif
/** \cond doxy_ignore */
typedef struct {
size_t hash;
void *fn;
} apop_vtable_elmt_s;
typedef struct {
char const *name;
unsigned long int hashed_name;
int elmt_ct;
apop_vtable_elmt_s *elmts;
#ifdef _OPENMP
omp_lock_t mutex;
#endif
} apop_vtable_s;
apop_vtable_s *vtable_list;
int ignore_me;
/** \endcond */ //End of Doxygen ignore.
//The Dan J Bernstein string hashing algorithm.
static unsigned long apop_settings_hash(char const *str){
unsigned long int hash = 5381;
char c;
while ((c = *str++)) hash = hash*33 + c;
return hash;
}
static apop_vtable_s *find_tab(unsigned long h, int *ctr){
apop_vtable_s *v = vtable_list;
*ctr = 0;
for ( ; v->hashed_name; (*ctr)++, v++) if (v->hashed_name== h) break;
return v;
}
//return 0 = found; removed
//return 1 = not found; no-op
int apop_vtable_drop(char const *tabname, unsigned long hash){
if (!vtable_list) return 1;
unsigned long h = apop_settings_hash(tabname);
apop_vtable_s *v = find_tab(h, &ignore_me);
lock
for (int i=0; i< v->elmt_ct; i++)
if (hash == v->elmts[i].hash) {
memmove(v->elmts+i, v->elmts+i+1, sizeof(apop_vtable_elmt_s)*(v->elmt_ct-i));
v->elmt_ct--;
unlock
return 0;
}
unlock
return 1;
}
int apop_vtable_add(char const *tabname, void *fn_in, unsigned long hash){
if (!vtable_list){vtable_list = calloc(1, sizeof(apop_vtable_s));}
unsigned long h = apop_settings_hash(tabname);
int ctr;
apop_vtable_s *v;
//add a table if need be.
OMP_critical (new_vtable)
{
v = find_tab(h, &ctr);
if (!v->hashed_name){
vtable_list = realloc(vtable_list, (ctr+2)* sizeof(apop_vtable_s));
vtable_list[ctr] = (apop_vtable_s){.elmts=calloc(1, sizeof(apop_vtable_elmt_s))};
vtable_list[ctr+1] = (apop_vtable_s){ };
#ifdef _OPENMP
omp_init_lock(&vtable_list[ctr].mutex);
omp_set_lock(&vtable_list[ctr].mutex);
#endif
vtable_list[ctr].name = tabname;
vtable_list[ctr].hashed_name = h;
v = vtable_list+ctr;
unlock
}
}
lock
//If this hash is already present, don't re-add.
for (int i=0; i< v->elmt_ct; i++) if (hash == v->elmts[i].hash) {unlock; return 0;}
//insert
v->elmts = realloc(v->elmts, (++(v->elmt_ct))* sizeof(apop_vtable_elmt_s));
v->elmts[v->elmt_ct-1] = (apop_vtable_elmt_s){.hash=hash, .fn=fn_in};
unlock
return 0;
}
void *apop_vtable_get(char const *tabname, unsigned long hash){
if (!vtable_list) return NULL;
unsigned long thash = apop_settings_hash(tabname);
apop_vtable_s *v = find_tab(thash, &ignore_me);
if (!v->hashed_name) return NULL;
lock
for (int i=0; i< v->elmt_ct; i++)
if (hash == v->elmts[i].hash) {unlock; return v->elmts[i].fn;}
unlock
return NULL;
}
|