did some tests - this seems to be faster and seems to match correctly in some

test cases i brewed up. doesnt seem to break e so far and thats a fairly
comprehensive test.


SVN revision: 33515
This commit is contained in:
Carsten Haitzler 2008-01-18 06:34:04 +00:00
parent 1683d650d4
commit fff9c738a2
6 changed files with 718 additions and 64 deletions

View File

@ -34,6 +34,7 @@ edje_container.h \
edje_message_queue.c \
edje_private.h \
edje_cache.c \
edje_match.c \
edje_textblock_styles.c
libedje_la_LIBADD = -lm @EDJE_LIBS@ @fnmatch_libs@

View File

@ -158,15 +158,16 @@ edje_file_group_exists(const char *file, const char *glob)
{
if (edf->collection_dir)
{
Evas_List *l;
Edje_Patterns *patterns;
for (l = edf->collection_dir->entries; l; l = l->next)
{
Edje_Part_Collection_Directory_Entry *ce;
ce = l->data;
if (_edje_glob_match(ce->entry, glob)) return 1;
}
patterns = edje_match_collection_dir_init(edf->collection_dir->entries);
if (edje_match_collection_dir_exec(patterns,
glob))
{
edje_match_patterns_free(patterns);
return 1;
}
edje_match_patterns_free(patterns);
}
_edje_cache_file_unref(edf);
}

View File

