@@ -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+
26662685static 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