summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOndrej Zajicek <santiago@crfreenet.org>2023-04-27 17:09:00 +0200
committerOndrej Zajicek <santiago@crfreenet.org>2023-04-27 17:09:00 +0200
commit9b471e72d75c154f3b8c4fa134c7c9f1a55fe27f (patch)
tree9b48f388f4d3f87d243d8a9df1adfcddf75a7a2e
parentca0f239c72486cebfe171e335e3b8a86f5999714 (diff)
Conf: Fix symbol lookup
The symbol table used just symbol name as a key, and used a trick with active flag to find symbols in active scopes with one hash table lookup. The disadvantage is that it can degenerate to O(n) for negative queries in situations where are many symbols with the same name in different scopes. Thanks to Yanko Kaneti for the bugreport.
-rw-r--r--conf/cf-lex.l22
-rw-r--r--conf/conf.h4
-rw-r--r--lib/hash.h2
3 files changed, 16 insertions, 12 deletions
diff --git a/conf/cf-lex.l b/conf/cf-lex.l
index ceedee8a..0a02dd73 100644
--- a/conf/cf-lex.l
+++ b/conf/cf-lex.l
@@ -73,10 +73,10 @@ static uint cf_hash(const byte *c);
#define KW_FN(k) cf_hash(k)
#define KW_ORDER 8 /* Fixed */
-#define SYM_KEY(n) n->name, n->scope->active
+#define SYM_KEY(n) n->name, n->scope
#define SYM_NEXT(n) n->next
#define SYM_EQ(a,s1,b,s2) !strcmp(a,b) && s1 == s2
-#define SYM_FN(k,s) cf_hash(k)
+#define SYM_FN(k,s) cf_hash(k) ^ ptr_hash(s)
#define SYM_ORDER 6 /* Initial */
#define SYM_REHASH sym_rehash
@@ -602,29 +602,31 @@ cf_new_symbol(const byte *c)
}
/**
- * cf_find_symbol - find a symbol by name
+ * cf_find_local_symbol - find a symbol by name
* @cfg: specificed config
+ * @scope: specified symbol scope
* @c: symbol name
*
* This functions searches the symbol table in the config @cfg for a symbol of
- * given name. First it examines the current scope, then the second recent one
+ * given name. First it examines the scope @scope, then the parent scope
* and so on until it either finds the symbol and returns a pointer to its
* &symbol structure or reaches the end of the scope chain and returns %NULL to
* signify no match.
*/
struct symbol *
-cf_find_symbol(const struct config *cfg, const byte *c)
+cf_find_local_symbol(const struct config *cfg, const struct sym_scope *scope, const byte *c)
{
struct symbol *s;
- if (cfg->sym_hash.data &&
- (s = HASH_FIND(cfg->sym_hash, SYM, c, 1)))
- return s;
+ if (cfg->sym_hash.data)
+ for (; scope; scope = scope->next)
+ if (s = HASH_FIND(cfg->sym_hash, SYM, c, scope))
+ return s;
/* In CLI command parsing, fallback points to the current config, otherwise it is NULL. */
if (cfg->fallback &&
cfg->fallback->sym_hash.data &&
- (s = HASH_FIND(cfg->fallback->sym_hash, SYM, c, 1)))
+ (s = HASH_FIND(cfg->fallback->sym_hash, SYM, c, cfg->fallback->root_scope)))
return s;
return NULL;
@@ -642,7 +644,7 @@ cf_find_symbol(const struct config *cfg, const byte *c)
struct symbol *
cf_get_symbol(const byte *c)
{
- return cf_find_symbol(new_config, c) ?: cf_new_symbol(c);
+ return cf_find_local_symbol(new_config, conf_this_scope, c) ?: cf_new_symbol(c);
}
/**
diff --git a/conf/conf.h b/conf/conf.h
index b409750e..cb47e7d0 100644
--- a/conf/conf.h
+++ b/conf/conf.h
@@ -187,7 +187,9 @@ int cf_lex(void);
void cf_lex_init(int is_cli, struct config *c);
void cf_lex_unwind(void);
-struct symbol *cf_find_symbol(const struct config *cfg, const byte *c);
+struct symbol *cf_find_local_symbol(const struct config *cfg, const struct sym_scope *scope, const byte *c);
+static inline struct symbol *cf_find_symbol(const struct config *cfg, const byte *c)
+{ return cf_find_local_symbol(cfg, cfg->root_scope, c); }
struct symbol *cf_get_symbol(const byte *c);
struct symbol *cf_default_name(char *template, int *counter);
diff --git a/lib/hash.h b/lib/hash.h
index 8febb33f..b30f7830 100644
--- a/lib/hash.h
+++ b/lib/hash.h
@@ -237,7 +237,7 @@ mem_hash(const void *p, uint s)
}
static inline uint
-ptr_hash(void *ptr)
+ptr_hash(const void *ptr)
{
uintptr_t p = (uintptr_t) ptr;
return p ^ (p << 8) ^ (p >> 16);