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