File: apop_vtables.c

package info (click to toggle)
apophenia 1.0%2Bds-10
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 3,152 kB
  • sloc: ansic: 19,483; makefile: 378; awk: 124; sh: 105; javascript: 35; sed: 32
file content (118 lines) | stat: -rw-r--r-- 3,157 bytes parent folder | download | duplicates (3)
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;
}