1 //
2 // Created by Martin Steinegger on 2019-08-20.
3 //
4 #ifndef MMSEQS_TAXONOMYEXPRESSION_H
5 #define MMSEQS_TAXONOMYEXPRESSION_H
6 
7 #include "NcbiTaxonomy.h"
8 #include "ExpressionParser.h"
9 
10 #include <vector>
11 #include <ctype.h>
12 
13 // class need one instance per thread
14 class TaxonomyExpression {
15 public:
16     enum CommaMeaning {
17         COMMA_IS_COMMA,
18         COMMA_IS_OR,
19         COMMA_IS_AND
20     };
21 
22     TaxonomyExpression(const std::string &expression, NcbiTaxonomy &taxonomy, CommaMeaning commaMeaning = COMMA_IS_OR) {
23         std::string bracketExpression;
24         bool inNumber = false;
25         for (size_t i = 0; i < expression.size(); i++) {
26             // make brackets around numbers for tinyexpr
27             const bool isDigit = isdigit(expression[i]);
28             if (isDigit && inNumber == true) {
29                 bracketExpression.push_back(expression[i]);
30             } else if (isDigit && inNumber == false) {
31                 bracketExpression.append("a(");
32                 bracketExpression.push_back(expression[i]);
33                 inNumber = true;
34             } else {
35                 if (inNumber == true) {
36                     bracketExpression.append(")");
37                     inNumber = false;
38                 }
39                 if (commaMeaning != COMMA_IS_COMMA && expression[i] == ',') {
40                     if (commaMeaning == COMMA_IS_OR) {
41                         bracketExpression.append("||");
42                     } else if (commaMeaning == COMMA_IS_AND) {
43                         bracketExpression.append("&&");
44                     }
45                 } else {
46                     bracketExpression.push_back(expression[i]);
47                 }
48             }
49         }
50         if (inNumber == true) {
51             bracketExpression.append(")");
52         }
53         tc.t = &taxonomy;
54         te_variable var;
55         var.name = "a";
56         // GCC 4.8 does not like casting functions to void*
57         // GCC > 4.8 is fine with this
58 #pragma GCC diagnostic push
59 #pragma GCC diagnostic ignored "-Wpedantic"
60         var.address = (const void *) &acst;
61 #pragma GCC diagnostic pop
62         var.type = TE_CLOSURE1;
63         var.context = (void *) &tc;
64         vars.push_back(var);
65         parser = new ExpressionParser(bracketExpression.c_str(), vars);
66     }
67 
~TaxonomyExpression()68     ~TaxonomyExpression() {
69         delete parser;
70     }
71 
isAncestor(TaxID taxId)72     bool isAncestor(TaxID taxId) {
73         tc.taxId = taxId;
74         const double result = parser->evaluate();
75         return (result != 0);
76     }
77 
78 private:
79     struct TaxContext {
80         NcbiTaxonomy *t;
81         TaxID taxId;
82     };
83     TaxContext tc;
84     ExpressionParser *parser;
85     std::vector<te_variable> vars;
86 
acst(void * context,double a)87     static double acst(void *context, double a) {
88         TaxContext *o = (TaxContext *) context;
89         bool retVal = o->t->IsAncestor((TaxID) a, o->taxId);
90         return (retVal) ? 1.0 : 0.0;
91     }
92 };
93 #endif //MMSEQS_TAXONOMYEXPRESSION_H
94