@ -0,0 +1,570 @@
#include <stdlib.h>
#include <stddef.h>
#include <Evas.h>
#include "Edje.h"
#include "edje_private.h"
/* States manipulations. */
typedef struct _Edje_State Edje_State;
struct _Edje_State
{
size_t idx;
size_t pos;
};
typedef struct _Edje_States Edje_States;
struct _Edje_States
{
size_t size;
Edje_State *states;
_Bool *has;
};
static void
_edje_match_states_free(Edje_States *states,
size_t states_size)
{
(void) states_size;
free(states);
}
#define ALIGN(Size) \
{ \
Size--; \
Size |= sizeof (void*) - 1; \
Size++; \
};
static Edje_States*
_edje_match_states_alloc(size_t n,
size_t patterns_size,
size_t patterns_max_length)
{
Edje_States *l;
const size_t array_len = (patterns_max_length + 1) * patterns_size;
size_t states_size;
size_t has_size;
size_t states_has_size;
size_t struct_size;
unsigned char *states;
unsigned char *has;
size_t i;
states_size = sizeof (*l->states) * array_len;
ALIGN(states_size);
has_size = sizeof (*l->has) * array_len;
ALIGN(has_size);
states_has_size = states_size + has_size;
struct_size = sizeof (*l);
ALIGN(struct_size);
struct_size += states_has_size;
l = malloc(n * struct_size);
if (!l) return NULL;
states = (unsigned char *) (l + n);
has = states + states_size;
for (i = 0; i < n; ++i)
{
l[i].states = (Edje_State *) states;
l[i].has = (_Bool *) has;
states += states_has_size;
has += states_has_size;
}
return l;
}
static void
_edje_match_states_insert(Edje_States *list,
size_t patterns_max_length,
size_t idx,
size_t pos)
{
{
const size_t i = idx * (patterns_max_length + 1) + pos;
if (list->has[i]) return;
list->has[i] = 1;
}
const size_t i = list->size;
list->states[i].idx = idx;
list->states[i].pos = pos;
++list->size;
}
static void
_edje_match_states_clear(Edje_States *list,
size_t patterns_size,
size_t patterns_max_length)
{
list->size = 0;
memset(list->has, 0, patterns_size * (patterns_max_length + 1) * sizeof (*list->has));
}
/* Token manipulation. */
enum status
{
patterns_not_found = 0,
patterns_found = 1,
patterns_syntax_error = 2
};
static size_t
_edje_match_patterns_exec_class_token(enum status *status,
const char *cl_tok,
char c)
{
if (! *cl_tok)
{
*status = patterns_syntax_error;
return 0;
}
else if (cl_tok[1] == '-' && cl_tok[2] != ']')
{
if (*cl_tok <= c && c <= cl_tok[2])
*status = patterns_found;
return 3;
}
else
{
if (c == *cl_tok)
*status = patterns_found;
return 1;
}
}
static Edje_Match_Error
_edje_match_patterns_exec_class_complement(const char *cl_tok, size_t *ret)
{
switch (*cl_tok)
{
case 0:
return EDJE_MATCH_SYNTAX_ERROR;
case '!':
*ret = 1;
return EDJE_MATCH_OK;
default:
*ret = 0;
return EDJE_MATCH_OK;
}
}
static Edje_Match_Error
_edje_match_patterns_exec_class(const char *cl,
char c,
size_t *ret)
{
enum status status = patterns_not_found;
int pos = 1;
size_t neg;
if (_edje_match_patterns_exec_class_complement(cl + 1, &neg) != EDJE_MATCH_OK)
return EDJE_MATCH_SYNTAX_ERROR;
pos += neg;
do
pos += _edje_match_patterns_exec_class_token(&status, cl + pos, c);
while (cl[pos] && cl[pos] != ']');
if (status == patterns_syntax_error || ! cl[pos])
return EDJE_MATCH_SYNTAX_ERROR;
if (status == patterns_found)
*ret = neg ? 0 : pos + 1;
else
*ret = neg ? pos + 1 : 0;
return EDJE_MATCH_OK;
}
static Edje_Match_Error
_edje_match_patterns_exec_token(const char *tok,
char c,
size_t *ret)
{
switch (*tok)
{
case '\\':
if (tok[1])
{
*ret = tok[1] == c ? 2 : 0;
return EDJE_MATCH_OK;
}
return EDJE_MATCH_SYNTAX_ERROR;
case '?':
*ret = 1;
return EDJE_MATCH_OK;
case '[':
return _edje_match_patterns_exec_class(tok, c, ret);
default:
*ret = *tok == c ? 1 : 0;
return EDJE_MATCH_OK;
}
}
static void
_edje_match_patterns_exec_init_states(Edje_States *states,
size_t patterns_size,
size_t patterns_max_length)
{
size_t i;
states->size = patterns_size;
memset(states->has,
0,
patterns_size * (patterns_max_length + 1) * sizeof (*states->has));
for (i = 0; i < patterns_size; ++i)
{
states->states[i].idx = i;
states->states[i].pos = 0;
states->has[i * (patterns_max_length + 1)] = 1;
}
}
/* Exported function. */
#define EDJE_MATCH_INIT(Func, Type, Source, Show) \
Edje_Patterns* \
Func(Evas_List *lst) \
{ \
Edje_Patterns *r; \
size_t i; \
\
if (!lst || evas_list_count(lst) <= 0) \
return NULL; \
\
r = malloc(sizeof (Edje_Patterns) + \
evas_list_count(lst) \
* sizeof (*r->finals) \
* sizeof(*r->patterns)); \
if (!r) return NULL; \
\
r->patterns_size = evas_list_count(lst); \
r->max_length = 0; \
r->patterns = (const char **) r->finals + r->patterns_size + 1; \
\
for (i = 0; lst; ++i) \
{ \
const char *str; \
Type *data; \
size_t j; \
\
data = evas_list_data(lst); \
if (!data) \
{ \
free(r); \
return NULL; \
} \
\
str = data->Source; \
if (!str) str = ""; \
r->patterns[i] = str; \
\
if (Show) \
fprintf(stderr, "%i [%s]\n", i, str); \
\
r->finals[i] = 0; \
for (j = 0; str[j]; ++j) \
if (str[j] != '*') \
r->finals[i] = j + 1; \
\
if (j > r->max_length) \
r->max_length = j; \
\
lst = evas_list_next(lst); \
} \
\
return r; \
}
EDJE_MATCH_INIT(edje_match_collection_dir_init,
Edje_Part_Collection_Directory_Entry,
entry, 0);
EDJE_MATCH_INIT(edje_match_programs_signal_init,
Edje_Program,
signal, 0);
EDJE_MATCH_INIT(edje_match_programs_source_init,
Edje_Program,
source, 0);
EDJE_MATCH_INIT(edje_match_callback_signal_init,
Edje_Signal_Callback,
signal, 0);
EDJE_MATCH_INIT(edje_match_callback_source_init,
Edje_Signal_Callback,
source, 0);
static int
_edje_match_collection_dir_exec_finals(const size_t *finals,
const Edje_States *states)
{
size_t i;
for (i = 0; i < states->size; ++i)
if (states->states[i].pos >= finals[states->states[i].idx])
return 1;
return 0;
}
static int
edje_match_programs_exec_check_finals(const size_t *signal_finals,
const size_t *source_finals,
const Edje_States *signal_states,
const Edje_States *source_states,
Evas_List *programs,
int (*func)(Edje_Program *pr, void *data),
void *data)
{
size_t i;
size_t j;
for (i = 0; i < signal_states->size; ++i)
if (signal_states->states[i].pos >= signal_finals[signal_states->states[i].idx])
for (j = 0; j < source_states->size; ++j)
if (signal_states->states[i].idx == source_states->states[j].idx
&& source_states->states[j].pos >= source_finals[source_states->states[j].idx])
{
Edje_Program *pr;
pr = evas_list_nth(programs, signal_states->states[i].idx);
if (pr)
{
if (func(pr, data))
return 0;
}
}
return 1;
}
static int
edje_match_callback_exec_check_finals(const size_t *signal_finals,
const size_t *source_finals,
const Edje_States *signal_states,
const Edje_States *source_states,
const char *signal,
const char *source,
Evas_List *callbacks,
Edje *ed)
{
size_t i;
size_t j;
int r = 1;
for (i = 0; i < signal_states->size; ++i)
if (signal_states->states[i].pos >= signal_finals[signal_states->states[i].idx])
for (j = 0; j < source_states->size; ++j)
if (signal_states->states[i].idx == source_states->states[j].idx
&& source_states->states[j].pos >= source_finals[source_states->states[j].idx])
{
Edje_Signal_Callback *escb;
escb = evas_list_nth(callbacks, signal_states->states[i].idx);
if (escb)
{
if ((!escb->just_added)
&& (!escb->delete_me))
{
escb->func(escb->data, ed->obj, signal, source);
r = 2;
}
if (_edje_block_break(ed))
return 0;
}
}
return r;
}
static Edje_States*
_edje_match_fn(const Edje_Patterns *ppat,
const char *string,
Edje_States *states)
{
Edje_States *new_states = states + 1;
const char *c;
for (c = string; *c && states->size; ++c)
{
size_t i;
_edje_match_states_clear(new_states, ppat->patterns_size, ppat->max_length);
for (i = 0; i < states->size; ++i)
{
const size_t idx = states->states[i].idx;
const size_t pos = states->states[i].pos;
if (!ppat->patterns[idx][pos])
continue;
else if (ppat->patterns[idx][pos] == '*')
{
_edje_match_states_insert(states, ppat->max_length, idx, pos + 1);
_edje_match_states_insert(new_states, ppat->max_length, idx, pos);
}
else
{
size_t m;
if (_edje_match_patterns_exec_token(ppat->patterns[idx] + pos,
*c,
&m) != EDJE_MATCH_OK)
return NULL;
if (m)
_edje_match_states_insert(new_states, ppat->max_length, idx, pos + m);
}
}
{
Edje_States *tmp = states;
states = new_states;
new_states = tmp;
}
}
return states;
}
int
edje_match_collection_dir_exec(const Edje_Patterns *ppat,
const char *string)
{
Edje_States *states = _edje_match_states_alloc(2,
ppat->patterns_size,
ppat->max_length);
Edje_States *result;
int r = 0;
if (!states)
return 0;
_edje_match_patterns_exec_init_states(states, ppat->patterns_size, ppat->max_length);
result = _edje_match_fn(ppat, string, states);
if (result)
r = _edje_match_collection_dir_exec_finals(ppat->finals, result);
_edje_match_states_free(states, 2);
return r;
}
int
edje_match_programs_exec(const Edje_Patterns *ppat_signal,
const Edje_Patterns *ppat_source,
const char *signal,
const char *source,
Evas_List *programs,
int (*func)(Edje_Program *pr, void *data),
void *data)
{
Edje_States *signal_states = _edje_match_states_alloc(2,
ppat_signal->patterns_size,
ppat_signal->max_length);
Edje_States *source_states = _edje_match_states_alloc(2,
ppat_source->patterns_size,
ppat_source->max_length);
Edje_States *signal_result;
Edje_States *source_result;
int r = 0;
if (!signal_states || !source_states)
return 0;
_edje_match_patterns_exec_init_states(signal_states,
ppat_signal->patterns_size,
ppat_signal->max_length);
_edje_match_patterns_exec_init_states(source_states,
ppat_source->patterns_size,
ppat_source->max_length);
signal_result = _edje_match_fn(ppat_signal, signal, signal_states);
source_result = _edje_match_fn(ppat_source, source, source_states);
if (signal_result && source_result)
r = edje_match_programs_exec_check_finals(ppat_signal->finals,
ppat_source->finals,
signal_result,
source_result,
programs,
func,
data);
_edje_match_states_free(source_states, 2);
_edje_match_states_free(signal_states, 2);
return r;
}
int
edje_match_callback_exec(const Edje_Patterns *ppat_signal,
const Edje_Patterns *ppat_source,
const char *signal,
const char *source,
Evas_List *callbacks,
Edje *ed)
{
Edje_States *signal_states = _edje_match_states_alloc(2,
ppat_signal->patterns_size,
ppat_signal->max_length);
Edje_States *source_states = _edje_match_states_alloc(2,
ppat_source->patterns_size,
ppat_source->max_length);
Edje_States *signal_result;
Edje_States *source_result;
int r = 0;
if (!signal_states || !source_states)
return 0;
_edje_match_patterns_exec_init_states(signal_states,
ppat_signal->patterns_size,
ppat_signal->max_length);
_edje_match_patterns_exec_init_states(source_states,
ppat_source->patterns_size,
ppat_source->max_length);
signal_result = _edje_match_fn(ppat_signal, signal, signal_states);
source_result = _edje_match_fn(ppat_source, source, source_states);
if (signal_result && source_result)
r = edje_match_callback_exec_check_finals(ppat_signal->finals,
ppat_source->finals,
signal_result,
source_result,
signal,
source,
callbacks,
ed);
_edje_match_states_free(source_states, 2);
_edje_match_states_free(signal_states, 2);
return r;
}
void
edje_match_patterns_free(Edje_Patterns *ppat)
{
free(ppat);
}

