/src/htslib/htslib/hts_expr.h
Line | Count | Source |
1 | | /* expr.c -- filter expression parsing and processing. |
2 | | |
3 | | Copyright (C) 2020, 2022 Genome Research Ltd. |
4 | | |
5 | | Author: James Bonfield <jkb@sanger.ac.uk> |
6 | | |
7 | | Permission is hereby granted, free of charge, to any person obtaining a copy |
8 | | of this software and associated documentation files (the "Software"), to deal |
9 | | in the Software without restriction, including without limitation the rights |
10 | | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
11 | | copies of the Software, and to permit persons to whom the Software is |
12 | | furnished to do so, subject to the following conditions: |
13 | | |
14 | | The above copyright notices and this permission notice shall be included in |
15 | | all copies or substantial portions of the Software. |
16 | | |
17 | | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
18 | | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
19 | | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
20 | | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
21 | | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
22 | | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
23 | | DEALINGS IN THE SOFTWARE. */ |
24 | | |
25 | | #ifndef HTS_EXPR_H |
26 | | #define HTS_EXPR_H |
27 | | |
28 | | #include <math.h> |
29 | | #include "kstring.h" |
30 | | #include "hts_defs.h" |
31 | | |
32 | | /// Holds a filter variable. This is also used to return the results. |
33 | | /** |
34 | | * The expression language has 3-states of string, numeric, and unknown. |
35 | | * The unknown state is either a NaN numeric or a null string, with both |
36 | | * internally considered to have the same "unknown" meaning. |
37 | | * |
38 | | * These largely match the IEE 754 semantics for NaN comparisons: <, >, ==, |
39 | | * != all fail, (even NaN == NaN). Similarly arithmetic (+,-,/,*,%) with |
40 | | * unknown values are still unknown (and false). |
41 | | * |
42 | | * The departure from NaN semantics though is that our unknown/null state is |
43 | | * considered to be false while NaN in C is true. Similarly the false nature |
44 | | * of our unknown state meants !val becomes true, !!val is once again false, |
45 | | * val && 1 is false, val || 0 is false, and val || 1 is true along with |
46 | | * !val || 0 and !val && 1. |
47 | | * |
48 | | * Note it is possible for empty strings and zero numbers to also be true. |
49 | | * An example of this is the aux string '[NM]' which returns true if the |
50 | | * NM tag is found, regardless of whether it is also zero. However the |
51 | | * better approach added in 1.16 is 'exists([NM])'. |
52 | | */ |
53 | | typedef struct hts_expr_val_t { |
54 | | char is_str; // Use .s vs .d |
55 | | char is_true; // Force true if even zero |
56 | | kstring_t s; // is_str and empty s permitted (eval as false) |
57 | | double d; // otherwise this |
58 | | } hts_expr_val_t; |
59 | | |
60 | | /// Returns true if an hts_expr_val_t is defined. |
61 | | /* An example usage of this is in the SAM expression filter where an |
62 | | * [X0] aux tag will be the value of X0 (string or numeric) if set, or |
63 | | * a false nul-string (not the same as an empty one) when not set. |
64 | | */ |
65 | 0 | static inline int hts_expr_val_exists(hts_expr_val_t *v) { |
66 | 0 | return v && !(v->is_str == 1 && v->s.s == NULL) |
67 | 0 | && !(v->is_str == 0 && isnan(v->d)); |
68 | 0 | } Unexecuted instantiation: hts.c:hts_expr_val_exists Unexecuted instantiation: hts_expr.c:hts_expr_val_exists Unexecuted instantiation: sam.c:hts_expr_val_exists |
69 | | |
70 | | /// Returns true if an hts_expr_val_t is defined or is undef-but-true |
71 | 0 | static inline int hts_expr_val_existsT(hts_expr_val_t *v) { |
72 | 0 | return (v && v->is_true) || hts_expr_val_exists(v); |
73 | 0 | } Unexecuted instantiation: hts.c:hts_expr_val_existsT Unexecuted instantiation: hts_expr.c:hts_expr_val_existsT Unexecuted instantiation: sam.c:hts_expr_val_existsT |
74 | | |
75 | | /// Set a value to be undefined (nan). |
76 | 0 | static inline void hts_expr_val_undef(hts_expr_val_t *v) { |
77 | 0 | ks_clear(&v->s); |
78 | 0 | v->is_true = 0; |
79 | 0 | v->is_str = 0; |
80 | 0 | v->d = NAN; |
81 | 0 | } Unexecuted instantiation: hts.c:hts_expr_val_undef Unexecuted instantiation: hts_expr.c:hts_expr_val_undef Unexecuted instantiation: sam.c:hts_expr_val_undef |
82 | | |
83 | | /// Frees a hts_expr_val_t type. |
84 | 0 | static inline void hts_expr_val_free(hts_expr_val_t *f) { |
85 | 0 | ks_free(&f->s); |
86 | 0 | } Unexecuted instantiation: hts.c:hts_expr_val_free Unexecuted instantiation: hts_expr.c:hts_expr_val_free Unexecuted instantiation: sam.c:hts_expr_val_free |
87 | | |
88 | | /// Opaque hts_filter_t type. Definition in hts_expr.c |
89 | | typedef struct hts_filter_t hts_filter_t; |
90 | | |
91 | | /// For static initialisation of hts_expr_val_t values |
92 | 0 | #define HTS_EXPR_VAL_INIT {0, 0, KS_INITIALIZE, 0} |
93 | | |
94 | | /// Creates a filter for expression "str". |
95 | | /** @param str The filter expression |
96 | | * @return A pointer on success, NULL on failure |
97 | | */ |
98 | | HTSLIB_EXPORT |
99 | | hts_filter_t *hts_filter_init(const char *str); |
100 | | |
101 | | /// Frees an hts_filter_t created via hts_filter_init |
102 | | /** @param filt The filter pointer. |
103 | | */ |
104 | | HTSLIB_EXPORT |
105 | | void hts_filter_free(hts_filter_t *filt); |
106 | | |
107 | | /// Type for expression symbol lookups; name -> value. |
108 | | typedef int (hts_expr_sym_func)(void *data, char *str, char **end, |
109 | | hts_expr_val_t *res); |
110 | | |
111 | | /// Evaluates a filter expression and returns the value |
112 | | /** @param filt The filter, produced by hts_filter_init |
113 | | * @param data Arbitrary caller data, passed into sym_func |
114 | | * @param sym_func Callback function to lookup variables. |
115 | | * @param res Filled out with the result of the filter evaluation |
116 | | * @return Returns 0 on success, -1 on failure |
117 | | * |
118 | | * sym_func and data may be NULL if the caller does not need its own data |
119 | | * pointer or if it has no variables to lookup. |
120 | | * |
121 | | * The type of the returned result may be numeric of string, as defined by |
122 | | * the is_str member. It can also be explicitly defined to be true even |
123 | | * for a null value. This may be used to check for the existence of |
124 | | * something, irrespective of whether that something evaluates to zero. |
125 | | * |
126 | | * @p res must be initialized using HTS_EXPR_VAL_INIT before passing it |
127 | | * to this function for the first time. |
128 | | */ |
129 | | HTSLIB_EXPORT |
130 | | int hts_filter_eval2(hts_filter_t *filt, |
131 | | void *data, hts_expr_sym_func *sym_func, |
132 | | hts_expr_val_t *res); |
133 | | |
134 | | /// Evaluate a filter expression (derecated API) |
135 | | /** |
136 | | * @copydetails hts_filter_eval2() |
137 | | * |
138 | | * If calling this function more than once with the same @p res |
139 | | * parameter, hts_expr_val_free(res) must be used between invocations |
140 | | * to clear any allocated memory prior to reuse. |
141 | | * |
142 | | * @deprecated This function has been replaced by hts_filter_eval2(), |
143 | | * which clears @p res properly itself. |
144 | | */ |
145 | | HTSLIB_EXPORT |
146 | | int hts_filter_eval(hts_filter_t *filt, |
147 | | void *data, hts_expr_sym_func *sym_func, |
148 | | hts_expr_val_t *res) |
149 | | HTS_DEPRECATED("Please use hts_filter_eval2 instead"); |
150 | | |
151 | | |
152 | | #endif /* HTS_EXPR_H */ |