Updated MSpec source to 46e80081.
[rbx.git] / shotgun / external_libs / libmquark / quark.c
blob8fccc1f6eb0a29306d24e1c31a05d457ce46b4cb
1 #ifdef _WIN32
2 # include <windows.h>
3 #else
4 # include <pthread.h>
5 #endif
7 #include <string.h>
8 #include <stdbool.h>
9 #include <stdint.h>
11 #include "quark.h"
12 #include "hashtable.h"
13 #include "ptr_array.h"
15 static struct hashtable *quark_string_hash = NULL; /* const char * -> int */
16 static ptr_array quark_string_index = NULL;
18 #ifdef _WIN32
19 static CRITICAL_SECTION quark_static_cs;
20 static bool cs_initialized = false;
22 static void mutex_lock()
24 if (!cs_initialized) {
25 InitializeCriticalSection(&quark_static_cs);
27 cs_initialized = true;
30 EnterCriticalSection(&quark_static_cs);
33 static void mutex_unlock()
35 LeaveCriticalSection(&quark_static_cs);
37 #else
38 static pthread_mutex_t quark_static_lock = PTHREAD_MUTEX_INITIALIZER;
40 static void mutex_lock()
42 pthread_mutex_lock(&quark_static_lock);
45 static void mutex_unlock()
47 pthread_mutex_unlock(&quark_static_lock);
49 #endif
51 enum {QUARK_NOT_FOUND = ~0L};
53 /* djb2 hash function */
54 static unsigned int string_hash(const void *val)
56 unsigned int hash = 5381;
57 const char *str = (const char *)val;
58 int c;
60 while ((c = *str++))
61 hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
63 return hash;
66 static int string_eq(const void* a1, const void* a2)
68 return strcmp((const char*) a1, (const char*) a2) == 0;
71 /* assumes static lock is held */
72 static inline bool quark_init_if_needed()
74 if (quark_string_hash == NULL)
76 quark_string_hash = create_hashtable(31, string_hash, string_eq);
77 quark_string_index = ptr_array_new(10);
78 ptr_array_append(quark_string_index, NULL);
79 return true;
81 return false;
84 quark quark_from_string(const char *string)
86 if (string == NULL) return 0;
87 mutex_lock();
88 if (!quark_init_if_needed())
90 uintptr_t value = (uintptr_t)hashtable_search(quark_string_hash, string);
91 if (value != 0)
93 mutex_unlock();
94 return value;
97 string = strdup(string);
98 if (!ptr_array_append(quark_string_index, string))
100 mutex_unlock();
101 return QUARK_NOT_FOUND;
103 size_t index = ptr_array_length(quark_string_index) - 1;
104 hashtable_insert(quark_string_hash, (char*) string, (void*) index);
105 mutex_unlock();
106 return index;
109 quark quark_from_static_string(const char *string)
111 if (string == NULL) return 0;
112 mutex_lock();
113 if (!quark_init_if_needed())
115 uintptr_t value = (uintptr_t)hashtable_search(quark_string_hash, string);
116 if (value != 0)
118 mutex_unlock();
119 return value;
122 if (!ptr_array_append(quark_string_index, string))
124 mutex_unlock();
125 return QUARK_NOT_FOUND;
127 size_t index = ptr_array_length(quark_string_index) - 1;
128 hashtable_insert(quark_string_hash, (char *)string, (void*) index);
129 mutex_unlock();
130 return index;
133 const char * quark_to_string(quark q)
135 const char *retval;
136 if (q == 0) return NULL;
137 mutex_lock();
138 if (quark_init_if_needed() || q >= ptr_array_length(quark_string_index))
140 mutex_unlock();
141 return NULL;
143 retval = ptr_array_get_index(quark_string_index, q);
144 mutex_unlock();
145 return retval;