View File

@ -906,6 +906,48 @@ typedef enum _Edje_Fill
EDJE_FILL_TYPE_TILE
} Edje_Fill;
typedef enum _Edje_Match_Error
{
EDJE_MATCH_OK,
EDJE_MATCH_ALLOC_ERROR,
EDJE_MATCH_SYNTAX_ERROR
} Edje_Match_Error;
typedef struct _Edje_Patterns Edje_Patterns;
struct _Edje_Patterns
{
const char **patterns;
size_t patterns_size;
size_t max_length;
size_t finals[];
};
Edje_Patterns *edje_match_collection_dir_init(Evas_List *lst);
Edje_Patterns *edje_match_programs_signal_init(Evas_List *lst);
Edje_Patterns *edje_match_programs_source_init(Evas_List *lst);
Edje_Patterns *edje_match_callback_signal_init(Evas_List *lst);
Edje_Patterns *edje_match_callback_source_init(Evas_List *lst);
int edje_match_collection_dir_exec(const Edje_Patterns *ppat,
const char *string);
int edje_match_programs_exec(const Edje_Patterns *ppat_signal,
const Edje_Patterns *ppat_source,
const char *signal,
const char *source,
Evas_List *programs,
int (*func)(Edje_Program *pr, void *data),
void *data);
int edje_match_callback_exec(const Edje_Patterns *ppat_signal,
const Edje_Patterns *ppat_source,
const char *signal,
const char *source,
Evas_List *callbacks,
Edje *ed);
void edje_match_patterns_free(Edje_Patterns *ppat);
EAPI extern Eet_Data_Descriptor *_edje_edd_edje_file;
EAPI extern Eet_Data_Descriptor *_edje_edd_edje_style;
EAPI extern Eet_Data_Descriptor *_edje_edd_edje_style_tag;
@ -998,7 +1040,6 @@ void _edje_text_class_members_free(void);
void _edje_text_class_hash_free(void);
Edje *_edje_fetch(Evas_Object *obj);
int _edje_glob_match(const char *str, const char *glob);
int _edje_freeze(Edje *ed);
int _edje_thaw(Edje *ed);
int _edje_block(Edje *ed);

