1 //
2 //  Copyright (C) 2001-2017 Greg Landrum and Rational Discovery LLC
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 #include <RDGeneral/export.h>
11 #ifndef _RD_QUERYATOM_H_
12 #define _RD_QUERYATOM_H_
13 
14 #include "Atom.h"
15 #include <Query/QueryObjects.h>
16 #include <GraphMol/QueryOps.h>
17 
18 namespace RDKit {
19 
20 //! Class for storing atomic queries
21 /*!
22   QueryAtom objects are derived from Atom objects, so they can be
23   added to molecules and the like, but they have much fancier
24   querying capabilities.
25 
26  */
27 class RDKIT_GRAPHMOL_EXPORT QueryAtom : public Atom {
28  public:
29   typedef Queries::Query<int, Atom const *, true> QUERYATOM_QUERY;
30 
QueryAtom()31   QueryAtom() : Atom(){};
QueryAtom(int num)32   explicit QueryAtom(int num) : Atom(num), dp_query(makeAtomNumQuery(num)){};
QueryAtom(const Atom & other)33   explicit QueryAtom(const Atom &other)
34       : Atom(other), dp_query(makeAtomNumQuery(other.getAtomicNum())) {
35     if (other.getIsotope()) {
36       this->expandQuery(makeAtomIsotopeQuery(other.getIsotope()),
37                         Queries::CompositeQueryType::COMPOSITE_AND);
38     }
39     if (other.getFormalCharge()) {
40       this->expandQuery(makeAtomFormalChargeQuery(other.getFormalCharge()),
41                         Queries::CompositeQueryType::COMPOSITE_AND);
42     }
43     if (other.getNumRadicalElectrons()) {
44       this->expandQuery(
45           makeAtomNumRadicalElectronsQuery(other.getNumRadicalElectrons()),
46           Queries::CompositeQueryType::COMPOSITE_AND);
47     }
48   };
QueryAtom(const QueryAtom & other)49   QueryAtom(const QueryAtom &other) : Atom(other) {
50     dp_query = other.dp_query->copy();
51   };
52   QueryAtom &operator=(const QueryAtom &other) {
53     if (this == &other) return *this;
54     Atom::operator=(other);
55     delete dp_query;
56     dp_query = other.dp_query->copy();
57     return *this;
58   }
59   ~QueryAtom();
60 
61   //! returns a copy of this query, owned by the caller
62   Atom *copy() const;
63 
64   // This method can be used to distinguish query atoms from standard atoms:
hasQuery()65   bool hasQuery() const { return dp_query != nullptr; };
66 
67   //! replaces our current query with the value passed in
setQuery(QUERYATOM_QUERY * what)68   void setQuery(QUERYATOM_QUERY *what) {
69     delete dp_query;
70     dp_query = what;
71   }
72   //! returns our current query
getQuery()73   QUERYATOM_QUERY *getQuery() const { return dp_query; };
74 
75   //! expands our current query
76   /*!
77     \param what          the Queries::Query to be added. The ownership of
78                          the query is passed to the current object, where it
79                          might be deleted, so that the pointer should not be
80                          used again in the calling code.
81     \param how           the operator to be used in the expansion
82     \param maintainOrder (optional) flags whether the relative order of
83                          the queries needs to be maintained, if this is
84                          false, the order is reversed
85     <b>Notes:</b>
86       - \c what should probably be constructed using one of the functions
87          defined in QueryOps.h
88       - the \c maintainOrder option can be useful because the combination
89         operators short circuit when possible.
90 
91   */
92   void expandQuery(QUERYATOM_QUERY *what,
93                    Queries::CompositeQueryType how = Queries::COMPOSITE_AND,
94                    bool maintainOrder = true);
95 
96   //! returns true if we match Atom \c what
97   bool Match(Atom const *what) const;
98 
99   //! returns true if our query details match those of QueryAtom \c what
100   bool QueryMatch(QueryAtom const *what) const;
101 
102  private:
103   QUERYATOM_QUERY *dp_query{nullptr};
104 
105 };  // end o' class
106 
107 namespace detail {
qhelper(Atom::QUERYATOM_QUERY * q,unsigned int depth)108 inline std::string qhelper(Atom::QUERYATOM_QUERY *q, unsigned int depth) {
109   std::string res = "";
110   if (q) {
111     for (unsigned int i = 0; i < depth; ++i) res += "  ";
112     res += q->getFullDescription() + "\n";
113     for (Atom::QUERYATOM_QUERY::CHILD_VECT_CI ci = q->beginChildren();
114          ci != q->endChildren(); ++ci) {
115       res += qhelper((*ci).get(), depth + 1);
116     }
117   }
118   return res;
119 }
120 }  // namespace detail
describeQuery(const Atom * atom)121 inline std::string describeQuery(const Atom *atom) {
122   PRECONDITION(atom, "bad atom");
123   std::string res = "";
124   if (atom->hasQuery()) {
125     res = detail::qhelper(atom->getQuery(), 0);
126   }
127   return res;
128 }
129 
130 };  // namespace RDKit
131 
132 #endif
133