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