Coverage Report

Created: 2026-09-28 07:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/htslib/cram/cram_stats.c
Line
Count
Source
1
/*
2
Copyright (c) 2012-2014, 2016, 2018, 2020, 2026 Genome Research Ltd.
3
Author: James Bonfield <jkb@sanger.ac.uk>
4
5
Redistribution and use in source and binary forms, with or without
6
modification, are permitted provided that the following conditions are met:
7
8
   1. Redistributions of source code must retain the above copyright notice,
9
this list of conditions and the following disclaimer.
10
11
   2. Redistributions in binary form must reproduce the above copyright notice,
12
this list of conditions and the following disclaimer in the documentation
13
and/or other materials provided with the distribution.
14
15
   3. Neither the names Genome Research Ltd and Wellcome Trust Sanger
16
Institute nor the names of its contributors may be used to endorse or promote
17
products derived from this software without specific prior written permission.
18
19
THIS SOFTWARE IS PROVIDED BY GENOME RESEARCH LTD AND CONTRIBUTORS "AS IS" AND
20
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
DISCLAIMED. IN NO EVENT SHALL GENOME RESEARCH LTD OR CONTRIBUTORS BE LIABLE
23
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
*/
30
31
#define HTS_BUILDING_LIBRARY // Enables HTSLIB_EXPORT, see htslib/hts_defs.h
32
#include <config.h>
33
34
#include <stdio.h>
35
#include <errno.h>
36
#include <assert.h>
37
#include <stdlib.h>
38
#include <string.h>
39
#include <zlib.h>
40
#include <sys/types.h>
41
#include <sys/stat.h>
42
#include <math.h>
43
#include <inttypes.h>
44
45
#include "cram.h"
46
#include "os.h"
47
#include "../htslib/hts_alloc.h"
48
49
1.28M
cram_stats *cram_stats_create(void) {
50
1.28M
    return calloc(1, sizeof(cram_stats));
51
1.28M
}
52
53
622M
int cram_stats_add(cram_stats *st, int64_t val) {
54
622M
    st->nsamp++;
55
56
    //assert(val >= 0);
57
58
622M
    if (val < MAX_STAT_VAL && val >= 0) {
59
593M
        st->freqs[val]++;
60
593M
    } else {
61
28.2M
        khint_t k;
62
28.2M
        int r;
63
64
28.2M
        if (!st->h) {
65
99.1k
            st->h = kh_init(m_i2i);
66
99.1k
            if (!st->h)
67
0
                return -1;
68
99.1k
        }
69
70
28.2M
        k = kh_put(m_i2i, st->h, val, &r);
71
28.2M
        if (r == 0)
72
28.1M
            kh_val(st->h, k)++;
73
109k
        else if (r != -1)
74
109k
            kh_val(st->h, k) = 1;
75
0
        else
76
0
            return -1;
77
28.2M
    }
78
622M
    return 0;
79
622M
}
80
81
15
void cram_stats_del(cram_stats *st, int64_t val) {
82
15
    st->nsamp--;
83
84
    //assert(val >= 0);
85
86
15
    if (val < MAX_STAT_VAL && val >= 0) {
87
12
        st->freqs[val]--;
88
12
        assert(st->freqs[val] >= 0);
89
12
    } else if (st->h) {
90
3
        khint_t k = kh_get(m_i2i, st->h, val);
91
92
3
        if (k != kh_end(st->h)) {
93
3
            if (--kh_val(st->h, k) == 0)
94
2
                kh_del(m_i2i, st->h, k);
95
3
        } else {
96
0
            hts_log_warning("Failed to remove val %"PRId64" from cram_stats", val);
97
0
            st->nsamp++;
98
0
        }
99
3
    } else {
100
0
        hts_log_warning("Failed to remove val %"PRId64" from cram_stats", val);
101
0
        st->nsamp++;
102
0
    }
103
15
}
104
105
#if DEBUG_CRAM_STATS
106
void cram_stats_dump(cram_stats *st) {
107
    int i;
108
    fprintf(stderr, "cram_stats:\n");
109
    for (i = 0; i < MAX_STAT_VAL; i++) {
110
        if (!st->freqs[i])
111
            continue;
112
        fprintf(stderr, "\t%d\t%d\n", i, st->freqs[i]);
113
    }
114
    if (st->h) {
115
        khint_t k;
116
        for (k = kh_begin(st->h); k != kh_end(st->h); k++) {
117
            if (!kh_exist(st->h, k))
118
                continue;
119
120
            fprintf(stderr, "\t%d\t%d\n", kh_key(st->h, k), kh_val(st->h, k));
121
        }
122
    }
123
}
124
#endif
125
126
/*
127
 * Computes entropy from integer frequencies for various encoding methods and
128
 * picks the best encoding.
129
 *
130
 * FIXME: we could reuse some of the code here for the actual encoding
131
 * parameters too. Eg the best 'k' for SUBEXP or the code lengths for huffman.
132
 *
133
 * Returns the best codec to use.
134
 */
