Coverage Report

Created: 2026-03-31 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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