1
0
mirror of https://github.com/libretro/RetroArch synced 2025-03-02 19:13:34 +00:00

Merge pull request from jdgleaver/config-file-hash-map

This commit is contained in:
Autechre 2021-04-22 00:35:35 +02:00 committed by GitHub
commit 7a5559aba0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 109 additions and 28 deletions
libretro-common

@ -39,6 +39,7 @@
#include <file/file_path.h>
#include <string/stdstring.h>
#include <streams/file_stream.h>
#include <array/rhmap.h>
#define MAX_INCLUDE_DEPTH 16
@ -48,6 +49,15 @@ struct config_include_list
struct config_include_list *next;
};
static uint32_t config_file_hash_string(const char *str)
{
unsigned char c;
uint32_t hash = (uint32_t)0x811c9dc5;
while ((c = (unsigned char)*(str++)) != '\0')
hash = ((hash * (uint32_t)0x01000193) ^ (uint32_t)c);
return (hash ? hash : 1);
}
/* Forward declaration */
static bool config_file_parse_line(config_file_t *conf,
struct config_entry_list *list, char *line, config_file_cb_t *cb);
@ -273,6 +283,8 @@ static char *config_file_extract_value(char *line, bool is_value)
static void config_file_add_child_list(config_file_t *parent, config_file_t *child)
{
struct config_entry_list *list = child->entries;
bool merge_hash_map = false;
if (parent->entries)
{
struct config_entry_list *head = parent->entries;
@ -286,6 +298,8 @@ static void config_file_add_child_list(config_file_t *parent, config_file_t *chi
list = list->next;
}
head->next = child->entries;
merge_hash_map = true;
}
else
{
@ -298,8 +312,6 @@ static void config_file_add_child_list(config_file_t *parent, config_file_t *chi
parent->entries = child->entries;
}
child->entries = NULL;
/* Rebase tail. */
if (parent->entries)
{
@ -312,6 +324,44 @@ static void config_file_add_child_list(config_file_t *parent, config_file_t *chi
}
else
parent->tail = NULL;
/* Update hash map */
if (merge_hash_map)
{
size_t i;
size_t cap;
/* We are merging two lists - if any child entry
* (key) is not present in the parent list, add it
* to the parent hash map */
for (i = 0, cap = RHMAP_CAP(child->entries_map); i != cap; i++)
{
uint32_t child_hash = RHMAP_KEY(child->entries_map, i);
if (!RHMAP_HAS(parent->entries_map, child_hash))
{
struct config_entry_list *entry =
RHMAP_GET(child->entries_map, child_hash);
if (entry)
RHMAP_SET(parent->entries_map, child_hash, entry);
}
}
/* Child entries map is no longer required,
* so free it now */
RHMAP_FREE(child->entries_map);
}
else
{
/* If parent list was originally empty,
* take map from child list */
RHMAP_FREE(parent->entries_map);
parent->entries_map = child->entries_map;
child->entries_map = NULL;
}
child->entries = NULL;
}
static void config_file_get_realpath(char *s, size_t len,
@ -426,8 +476,21 @@ static int config_file_load_internal(
conf->tail = list;
if (cb && list->key && list->value)
cb->config_file_new_entry_cb(list->key, list->value) ;
if (list->key)
{
/* Only add entry to the map if an entry
* with the specified value does not
* already exist */
uint32_t hash = config_file_hash_string(list->key);
if (!RHMAP_HAS(conf->entries_map, hash))
{
RHMAP_SET(conf->entries_map, hash, list);
if (cb && list->value)
cb->config_file_new_entry_cb(list->key, list->value);
}
}
}
free(line);
@ -628,6 +691,16 @@ static int config_file_from_string_internal(
conf->entries = list;
conf->tail = list;
if (list->key)
{
/* Only add entry to the map if an entry
* with the specified value does not
* already exist */
uint32_t hash = config_file_hash_string(list->key);
if (!RHMAP_HAS(conf->entries_map, hash))
RHMAP_SET(conf->entries_map, hash, list);
}
}
if (list != conf->tail)
@ -705,6 +778,9 @@ bool config_file_deinitialize(config_file_t *conf)
if (conf->path)
free(conf->path);
RHMAP_FREE(conf->entries_map);
return true;
}
@ -718,9 +794,22 @@ void config_file_free(config_file_t *conf)
bool config_append_file(config_file_t *conf, const char *path)
{
config_file_t *new_conf = config_file_new_from_path_to_string(path);
size_t i;
size_t cap;
if (!new_conf)
return false;
/* Update hash map */
for (i = 0, cap = RHMAP_CAP(new_conf->entries_map); i != cap; i++)
{
uint32_t new_hash = RHMAP_KEY(new_conf->entries_map, i);
struct config_entry_list *entry = RHMAP_GET(new_conf->entries_map, new_hash);
if (entry)
RHMAP_SET(conf->entries_map, new_hash, entry);
}
if (new_conf->tail)
{
new_conf->tail->next = conf->entries;
@ -818,6 +907,7 @@ void config_file_initialize(struct config_file *conf)
return;
conf->path = NULL;
conf->entries_map = NULL;
conf->entries = NULL;
conf->tail = NULL;
conf->last = NULL;
@ -844,16 +934,18 @@ static struct config_entry_list *config_get_entry_internal(
struct config_entry_list *entry = NULL;
struct config_entry_list *previous = prev ? *prev : NULL;
for (entry = conf->entries; entry; entry = entry->next)
{
if (string_is_equal(key, entry->key))
return entry;
entry = RHMAP_GET(conf->entries_map, config_file_hash_string(key));
previous = entry;
}
if (entry)
return entry;
if (prev)
{
for (entry = conf->entries; entry; entry = entry->next)
previous = entry;
*prev = previous;
}
return NULL;
}
@ -861,16 +953,9 @@ static struct config_entry_list *config_get_entry_internal(
struct config_entry_list *config_get_entry(
const config_file_t *conf, const char *key)
{
struct config_entry_list *entry = NULL;
for (entry = conf->entries; entry; entry = entry->next)
{
if (string_is_equal(key, entry->key))
return entry;
}
return NULL;
return RHMAP_GET(conf->entries_map, config_file_hash_string(key));
}
bool config_get_double(config_file_t *conf, const char *key, double *in)
{
const struct config_entry_list *entry = config_get_entry(conf, key);
@ -1141,6 +1226,8 @@ void config_set_string(config_file_t *conf, const char *key, const char *val)
conf->entries = entry;
conf->last = entry;
RHMAP_SET(conf->entries_map, config_file_hash_string(entry->key), entry);
}
void config_unset(config_file_t *conf, const char *key)
@ -1157,6 +1244,8 @@ void config_unset(config_file_t *conf, const char *key)
if (!entry)
return;
(void)RHMAP_DEL(conf->entries_map, config_file_hash_string(entry->key));
if (entry->key)
free(entry->key);
@ -1376,16 +1465,7 @@ void config_file_dump(config_file_t *conf, FILE *file, bool sort)
bool config_entry_exists(config_file_t *conf, const char *entry)
{
struct config_entry_list *list = conf->entries;
while (list)
{
if (string_is_equal(entry, list->key))
return true;
list = list->next;
}
return false;
return (bool)RHMAP_HAS(conf->entries_map, config_file_hash_string(entry));
}
bool config_get_entry_list_head(config_file_t *conf,

@ -55,6 +55,7 @@ struct config_file
{
char *path;
char *reference;
struct config_entry_list **entries_map;
struct config_entry_list *entries;
struct config_entry_list *tail;
struct config_entry_list *last;