135
823k
enum cram_encoding cram_stats_encoding(cram_fd *fd, cram_stats *st) {
136
823k
    int nvals, i, max_val = 0, min_val = INT_MAX;
137
823k
    int *vals = NULL, *freqs = NULL, vals_alloc = 0;
138
823k
    int ntot HTS_UNUSED = 0;
139
140
#if DEBUG_CRAM_STATS
141
    cram_stats_dump(st);
142
#endif
143
144
    /* Count number of unique symbols */
145
844M
    for (nvals = i = 0; i < MAX_STAT_VAL; i++) {
146
843M
        if (!st->freqs[i])
147
842M
            continue;
148
515k
        if (nvals >= vals_alloc) {
149
437k
            vals_alloc = vals_alloc ? vals_alloc*2 : 1024;
150
437k
            int *vals_tmp  = hts_realloc_p(vals,  sizeof(*vals),  vals_alloc);
151
437k
            int *freqs_tmp = hts_realloc_p(freqs, sizeof(*freqs), vals_alloc);
152
437k
            if (!vals_tmp || !freqs_tmp) {
153
0
                free(vals_tmp  ? vals_tmp  : vals);
154
0
                free(freqs_tmp ? freqs_tmp : freqs);
155
0
                return E_HUFFMAN; // Cannot do much else atm
156
0
            }
157
437k
            vals = vals_tmp;
158
437k
            freqs = freqs_tmp;
159
437k
        }
160
515k
        vals[nvals] = i;
161
515k
        freqs[nvals] = st->freqs[i];
162
515k
        ntot += freqs[nvals];
163
515k
        if (max_val < i) max_val = i;
164
515k
        if (min_val > i) min_val = i;
165
515k
        nvals++;
166
515k
    }
167
823k
    if (st->h) {
168
113k
        khint_t k;
169
113k
        int i;
170
171
586k
        for (k = kh_begin(st->h); k != kh_end(st->h); k++) {
172
472k
            if (!kh_exist(st->h, k))
173
348k
                continue;
174
175
123k
            if (nvals >= vals_alloc) {
176
106k
                vals_alloc = vals_alloc ? vals_alloc*2 : 1024;
177
106k
                int *vals_tmp  = hts_realloc_p(vals,  sizeof(*vals),  vals_alloc);
178
106k
                int *freqs_tmp = hts_realloc_p(freqs, sizeof(*freqs), vals_alloc);
179
106k
                if (!vals_tmp || !freqs_tmp) {
180
0
                    free(vals_tmp  ? vals_tmp  : vals);
181
0
                    free(freqs_tmp ? freqs_tmp : freqs);
182
0
                    return E_HUFFMAN; // Cannot do much else atm
183
0
                }
184
106k
                vals = vals_tmp;
185
106k
                freqs = freqs_tmp;
186
106k
            }
187
123k
            i = kh_key(st->h, k);
188
123k
            vals[nvals]=i;
189
123k
            freqs[nvals] = kh_val(st->h, k);
190
123k
            ntot += freqs[nvals];
191
123k
            if (max_val < i) max_val = i;
192
123k
            if (min_val > i) min_val = i;
193
123k
            nvals++;
194
123k
        }
195
113k
    }
196
197
823k
    st->nvals = nvals;
198
823k
    st->min_val = min_val;
199
823k
    st->max_val = max_val;
200
823k
    assert(ntot == st->nsamp);
201
202
823k
    free(vals);
203
823k
    free(freqs);
204
205
    /*
206
     * Simple policy that everything is external unless it can be
207
     * encoded using zero bits as a unary item huffman table.
208
     */
209
823k
    return nvals <= 1 ? E_HUFFMAN : E_EXTERNAL;
210
823k
}
211
212
1.28M
void cram_stats_free(cram_stats *st) {
213
1.28M
    if (st->h)
214
99.1k
        kh_destroy(m_i2i, st->h);
215
1.28M
    free(st);
216
1.28M
}