View File

@ -823,12 +823,46 @@ _edje_emit(Edje *ed, const char *sig, const char *src)
_edje_message_send(ed, EDJE_QUEUE_SCRIPT, EDJE_MESSAGE_SIGNAL, 0, &emsg);
}
struct _Edje_Program_Data
{
#ifdef EDJE_PROGRAM_CACHE
Evas_List *matches;
int matched;
#endif
Edje *ed;
const char *signal;
const char *source;
};
static int _edje_glob_callback(Edje_Program *pr, void *dt)
{
struct _Edje_Program_Data *data = dt;
#ifdef EDJE_PROGRAM_CACHE
data->matched++;
#endif
_edje_program_run(data->ed, pr, 0, data->signal, data->source);
if (_edje_block_break(data->ed))
{
#ifdef EDJE_PROGRAM_CACHE
evas_list_free(data->matches);
data->matches = NULL;
#endif
return 1;
}
#ifdef EDJE_PROGRAM_CACHE
data->matches = evas_list_append(data->matches, pr);
#endif
return 0;
}
/* FIXME: what if we delete the evas object??? */
void
_edje_emit_handle(Edje *ed, const char *sig, const char *src)
{
Evas_List *l;
if (ed->delete_me) return;
if (!sig) sig = "";
if (!src) src = "";
@ -883,35 +917,40 @@ _edje_emit_handle(Edje *ed, const char *sig, const char *src)
#endif
if (!done)
{
#ifdef EDJE_PROGRAM_CACHE
int matched = 0;
Evas_List *matches = NULL;
#endif
struct _Edje_Program_Data data;
for (l = ed->collection->programs; l; l = l->next)
{
Edje_Program *pr;
data.ed = ed;
data.source = src;
data.signal = sig;
#ifdef EDJE_PROGRAM_CACHE
data.matched = 0;
data.matches = NULL;
#endif
Edje_Patterns *signals_patterns;
Edje_Patterns *sources_patterns;
if (ed->collection->programs)
{
signals_patterns = edje_match_programs_signal_init(ed->collection->programs);
sources_patterns = edje_match_programs_source_init(ed->collection->programs);
if (edje_match_programs_exec(signals_patterns,
sources_patterns,
sig,
src,
ed->collection->programs,
_edje_glob_callback,
&data) == 0)
{
edje_match_patterns_free(signals_patterns);
edje_match_patterns_free(sources_patterns);
goto break_prog;
}
edje_match_patterns_free(signals_patterns);
edje_match_patterns_free(sources_patterns);
}
pr = l->data;
if ((_edje_glob_match(sig, pr->signal)) &&
(_edje_glob_match(src, pr->source)))
{
#ifdef EDJE_PROGRAM_CACHE
matched++;
#endif
_edje_program_run(ed, pr, 0, sig, src);
if (_edje_block_break(ed))
{
#ifdef EDJE_PROGRAM_CACHE
evas_list_free(matches);
#endif
goto break_prog;
}
#ifdef EDJE_PROGRAM_CACHE
matches = evas_list_append(matches, pr);
#endif
}
}
#ifdef EDJE_PROGRAM_CACHE
if (tmps)
{
@ -920,7 +959,7 @@ _edje_emit_handle(Edje *ed, const char *sig, const char *src)
evas_hash_add(ec->prog_cache.no_matches, tmps, ed);
else
ec->prog_cache.matches =
evas_hash_add(ec->prog_cache.matches, tmps, matches);
evas_hash_add(ec->prog_cache.matches, tmps, data.matches);
}
#endif
}
@ -940,25 +979,41 @@ _edje_emit_handle(Edje *ed, const char *sig, const char *src)
static void
_edje_emit_cb(Edje *ed, const char *sig, const char *src)
{
Evas_List *l;
Edje_Patterns *signals_patterns;
Edje_Patterns *sources_patterns;
Evas_List *l;
if (ed->delete_me) return;
_edje_ref(ed);
_edje_freeze(ed);
_edje_block(ed);
ed->walking_callbacks = 1;
for (l = ed->callbacks; l; l = l->next)
{
Edje_Signal_Callback *escb;
escb = l->data;
if ((!escb->just_added) &&
(!escb->delete_me) &&
(_edje_glob_match(sig, escb->signal)) &&
(_edje_glob_match(src, escb->source)))
escb->func(escb->data, ed->obj, sig, src);
if (_edje_block_break(ed)) goto break_prog;
if (ed->callbacks)
{
int r;
signals_patterns = edje_match_callback_signal_init(ed->callbacks);
sources_patterns = edje_match_callback_source_init(ed->callbacks);
r = edje_match_callback_exec(signals_patterns,
sources_patterns,
sig,
src,
ed->callbacks,
ed);
if (!r)
{
edje_match_patterns_free(signals_patterns);
edje_match_patterns_free(sources_patterns);
goto break_prog;
}
edje_match_patterns_free(signals_patterns);
edje_match_patterns_free(sources_patterns);
}
ed->walking_callbacks = 0;
if ((ed->delete_callbacks) || (ed->just_added_callbacks))
{

View File

@ -1950,20 +1950,6 @@ _edje_fetch(Evas_Object *obj)
return ed;
}
int
_edje_glob_match(const char *str, const char *glob)
{
if ((!glob) || (glob[0] == 0))
{
if ((!str) || (str[0] == 0)) return 1;
if ((glob) && (glob[0] == '*')) return 1;
return 0;
}
if (glob[0] == '*') return 1;
if ((glob) && (str) && (!fnmatch(glob, str, 0))) return 1;
return 0;
}
int
_edje_freeze(Edje *ed)
{