/* Deduplicates an array on tags using the inbuilt comparison function based on the attributes specified. Called by tm_tags_sort() when dedup is TRUE. @param tags_array Array of tags to dedup. @param sort_attributes Attributes the array is sorted on. They will be deduped on the same criteria. @return TRUE on success, FALSE on failure */ gboolean tm_tags_dedup(GPtrArray *tags_array, TMTagAttrType *sort_attributes, gboolean unref_duplicates) { TMSortOptions sort_options; guint i; if ((!tags_array) || (!tags_array->len)) return TRUE; sort_options.sort_attrs = sort_attributes; sort_options.partial = FALSE; for (i = 1; i < tags_array->len; ++i) { if (0 == tm_tag_compare(&(tags_array->pdata[i - 1]), &(tags_array->pdata[i]), &sort_options)) { if (unref_duplicates) tm_tag_unref(tags_array->pdata[i-1]); tags_array->pdata[i-1] = NULL; } } tm_tags_prune(tags_array); return TRUE; }
/* Deduplicates an array on tags using the inbuilt comparison function based on the attributes specified. Called by tm_tags_sort() when dedup is TRUE. @param tags_array Array of tags to dedup. @param sort_attributes Attributes the array is sorted on. They will be deduped on the same criteria. */ void tm_tags_dedup(GPtrArray *tags_array, TMTagAttrType *sort_attributes, gboolean unref_duplicates) { TMSortOptions sort_options; guint i; g_return_if_fail(tags_array); if (tags_array->len < 2) return; sort_options.sort_attrs = sort_attributes; sort_options.cmp_len = -1; for (i = 1; i < tags_array->len; ++i) { if (0 == tm_tag_compare(&(tags_array->pdata[i - 1]), &(tags_array->pdata[i]), &sort_options)) { if (unref_duplicates) tm_tag_unref(tags_array->pdata[i-1]); tags_array->pdata[i-1] = NULL; } } tm_tags_prune(tags_array); }
void tm_tags_remove_file_tags(TMSourceFile *source_file, GPtrArray *tags_array) { guint i; /* Now we choose between an algorithm with complexity O(tags_array->len) and * O(source_file->tags_array->len * log(tags_array->len)). The latter algorithm * is better when tags_array contains many times more tags than * source_file->tags_array so instead of trying to find the removed tags * linearly, binary search is used. The constant 20 is more or less random * but seems to work well. It's exact value isn't so critical because it's * the extremes where the difference is the biggest: when * source_file->tags_array->len == tags_array->len (single file open) and * source_file->tags_array->len << tags_array->len (the number of tags * from the file is a small fraction of all tags). */ if (source_file->tags_array->len != 0 && tags_array->len / source_file->tags_array->len < 20) { for (i = 0; i < tags_array->len; i++) { TMTag *tag = tags_array->pdata[i]; if (tag->file == source_file) tags_array->pdata[i] = NULL; } } else { GPtrArray *to_delete = g_ptr_array_sized_new(source_file->tags_array->len); for (i = 0; i < source_file->tags_array->len; i++) { guint j; guint tag_count; TMTag **found; TMTag *tag = source_file->tags_array->pdata[i]; found = tm_tags_find(tags_array, tag->name, FALSE, TRUE, &tag_count); for (j = 0; j < tag_count; j++) { if (*found != NULL && (*found)->file == source_file) { /* we cannot set the pointer to NULL now because the search wouldn't work */ g_ptr_array_add(to_delete, found); /* no break - if there are multiple tags of the same name, we would * always find the first instance and wouldn't remove others; duplicates * in the to_delete list aren't a problem */ } found++; } } for (i = 0; i < to_delete->len; i++) { TMTag **tag = to_delete->pdata[i]; *tag = NULL; } g_ptr_array_free(to_delete, TRUE); } tm_tags_prune(tags_array); }