Skip to content

Commit 2a7ccea

Browse files
committed
Improve comments and self-describing code
1 parent f5030b1 commit 2a7ccea

1 file changed

Lines changed: 72 additions & 16 deletions

File tree

vcf.c

Lines changed: 72 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2663,6 +2663,25 @@ typedef struct {
26632663
uint8_t *buf; // Pointer into h->mem
26642664
} fmt_aux_t;
26652665

2666+
// fmt_aux_t field notes:
2667+
// max_* are biggest sizes of the various FORMAT fields across all samples.
2668+
// We use these after pivoting the data to ensure easy random access
2669+
// of a specific sample.
2670+
//
2671+
// max_m is only used for type BCF_HT_REAL or BCF_HT_INT
2672+
// max_g is only used for is_gt == 1 (will be BCF_HT_STR)
2673+
// max_l is only used for is_gt == 0 (will be BCF_HT_STR)
2674+
//
2675+
// These are computed in vcf_parse_format_max3 and used in
2676+
// vcf_parse_format_alloc4 to get the size.
2677+
//
2678+
// size is computed from max_g, max_l, max_m and is_gt. Once computed
2679+
// the max values are never accessed again.
2680+
//
2681+
// In theory all 4 vars could be coalesced into a single variable, but this
2682+
// significantly harms speed (even if done via a union). It's about 25-30%
2683+
// slower.
2684+
26662685
static inline int align_mem(kstring_t *s)
26672686
{
26682687
int e = 0;
@@ -2919,15 +2938,19 @@ static int vcf_parse_format_fill5(kstring_t *s, const bcf_hdr_t *h, bcf1_t *v,
29192938
while ( t < end )
29202939
{
29212940
fmt_aux_t *z = &fmt[j++];
2941+
const int htype = z->y>>4&0xf;
29222942
if (!z->buf) {
29232943
hts_log_error("Memory allocation failure for FORMAT field type %d at %s:%"PRIhts_pos,
29242944
z->y>>4&0xf, bcf_seqname_safe(h,v), v->pos+1);
29252945
v->errcode |= BCF_ERR_LIMITS;
29262946
return -1;
29272947
}
2928-
if ((z->y>>4&0xf) == BCF_HT_STR) {
2948+
2949+
if (htype == BCF_HT_STR) {
29292950
int l;
2930-
if (z->is_gt) { // genotypes
2951+
if (z->is_gt) {
2952+
// Genotypes.
2953+
// <val>([|/]<val>)+... where <val> is [0-9]+ or ".".
29312954
int32_t is_phased = 0;
29322955
uint32_t *x = (uint32_t*)(z->buf + z->size * (size_t)m);
29332956
uint32_t unreadable = 0;
@@ -2966,14 +2989,20 @@ static int vcf_parse_format_fill5(kstring_t *s, const bcf_hdr_t *h, bcf1_t *v,
29662989
return -1;
29672990
}
29682991
if ( !l ) x[l++] = 0; // An empty field, insert missing value
2969-
for (; l < z->size>>2; ++l) x[l] = bcf_int32_vector_end;
2992+
for (; l < z->size>>2; ++l)
2993+
x[l] = bcf_int32_vector_end;
2994+
29702995
} else {
2996+
// Otherwise arbitrary strings
29712997
char *x = (char*)z->buf + z->size * (size_t)m;
2972-
for (l = 0; *t != ':' && *t; ++t) x[l++] = *t;
2998+
for (l = 0; *t != ':' && *t; ++t)
2999+
x[l++] = *t;
29733000
if (z->size > l)
29743001
memset(&x[l], 0, (z->size-l) * sizeof(*x));
29753002
}
2976-
} else if ((z->y>>4&0xf) == BCF_HT_INT) {
3003+
3004+
} else if (htype == BCF_HT_INT) {
3005+
// One or more integers in an array
29773006
int32_t *x = (int32_t*)(z->buf + z->size * (size_t)m);
29783007
int l;
29793008
for (l = 0;; ++t) {
@@ -2987,7 +3016,8 @@ static int vcf_parse_format_fill5(kstring_t *s, const bcf_hdr_t *h, bcf1_t *v,
29873016
{
29883017
if ( !extreme_val_warned )
29893018
{
2990-
hts_log_warning("Extreme FORMAT/%s value encountered and set to missing at %s:%"PRIhts_pos, h->id[BCF_DT_ID][fmt[j-1].key].key, bcf_seqname_safe(h,v), v->pos+1);
3019+
hts_log_warning("Extreme FORMAT/%s value encountered and set to missing at %s:%"PRIhts_pos,
3020+
h->id[BCF_DT_ID][fmt[j-1].key].key, bcf_seqname_safe(h,v), v->pos+1);
29913021
extreme_val_warned = 1;
29923022
}
29933023
tmp_val = bcf_int32_missing;
@@ -2997,9 +3027,13 @@ static int vcf_parse_format_fill5(kstring_t *s, const bcf_hdr_t *h, bcf1_t *v,
29973027
}
29983028
if (*t != ',') break;
29993029
}
3000-
if ( !l ) x[l++] = bcf_int32_missing;
3001-
for (; l < z->size>>2; ++l) x[l] = bcf_int32_vector_end;
3002-
} else if ((z->y>>4&0xf) == BCF_HT_REAL) {
3030+
if ( !l )
3031+
x[l++] = bcf_int32_missing;
3032+
for (; l < z->size>>2; ++l)
3033+
x[l] = bcf_int32_vector_end;
3034+
3035+
} else if (htype == BCF_HT_REAL) {
3036+
// One of more floating point values in an array
30033037
float *x = (float*)(z->buf + z->size * (size_t)m);
30043038
int l;
30053039
for (l = 0;; ++t) {
@@ -3019,10 +3053,13 @@ static int vcf_parse_format_fill5(kstring_t *s, const bcf_hdr_t *h, bcf1_t *v,
30193053
}
30203054
if (*t != ',') break;
30213055
}
3022-
if ( !l ) bcf_float_set_missing(x[l++]); // An empty field, insert missing value
3023-
for (; l < z->size>>2; ++l) bcf_float_set_vector_end(x[l]);
3056+
if ( !l )
3057+
// An empty field, insert missing value
3058+
bcf_float_set_missing(x[l++]);
3059+
for (; l < z->size>>2; ++l)
3060+
bcf_float_set_vector_end(x[l]);
30243061
} else {
3025-
hts_log_error("Unknown FORMAT field type %d at %s:%"PRIhts_pos, z->y>>4&0xf, bcf_seqname_safe(h,v), v->pos+1);
3062+
hts_log_error("Unknown FORMAT field type %d at %s:%"PRIhts_pos, htype, bcf_seqname_safe(h,v), v->pos+1);
30263063
v->errcode |= BCF_ERR_TAG_INVALID;
30273064
return -1;
30283065
}
@@ -3043,10 +3080,12 @@ static int vcf_parse_format_fill5(kstring_t *s, const bcf_hdr_t *h, bcf1_t *v,
30433080
}
30443081
}
30453082

3046-
for (; j < v->n_fmt; ++j) { // fill end-of-vector values
3083+
// fill end-of-vector values
3084+
for (; j < v->n_fmt; ++j) {
30473085
fmt_aux_t *z = &fmt[j];
3086+
const int htype = z->y>>4&0xf;
30483087
int l;
3049-
if ((z->y>>4&0xf) == BCF_HT_STR) {
3088+
if (htype == BCF_HT_STR) {
30503089
if (z->is_gt) {
30513090
int32_t *x = (int32_t*)(z->buf + z->size * (size_t)m);
30523091
if (z->size) x[0] = bcf_int32_missing;
@@ -3058,11 +3097,11 @@ static int vcf_parse_format_fill5(kstring_t *s, const bcf_hdr_t *h, bcf1_t *v,
30583097
memset(&x[1], 0, (z->size-1) * sizeof(*x));
30593098
}
30603099
}
3061-
} else if ((z->y>>4&0xf) == BCF_HT_INT) {
3100+
} else if (htype == BCF_HT_INT) {
30623101
int32_t *x = (int32_t*)(z->buf + z->size * (size_t)m);
30633102
x[0] = bcf_int32_missing;
30643103
for (l = 1; l < z->size>>2; ++l) x[l] = bcf_int32_vector_end;
3065-
} else if ((z->y>>4&0xf) == BCF_HT_REAL) {
3104+
} else if (htype == BCF_HT_REAL) {
30663105
float *x = (float*)(z->buf + z->size * (size_t)m);
30673106
bcf_float_set_missing(x[0]);
30683107
for (l = 1; l < z->size>>2; ++l) bcf_float_set_vector_end(x[l]);
@@ -3145,6 +3184,23 @@ static int vcf_parse_format(kstring_t *s, const bcf_hdr_t *h, bcf1_t *v,
31453184
if (vcf_parse_format_dict2(s, h, v, p, q, fmt) < 0)
31463185
return -1;
31473186

3187+
// FORMAT data is per-sample A:B:C A:B:C A:B:C ... but in memory it is
3188+
// stored as per-type arrays AAA... BBB... CCC... This is basically
3189+
// a data rotation or pivot.
3190+
3191+
// The size of elements in the array grow to their maximum needed,
3192+
// permitting fast random access. This means however we have to first
3193+
// scan the whole FORMAT line to find the maximum of each type, and
3194+
// then scan it again to find the store the data.
3195+
// We break this down into compute-max, allocate, fill-out-buffers
3196+
3197+
// TODO: ?
3198+
// The alternative would be to pivot on the first pass, with fixed
3199+
// size entries for numerics and concatenated strings otherwise, also
3200+
// tracking maximum sizes. Then on a second pass we reallocate and
3201+
// copy the data again to a uniformly sized array. Two passes through
3202+
// memory, but without doubling string parsing.
3203+
31483204
// compute max
31493205
if (vcf_parse_format_max3(s, h, v, p, q, fmt) < 0)
31503206
return -1;

0 commit comments

Comments
 (0)