static long* all_id_ranges( struct mhdf_FileDesc* desc, int include_null, int* num_ranges_out ) { int i, num_ranges = 0; struct mhdf_EntDesc* group; long* ranges = malloc(2*sizeof(long)*(desc->num_elem_desc + 2 + !!include_null)); if (include_null) { num_ranges = 1; ranges[0] = 0; ranges[1] = 1; } for (i = -1; i <= desc->num_elem_desc; ++i) { if (i == -1) group = &desc->nodes; else if (i == desc->num_elem_desc) group = &desc->sets; else group = &desc->elems[i].desc; if (num_ranges && ranges[2*num_ranges - 2] + ranges[2*num_ranges-1] == group->start_id) { ranges[2*num_ranges-1] += group->count; } else { ranges[2*num_ranges] = group->start_id; ranges[2*num_ranges+1] = group->count; ++num_ranges; } } *num_ranges_out = merge_ranges( ranges, num_ranges ); return ranges; }
static long* get_dim_ranges( struct mhdf_FileDesc* desc, int dim, int* num_ranges_out ) { long* ranges = 0; int i, j; const char* const types1D[] = { mhdf_EDGE_TYPE_NAME, 0 }; const char* const types2D[] = { mhdf_TRI_TYPE_NAME, mhdf_QUAD_TYPE_NAME, mhdf_POLYGON_TYPE_NAME, 0 }; const char* const types3D[] = { mhdf_TET_TYPE_NAME, mhdf_PYRAMID_TYPE_NAME, mhdf_PRISM_TYPE_NAME, mdhf_KNIFE_TYPE_NAME, mdhf_HEX_TYPE_NAME, mhdf_POLYHEDRON_TYPE_NAME, mhdf_SEPTAHEDRON_TYPE_NAME, 0 }; char const* const* typelist; switch (dim) { case 0: *num_ranges_out = 1; ranges = malloc(2*sizeof(long)); ranges[0] = desc->nodes.start_id; ranges[1] = desc->nodes.count; return ranges; case 1: typelist = types1D; break; case 2: typelist = types2D; break; case 3: typelist = types3D; break; default: fprintf(stderr,"Internal error at %s:%d: request for entities of dimesion %d\n", __FILE__, __LINE__, dim ); abort(); } *num_ranges_out = 0; for (i = 0; i < desc->num_elem_desc; ++i) if (string_contained( desc->elems[i].type, typelist )) ++*num_ranges_out; ranges = malloc(*num_ranges_out * 2 * sizeof(long)); for (i = 0, j = 0; i < desc->num_elem_desc; ++i) if (string_contained( desc->elems[i].type, typelist )) { ranges[j++] = desc->elems[i].desc.start_id; ranges[j++] = desc->elems[i].desc.count; } *num_ranges_out = merge_ranges( ranges, *num_ranges_out ); return ranges; }
static int collapse_ranges(struct match_t *reduced, int nonuniques) /* collapse together overlapping ranges in the hit list */ { struct match_t *sp, *tp; int spancount, removed = 0; /* * For two matches to be eligible for merger, all their filenames must * match pairwise. If there are no such matches, these chunks are * completely irrelevant to each other. It might be that for some * values of i the filenames are equal and for others not. In * that case the pair of lists of ranges cannot represent the same * overlapping segments of text, which is the only case we are * interested in. * * This gives us leverage to apply the qsort trick again. The naive * way to check for range overlaps would be to write a quadratic * double loop compairing all matches pairwise. Instead we can * use this sort to partition the matches into spans such that * all overlaps must take place within spans. */ qsort(reduced, nonuniques, sizeof(struct match_t), compare_files); #ifdef DEBUG for (sp = reduced; sp < reduced + nonuniques; sp++) { struct sorthash_t *rp; printf("Clique beginning at %d:\n", sp - reduced); for (rp = sp->matches; rp < sp->matches + sp->nmatches; rp++) printf("%s:%d:%d\n", rp->file->name, rp->hash.start, rp->hash.end); } #endif /* DEBUG */ /* time to merge overlapping shreds */ spancount = 0; for (sp = reduced; sp < reduced + nonuniques; sp++, spancount--) { int remaining; /* * This optimization drastically reduces the number of compare_files * calls. The continue condition in the inner loop below would * otherwise involve one every time for O(n**2) calls; this reduces * the number to O(n). */ if (spancount <= 0) { spancount = 0; for (tp = sp + 1; !compare_files(sp, tp) && tp < reduced + nonuniques; tp++) spancount++; } for (tp = sp + 1, remaining = spancount; remaining--; tp++) { #ifdef DEBUG printf("Trying merge of %d into %d\n", tp-reduced, sp-reduced); #endif /* DEBUG */ /* neither must have been deleted */ if (!sp->nmatches || !tp->nmatches) { #ifdef DEBUG printf("Null match pointer: %d=%p, %d=%p\n", sp-reduced, sp->matches, tp-reduced, tp->matches); #endif /* DEBUG */ continue; } /* attempt the merge */ if (merge_ranges(tp->matches, sp->matches, sp->nmatches)) { #ifdef DEBUG struct sorthash_t *rp; printf("*** Merged %d into %d\n", tp-reduced, sp-reduced); for (rp=sp->matches; rp < sp->matches+sp->nmatches; rp++) printf("%s:%d:%d\n",rp->file->name,rp->hash.start,rp->hash.end); #endif /* DEBUG */ removed++; sp->nmatches = 0; } } } #ifdef DEBUG for (sp = reduced; sp < reduced + nonuniques; sp++) { struct sorthash_t *rp; printf("Clique beginning at %d (%d):\n", sp - reduced, sp->nmatches); for (rp = sp->matches; rp < sp->matches + sp->nmatches; rp++) printf("%s:%d:%d\n", rp->file->name, rp->hash.start, rp->hash.end); } #endif /* DEBUG */ return(nonuniques - removed); }