1 //
2 //  Copyright (C) 2003-2021 Greg Landrum and other RDKit contributors
3 //
4 //   @@ All Rights Reserved @@
5 //  This file is part of the RDKit.
6 //  The contents are covered by the terms of the BSD license
7 //  which is included in the file license.txt, found at the root
8 //  of the RDKit source tree.
9 //
10 
11 //! \file QueryOps.h
12 /*!
13     \brief Includes a bunch of functionality for handling Atom and Bond queries.
14 */
15 #include <RDGeneral/export.h>
16 #ifndef RD_QUERY_OPS_H
17 #define RD_QUERY_OPS_H
18 
19 #include <GraphMol/RDKitBase.h>
20 #include <Query/QueryObjects.h>
21 #include <Query/Query.h>
22 #include <DataStructs/BitVects.h>
23 #include <DataStructs/BitOps.h>
24 
25 #ifdef RDK_THREADSAFE_SSS
26 #include <mutex>
27 #endif
28 
29 namespace RDKit {
30 typedef Queries::Query<bool, Atom const *, true> ATOM_BOOL_QUERY;
31 typedef Queries::Query<bool, Bond const *, true> BOND_BOOL_QUERY;
32 
33 typedef Queries::AndQuery<int, Atom const *, true> ATOM_AND_QUERY;
34 typedef Queries::AndQuery<int, Bond const *, true> BOND_AND_QUERY;
35 
36 typedef Queries::OrQuery<int, Atom const *, true> ATOM_OR_QUERY;
37 typedef Queries::OrQuery<int, Bond const *, true> BOND_OR_QUERY;
38 
39 typedef Queries::XOrQuery<int, Atom const *, true> ATOM_XOR_QUERY;
40 typedef Queries::XOrQuery<int, Bond const *, true> BOND_XOR_QUERY;
41 
42 typedef Queries::EqualityQuery<int, Atom const *, true> ATOM_EQUALS_QUERY;
43 typedef Queries::EqualityQuery<int, Bond const *, true> BOND_EQUALS_QUERY;
44 
45 typedef Queries::GreaterQuery<int, Atom const *, true> ATOM_GREATER_QUERY;
46 typedef Queries::GreaterQuery<int, Bond const *, true> BOND_GREATER_QUERY;
47 
48 typedef Queries::GreaterEqualQuery<int, Atom const *, true>
49     ATOM_GREATEREQUAL_QUERY;
50 typedef Queries::GreaterEqualQuery<int, Bond const *, true>
51     BOND_GREATEREQUAL_QUERY;
52 
53 typedef Queries::LessQuery<int, Atom const *, true> ATOM_LESS_QUERY;
54 typedef Queries::LessQuery<int, Bond const *, true> BOND_LESS_QUERY;
55 
56 typedef Queries::LessEqualQuery<int, Atom const *, true> ATOM_LESSEQUAL_QUERY;
57 typedef Queries::LessEqualQuery<int, Bond const *, true> BOND_LESSEQUAL_QUERY;
58 
59 typedef Queries::RangeQuery<int, Atom const *, true> ATOM_RANGE_QUERY;
60 typedef Queries::RangeQuery<int, Bond const *, true> BOND_RANGE_QUERY;
61 
62 typedef Queries::SetQuery<int, Atom const *, true> ATOM_SET_QUERY;
63 typedef Queries::SetQuery<int, Bond const *, true> BOND_SET_QUERY;
64 
65 typedef Queries::Query<int, Bond const *, true> BOND_NULL_QUERY;
66 typedef Queries::Query<int, Atom const *, true> ATOM_NULL_QUERY;
67 
68 // -------------------------------------------------
69 // common atom queries
70 
queryAtomAromatic(Atom const * at)71 static inline int queryAtomAromatic(Atom const *at) {
72   return at->getIsAromatic();
73 };
queryAtomAliphatic(Atom const * at)74 static inline int queryAtomAliphatic(Atom const *at) {
75   return !(at->getIsAromatic());
76 };
queryAtomExplicitDegree(Atom const * at)77 static inline int queryAtomExplicitDegree(Atom const *at) {
78   return at->getDegree();
79 };
queryAtomTotalDegree(Atom const * at)80 static inline int queryAtomTotalDegree(Atom const *at) {
81   return at->getTotalDegree();
82 };
83 //! D and T are treated as "non-hydrogen" here
queryAtomNonHydrogenDegree(Atom const * at)84 static inline int queryAtomNonHydrogenDegree(Atom const *at) {
85   int res = 0;
86   for (const auto &nbri :
87        boost::make_iterator_range(at->getOwningMol().getAtomNeighbors(at))) {
88     const auto nbr = at->getOwningMol()[nbri];
89     if (nbr->getAtomicNum() != 1 || nbr->getIsotope() > 1) {
90       res++;
91     }
92   }
93 
94   return res;
95 };
96 //! D and T are not treated as heavy atoms here
queryAtomHeavyAtomDegree(Atom const * at)97 static inline int queryAtomHeavyAtomDegree(Atom const *at) {
98   int heavyDegree = 0;
99   for (const auto &nbri :
100        boost::make_iterator_range(at->getOwningMol().getAtomNeighbors(at))) {
101     const auto nbr = at->getOwningMol()[nbri];
102     if (nbr->getAtomicNum() > 1) {
103       heavyDegree++;
104     }
105   }
106 
107   return heavyDegree;
108 };
queryAtomHCount(Atom const * at)109 static inline int queryAtomHCount(Atom const *at) {
110   return at->getTotalNumHs(true);
111 };
queryAtomImplicitHCount(Atom const * at)112 static inline int queryAtomImplicitHCount(Atom const *at) {
113   return at->getTotalNumHs(false);
114 };
queryAtomHasImplicitH(Atom const * at)115 static inline int queryAtomHasImplicitH(Atom const *at) {
116   return int(at->getTotalNumHs(false) > 0);
117 };
queryAtomImplicitValence(Atom const * at)118 static inline int queryAtomImplicitValence(Atom const *at) {
119   return at->getImplicitValence();
120 };
queryAtomExplicitValence(Atom const * at)121 static inline int queryAtomExplicitValence(Atom const *at) {
122   return at->getExplicitValence() - at->getNumExplicitHs();
123 };
queryAtomTotalValence(Atom const * at)124 static inline int queryAtomTotalValence(Atom const *at) {
125   return at->getTotalValence();
126 };
queryAtomUnsaturated(Atom const * at)127 static inline int queryAtomUnsaturated(Atom const *at) {
128   return at->getTotalDegree() < at->getTotalValence();
129 };
queryAtomNum(Atom const * at)130 static inline int queryAtomNum(Atom const *at) { return at->getAtomicNum(); };
makeAtomType(int atomic_num,bool aromatic)131 static inline int makeAtomType(int atomic_num, bool aromatic) {
132   return atomic_num + 1000 * static_cast<int>(aromatic);
133 }
parseAtomType(int val,int & atomic_num,bool & aromatic)134 static inline void parseAtomType(int val, int &atomic_num, bool &aromatic) {
135   if (val > 1000) {
136     aromatic = true;
137     atomic_num = val - 1000;
138   } else {
139     aromatic = false;
140     atomic_num = val;
141   }
142 }
getAtomTypeIsAromatic(int val)143 static inline bool getAtomTypeIsAromatic(int val) {
144   if (val > 1000) return true;
145   return false;
146 }
getAtomTypeAtomicNum(int val)147 static inline int getAtomTypeAtomicNum(int val) {
148   if (val > 1000) return val - 1000;
149   return val;
150 }
151 
queryAtomType(Atom const * at)152 static inline int queryAtomType(Atom const *at) {
153   return makeAtomType(at->getAtomicNum(), at->getIsAromatic());
154 };
155 const int massIntegerConversionFactor = 1000;
queryAtomMass(Atom const * at)156 static inline int queryAtomMass(Atom const *at) {
157   return static_cast<int>(
158       std::round(massIntegerConversionFactor * at->getMass()));
159 };
queryAtomIsotope(Atom const * at)160 static inline int queryAtomIsotope(Atom const *at) {
161   return static_cast<int>(at->getIsotope());
162 };
queryAtomFormalCharge(Atom const * at)163 static inline int queryAtomFormalCharge(Atom const *at) {
164   return static_cast<int>(at->getFormalCharge());
165 };
queryAtomNegativeFormalCharge(Atom const * at)166 static inline int queryAtomNegativeFormalCharge(Atom const *at) {
167   return static_cast<int>(-1 * at->getFormalCharge());
168 };
queryAtomHybridization(Atom const * at)169 static inline int queryAtomHybridization(Atom const *at) {
170   return at->getHybridization();
171 };
queryAtomNumRadicalElectrons(Atom const * at)172 static inline int queryAtomNumRadicalElectrons(Atom const *at) {
173   return at->getNumRadicalElectrons();
174 };
queryAtomHasChiralTag(Atom const * at)175 static inline int queryAtomHasChiralTag(Atom const *at) {
176   return at->getChiralTag() != Atom::CHI_UNSPECIFIED;
177 };
queryAtomMissingChiralTag(Atom const * at)178 static inline int queryAtomMissingChiralTag(Atom const *at) {
179   return at->getChiralTag() == Atom::CHI_UNSPECIFIED &&
180          at->hasProp(common_properties::_ChiralityPossible);
181 };
182 
queryAtomHasHeteroatomNbrs(Atom const * at)183 static inline int queryAtomHasHeteroatomNbrs(Atom const *at) {
184   ROMol::ADJ_ITER nbrIdx, endNbrs;
185   boost::tie(nbrIdx, endNbrs) = at->getOwningMol().getAtomNeighbors(at);
186   while (nbrIdx != endNbrs) {
187     const Atom *nbr = at->getOwningMol()[*nbrIdx];
188     if (nbr->getAtomicNum() != 6 && nbr->getAtomicNum() != 1) {
189       return 1;
190     }
191     ++nbrIdx;
192   }
193   return 0;
194 };
195 
queryAtomNumHeteroatomNbrs(Atom const * at)196 static inline int queryAtomNumHeteroatomNbrs(Atom const *at) {
197   int res = 0;
198   ROMol::ADJ_ITER nbrIdx, endNbrs;
199   boost::tie(nbrIdx, endNbrs) = at->getOwningMol().getAtomNeighbors(at);
200   while (nbrIdx != endNbrs) {
201     const Atom *nbr = at->getOwningMol()[*nbrIdx];
202     if (nbr->getAtomicNum() != 6 && nbr->getAtomicNum() != 1) {
203       ++res;
204     }
205     ++nbrIdx;
206   }
207   return res;
208 };
209 
queryAtomHasAliphaticHeteroatomNbrs(Atom const * at)210 static inline int queryAtomHasAliphaticHeteroatomNbrs(Atom const *at) {
211   ROMol::ADJ_ITER nbrIdx, endNbrs;
212   boost::tie(nbrIdx, endNbrs) = at->getOwningMol().getAtomNeighbors(at);
213   while (nbrIdx != endNbrs) {
214     const Atom *nbr = at->getOwningMol()[*nbrIdx];
215     if ((!nbr->getIsAromatic()) && nbr->getAtomicNum() != 6 &&
216         nbr->getAtomicNum() != 1) {
217       return 1;
218     }
219     ++nbrIdx;
220   }
221   return 0;
222 };
223 
queryAtomNumAliphaticHeteroatomNbrs(Atom const * at)224 static inline int queryAtomNumAliphaticHeteroatomNbrs(Atom const *at) {
225   int res = 0;
226   ROMol::ADJ_ITER nbrIdx, endNbrs;
227   boost::tie(nbrIdx, endNbrs) = at->getOwningMol().getAtomNeighbors(at);
228   while (nbrIdx != endNbrs) {
229     const Atom *nbr = at->getOwningMol()[*nbrIdx];
230     if ((!nbr->getIsAromatic()) && nbr->getAtomicNum() != 6 &&
231         nbr->getAtomicNum() != 1) {
232       ++res;
233     }
234     ++nbrIdx;
235   }
236   return res;
237 };
238 
239 RDKIT_GRAPHMOL_EXPORT unsigned int queryAtomBondProduct(Atom const *at);
240 RDKIT_GRAPHMOL_EXPORT unsigned int queryAtomAllBondProduct(Atom const *at);
241 
242 // -------------------------------------------------
243 // common bond queries
244 
queryBondOrder(Bond const * bond)245 static inline int queryBondOrder(Bond const *bond) {
246   return static_cast<int>(bond->getBondType());
247 };
queryBondIsSingleOrAromatic(Bond const * bond)248 static inline int queryBondIsSingleOrAromatic(Bond const *bond) {
249   return static_cast<int>(bond->getBondType() == Bond::SINGLE ||
250                           bond->getBondType() == Bond::AROMATIC);
251 };
queryBondIsDoubleOrAromatic(Bond const * bond)252 static inline int queryBondIsDoubleOrAromatic(Bond const *bond) {
253   return static_cast<int>(bond->getBondType() == Bond::DOUBLE ||
254                           bond->getBondType() == Bond::AROMATIC);
255 };
queryBondIsSingleOrDouble(Bond const * bond)256 static inline int queryBondIsSingleOrDouble(Bond const *bond) {
257   return static_cast<int>(bond->getBondType() == Bond::SINGLE ||
258                           bond->getBondType() == Bond::DOUBLE);
259 };
queryBondIsSingleOrDoubleOrAromatic(Bond const * bond)260 static inline int queryBondIsSingleOrDoubleOrAromatic(Bond const *bond) {
261   return static_cast<int>(bond->getBondType() == Bond::SINGLE ||
262                           bond->getBondType() == Bond::DOUBLE ||
263                           bond->getBondType() == Bond::AROMATIC);
264 };
queryBondDir(Bond const * bond)265 static inline int queryBondDir(Bond const *bond) {
266   return static_cast<int>(bond->getBondDir());
267 };
queryIsBondInNRings(Bond const * at)268 static inline int queryIsBondInNRings(Bond const *at) {
269   return at->getOwningMol().getRingInfo()->numBondRings(at->getIdx());
270 };
queryBondHasStereo(Bond const * bnd)271 static inline int queryBondHasStereo(Bond const *bnd) {
272   return bnd->getStereo() > Bond::STEREONONE;
273 };
274 
275 // -------------------------------------------------
276 // ring queries
277 
queryIsAtomInNRings(Atom const * at)278 static inline int queryIsAtomInNRings(Atom const *at) {
279   return at->getOwningMol().getRingInfo()->numAtomRings(at->getIdx());
280 };
queryIsAtomInRing(Atom const * at)281 static inline int queryIsAtomInRing(Atom const *at) {
282   return at->getOwningMol().getRingInfo()->numAtomRings(at->getIdx()) != 0;
283 };
queryAtomHasRingBond(Atom const * at)284 static inline int queryAtomHasRingBond(Atom const *at) {
285   ROMol::OBOND_ITER_PAIR atomBonds = at->getOwningMol().getAtomBonds(at);
286   while (atomBonds.first != atomBonds.second) {
287     unsigned int bondIdx =
288         at->getOwningMol().getTopology()[*atomBonds.first]->getIdx();
289     if (at->getOwningMol().getRingInfo()->numBondRings(bondIdx)) {
290       return 1;
291     }
292     ++atomBonds.first;
293   }
294   return 0;
295 };
296 RDKIT_GRAPHMOL_EXPORT int queryIsAtomBridgehead(Atom const *at);
297 
queryIsBondInRing(Bond const * bond)298 static inline int queryIsBondInRing(Bond const *bond) {
299   return bond->getOwningMol().getRingInfo()->numBondRings(bond->getIdx()) != 0;
300 };
queryAtomMinRingSize(Atom const * at)301 static inline int queryAtomMinRingSize(Atom const *at) {
302   return at->getOwningMol().getRingInfo()->minAtomRingSize(at->getIdx());
303 };
queryBondMinRingSize(Bond const * bond)304 static inline int queryBondMinRingSize(Bond const *bond) {
305   return bond->getOwningMol().getRingInfo()->minBondRingSize(bond->getIdx());
306 };
307 
queryAtomRingBondCount(Atom const * at)308 static inline int queryAtomRingBondCount(Atom const *at) {
309   // EFF: cache this result
310   int res = 0;
311   ROMol::OBOND_ITER_PAIR atomBonds = at->getOwningMol().getAtomBonds(at);
312   while (atomBonds.first != atomBonds.second) {
313     unsigned int bondIdx =
314         at->getOwningMol().getTopology()[*atomBonds.first]->getIdx();
315     if (at->getOwningMol().getRingInfo()->numBondRings(bondIdx)) {
316       res++;
317     }
318     ++atomBonds.first;
319   }
320   return res;
321 }
322 
323 template <int tgt>
queryAtomIsInRingOfSize(Atom const * at)324 int queryAtomIsInRingOfSize(Atom const *at) {
325   if (at->getOwningMol().getRingInfo()->isAtomInRingOfSize(at->getIdx(), tgt)) {
326     return tgt;
327   } else {
328     return 0;
329   }
330 };
331 template <int tgt>
queryBondIsInRingOfSize(Bond const * bond)332 int queryBondIsInRingOfSize(Bond const *bond) {
333   if (bond->getOwningMol().getRingInfo()->isBondInRingOfSize(bond->getIdx(),
334                                                              tgt)) {
335     return tgt;
336   } else {
337     return 0;
338   }
339 };
340 
341 template <class T>
342 T *makeAtomSimpleQuery(int what, int func(Atom const *),
343                        const std::string &description = "Atom Simple") {
344   T *res = new T;
345   res->setVal(what);
346   res->setDataFunc(func);
347   res->setDescription(description);
348   return res;
349 }
350 
351 static inline ATOM_RANGE_QUERY *makeAtomRangeQuery(
352     int lower, int upper, bool lowerOpen, bool upperOpen,
353     int func(Atom const *), const std::string &description = "Atom Range") {
354   ATOM_RANGE_QUERY *res = new ATOM_RANGE_QUERY(lower, upper);
355   res->setDataFunc(func);
356   res->setDescription(description);
357   res->setEndsOpen(lowerOpen, upperOpen);
358   return res;
359 }
360 
361 //! returns a Query for matching atomic number
362 template <class T>
makeAtomNumQuery(int what,const std::string & descr)363 T *makeAtomNumQuery(int what, const std::string &descr) {
364   return makeAtomSimpleQuery<T>(what, queryAtomNum, descr);
365 }
366 //! \overload
367 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomNumQuery(int what);
368 
369 //! returns a Query for matching atomic number and aromaticity
370 template <class T>
makeAtomTypeQuery(int num,int aromatic,const std::string & descr)371 T *makeAtomTypeQuery(int num, int aromatic, const std::string &descr) {
372   return makeAtomSimpleQuery<T>(makeAtomType(num, aromatic), queryAtomType,
373                                 descr);
374 }
375 //! \overload
376 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomTypeQuery(int num,
377                                                            int aromatic);
378 
379 //! returns a Query for matching implicit valence
380 template <class T>
makeAtomImplicitValenceQuery(int what,const std::string & descr)381 T *makeAtomImplicitValenceQuery(int what, const std::string &descr) {
382   return makeAtomSimpleQuery<T>(what, queryAtomImplicitValence, descr);
383 }
384 //! \overload
385 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomImplicitValenceQuery(int what);
386 
387 //! returns a Query for matching explicit valence
388 template <class T>
makeAtomExplicitValenceQuery(int what,const std::string & descr)389 T *makeAtomExplicitValenceQuery(int what, const std::string &descr) {
390   return makeAtomSimpleQuery<T>(what, queryAtomExplicitValence, descr);
391 }
392 //! \overload
393 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomExplicitValenceQuery(int what);
394 
395 //! returns a Query for matching total valence
396 template <class T>
makeAtomTotalValenceQuery(int what,const std::string & descr)397 T *makeAtomTotalValenceQuery(int what, const std::string &descr) {
398   return makeAtomSimpleQuery<T>(what, queryAtomTotalValence, descr);
399 }
400 //! \overload
401 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomTotalValenceQuery(int what);
402 
403 //! returns a Query for matching explicit degree
404 template <class T>
makeAtomExplicitDegreeQuery(int what,const std::string & descr)405 T *makeAtomExplicitDegreeQuery(int what, const std::string &descr) {
406   return makeAtomSimpleQuery<T>(what, queryAtomExplicitDegree, descr);
407 }
408 //! \overload
409 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomExplicitDegreeQuery(int what);
410 
411 //! returns a Query for matching atomic degree
412 template <class T>
makeAtomTotalDegreeQuery(int what,const std::string & descr)413 T *makeAtomTotalDegreeQuery(int what, const std::string &descr) {
414   return makeAtomSimpleQuery<T>(what, queryAtomTotalDegree, descr);
415 }
416 //! \overload
417 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomTotalDegreeQuery(int what);
418 
419 //! returns a Query for matching heavy atom degree
420 template <class T>
makeAtomHeavyAtomDegreeQuery(int what,const std::string & descr)421 T *makeAtomHeavyAtomDegreeQuery(int what, const std::string &descr) {
422   return makeAtomSimpleQuery<T>(what, queryAtomHeavyAtomDegree, descr);
423 }
424 //! \overload
425 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomHeavyAtomDegreeQuery(int what);
426 
427 //! returns a Query for matching hydrogen count
428 template <class T>
makeAtomHCountQuery(int what,const std::string & descr)429 T *makeAtomHCountQuery(int what, const std::string &descr) {
430   return makeAtomSimpleQuery<T>(what, queryAtomHCount, descr);
431 }
432 //! \overload
433 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomHCountQuery(int what);
434 
435 //! returns a Query for matching ring atoms
436 template <class T>
makeAtomHasImplicitHQuery(const std::string & descr)437 T *makeAtomHasImplicitHQuery(const std::string &descr) {
438   return makeAtomSimpleQuery<T>(true, queryAtomHasImplicitH, descr);
439 }
440 //! \overload
441 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomHasImplicitHQuery();
442 
443 //! returns a Query for matching implicit hydrogen count
444 template <class T>
makeAtomImplicitHCountQuery(int what,const std::string & descr)445 T *makeAtomImplicitHCountQuery(int what, const std::string &descr) {
446   return makeAtomSimpleQuery<T>(what, queryAtomImplicitHCount, descr);
447 }
448 //! \overload
449 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomImplicitHCountQuery(int what);
450 
451 //! returns a Query for matching the \c isAromatic flag
452 template <class T>
makeAtomAromaticQuery(const std::string & descr)453 T *makeAtomAromaticQuery(const std::string &descr) {
454   return makeAtomSimpleQuery<T>(true, queryAtomAromatic, descr);
455 }
456 //! \overload
457 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomAromaticQuery();
458 
459 //! returns a Query for matching aliphatic atoms
460 template <class T>
makeAtomAliphaticQuery(const std::string & descr)461 T *makeAtomAliphaticQuery(const std::string &descr) {
462   return makeAtomSimpleQuery<T>(true, queryAtomAliphatic, descr);
463 }
464 //! \overload
465 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomAliphaticQuery();
466 
467 //! returns a Query for matching atoms with a particular mass
468 template <class T>
makeAtomMassQuery(int what,const std::string & descr)469 T *makeAtomMassQuery(int what, const std::string &descr) {
470   return makeAtomSimpleQuery<T>(massIntegerConversionFactor * what,
471                                 queryAtomMass, descr);
472 }
473 //! \overload
474 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomMassQuery(int what);
475 
476 //! returns a Query for matching atoms with a particular isotope
477 template <class T>
makeAtomIsotopeQuery(int what,const std::string & descr)478 T *makeAtomIsotopeQuery(int what, const std::string &descr) {
479   return makeAtomSimpleQuery<T>(what, queryAtomIsotope, descr);
480 }
481 //! \overload
482 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomIsotopeQuery(int what);
483 
484 //! returns a Query for matching formal charge
485 template <class T>
makeAtomFormalChargeQuery(int what,const std::string & descr)486 T *makeAtomFormalChargeQuery(int what, const std::string &descr) {
487   return makeAtomSimpleQuery<T>(what, queryAtomFormalCharge, descr);
488 }
489 //! \overload
490 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomFormalChargeQuery(int what);
491 
492 //! returns a Query for matching negative formal charges (i.e. a query val of 1
493 //! matches a formal charge of -1)
494 template <class T>
makeAtomNegativeFormalChargeQuery(int what,const std::string & descr)495 T *makeAtomNegativeFormalChargeQuery(int what, const std::string &descr) {
496   return makeAtomSimpleQuery<T>(what, queryAtomNegativeFormalCharge, descr);
497 }
498 //! \overload
499 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomNegativeFormalChargeQuery(
500     int what);
501 
502 //! returns a Query for matching hybridization
503 template <class T>
makeAtomHybridizationQuery(int what,const std::string & descr)504 T *makeAtomHybridizationQuery(int what, const std::string &descr) {
505   return makeAtomSimpleQuery<T>(what, queryAtomHybridization, descr);
506 }
507 //! \overload
508 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomHybridizationQuery(int what);
509 
510 //! returns a Query for matching the number of radical electrons
511 template <class T>
makeAtomNumRadicalElectronsQuery(int what,const std::string & descr)512 T *makeAtomNumRadicalElectronsQuery(int what, const std::string &descr) {
513   return makeAtomSimpleQuery<T>(what, queryAtomNumRadicalElectrons, descr);
514 }
515 //! \overload
516 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomNumRadicalElectronsQuery(
517     int what);
518 
519 //! returns a Query for matching whether or not chirality has been set on the
520 //! atom
521 template <class T>
makeAtomHasChiralTagQuery(const std::string & descr)522 T *makeAtomHasChiralTagQuery(const std::string &descr) {
523   return makeAtomSimpleQuery<T>(true, queryAtomHasChiralTag, descr);
524 }
525 //! \overloadquery
526 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomHasChiralTagQuery();
527 
528 //! returns a Query for matching whether or not a potentially chiral atom is
529 //! missing a chiral tag
530 template <class T>
makeAtomMissingChiralTagQuery(const std::string & descr)531 T *makeAtomMissingChiralTagQuery(const std::string &descr) {
532   return makeAtomSimpleQuery<T>(true, queryAtomMissingChiralTag, descr);
533 }
534 //! \overloadquery
535 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomMissingChiralTagQuery();
536 
537 //! returns a Query for matching atoms with unsaturation:
538 template <class T>
makeAtomUnsaturatedQuery(const std::string & descr)539 T *makeAtomUnsaturatedQuery(const std::string &descr) {
540   return makeAtomSimpleQuery<T>(true, queryAtomUnsaturated, descr);
541 }
542 //! \overload
543 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomUnsaturatedQuery();
544 
545 //! returns a Query for matching ring atoms
546 template <class T>
makeAtomInRingQuery(const std::string & descr)547 T *makeAtomInRingQuery(const std::string &descr) {
548   return makeAtomSimpleQuery<T>(true, queryIsAtomInRing, descr);
549 }
550 //! \overload
551 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomInRingQuery();
552 
553 //! returns a Query for matching atoms in a particular number of rings
554 template <class T>
makeAtomInNRingsQuery(int what,const std::string & descr)555 T *makeAtomInNRingsQuery(int what, const std::string &descr) {
556   return makeAtomSimpleQuery<T>(what, queryIsAtomInNRings, descr);
557 }
558 //! \overload
559 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomInNRingsQuery(int what);
560 
561 //! returns a Query for matching atoms in rings of a particular size
562 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomInRingOfSizeQuery(int tgt);
563 
564 //! returns a Query for matching an atom's minimum ring size
565 template <class T>
makeAtomMinRingSizeQuery(int tgt,const std::string & descr)566 T *makeAtomMinRingSizeQuery(int tgt, const std::string &descr) {
567   return makeAtomSimpleQuery<T>(tgt, queryAtomMinRingSize, descr);
568 }
569 //! \overload
570 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomMinRingSizeQuery(int tgt);
571 
572 //! returns a Query for matching atoms with a particular number of ring bonds
573 template <class T>
makeAtomRingBondCountQuery(int what,const std::string & descr)574 T *makeAtomRingBondCountQuery(int what, const std::string &descr) {
575   return makeAtomSimpleQuery<T>(what, queryAtomRingBondCount, descr);
576 }
577 //! \overload
578 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomRingBondCountQuery(int what);
579 
580 //! returns a Query for matching generic A atoms (heavy atoms)
581 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAAtomQuery();
582 //! returns a Query for matching generic AH atoms (any atom)
583 RDKIT_GRAPHMOL_EXPORT ATOM_NULL_QUERY *makeAHAtomQuery();
584 //! returns a Query for matching generic Q atoms (heteroatoms)
585 RDKIT_GRAPHMOL_EXPORT ATOM_OR_QUERY *makeQAtomQuery();
586 //! returns a Query for matching generic QH atoms (heteroatom or H)
587 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeQHAtomQuery();
588 //! returns a Query for matching generic X atoms (halogens)
589 RDKIT_GRAPHMOL_EXPORT ATOM_OR_QUERY *makeXAtomQuery();
590 //! returns a Query for matching generic XH atoms (halogen or H)
591 RDKIT_GRAPHMOL_EXPORT ATOM_OR_QUERY *makeXHAtomQuery();
592 //! returns a Query for matching generic M atoms (metals)
593 RDKIT_GRAPHMOL_EXPORT ATOM_OR_QUERY *makeMAtomQuery();
594 //! returns a Query for matching generic MH atoms (metals or H)
595 RDKIT_GRAPHMOL_EXPORT ATOM_OR_QUERY *makeMHAtomQuery();
596 
597 //! returns a Query for matching atoms that have ring bonds
598 template <class T>
makeAtomHasRingBondQuery(const std::string & descr)599 T *makeAtomHasRingBondQuery(const std::string &descr) {
600   return makeAtomSimpleQuery<T>(1, queryAtomHasRingBond, descr);
601 }
602 //! \overload
603 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomHasRingBondQuery();
604 
605 //! returns a Query for matching the number of heteroatom neighbors
606 template <class T>
makeAtomNumHeteroatomNbrsQuery(int what,const std::string & descr)607 T *makeAtomNumHeteroatomNbrsQuery(int what, const std::string &descr) {
608   return makeAtomSimpleQuery<T>(what, queryAtomNumHeteroatomNbrs, descr);
609 }
610 //! \overload
611 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomNumHeteroatomNbrsQuery(
612     int what);
613 
614 //! returns a Query for matching atoms that have heteroatom neighbors
615 template <class T>
makeAtomHasHeteroatomNbrsQuery(const std::string & descr)616 T *makeAtomHasHeteroatomNbrsQuery(const std::string &descr) {
617   return makeAtomSimpleQuery<T>(1, queryAtomHasHeteroatomNbrs, descr);
618 }
619 //! \overload
620 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomHasHeteroatomNbrsQuery();
621 
622 //! returns a Query for matching the number of aliphatic heteroatom neighbors
623 template <class T>
makeAtomNumAliphaticHeteroatomNbrsQuery(int what,const std::string & descr)624 T *makeAtomNumAliphaticHeteroatomNbrsQuery(int what, const std::string &descr) {
625   return makeAtomSimpleQuery<T>(what, queryAtomNumAliphaticHeteroatomNbrs,
626                                 descr);
627 }
628 //! \overload
629 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *
630 makeAtomNumAliphaticHeteroatomNbrsQuery(int what);
631 
632 //! returns a Query for matching atoms that have heteroatom neighbors
633 template <class T>
makeAtomHasAliphaticHeteroatomNbrsQuery(const std::string & descr)634 T *makeAtomHasAliphaticHeteroatomNbrsQuery(const std::string &descr) {
635   return makeAtomSimpleQuery<T>(1, queryAtomHasAliphaticHeteroatomNbrs, descr);
636 }
637 //! \overload
638 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *
639 makeAtomHasAliphaticHeteroatomNbrsQuery();
640 
641 //! returns a Query for matching the number of non-hydrogen neighbors
642 template <class T>
makeAtomNonHydrogenDegreeQuery(int what,const std::string & descr)643 T *makeAtomNonHydrogenDegreeQuery(int what, const std::string &descr) {
644   return makeAtomSimpleQuery<T>(what, queryAtomNonHydrogenDegree, descr);
645 }
646 //! \overload
647 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomNonHydrogenDegreeQuery(
648     int what);
649 
650 //! returns a Query for matching bridgehead atoms
651 template <class T>
makeAtomIsBridgeheadQuery(const std::string & descr)652 T *makeAtomIsBridgeheadQuery(const std::string &descr) {
653   return makeAtomSimpleQuery<T>(true, queryIsAtomBridgehead, descr);
654 }
655 //! \overload
656 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomIsBridgeheadQuery();
657 
658 //! returns a Query for matching bond orders
659 RDKIT_GRAPHMOL_EXPORT BOND_EQUALS_QUERY *makeBondOrderEqualsQuery(
660     Bond::BondType what);
661 //! returns a Query for unspecified SMARTS bonds
662 RDKIT_GRAPHMOL_EXPORT BOND_EQUALS_QUERY *makeSingleOrAromaticBondQuery();
663 //! returns a Query for double|aromatic bonds
664 RDKIT_GRAPHMOL_EXPORT BOND_EQUALS_QUERY *makeDoubleOrAromaticBondQuery();
665 //! returns a Query for single|double bonds
666 RDKIT_GRAPHMOL_EXPORT BOND_EQUALS_QUERY *makeSingleOrDoubleBondQuery();
667 //! returns a Query for tautomeric bonds
668 RDKIT_GRAPHMOL_EXPORT BOND_EQUALS_QUERY *
669 makeSingleOrDoubleOrAromaticBondQuery();
670 
671 //! returns a Query for matching bond directions
672 RDKIT_GRAPHMOL_EXPORT BOND_EQUALS_QUERY *makeBondDirEqualsQuery(
673     Bond::BondDir what);
674 //! returns a Query for matching bonds with stereo set
675 RDKIT_GRAPHMOL_EXPORT BOND_EQUALS_QUERY *makeBondHasStereoQuery();
676 //! returns a Query for matching ring bonds
677 RDKIT_GRAPHMOL_EXPORT BOND_EQUALS_QUERY *makeBondIsInRingQuery();
678 //! returns a Query for matching bonds in rings of a particular size
679 RDKIT_GRAPHMOL_EXPORT BOND_EQUALS_QUERY *makeBondInRingOfSizeQuery(int what);
680 //! returns a Query for matching a bond's minimum ring size
681 RDKIT_GRAPHMOL_EXPORT BOND_EQUALS_QUERY *makeBondMinRingSizeQuery(int what);
682 //! returns a Query for matching bonds in a particular number of rings
683 RDKIT_GRAPHMOL_EXPORT BOND_EQUALS_QUERY *makeBondInNRingsQuery(int tgt);
684 
685 //! returns a Query for matching any bond
686 RDKIT_GRAPHMOL_EXPORT BOND_NULL_QUERY *makeBondNullQuery();
687 //! returns a Query for matching any atom
688 RDKIT_GRAPHMOL_EXPORT ATOM_NULL_QUERY *makeAtomNullQuery();
689 
queryAtomRingMembership(Atom const * at)690 static inline int queryAtomRingMembership(Atom const *at) {
691   return static_cast<int>(
692       at->getOwningMol().getRingInfo()->numAtomRings(at->getIdx()));
693 }
694 // I'm pretty sure that this typedef shouldn't be necessary,
695 // but VC++ generates a warning about const Atom const * in
696 // the definition of Match, then complains about an override
697 // that differs only by const/volatile (c4301), then generates
698 // incorrect code if we don't do this... so let's do it.
699 typedef Atom const *ConstAtomPtr;
700 
701 class RDKIT_GRAPHMOL_EXPORT AtomRingQuery
702     : public Queries::EqualityQuery<int, ConstAtomPtr, true> {
703  public:
AtomRingQuery()704   AtomRingQuery() : Queries::EqualityQuery<int, ConstAtomPtr, true>(-1) {
705     // default is to just do a number of rings query:
706     this->setDescription("AtomInNRings");
707     this->setDataFunc(queryAtomRingMembership);
708   };
AtomRingQuery(int v)709   explicit AtomRingQuery(int v)
710       : Queries::EqualityQuery<int, ConstAtomPtr, true>(v) {
711     // default is to just do a number of rings query:
712     this->setDescription("AtomInNRings");
713     this->setDataFunc(queryAtomRingMembership);
714   };
715 
Match(const ConstAtomPtr what)716   virtual bool Match(const ConstAtomPtr what) const {
717     int v = this->TypeConvert(what, Queries::Int2Type<true>());
718     bool res;
719     if (this->d_val < 0) {
720       res = v != 0;
721     } else {
722       res = !Queries::queryCmp(v, this->d_val, this->d_tol);
723     }
724     if (this->getNegation()) {
725       res = !res;
726     }
727     return res;
728   }
729 
730   //! returns a copy of this query
copy()731   Queries::Query<int, ConstAtomPtr, true> *copy() const {
732     AtomRingQuery *res = new AtomRingQuery(this->d_val);
733     res->setNegation(getNegation());
734     res->setTol(this->getTol());
735     res->d_description = this->d_description;
736     res->d_dataFunc = this->d_dataFunc;
737     return res;
738   }
739 };
740 
741 //! allows use of recursive structure queries (e.g. recursive SMARTS)
742 class RDKIT_GRAPHMOL_EXPORT RecursiveStructureQuery
743     : public Queries::SetQuery<int, Atom const *, true> {
744  public:
RecursiveStructureQuery()745   RecursiveStructureQuery() : Queries::SetQuery<int, Atom const *, true>() {
746     setDataFunc(getAtIdx);
747     setDescription("RecursiveStructure");
748   };
749   //! initialize from an ROMol pointer
750   /*!
751     <b>Notes</b>
752       - this takes over ownership of the pointer
753   */
754   RecursiveStructureQuery(ROMol const *query, unsigned int serialNumber = 0)
755       : Queries::SetQuery<int, Atom const *, true>(),
756         d_serialNumber(serialNumber) {
757     setQueryMol(query);
758     setDataFunc(getAtIdx);
759     setDescription("RecursiveStructure");
760   };
761   //! returns the index of an atom
getAtIdx(Atom const * at)762   static inline int getAtIdx(Atom const *at) {
763     PRECONDITION(at, "bad atom argument");
764     return at->getIdx();
765   };
766 
767   //! sets the molecule we'll use recursively
768   /*!
769     <b>Notes</b>
770       - this takes over ownership of the pointer
771   */
setQueryMol(ROMol const * query)772   void setQueryMol(ROMol const *query) { dp_queryMol.reset(query); }
773   //! returns a pointer to our query molecule
getQueryMol()774   ROMol const *getQueryMol() const { return dp_queryMol.get(); };
775 
776   //! returns a copy of this query
copy()777   Queries::Query<int, Atom const *, true> *copy() const {
778     RecursiveStructureQuery *res = new RecursiveStructureQuery();
779     res->dp_queryMol.reset(new ROMol(*dp_queryMol, true));
780 
781     std::set<int>::const_iterator i;
782     for (i = d_set.begin(); i != d_set.end(); i++) {
783       res->insert(*i);
784     }
785     res->setNegation(getNegation());
786     res->d_description = d_description;
787     res->d_serialNumber = d_serialNumber;
788     return res;
789   }
getSerialNumber()790   unsigned int getSerialNumber() const { return d_serialNumber; };
791 
792 #ifdef RDK_THREADSAFE_SSS
793   std::mutex d_mutex;
794 #endif
795  private:
796   boost::shared_ptr<const ROMol> dp_queryMol;
797   unsigned int d_serialNumber{0};
798 };
799 
800 template <typename T>
nullDataFun(T)801 int nullDataFun(T) {
802   return 1;
803 }
804 template <typename T>
nullQueryFun(T)805 bool nullQueryFun(T) {
806   return true;
807 }
808 
809 typedef Bond const *ConstBondPtr;
810 
811 // ! Query whether an atom has a property
812 template <class TargetPtr>
813 class HasPropQuery : public Queries::EqualityQuery<int, TargetPtr, true> {
814   std::string propname;
815 
816  public:
HasPropQuery()817   HasPropQuery() : Queries::EqualityQuery<int, TargetPtr, true>(), propname() {
818     // default is to just do a number of rings query:
819     this->setDescription("AtomHasProp");
820     this->setDataFunc(0);
821   };
HasPropQuery(const std::string & v)822   explicit HasPropQuery(const std::string &v)
823       : Queries::EqualityQuery<int, TargetPtr, true>(), propname(v) {
824     // default is to just do a number of rings query:
825     this->setDescription("AtomHasProp");
826     this->setDataFunc(nullptr);
827   };
828 
Match(const TargetPtr what)829   virtual bool Match(const TargetPtr what) const {
830     bool res = what->hasProp(propname);
831     if (this->getNegation()) {
832       res = !res;
833     }
834     return res;
835   }
836 
837   //! returns a copy of this query
copy()838   Queries::Query<int, TargetPtr, true> *copy() const {
839     HasPropQuery *res = new HasPropQuery(this->propname);
840     res->setNegation(this->getNegation());
841     res->d_description = this->d_description;
842     return res;
843   }
844 };
845 
846 typedef Queries::EqualityQuery<int, Atom const *, true> ATOM_PROP_QUERY;
847 typedef Queries::EqualityQuery<int, Bond const *, true> BOND_PROP_QUERY;
848 
849 //! returns a Query for matching atoms that have a particular property
850 template <class Target>
makeHasPropQuery(const std::string & property)851 Queries::EqualityQuery<int, const Target *, true> *makeHasPropQuery(
852     const std::string &property) {
853   return new HasPropQuery<const Target *>(property);
854 }
855 
856 // ! Query whether an atom has a property with a value
857 template <class TargetPtr, class T>
858 class HasPropWithValueQuery
859     : public Queries::EqualityQuery<int, TargetPtr, true> {
860   std::string propname;
861   T val;
862   T tolerance;
863 
864  public:
HasPropWithValueQuery()865   HasPropWithValueQuery()
866       : Queries::EqualityQuery<int, TargetPtr, true>(), propname(), val() {
867     // default is to just do a number of rings query:
868     this->setDescription("HasPropWithValue");
869     this->setDataFunc(0);
870   };
871   explicit HasPropWithValueQuery(const std::string &prop, const T &v,
872                                  const T &tol = 0.0)
873       : Queries::EqualityQuery<int, TargetPtr, true>(),
874         propname(prop),
875         val(v),
876         tolerance(tol) {
877     // default is to just do a number of rings query:
878     this->setDescription("HasPropWithValue");
879     this->setDataFunc(nullptr);
880   };
881 
Match(const TargetPtr what)882   virtual bool Match(const TargetPtr what) const {
883     bool res = what->hasProp(propname);
884     if (res) {
885       try {
886         T atom_val = what->template getProp<T>(propname);
887         res = Queries::queryCmp(atom_val, this->val, this->tolerance) == 0;
888       } catch (KeyErrorException &) {
889         res = false;
890       } catch (boost::bad_any_cast &) {
891         res = false;
892       }
893 #ifdef __GNUC__
894 #if (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 2))
895       catch (...) {
896         // catch all -- this is currently necessary to
897         //  trap some bugs in boost+gcc configurations
898         //  Normally, this is not the correct thing to
899         //  do, but the only exception above is due
900         //  to the boost any_cast which is trapped
901         //  by the Boost python wrapper when it shouldn't
902         //  be.
903         res = false;
904       }
905 #endif
906 #endif
907     }
908     if (this->getNegation()) {
909       res = !res;
910     }
911     return res;
912   }
913 
914   //! returns a copy of this query
copy()915   Queries::Query<int, TargetPtr, true> *copy() const {
916     HasPropWithValueQuery *res =
917         new HasPropWithValueQuery(this->propname, this->val, this->tolerance);
918     res->setNegation(this->getNegation());
919     res->d_description = this->d_description;
920     return res;
921   }
922 };
923 
924 template <class TargetPtr>
925 class HasPropWithValueQuery<TargetPtr, std::string>
926     : public Queries::EqualityQuery<int, TargetPtr, true> {
927   std::string propname;
928   std::string val;
929 
930  public:
HasPropWithValueQuery()931   HasPropWithValueQuery()
932       : Queries::EqualityQuery<int, TargetPtr, true>(), propname(), val() {
933     // default is to just do a number of rings query:
934     this->setDescription("HasPropWithValue");
935     this->setDataFunc(0);
936   };
937   explicit HasPropWithValueQuery(const std::string &prop, const std::string &v,
938                                  const std::string &tol = "")
939       : Queries::EqualityQuery<int, TargetPtr, true>(), propname(prop), val(v) {
940     RDUNUSED_PARAM(tol);
941     // default is to just do a number of rings query:
942     this->setDescription("HasPropWithValue");
943     this->setDataFunc(nullptr);
944   };
945 
Match(const TargetPtr what)946   virtual bool Match(const TargetPtr what) const {
947     bool res = what->hasProp(propname);
948     if (res) {
949       try {
950         std::string atom_val = what->template getProp<std::string>(propname);
951         res = atom_val == this->val;
952       } catch (KeyErrorException &) {
953         res = false;
954       } catch (boost::bad_any_cast &) {
955         res = false;
956       }
957 #ifdef __GNUC__
958 #if (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 2))
959       catch (...) {
960         // catch all -- this is currently necessary to
961         //  trap some bugs in boost+gcc configurations
962         //  Normally, this is not the correct thing to
963         //  do, but the only exception above is due
964         //  to the boost any_cast which is trapped
965         //  by the Boost python wrapper when it shouldn't
966         //  be.
967         res = false;
968       }
969 #endif
970 #endif
971     }
972     if (this->getNegation()) {
973       res = !res;
974     }
975     return res;
976   }
977 
978   //! returns a copy of this query
copy()979   Queries::Query<int, TargetPtr, true> *copy() const {
980     HasPropWithValueQuery<TargetPtr, std::string> *res =
981         new HasPropWithValueQuery<TargetPtr, std::string>(this->propname,
982                                                           this->val);
983     res->setNegation(this->getNegation());
984     res->d_description = this->d_description;
985     return res;
986   }
987 };
988 
989 template <class TargetPtr>
990 class HasPropWithValueQuery<TargetPtr, ExplicitBitVect>
991     : public Queries::EqualityQuery<int, TargetPtr, true> {
992   std::string propname;
993   ExplicitBitVect val;
994   float tol{0.0};
995 
996  public:
HasPropWithValueQuery()997   HasPropWithValueQuery()
998       : Queries::EqualityQuery<int, TargetPtr, true>(), propname(), val() {
999     this->setDescription("HasPropWithValue");
1000     this->setDataFunc(0);
1001   };
1002 
1003   explicit HasPropWithValueQuery(const std::string &prop,
1004                                  const ExplicitBitVect &v, float tol = 0.0)
1005       : Queries::EqualityQuery<int, TargetPtr, true>(),
1006         propname(prop),
1007         val(v),
1008         tol(tol) {
1009     this->setDescription("HasPropWithValue");
1010     this->setDataFunc(nullptr);
1011   };
1012 
Match(const TargetPtr what)1013   virtual bool Match(const TargetPtr what) const {
1014     bool res = what->hasProp(propname);
1015     if (res) {
1016       try {
1017         const ExplicitBitVect &bv =
1018             what->template getProp<const ExplicitBitVect &>(propname);
1019         const double tani = TanimotoSimilarity(val, bv);
1020         res = (1.0 - tani) <= tol;
1021       } catch (KeyErrorException &) {
1022         res = false;
1023       } catch (boost::bad_any_cast &) {
1024         res = false;
1025       }
1026 #ifdef __GNUC__
1027 #if (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 2))
1028       catch (...) {
1029         // catch all -- this is currently necessary to
1030         //  trap some bugs in boost+gcc configurations
1031         //  Normally, this is not the correct thing to
1032         //  do, but the only exception above is due
1033         //  to the boost any_cast which is trapped
1034         //  by the Boost python wrapper when it shouldn't
1035         //  be.
1036         res = false;
1037       }
1038 #endif
1039 #endif
1040     }
1041     if (this->getNegation()) {
1042       res = !res;
1043     }
1044     return res;
1045   }
1046 
1047   //! returns a copy of this query
copy()1048   Queries::Query<int, TargetPtr, true> *copy() const {
1049     HasPropWithValueQuery<TargetPtr, ExplicitBitVect> *res =
1050         new HasPropWithValueQuery<TargetPtr, ExplicitBitVect>(
1051             this->propname, this->val, this->tol);
1052     res->setNegation(this->getNegation());
1053     res->d_description = this->d_description;
1054     return res;
1055   }
1056 };
1057 
1058 template <class Target, class T>
1059 Queries::EqualityQuery<int, const Target *, true> *makePropQuery(
1060     const std::string &propname, const T &val, const T &tolerance = T()) {
1061   return new HasPropWithValueQuery<const Target *, T>(propname, val, tolerance);
1062 }
1063 
1064 template <class Target>
1065 Queries::EqualityQuery<int, const Target *, true> *makePropQuery(
1066     const std::string &propname, const ExplicitBitVect &val,
1067     float tolerance = 0.0) {
1068   return new HasPropWithValueQuery<const Target *, ExplicitBitVect>(
1069       propname, val, tolerance);
1070 }
1071 
1072 RDKIT_GRAPHMOL_EXPORT bool isComplexQuery(const Bond *b);
1073 RDKIT_GRAPHMOL_EXPORT bool isComplexQuery(const Atom *a);
1074 RDKIT_GRAPHMOL_EXPORT bool isAtomAromatic(const Atom *a);
1075 RDKIT_GRAPHMOL_EXPORT bool isAtomListQuery(const Atom *a);
1076 RDKIT_GRAPHMOL_EXPORT void getAtomListQueryVals(const Atom::QUERYATOM_QUERY *q,
1077                                                 std::vector<int> &vals);
1078 
1079 namespace QueryOps {
1080 RDKIT_GRAPHMOL_EXPORT void completeMolQueries(
1081     RWMol *mol, unsigned int magicVal = 0xDEADBEEF);
1082 RDKIT_GRAPHMOL_EXPORT Atom *replaceAtomWithQueryAtom(RWMol *mol, Atom *atom);
1083 
1084 RDKIT_GRAPHMOL_EXPORT bool hasBondTypeQuery(
1085     const Queries::Query<int, Bond const *, true> &qry);
hasBondTypeQuery(const Bond & bond)1086 inline bool hasBondTypeQuery(const Bond &bond) {
1087   if (!bond.hasQuery()) {
1088     return false;
1089   }
1090   return hasBondTypeQuery(*bond.getQuery());
1091 }
1092 RDKIT_GRAPHMOL_EXPORT bool hasComplexBondTypeQuery(
1093     const Queries::Query<int, Bond const *, true> &qry);
hasComplexBondTypeQuery(const Bond & bond)1094 inline bool hasComplexBondTypeQuery(const Bond &bond) {
1095   if (!bond.hasQuery()) {
1096     return false;
1097   }
1098   return hasComplexBondTypeQuery(*bond.getQuery());
1099 }
1100 
1101 }  // namespace QueryOps
1102 }  // namespace RDKit
1103 #endif
1104