C-API: string to pointer map
Optimization of yspec+namespace lookup Optimization of non-presence container default tree
This commit is contained in:
parent
3be786c211
commit
b09e326307
10 changed files with 303 additions and 20 deletions
|
|
@ -233,3 +233,16 @@
|
|||
* A more intelligent algorithm is needed
|
||||
*/
|
||||
#define XML_DEFAULT_WHEN_TWICE
|
||||
|
||||
/*! If set, make optimized lookup of yspec + namespace -> module
|
||||
*
|
||||
* see yang_find_module_by_namespace
|
||||
*/
|
||||
#define OPTIMIZE_YSPEC_NAMESPACE
|
||||
|
||||
/*! If set, make optimization of non-presence default container
|
||||
*
|
||||
* Save the default XML in YANG and reuse next time
|
||||
* see xml_default
|
||||
*/
|
||||
#define OPTIMIZE_NO_PRESENCE_CONTAINER
|
||||
|
|
|
|||
|
|
@ -54,19 +54,27 @@ static const map_str2int atmap[] = {
|
|||
* @see clicon_str2int
|
||||
*/
|
||||
struct map_str2int{
|
||||
char *ms_str;
|
||||
int ms_int;
|
||||
char *ms_str;
|
||||
int ms_int;
|
||||
};
|
||||
typedef struct map_str2int map_str2int;
|
||||
|
||||
/*! Struct used to map between two strings.
|
||||
*/
|
||||
struct map_str2str{
|
||||
char *ms_s0;
|
||||
char *ms_s1;
|
||||
char *ms_s0;
|
||||
char *ms_s1;
|
||||
};
|
||||
typedef struct map_str2str map_str2str;
|
||||
|
||||
/*! Struct used to map from string to pointer
|
||||
*/
|
||||
struct map_str2ptr{
|
||||
char *mp_str;
|
||||
void *mp_ptr;
|
||||
};
|
||||
typedef struct map_str2ptr map_str2ptr;
|
||||
|
||||
/*! Map from ptr to ptr
|
||||
*/
|
||||
struct map_ptr2ptr{
|
||||
|
|
@ -82,6 +90,9 @@ const char *clicon_int2str(const map_str2int *mstab, int i);
|
|||
int clicon_str2int(const map_str2int *mstab, char *str);
|
||||
int clicon_str2int_search(const map_str2int *mstab, char *str, int upper);
|
||||
char *clicon_str2str(const map_str2str *mstab, char *str);
|
||||
void clixon_str2ptr_sort(map_str2ptr *mptab, size_t len);
|
||||
void *clixon_str2ptr(map_str2ptr *mptab, char *str, size_t len);
|
||||
int clixon_str2ptr_print(FILE *f, map_str2ptr *mptab);
|
||||
void *clixon_ptr2ptr(map_ptr2ptr *mptab, void *ptr);
|
||||
int clixon_ptr2ptr_add(map_ptr2ptr **mptab, void *ptr0, void *ptr1);
|
||||
|
||||
|
|
|
|||
|
|
@ -354,6 +354,10 @@ int yang_sort_subelements(yang_stmt *ys);
|
|||
int yang_single_child_type(yang_stmt *ys, enum rfc_6020 subkeyw);
|
||||
void *yang_action_cb_get(yang_stmt *ys);
|
||||
int yang_action_cb_add(yang_stmt *ys, void *rc);
|
||||
#ifdef OPTIMIZE_NO_PRESENCE_CONTAINER
|
||||
void *yang_nopresence_cache_get(yang_stmt *ys);
|
||||
int yang_nopresence_cache_set(yang_stmt *ys, void *x);
|
||||
#endif
|
||||
int ys_populate_feature(clixon_handle h, yang_stmt *ys);
|
||||
int yang_init(clixon_handle h);
|
||||
int yang_start(clixon_handle h);
|
||||
|
|
|
|||
|
|
@ -65,5 +65,10 @@ int yang_spec_load_dir(clixon_handle h, char *dir, yang_stmt *yspec);
|
|||
int ys_parse_date_arg(char *datearg, uint32_t *dateint);
|
||||
cg_var *ys_parse(yang_stmt *ys, enum cv_type cvtype);
|
||||
int ys_parse_sub(yang_stmt *ys, const char *filename, char *extra);
|
||||
#ifdef OPTIMIZE_YSPEC_NAMESPACE
|
||||
int yspec_nscache_clear(yang_stmt *yspec);
|
||||
yang_stmt *yspec_nscache_get(yang_stmt *yspec, char *ns);
|
||||
int yspec_nscache_new(yang_stmt *yspec);
|
||||
#endif
|
||||
|
||||
#endif /* _CLIXON_YANG_LIB_H_ */
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@
|
|||
#include "clixon_yang.h"
|
||||
#include "clixon_xml.h"
|
||||
#include "clixon_err.h"
|
||||
#include "clixon_string.h"
|
||||
|
||||
/*! Map from int to string using str2int map
|
||||
*
|
||||
|
|
@ -116,9 +117,9 @@ str2int_search1(const map_str2int *mstab,
|
|||
int len,
|
||||
int *found)
|
||||
{
|
||||
const struct map_str2int *ms;
|
||||
int mid;
|
||||
int cmp;
|
||||
const map_str2int *ms;
|
||||
int mid;
|
||||
int cmp;
|
||||
|
||||
if (upper < low)
|
||||
return 0; /* not found */
|
||||
|
|
@ -136,10 +137,58 @@ str2int_search1(const map_str2int *mstab,
|
|||
return str2int_search1(mstab, str, mid+1, upper, len, found);
|
||||
}
|
||||
|
||||
/*! Map from string to ptr using binary (alphatical) search
|
||||
*
|
||||
* Assumes sorted strings, tree search. If two are equal take first
|
||||
* @param[in] ms String, integer map
|
||||
* @param[in] str Input string
|
||||
* @param[in] low Lower bound index
|
||||
* @param[in] upper Upper bound index
|
||||
* @param[in] len Length of array (max)
|
||||
* @param[out] found element
|
||||
* @retval 1 Found with "found" value set.
|
||||
* @retval 0 Not found
|
||||
|
||||
*/
|
||||
static int
|
||||
str2ptr_search1(const map_str2ptr *mptab,
|
||||
char *str,
|
||||
size_t low,
|
||||
size_t upper,
|
||||
size_t len,
|
||||
map_str2ptr **found)
|
||||
{
|
||||
const map_str2ptr *mp;
|
||||
int mid;
|
||||
int cmp;
|
||||
int i;
|
||||
|
||||
if (upper < low)
|
||||
return 0; /* not found */
|
||||
mid = (low + upper) / 2;
|
||||
if (mid >= len) /* beyond range */
|
||||
return 0; /* not found */
|
||||
mp = &mptab[mid];
|
||||
if ((cmp = clicon_strcmp(str, mp->mp_str)) == 0){
|
||||
i = mid;
|
||||
while (i >= 0 && clicon_strcmp(str, mptab[i].mp_str) == 0){
|
||||
mp = &mptab[i];
|
||||
i--;
|
||||
}
|
||||
*found = (map_str2ptr *)mp;
|
||||
return 1; /* found */
|
||||
}
|
||||
else if (cmp < 0)
|
||||
return str2ptr_search1(mptab, str, low, mid-1, len, found);
|
||||
else
|
||||
return str2ptr_search1(mptab, str, mid+1, upper, len, found);
|
||||
}
|
||||
|
||||
/*! Map from string to int using str2int map
|
||||
*
|
||||
* @param[in] ms String, integer map
|
||||
* @param[in] str Input string
|
||||
* @param[in] len
|
||||
* @retval int Value
|
||||
* @retval -1 Error, not found
|
||||
* @note Assumes sorted strings, tree search
|
||||
|
|
@ -176,6 +225,67 @@ clicon_str2str(const map_str2str *mstab,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
str2ptr_qsort(const void* arg1,
|
||||
const void* arg2)
|
||||
{
|
||||
map_str2ptr *mp1 = (map_str2ptr*)arg1;
|
||||
map_str2ptr *mp2 = (map_str2ptr*)arg2;
|
||||
int eq;
|
||||
yang_stmt *yrev;
|
||||
char *rev1 = NULL;
|
||||
char *rev2 = NULL;
|
||||
|
||||
eq = clicon_strcmp(mp1->mp_str, mp2->mp_str);
|
||||
if (0 && eq == 0){
|
||||
if ((yrev = yang_find(mp1->mp_ptr, Y_REVISION, NULL)) != NULL)
|
||||
rev1 = yang_argument_get(yrev);
|
||||
if ((yrev = yang_find(mp2->mp_ptr, Y_REVISION, NULL)) != NULL)
|
||||
rev2 = yang_argument_get(yrev);
|
||||
eq = clicon_strcmp(rev1, rev2);
|
||||
}
|
||||
return eq;
|
||||
}
|
||||
|
||||
void
|
||||
clixon_str2ptr_sort(map_str2ptr *mptab,
|
||||
size_t len)
|
||||
{
|
||||
qsort(mptab, len, sizeof(*mptab), str2ptr_qsort);
|
||||
}
|
||||
|
||||
/*! Map from string to string using str2str map
|
||||
*
|
||||
* @param[in] mptab String to ptr map
|
||||
* @param[in] str Input string
|
||||
* @retval ptr Output pointer
|
||||
* @retval NULL Error, not found
|
||||
*/
|
||||
void*
|
||||
clixon_str2ptr(map_str2ptr *mptab,
|
||||
char *str,
|
||||
size_t len)
|
||||
{
|
||||
map_str2ptr *mp = NULL;
|
||||
|
||||
if (str2ptr_search1(mptab, str, 0, len, len, &mp))
|
||||
return mp->mp_ptr;
|
||||
return NULL; /* not found */
|
||||
}
|
||||
|
||||
int
|
||||
clixon_str2ptr_print(FILE *f,
|
||||
map_str2ptr *mptab)
|
||||
{
|
||||
map_str2ptr *mp = NULL;
|
||||
int i;
|
||||
|
||||
i = 0;
|
||||
for (mp = &mptab[0]; mp->mp_str; mp++)
|
||||
fprintf(f, "%d %s %p\n", i++, mp->mp_str, mp->mp_ptr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Map from pointer to pointer using mptab map
|
||||
*
|
||||
* @param[in] mptab Ptr to ptr map
|
||||
|
|
|
|||
|
|
@ -297,6 +297,9 @@ xml_default(yang_stmt *yt,
|
|||
int retval = -1;
|
||||
yang_stmt *yc;
|
||||
cxobj *xc;
|
||||
#ifdef OPTIMIZE_NO_PRESENCE_CONTAINER
|
||||
cxobj *xc1;
|
||||
#endif
|
||||
int top = 0; /* Top symbol (set default namespace) */
|
||||
int create = 0;
|
||||
int nr = 0;
|
||||
|
|
@ -361,19 +364,37 @@ xml_default(yang_stmt *yt,
|
|||
* defaults.
|
||||
*/
|
||||
if (xml_find_type(xt, NULL, yang_argument_get(yc), CX_ELMNT) == NULL){
|
||||
/* No such container exist, recursively try if needed */
|
||||
if (xml_nopresence_try(yc, state, &create) < 0)
|
||||
goto done;
|
||||
if (create){
|
||||
/* Retval shows there is a default value need to create the
|
||||
* container */
|
||||
if (xml_default_create1(yc, xt, &xc) < 0)
|
||||
#ifdef OPTIMIZE_NO_PRESENCE_CONTAINER
|
||||
if ((xc = yang_nopresence_cache_get(yc)) != NULL){
|
||||
if ((xc1 = xml_dup(xc)) == NULL)
|
||||
goto done;
|
||||
if (xml_addsub(xt, xc1) < 0)
|
||||
goto done;
|
||||
xml_sort(xt);
|
||||
/* Then call it recursively */
|
||||
if (xml_default(yc, xc, state) < 0)
|
||||
goto done;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* No such container exist, recursively try if needed */
|
||||
if (xml_nopresence_try(yc, state, &create) < 0)
|
||||
goto done;
|
||||
if (create){
|
||||
/* Retval shows there is a default value need to create the
|
||||
* container */
|
||||
if (xml_default_create1(yc, xt, &xc) < 0)
|
||||
goto done;
|
||||
xml_sort(xt);
|
||||
/* Then call it recursively */
|
||||
if (xml_default(yc, xc, state) < 0)
|
||||
goto done;
|
||||
#ifdef OPTIMIZE_NO_PRESENCE_CONTAINER
|
||||
if ((xc1 = xml_dup(xc)) == NULL)
|
||||
goto done;
|
||||
if (yang_nopresence_cache_set(yc, xc1) < 0)
|
||||
goto done;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -1090,6 +1090,19 @@ ys_free1(yang_stmt *ys,
|
|||
if (ys->ys_filename)
|
||||
free(ys->ys_filename);
|
||||
break;
|
||||
#ifdef OPTIMIZE_NO_PRESENCE_CONTAINER
|
||||
case Y_CONTAINER:
|
||||
if (ys->ys_nopres_cache)
|
||||
xml_free(ys->ys_nopres_cache);
|
||||
break;
|
||||
#endif
|
||||
#ifdef OPTIMIZE_YSPEC_NAMESPACE
|
||||
case Y_SPEC:
|
||||
if (ys->ys_nscache)
|
||||
free(ys->ys_nscache);
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -1220,6 +1233,11 @@ yn_realloc(yang_stmt *yn)
|
|||
return -1;
|
||||
}
|
||||
yn->ys_stmt[yn->ys_len - 1] = NULL; /* init field */
|
||||
#ifdef OPTIMIZE_YSPEC_NAMESPACE
|
||||
if (yn->ys_keyword == Y_SPEC && yn->ys_nscache){ /* Clear cache */
|
||||
yspec_nscache_clear(yn);
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1336,6 +1354,16 @@ ys_cp_one(yang_stmt *ynew,
|
|||
if (yang_typecache_get(yold)) /* Dont copy type cache, use only original */
|
||||
yang_typecache_set(ynew, NULL);
|
||||
break;
|
||||
#ifdef OPTIMIZE_NO_PRESENCE_CONTAINER
|
||||
case Y_CONTAINER:
|
||||
yold->ys_nopres_cache = NULL;
|
||||
break;
|
||||
#endif
|
||||
#ifdef OPTIMIZE_YSPEC_NAMESPACE
|
||||
case Y_SPEC:
|
||||
yold->ys_nscache = NULL;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -4034,11 +4062,12 @@ int
|
|||
yang_config(yang_stmt *ys)
|
||||
{
|
||||
yang_stmt *ym;
|
||||
cg_var *cv;
|
||||
|
||||
if ((ym = yang_find(ys, Y_CONFIG, NULL)) != NULL){
|
||||
if (yang_cv_get(ym) == NULL) /* shouldnt happen */
|
||||
if ((cv = yang_cv_get(ym)) == NULL) /* shouldnt happen */
|
||||
return 1;
|
||||
return cv_bool_get(yang_cv_get(ym));
|
||||
return cv_bool_get(cv);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -4610,6 +4639,24 @@ yang_action_cb_add(yang_stmt *ys,
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef OPTIMIZE_NO_PRESENCE_CONTAINER
|
||||
void *
|
||||
yang_nopresence_cache_get(yang_stmt *ys)
|
||||
{
|
||||
return ys->ys_nopres_cache;
|
||||
}
|
||||
|
||||
int
|
||||
yang_nopresence_cache_set(yang_stmt *ys,
|
||||
void *x)
|
||||
{
|
||||
if (ys->ys_nopres_cache)
|
||||
xml_free(ys->ys_nopres_cache);
|
||||
ys->ys_nopres_cache = x;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*! Init yang code. Called before any yang code, before options
|
||||
*
|
||||
* Add two external tables for YANGs
|
||||
|
|
|
|||
|
|
@ -114,7 +114,12 @@ struct yang_stmt {
|
|||
rpc_callback_t *ysu_action_cb; /* Y_ACTION: Action callback list*/
|
||||
char *ysu_filename; /* Y_MODULE/Y_SUBMODULE: For debug/errors: filename */
|
||||
yang_type_cache *ysu_typecache; /* Y_TYPE: cache all typedef data except unions */
|
||||
|
||||
#ifdef OPTIMIZE_YSPEC_NAMESPACE
|
||||
map_str2ptr *ysu_nscache; /* Y_SPEC: namespace to module cache */
|
||||
#endif
|
||||
#ifdef OPTIMIZE_NO_PRESENCE_CONTAINER
|
||||
cxobj *ysu_nopres_cache; /* Y_CONTAINER: no-presence XML cache */
|
||||
#endif
|
||||
} u;
|
||||
};
|
||||
|
||||
|
|
@ -122,5 +127,11 @@ struct yang_stmt {
|
|||
#define ys_action_cb u.ysu_action_cb
|
||||
#define ys_filename u.ysu_filename
|
||||
#define ys_typecache u.ysu_typecache
|
||||
#ifdef OPTIMIZE_YSPEC_NAMESPACE
|
||||
#define ys_nscache u.ysu_nscache
|
||||
#endif
|
||||
#ifdef OPTIMIZE_NO_PRESENCE_CONTAINER
|
||||
#define ys_nopres_cache u.ysu_nopres_cache
|
||||
#endif
|
||||
|
||||
#endif /* _CLIXON_YANG_INTERNAL_H_ */
|
||||
|
|
|
|||
|
|
@ -609,6 +609,9 @@ yang_stmt *
|
|||
yang_find_module_by_namespace(yang_stmt *yspec,
|
||||
char *ns)
|
||||
{
|
||||
#ifdef OPTIMIZE_YSPEC_NAMESPACE
|
||||
return yspec_nscache_get(yspec, ns);
|
||||
#else
|
||||
yang_stmt *ymod = NULL;
|
||||
int inext;
|
||||
|
||||
|
|
@ -621,6 +624,7 @@ yang_find_module_by_namespace(yang_stmt *yspec,
|
|||
}
|
||||
done:
|
||||
return ymod;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*! Given a yang spec, a namespace and revision, return yang module
|
||||
|
|
|
|||
|
|
@ -903,6 +903,9 @@ yang_parse_str(char *str,
|
|||
/* Add filename for debugging and errors, see also ys_linenum on (each symbol?) */
|
||||
if (yang_filename_set(ymod, name) < 0)
|
||||
goto done;
|
||||
#ifdef OPTIMIZE_YSPEC_NAMESPACE
|
||||
yspec_nscache_clear(yspec);
|
||||
#endif
|
||||
done:
|
||||
clixon_debug(CLIXON_DBG_PARSE, "retval:%p", ymod);
|
||||
ystack_pop(&yy);
|
||||
|
|
@ -2109,3 +2112,57 @@ ys_parse_sub(yang_stmt *ys,
|
|||
free(extra);
|
||||
return retval;
|
||||
}
|
||||
|
||||
#ifdef OPTIMIZE_YSPEC_NAMESPACE
|
||||
int
|
||||
yspec_nscache_clear(yang_stmt *yspec)
|
||||
{
|
||||
if (yspec->ys_nscache){ /* Clear cache */
|
||||
free(yspec->ys_nscache);
|
||||
yspec->ys_nscache = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
*/
|
||||
yang_stmt *
|
||||
yspec_nscache_get(yang_stmt *yspec,
|
||||
char *ns)
|
||||
{
|
||||
if (yspec->ys_nscache == NULL){
|
||||
if (yspec_nscache_new(yspec) < 0)
|
||||
return NULL;
|
||||
}
|
||||
return clixon_str2ptr(yspec->ys_nscache, ns, yang_len_get(yspec)+1);
|
||||
}
|
||||
|
||||
/*!
|
||||
*/
|
||||
int
|
||||
yspec_nscache_new(yang_stmt *yspec)
|
||||
{
|
||||
int retval = -1;
|
||||
map_str2ptr *mp;
|
||||
yang_stmt *ym;
|
||||
int i;
|
||||
|
||||
yspec_nscache_clear(yspec);
|
||||
if ((yspec->ys_nscache = calloc(yang_len_get(yspec)+1, sizeof(*yspec->ys_nscache))) == NULL){
|
||||
clixon_err(OE_UNIX, errno, "calloc");
|
||||
goto done;
|
||||
}
|
||||
for (i=0; i<yang_len_get(yspec); i++){
|
||||
ym = yang_child_i(yspec, i);
|
||||
if (yang_keyword_get(ym) != Y_MODULE)
|
||||
continue;
|
||||
mp = &yspec->ys_nscache[i];
|
||||
mp->mp_str = yang_find_mynamespace(ym);
|
||||
mp->mp_ptr = ym;
|
||||
}
|
||||
clixon_str2ptr_sort(yspec->ys_nscache, yang_len_get(yspec)+1);
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue