1 #include <assert.h>
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include "gtf.h"
5 
6 /*******************************************************************************
7 *
8 * Comparison functions
9 *
10 * These are according to Allen's Interval Algebra
11 *
12 *******************************************************************************/
rangeAny(uint32_t start,uint32_t end,GTFentry * e)13 static inline int rangeAny(uint32_t start, uint32_t end, GTFentry *e) {
14     if(end <= e->start) return -1;
15     if(start >= e->end) return 1;
16     return 0;
17 }
18 
rangeContains(uint32_t start,uint32_t end,GTFentry * e)19 static inline int rangeContains(uint32_t start, uint32_t end, GTFentry *e) {
20     if(e->start >= start && e->end <= end) return 0;
21     if(e->end < end) return -1;
22     return 1;
23 }
24 
rangeWithin(uint32_t start,uint32_t end,GTFentry * e)25 static inline int rangeWithin(uint32_t start, uint32_t end, GTFentry *e) {
26     if(start >= e->start && end <= e->end) return 0;
27     if(start < e->start) return -1;
28     return 1;
29 }
30 
rangeExact(uint32_t start,uint32_t end,GTFentry * e)31 static inline int rangeExact(uint32_t start, uint32_t end, GTFentry *e) {
32     if(start == e->start && end == e->end) return 0;
33     if(start < e->start) return -1;
34     if(end < e->end) return -1;
35     return 1;
36 }
37 
rangeStart(uint32_t start,uint32_t end,GTFentry * e)38 static inline int rangeStart(uint32_t start, uint32_t end, GTFentry *e) {
39     if(start == e->start) return 0;
40     if(start < e->start) return -1;
41     return 1;
42 }
43 
rangeEnd(uint32_t start,uint32_t end,GTFentry * e)44 static inline int rangeEnd(uint32_t start, uint32_t end, GTFentry *e) {
45     if(end == e->end) return 0;
46     if(end < e->end) return -1;
47     return 1;
48 }
49 
exactSameStrand(int strand,GTFentry * e)50 static inline int exactSameStrand(int strand, GTFentry *e) {
51     return strand == e->strand;
52 }
53 
sameStrand(int strand,GTFentry * e)54 static inline int sameStrand(int strand, GTFentry *e) {
55     if(strand == 3 || e->strand == 3) return 1;
56     if(strand == e->strand) return 1;
57     return 0;
58 }
59 
oppositeStrand(int strand,GTFentry * e)60 static inline int oppositeStrand(int strand, GTFentry *e) {
61     if(strand == 3 || e->strand == 3) return 1;
62     if(strand != e->strand) return 1;
63     return 0;
64 }
65 
66 /*******************************************************************************
67 *
68 * OverlapSet functions
69 *
70 *******************************************************************************/
os_init(GTFtree * t)71 overlapSet *os_init(GTFtree *t) {
72     overlapSet *os = calloc(1, sizeof(overlapSet));
73     assert(os);
74     os->tree = t;
75     return os;
76 }
77 
os_reset(overlapSet * os)78 void os_reset(overlapSet *os) {
79     int i;
80     for(i=0; i<os->l; i++) os->overlaps[i] = NULL;
81     os->l = 0;
82 }
83 
os_destroy(overlapSet * os)84 void os_destroy(overlapSet *os) {
85     if(os->overlaps) free(os->overlaps);
86     free(os);
87 }
88 
os_grow(overlapSet * os)89 overlapSet *os_grow(overlapSet *os) {
90     int i;
91     os->m++;
92     kroundup32(os->m);
93     os->overlaps = realloc(os->overlaps, os->m * sizeof(GTFentry*));
94     assert(os->overlaps);
95     for(i=os->l; i<os->m; i++) os->overlaps[i] = NULL;
96 
97     return os;
98 }
99 
os_push(overlapSet * os,GTFentry * e)100 static void os_push(overlapSet *os, GTFentry *e) {
101     if(os->l+1 >= os->m) os = os_grow(os);
102     os->overlaps[os->l++] = e;
103 }
104 
os_dup(overlapSet * os)105 overlapSet *os_dup(overlapSet *os) {
106     int i;
107     overlapSet *os2 = os_init(os->tree);
108     for(i=0; i<os->l; i++) os_push(os2, os->overlaps[i]);
109     return os2;
110 }
111 
os_exclude(overlapSet * os,int i)112 void os_exclude(overlapSet *os, int i) {
113     int j;
114     for(j=i; j<os->l-1; j++) os->overlaps[j] = os->overlaps[j+1];
115     os->overlaps[--os->l] = NULL;
116 }
117 
os_sortFunc(const void * a,const void * b)118 static int os_sortFunc(const void *a, const void *b) {
119     GTFentry *pa = *(GTFentry**) a;
120     GTFentry *pb = *(GTFentry**) b;
121 
122     if(pa->start < pb->start) return -1;
123     if(pb->start < pa->start) return 1;
124     if(pa->end < pb->end) return -1;
125     if(pb->end < pa->end) return 1;
126     return 0;
127 }
128 
os_sort(overlapSet * os)129 static void os_sort(overlapSet *os) {
130     qsort((void *) os->overlaps, os->l, sizeof(GTFentry**), os_sortFunc);
131 }
132 
133 //Non-existant keys/values will be ignored
os_requireAttributes(overlapSet * os,char ** key,char ** val,int len)134 void os_requireAttributes(overlapSet *os, char **key, char **val, int len) {
135     int i, j, k, filter;
136     int32_t keyHash, valHash;
137 
138     for(i=0; i<len; i++) {
139         if(!os->l) break;
140 
141         keyHash = str2valHT(os->tree->htAttributes, key[i]);
142         valHash = str2valHT(os->tree->htAttributes, val[i]);
143         assert(keyHash>=0);
144         assert(valHash>=0);
145         for(j=0; j<os->l; j++) {
146             filter = 1;
147             for(k=0; k<os->overlaps[j]->nAttributes; k++) {
148                 if(os->overlaps[j]->attrib[k]->key == keyHash) {
149                     if(os->overlaps[j]->attrib[k]->val == valHash) {
150                         filter = 0;
151                         break;
152                     }
153                 }
154             }
155             if(filter) {
156                 os_exclude(os, j);
157                 j--; //os_exclude shifts everything
158             }
159         }
160     }
161 }
162 
163 //This is an inefficient implementation. It would be faster to sort according
164 //to COMPARE_FUNC and then do an O(n) merge.
os_intersect(overlapSet * os1,overlapSet * os2,COMPARE_FUNC f)165 overlapSet *os_intersect(overlapSet *os1, overlapSet *os2, COMPARE_FUNC f) {
166     overlapSet *os = os_init(os1->tree);
167     int i, j;
168 
169     for(i=0; i<os1->l; i++) {
170         for(j=0; j<os2->l; j++) {
171             if(f(os1->overlaps[i],os2->overlaps[j]) == 0) {
172                 os_push(os, os1->overlaps[i]);
173                 os_exclude(os2, j);
174                 break;
175             }
176         }
177     }
178 
179     return os;
180 }
181 /*******************************************************************************
182 *
183 * OverlapSetList functions
184 *
185 *******************************************************************************/
osl_init()186 overlapSetList *osl_init() {
187     overlapSetList *osl = calloc(1, sizeof(overlapSetList));
188     assert(osl);
189     return osl;
190 }
191 
osl_reset(overlapSetList * osl)192 void osl_reset(overlapSetList *osl) {
193     int i;
194     for(i=0; i<osl->l; i++) os_destroy(osl->os[i]);
195     osl->l = 0;
196 }
197 
osl_destroy(overlapSetList * osl)198 void osl_destroy(overlapSetList *osl) {
199     osl_reset(osl);
200     if(osl->os) free(osl->os);
201     free(osl);
202 }
203 
osl_grow(overlapSetList * osl)204 void osl_grow(overlapSetList *osl) {
205     int i;
206     osl->m++;
207     kroundup32(osl->m);
208     osl->os = realloc(osl->os, osl->m * sizeof(overlapSet*));
209     assert(osl->os);
210     for(i=osl->l; i<osl->m; i++) osl->os[i] = NULL;
211 }
212 
osl_push(overlapSetList * osl,overlapSet * os)213 void osl_push(overlapSetList *osl, overlapSet *os) {
214     if(osl->l+1 >= osl->m) osl_grow(osl);
215     osl->os[osl->l++] = os;
216 }
217 
218 //The output needs to be destroyed
osl_intersect(overlapSetList * osl,COMPARE_FUNC f)219 overlapSet *osl_intersect(overlapSetList *osl, COMPARE_FUNC f) {
220     int i;
221     if(!osl->l) return NULL;
222 
223     overlapSet *osTmp, *os = os_dup(osl->os[0]);
224     for(i=1; i<osl->l; i++) {
225         osTmp = os_intersect(os, osl->os[i], f);
226         os_destroy(os);
227         os = osTmp;
228         if(os->l == 0) break;
229     }
230     return os;
231 }
232 
233 //Returns 1 if the node is in the overlapSet, otherwise 0.
os_contains(overlapSet * os,GTFentry * e)234 int os_contains(overlapSet *os, GTFentry *e) {
235     int i;
236     for(i=0; i<os->l; i++) {
237         if(os->overlaps[i] == e) return 1;
238     }
239     return 0;
240 }
241 
242 //This could be made much more efficient
osl_union(overlapSetList * osl)243 overlapSet *osl_union(overlapSetList *osl) {
244     int i, j;
245     if(!osl->l) NULL;
246 
247     if(!osl->os) return NULL;
248     if(!osl->os[0]) return NULL;
249     overlapSet *os = os_dup(osl->os[0]);
250     for(i=1; i<osl->l; i++) {
251         for(j=0; j<osl->os[i]->l; j++) {
252             if(!os_contains(os, osl->os[i]->overlaps[j])) {
253                 os_push(os, osl->os[i]->overlaps[j]);
254             }
255         }
256     }
257     return os;
258 }
259 
260 /*******************************************************************************
261 *
262 * uniqueSet functions
263 *
264 *******************************************************************************/
us_init(hashTable * ht)265 static uniqueSet *us_init(hashTable *ht) {
266     uniqueSet *us = calloc(1, sizeof(uniqueSet));
267     assert(us);
268     us->ht = ht;
269     return us;
270 }
271 
us_destroy(uniqueSet * us)272 void us_destroy(uniqueSet *us) {
273     if(!us) return;
274     if(us->IDs) {
275         free(us->IDs);
276         free(us->cnts);
277     }
278     free(us);
279 }
280 
us_grow(uniqueSet * us)281 static uniqueSet *us_grow(uniqueSet *us) {
282     int i;
283     us->m++;
284     kroundup32(us->m);
285     us->IDs = realloc(us->IDs, us->m * sizeof(int32_t));
286     assert(us->IDs);
287     us->cnts = realloc(us->cnts, us->m * sizeof(uint32_t));
288     assert(us->cnts);
289     for(i=us->l; i<us->m; i++) {
290         us->IDs[i] = -1;
291         us->cnts[i] = 0;
292     }
293 
294     return us;
295 }
296 
us_push(uniqueSet * us,int32_t ID)297 static void us_push(uniqueSet *us, int32_t ID) {
298     if(us->l+1 >= us->m) us = us_grow(us);
299     us->IDs[us->l] = ID;
300     us->cnts[us->l++] = 1;
301 }
302 
us_inc(uniqueSet * us)303 static void us_inc(uniqueSet *us) {
304     assert(us->l<=us->m);
305     us->cnts[us->l-1]++;
306 }
307 
us_cnt(uniqueSet * us,int32_t i)308 uint32_t us_cnt(uniqueSet *us, int32_t i) {
309     assert(i<us->l);
310     return us->cnts[i];
311 }
312 
us_val(uniqueSet * us,int32_t i)313 char *us_val(uniqueSet *us, int32_t i) {
314     if(i>=us->l) return NULL;
315     return val2strHT(us->ht, us->IDs[i]);
316 }
317 
318 /*******************************************************************************
319 *
320 * Overlap set count/unique functions
321 *
322 *******************************************************************************/
int32_t_cmp(const void * a,const void * b)323 static int int32_t_cmp(const void *a, const void *b) {
324     int32_t ia = *((int32_t*) a);
325     int32_t ib = *((int32_t*) b);
326     return ia-ib;
327 }
328 
cntAttributes(overlapSet * os,char * attributeName)329 int32_t cntAttributes(overlapSet *os, char *attributeName) {
330     int32_t IDs[os->l], i, j, key, last, n = 0;
331     if(!strExistsHT(os->tree->htAttributes, attributeName)) return n;
332 
333     key = str2valHT(os->tree->htAttributes, attributeName);
334     for(i=0; i<os->l; i++) {
335         IDs[i] = -1;
336         for(j=0; j<os->overlaps[i]->nAttributes; j++) {
337             if(os->overlaps[i]->attrib[j]->key == key) {
338                 IDs[i] = os->overlaps[i]->attrib[j]->val;
339                 break;
340             }
341         }
342     }
343     qsort((void*) IDs, os->l, sizeof(int32_t), int32_t_cmp);
344 
345     last = IDs[0];
346     n = (last >= 0) ? 1 : 0;
347     for(i = 1; i<os->l; i++) {
348         if(IDs[i] != last) {
349             n++;
350             last = IDs[i];
351         }
352     }
353     return n;
354 }
355 
uniqueAttributes(overlapSet * os,char * attributeName)356 uniqueSet *uniqueAttributes(overlapSet *os, char *attributeName) {
357     if(!os) return NULL;
358     if(os->l == 0) return NULL;
359     int32_t IDs[os->l], i, j, key, last;
360     if(!strExistsHT(os->tree->htAttributes, attributeName)) return NULL;
361     uniqueSet *us = us_init(os->tree->htAttributes);
362 
363     key = str2valHT(os->tree->htAttributes, attributeName);
364     for(i=0; i<os->l; i++) {
365         IDs[i] = -1;
366         for(j=0; j<os->overlaps[i]->nAttributes; j++) {
367             if(os->overlaps[i]->attrib[j]->key == key) {
368                 IDs[i] = os->overlaps[i]->attrib[j]->val;
369                 break;
370             }
371         }
372     }
373     qsort((void*) IDs, os->l, sizeof(int32_t), int32_t_cmp);
374 
375     last = -1;
376     for(i=0; i<os->l; i++) {
377         if(IDs[i] != last || last < 0) {
378             us_push(us, IDs[i]);
379             last = IDs[i];
380         } else {
381             us_inc(us);
382         }
383     }
384 
385     if(us->l) return us;
386     us_destroy(us);
387     return NULL;
388 }
389 
390 /*******************************************************************************
391 *
392 * Node iterator functions
393 *
394 *******************************************************************************/
395 //bit 1: go left, bit 2: go right (a value of 3 is then "do both")
centerDirection(uint32_t start,uint32_t end,GTFnode * n)396 static int centerDirection(uint32_t start, uint32_t end, GTFnode *n) {
397     if(n->center >= start && n->center < end) return 3;
398     if(n->center < start) return 2;
399     return 1;
400 }
401 
matchingStrand(GTFentry * e,int strand,int strandType)402 static int matchingStrand(GTFentry *e, int strand, int strandType) {
403     if(strandType == GTF_IGNORE_STRAND) return 1;
404 
405     if(strandType == GTF_SAME_STRAND) {
406         return sameStrand(strand, e);
407     } else if(strandType == GTF_OPPOSITE_STRAND) {
408         return oppositeStrand(strand, e);
409     } else if(strandType == GTF_EXACT_SAME_STRAND) {
410         return exactSameStrand(strand, e);
411     }
412 
413     fprintf(stderr, "[matchingStrand] Unknown strand type %i. Assuming a match.\n", strandType);
414     return 1;
415 }
416 
filterStrand(overlapSet * os,int strand,int strandType)417 static void filterStrand(overlapSet *os, int strand, int strandType) {
418     int i;
419 
420     if(strandType == GTF_IGNORE_STRAND) return;
421 
422     for(i=os->l-1; i>=0; i--) {
423         if(strandType == GTF_SAME_STRAND) {
424             if(!sameStrand(strand, os->overlaps[i])) os_exclude(os, i);
425         } else if(strandType == GTF_OPPOSITE_STRAND) {
426             if(!oppositeStrand(strand, os->overlaps[i])) os_exclude(os, i);
427         } else if(strandType == GTF_EXACT_SAME_STRAND) {
428             if(!exactSameStrand(strand, os->overlaps[i])) os_exclude(os, i);
429         }
430     }
431 }
432 
pushOverlaps(overlapSet * os,GTFtree * t,GTFentry * e,uint32_t start,uint32_t end,int comparisonType,int direction,FILTER_ENTRY_FUNC ffunc)433 static void pushOverlaps(overlapSet *os, GTFtree *t, GTFentry *e, uint32_t start, uint32_t end, int comparisonType, int direction, FILTER_ENTRY_FUNC ffunc) {
434     int dir;
435     int keep = 1;
436     if(!e) return;
437 
438     if(ffunc) keep = ffunc(t, e);
439 
440     switch(comparisonType) {
441     case GTF_MATCH_EXACT :
442         if((dir = rangeExact(start, end, e)) == 0) {
443             if(keep) os_push(os, e);
444         }
445         break;
446     case GTF_MATCH_WITHIN :
447         if((dir = rangeAny(start, end, e)) == 0) {
448             if(keep) if(rangeWithin(start, end ,e) == 0) os_push(os, e);
449         }
450         break;
451     case GTF_MATCH_CONTAIN :
452         if((dir = rangeAny(start, end, e)) == 0) {
453             if(keep) if(rangeContains(start, end, e) == 0) os_push(os, e);
454         }
455         break;
456     case GTF_MATCH_START :
457         if((dir = rangeStart(start, end, e)) == 0) {
458             if(keep) os_push(os, e);
459         }
460         break;
461     case GTF_MATCH_END :
462         if((dir = rangeEnd(start, end, e)) == 0) {
463             if(keep) os_push(os, e);
464         }
465         break;
466     default :
467         if((dir = rangeAny(start, end, e)) == 0) {
468             if(keep) os_push(os, e);
469         }
470         break;
471     }
472 
473     if(direction) {
474         if(dir > 0) return;
475         pushOverlaps(os, t, e->right, start, end, comparisonType, direction, ffunc);
476     } else {
477         if(dir < 0) return;
478         pushOverlaps(os, t, e->left, start, end, comparisonType, direction, ffunc);
479     }
480 }
481 
countOverlapsEntry(GTFtree * t,GTFentry * e,uint32_t start,uint32_t end,int strand,int matchType,int strandType,int direction,int32_t max,FILTER_ENTRY_FUNC ffunc)482 static int32_t countOverlapsEntry(GTFtree *t, GTFentry *e, uint32_t start, uint32_t end, int strand, int matchType, int strandType, int direction, int32_t max, FILTER_ENTRY_FUNC ffunc) {
483     int dir;
484     int32_t cnt = 0;
485     if(!e) return cnt;
486 
487     switch(matchType) {
488     case GTF_MATCH_EXACT :
489         if((dir = rangeExact(start, end, e)) == 0) {
490             cnt = 1;
491         }
492         break;
493     case GTF_MATCH_WITHIN :
494         if((dir = rangeAny(start, end, e)) == 0) {
495             if(rangeWithin(start, end, e) == 0) cnt = 1;
496         }
497         break;
498     case GTF_MATCH_CONTAIN :
499         if((dir = rangeAny(start, end, e)) == 0) {
500             if(rangeContains(start, end, e) == 0) cnt = 1;
501         }
502         break;
503     case GTF_MATCH_START :
504         if((dir = rangeStart(start, end, e)) == 0) {
505             cnt = 1;
506         }
507         break;
508     case GTF_MATCH_END :
509         if((dir = rangeEnd(start, end, e)) == 0) {
510             cnt = 1;
511         }
512         break;
513     default :
514         if((dir = rangeAny(start, end, e)) == 0) {
515             cnt = 1;
516         }
517         break;
518     }
519 
520     if(cnt) {
521         if(!matchingStrand(e, strand, strandType)) cnt = 0;
522     }
523 
524     if(cnt && ffunc) {
525         if(!ffunc(t, e)) cnt = 0;
526     }
527 
528     if(max && cnt >= max) return max;
529 
530     if(direction) {
531         if(dir > 0) return cnt;
532         return cnt + countOverlapsEntry(t, e->right, start, end, strand, matchType, strandType, direction, max, ffunc);
533     } else {
534         if(dir < 0) return cnt;
535         return cnt + countOverlapsEntry(t, e->left, start, end, strand, matchType, strandType, direction, max, ffunc);
536     }
537 }
538 
pushOverlapsNode(overlapSet * os,GTFtree * t,GTFnode * n,uint32_t start,uint32_t end,int matchType,FILTER_ENTRY_FUNC ffunc)539 static void pushOverlapsNode(overlapSet *os, GTFtree *t, GTFnode *n, uint32_t start, uint32_t end, int matchType, FILTER_ENTRY_FUNC ffunc) {
540     int dir;
541     if(!n) return;
542     dir = centerDirection(start, end, n);
543 
544     if(dir&1) {
545         pushOverlaps(os, t, n->starts, start, end, matchType, 1, ffunc);
546         pushOverlapsNode(os, t, n->left, start, end, matchType, ffunc);
547     }
548     if(dir&2) {
549         if(dir!=3) pushOverlaps(os, t, n->ends, start, end, matchType, 0, ffunc);
550         pushOverlapsNode(os, t, n->right, start, end, matchType, ffunc);
551     }
552 }
553 
countOverlapsNode(GTFtree * t,GTFnode * n,uint32_t start,uint32_t end,int strand,int matchType,int strandType,int32_t max,FILTER_ENTRY_FUNC ffunc)554 static int32_t countOverlapsNode(GTFtree *t, GTFnode *n, uint32_t start, uint32_t end, int strand, int matchType, int strandType, int32_t max, FILTER_ENTRY_FUNC ffunc) {
555     int32_t cnt = 0;
556     int dir;
557     if(!n) return cnt;
558     dir = centerDirection(start, end, n);
559 
560     if(dir&1) {
561         cnt += countOverlapsEntry(t, n->starts, start, end, strand, matchType, strandType, 1, max, ffunc);
562         if(max && cnt >= max) return max;
563         cnt += countOverlapsNode(t, n->left, start, end, strand, matchType, strandType, max, ffunc);
564         if(max && cnt >= max) return max;
565     }
566     if(dir&2) {
567         if(dir!=3) cnt += countOverlapsEntry(t, n->starts, start, end, strand, matchType, strandType, 0, max, ffunc);
568         if(max && cnt >= max) return max;
569         cnt += countOverlapsNode(t, n->right, start, end, strand, matchType, strandType, max, ffunc);
570         if(max && cnt >= max) return max;
571     }
572     return cnt;
573 }
574 
575 /*******************************************************************************
576 *
577 * Driver functions for end use.
578 *
579 *******************************************************************************/
findOverlaps(overlapSet * os,GTFtree * t,char * chrom,uint32_t start,uint32_t end,int strand,int matchType,int strandType,int keepOS,FILTER_ENTRY_FUNC ffunc)580 overlapSet * findOverlaps(overlapSet *os, GTFtree *t, char *chrom, uint32_t start, uint32_t end, int strand, int matchType, int strandType, int keepOS, FILTER_ENTRY_FUNC ffunc) {
581     int32_t tid = str2valHT(t->htChroms, chrom);
582     overlapSet *out = os;
583 
584     if(out && !keepOS) os_reset(out);
585     else if(!out) out = os_init(t);
586 
587     if(tid<0) return out;
588     if(!t->balanced) {
589         fprintf(stderr, "[findOverlaps] The tree has not been balanced! No overlaps will be returned.\n");
590         return out;
591     }
592 
593     pushOverlapsNode(out, t, (GTFnode*) t->chroms[tid]->tree, start, end, matchType, ffunc);
594     if(out->l) filterStrand(out, strand, strandType);
595     if(out->l) os_sort(out);
596 
597     return out;
598 }
599 
countOverlaps(GTFtree * t,char * chrom,uint32_t start,uint32_t end,int strand,int matchType,int strandType,FILTER_ENTRY_FUNC ffunc)600 int32_t countOverlaps(GTFtree *t, char *chrom, uint32_t start, uint32_t end, int strand, int matchType, int strandType, FILTER_ENTRY_FUNC ffunc) {
601     int32_t tid = str2valHT(t->htChroms, chrom);
602     if(tid<0) return 0;
603 
604     if(!t->balanced) {
605         fprintf(stderr, "[countOverlaps] The tree has not been balanced! No overlaps will be returned.\n");
606         return 0;
607     }
608 
609     return countOverlapsNode(t, (GTFnode*) t->chroms[tid]->tree, start, end, strand, matchType, strandType, 0, ffunc);
610 }
611 
overlapsAny(GTFtree * t,char * chrom,uint32_t start,uint32_t end,int strand,int matchType,int strandType,FILTER_ENTRY_FUNC ffunc)612 int overlapsAny(GTFtree *t, char *chrom, uint32_t start, uint32_t end, int strand, int matchType, int strandType, FILTER_ENTRY_FUNC ffunc) {
613     int32_t tid = str2valHT(t->htChroms, chrom);
614     if(tid<0) return 0;
615 
616     if(!t->balanced) {
617         fprintf(stderr, "[overlapsAny] The tree has not been balanced! No overlaps will be returned.\n");
618         return 0;
619     }
620 
621     return countOverlapsNode(t, (GTFnode*) t->chroms[tid]->tree, start, end, strand, matchType, strandType, 1, ffunc);
622 }
623