#include #include 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; }