Imported Upstream version 0.5
[pysam.git] / samtools / bedidx.c.pysam.c
1 #include "pysam.h"
2
3 #include <stdlib.h>
4 #include <stdint.h>
5 #include <string.h>
6 #include <stdio.h>
7 #include <zlib.h>
8
9 #include "ksort.h"
10 KSORT_INIT_GENERIC(uint64_t)
11
12 #include "kseq.h"
13 KSTREAM_INIT(gzFile, gzread, 8192)
14
15 typedef struct {
16         int n, m;
17         uint64_t *a;
18         int *idx;
19 } bed_reglist_t;
20
21 #include "khash.h"
22 KHASH_MAP_INIT_STR(reg, bed_reglist_t)
23
24 #define LIDX_SHIFT 13
25
26 typedef kh_reg_t reghash_t;
27
28 int *bed_index_core(int n, uint64_t *a, int *n_idx)
29 {
30         int i, j, m, *idx;
31         m = *n_idx = 0; idx = 0;
32         for (i = 0; i < n; ++i) {
33                 int beg, end;
34                 beg = a[i]>>32 >> LIDX_SHIFT; end = ((uint32_t)a[i]) >> LIDX_SHIFT;
35                 if (m < end + 1) {
36                         int oldm = m;
37                         m = end + 1;
38                         kroundup32(m);
39                         idx = realloc(idx, m * sizeof(int));
40                         for (j = oldm; j < m; ++j) idx[j] = -1;
41                 }
42                 if (beg == end) {
43                         if (idx[beg] < 0) idx[beg] = i;
44                 } else {
45                         for (j = beg; j <= end; ++j)
46                                 if (idx[j] < 0) idx[j] = i;
47                 }
48                 *n_idx = end + 1;
49         }
50         return idx;
51 }
52
53 void bed_index(void *_h)
54 {
55         reghash_t *h = (reghash_t*)_h;
56         khint_t k;
57         for (k = 0; k < kh_end(h); ++k) {
58                 if (kh_exist(h, k)) {
59                         bed_reglist_t *p = &kh_val(h, k);
60                         if (p->idx) free(p->idx);
61                         ks_introsort(uint64_t, p->n, p->a);
62                         p->idx = bed_index_core(p->n, p->a, &p->m);
63                 }
64         }
65 }
66
67 int bed_overlap_core(const bed_reglist_t *p, int beg, int end)
68 {
69         int i, min_off;
70         if (p->n == 0) return 0;
71         min_off = (beg>>LIDX_SHIFT >= p->n)? p->idx[p->n-1] : p->idx[beg>>LIDX_SHIFT];
72         if (min_off < 0) { // TODO: this block can be improved, but speed should not matter too much here
73                 int n = beg>>LIDX_SHIFT;
74                 if (n > p->n) n = p->n;
75                 for (i = n - 1; i >= 0; --i)
76                         if (p->idx[i] >= 0) break;
77                 min_off = i >= 0? p->idx[i] : 0;
78         }
79         for (i = min_off; i < p->n; ++i) {
80                 if ((int)(p->a[i]>>32) >= end) break; // out of range; no need to proceed
81                 if ((int32_t)p->a[i] > beg && (int32_t)(p->a[i]>>32) < end)
82                         return 1; // find the overlap; return
83         }
84         return 0;
85 }
86
87 int bed_overlap(const void *_h, const char *chr, int beg, int end)
88 {
89         const reghash_t *h = (const reghash_t*)_h;
90         khint_t k;
91         if (!h) return 0;
92         k = kh_get(reg, h, chr);
93         if (k == kh_end(h)) return 0;
94         return bed_overlap_core(&kh_val(h, k), beg, end);
95 }
96
97 void *bed_read(const char *fn)
98 {
99         reghash_t *h = kh_init(reg);
100         gzFile fp;
101         kstream_t *ks;
102         int dret;
103         kstring_t *str;
104         // read the list
105         fp = strcmp(fn, "-")? gzopen(fn, "r") : gzdopen(fileno(stdin), "r");
106         if (fp == 0) return 0;
107         str = calloc(1, sizeof(kstring_t));
108         ks = ks_init(fp);
109         while (ks_getuntil(ks, 0, str, &dret) >= 0) { // read the chr name
110                 int beg = -1, end = -1;
111                 bed_reglist_t *p;
112                 khint_t k = kh_get(reg, h, str->s);
113                 if (k == kh_end(h)) { // absent from the hash table
114                         int ret;
115                         char *s = strdup(str->s);
116                         k = kh_put(reg, h, s, &ret);
117                         memset(&kh_val(h, k), 0, sizeof(bed_reglist_t));
118                 }
119                 p = &kh_val(h, k);
120                 if (dret != '\n') { // if the lines has other characters
121                         if (ks_getuntil(ks, 0, str, &dret) > 0 && isdigit(str->s[0])) {
122                                 beg = atoi(str->s); // begin
123                                 if (dret != '\n') {
124                                         if (ks_getuntil(ks, 0, str, &dret) > 0 && isdigit(str->s[0]))
125                                                 end = atoi(str->s); // end
126                                 }
127                         }
128                 }
129                 if (dret != '\n') while ((dret = ks_getc(ks)) > 0 && dret != '\n'); // skip the rest of the line
130                 if (end < 0 && beg > 0) end = beg, beg = beg - 1; // if there is only one column
131                 if (beg >= 0 && end > beg) {
132                         if (p->n == p->m) {
133                                 p->m = p->m? p->m<<1 : 4;
134                                 p->a = realloc(p->a, p->m * 8);
135                         }
136                         p->a[p->n++] = (uint64_t)beg<<32 | end;
137                 }
138         }
139         ks_destroy(ks);
140         gzclose(fp);
141         free(str->s); free(str);
142         bed_index(h);
143         return h;
144 }
145
146 void bed_destroy(void *_h)
147 {
148         reghash_t *h = (reghash_t*)_h;
149         khint_t k;
150         for (k = 0; k < kh_end(h); ++k) {
151                 if (kh_exist(h, k)) {
152                         free(kh_val(h, k).a);
153                         free(kh_val(h, k).idx);
154                         free((char*)kh_key(h, k));
155                 }
156         }
157         kh_destroy(reg, h);
158 }