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