108 lines
3.4 KiB
C
108 lines
3.4 KiB
C
|
#include <state.h>
|
||
|
#include <entity.h>
|
||
|
|
||
|
usz_t mt_find_tag_with_least_entries(MtState *state, const char **tags)
|
||
|
{
|
||
|
u32_t least_entries_count = 0xffffffff;
|
||
|
usz_t least_entries_index = 0;
|
||
|
|
||
|
usz_t tag_index = 0;
|
||
|
while(tags[tag_index] != NULL)
|
||
|
{
|
||
|
MtTagEntry *tag_entry = mt_get_tag_entry(&state->tag_registry, tags[tag_index]);
|
||
|
if(tag_entry->num_entities > least_entries_count)
|
||
|
{
|
||
|
least_entries_count = tag_entry->num_entities;
|
||
|
least_entries_index = tag_index;
|
||
|
}
|
||
|
++tag_index;
|
||
|
}
|
||
|
return least_entries_index;
|
||
|
}
|
||
|
|
||
|
usz_t mt_count_entities_with_matching_tags(MtState *state, const char **tags)
|
||
|
{
|
||
|
usz_t num_matching_entities = 0;
|
||
|
|
||
|
const char *least_used_tag = tags[mt_find_tag_with_least_entries(state, tags)];
|
||
|
MtTagEntry *tag_entry = mt_get_tag_entry(&state->tag_registry, least_used_tag);
|
||
|
usz_t entity_index = 0;
|
||
|
while(entity_index < tag_entry->num_entities)
|
||
|
{
|
||
|
MtEntity *entity = mt_get_entity(state, tag_entry->entity_identifiers[entity_index]);
|
||
|
bool_t matching = TRUE;
|
||
|
usz_t wanted_tag_index = 0;
|
||
|
while(tags[wanted_tag_index] != NULL)
|
||
|
{
|
||
|
if(!mt_has_tag(entity, tags[wanted_tag_index]))
|
||
|
{
|
||
|
matching = FALSE;
|
||
|
break;
|
||
|
}
|
||
|
++wanted_tag_index;
|
||
|
}
|
||
|
if(matching)
|
||
|
++num_matching_entities;
|
||
|
|
||
|
++entity_index;
|
||
|
}
|
||
|
return num_matching_entities;
|
||
|
}
|
||
|
|
||
|
usz_t mt_query(MtState *state, const char **tags, MtEntity **entities, usz_t count)
|
||
|
{
|
||
|
if(count == 0)
|
||
|
return mt_count_entities_with_matching_tags(state, tags);;
|
||
|
|
||
|
usz_t num_written_entities = 0;
|
||
|
const char *least_used_tag = tags[mt_find_tag_with_least_entries(state, tags)];
|
||
|
MtTagEntry *tag_entry = mt_get_tag_entry(&state->tag_registry, least_used_tag);
|
||
|
usz_t entity_index = 0;
|
||
|
while((entity_index < tag_entry->num_entities) && (num_written_entities < count))
|
||
|
{
|
||
|
MtEntity *entity = mt_get_entity(state, tag_entry->entity_identifiers[entity_index]);
|
||
|
bool_t matching = TRUE;
|
||
|
usz_t wanted_tag_index = 0;
|
||
|
while(tags[wanted_tag_index] != NULL)
|
||
|
{
|
||
|
if(!mt_has_tag(entity, tags[wanted_tag_index]))
|
||
|
{
|
||
|
matching = FALSE;
|
||
|
break;
|
||
|
}
|
||
|
++wanted_tag_index;
|
||
|
}
|
||
|
if(matching)
|
||
|
{
|
||
|
entities[num_written_entities] = entity;
|
||
|
++num_written_entities;
|
||
|
}
|
||
|
++entity_index;
|
||
|
}
|
||
|
return num_written_entities;
|
||
|
}
|
||
|
|
||
|
usz_t mt_match_query(MtState *state, const char **tags, MtEntity **entities, usz_t count, MtQueryMatcherFn matcher, void *userdata)
|
||
|
{
|
||
|
usz_t num_matching_entities = mt_query(state, tags, entities, 0);
|
||
|
if(count == 0)
|
||
|
return num_matching_entities;
|
||
|
|
||
|
// TODO: If 'num_matching_entities" is too big, this must be allocated on the heap!
|
||
|
MtEntity *generally_matching_entities[num_matching_entities];
|
||
|
mt_query(state, tags, &generally_matching_entities[0], num_matching_entities);
|
||
|
|
||
|
usz_t written_entities = 0;
|
||
|
usz_t entity_index = 0;
|
||
|
while((entity_index < num_matching_entities) && (written_entities < count))
|
||
|
{
|
||
|
if(matcher(generally_matching_entities[entity_index], userdata))
|
||
|
{
|
||
|
entities[written_entities] = generally_matching_entities[entity_index];
|
||
|
++written_entities;
|
||
|
}
|
||
|
++entity_index;
|
||
|
}
|
||
|
return written_entities;
|
||
|
}
|