#include "file_tab.h" #include "threading.h" #include "config.h" #include "hashing.h" #define NAME_CAP(cap) ((cap)*128) typedef struct { rt_file_id *ids; unsigned int *name_offsets; char *names; unsigned int capacity; unsigned int name_head; rt_mutex *mutex; } rt_file_tab; static rt_file_tab _file_tab; RT_CVAR_I(rt_FileTabCapacity, "Maximum number of filetab entries. Default: 1024", 1024); rt_result InitFileTab(void) { unsigned int max_files = (unsigned int)rt_FileTabCapacity.i; _file_tab.ids = calloc(max_files, sizeof(rt_file_id)); if (!_file_tab.ids) return 1; _file_tab.name_offsets = calloc(max_files, sizeof(unsigned int)); if (!_file_tab.name_offsets) return 1; _file_tab.names = malloc(NAME_CAP(max_files)); if (!_file_tab.names) return 1; _file_tab.capacity = max_files; _file_tab.name_head = 0; _file_tab.mutex = rtCreateMutex(); return RT_SUCCESS; } void ShutdownFileTab(void) { free(_file_tab.ids); free(_file_tab.names); free(_file_tab.name_offsets); rtDestroyMutex(_file_tab.mutex); } RT_DLLEXPORT rt_file_id rtGetFileId(const char *path) { rt_text_span span; span.start = path; span.length = (unsigned int)strlen(path); return rtGetFileIdFromSpan(span); } RT_DLLEXPORT rt_file_id rtGetFileIdFromSpan(rt_text_span path) { /* Randomly choosen, aka finger smash keyboard */ rt_file_id fid = (rt_file_id)rtHashBytes(path.start, path.length); if (fid == 0) fid = ~fid; return fid; } RT_DLLEXPORT rt_file_id rtAddFileFromSpan(rt_text_span path) { rt_file_id fid = rtGetFileIdFromSpan(path); if (!rtLockMutex(_file_tab.mutex)) { rtReportError("fio", "Failed to lock the guard mutex."); return 0; } /* Hash Insert */ unsigned int i = 0; unsigned int base = (unsigned int)(fid % _file_tab.capacity); while (i < _file_tab.capacity) { unsigned int at = (base + i) % _file_tab.capacity; if (_file_tab.ids[at] == 0) { /* Insert */ unsigned int slen = (unsigned int)path.length + 1; if ((_file_tab.name_head + slen) >= NAME_CAP(_file_tab.capacity)) { /* Out of name storage */ fid = 0; break; } memcpy(_file_tab.names + _file_tab.name_head, path.start, slen); _file_tab.names[_file_tab.name_head + slen - 1] = '\0'; _file_tab.name_offsets[at] = _file_tab.name_head; _file_tab.ids[at] = fid; _file_tab.name_head += slen; break; } else if (_file_tab.ids[at] == fid) { break; } ++i; } /* Out of space */ if (i == _file_tab.capacity) fid = 0; rtUnlockMutex(_file_tab.mutex); return fid; } RT_DLLEXPORT rt_file_id rtAddFile(const char *path) { rt_text_span span; span.start = path; span.length = (unsigned int)strlen(path); return rtAddFileFromSpan(span); } RT_DLLEXPORT const char *rtGetFilePath(rt_file_id fid) { /* Hash Lookup */ if (fid == 0) return NULL; if (!rtLockMutex(_file_tab.mutex)) { rtReportError("fio", "Failed to lock the guard mutex."); return 0; } const char *result = NULL; unsigned int i = 0; unsigned int base = (unsigned int)(fid % _file_tab.capacity); while (i < _file_tab.capacity) { unsigned int at = (base + i) % _file_tab.capacity; if (_file_tab.ids[at] == fid) { result = _file_tab.names + _file_tab.name_offsets[at]; break; } else if (_file_tab.ids[at] == 0) { break; } ++i; } rtUnlockMutex(_file_tab.mutex); return result; }