diff --git a/include/openbabel/atom.h b/include/openbabel/atom.h index 450a5b843..cc234d44a 100644 --- a/include/openbabel/atom.h +++ b/include/openbabel/atom.h @@ -65,6 +65,62 @@ namespace OpenBabel if (value) SetFlag(X); \ else UnsetFlag(X); + class OBAPI OBAtomAtomIterAdaptor + { + public: + using Iter = std::vector::const_iterator; + + using value_type = OBAtom*; + using difference_type = std::ptrdiff_t; + using pointer = OBAtom**; + using reference = OBAtom*&; + using iterator_category = std::forward_iterator_tag; + + OBAtomAtomIterAdaptor() = default; + + OBAtomAtomIterAdaptor(Iter iter, const OBAtom *atom = nullptr) + : m_iter(iter), m_atom(atom) + { + } + + OBAtom* operator*() const; + + OBAtomAtomIterAdaptor& operator++() + { + ++m_iter; + return *this; + } + + OBAtomAtomIterAdaptor operator++(int) + { + auto tmp = *this; + ++m_iter; + return tmp; + } + + bool operator==(const OBAtomAtomIterAdaptor &other) const + { + return m_iter == other.m_iter; + } + + bool operator!=(const OBAtomAtomIterAdaptor &other) const + { + return m_iter != other.m_iter; + } + + private: + Iter m_iter; + const OBAtom *m_atom = nullptr; + }; + + using OBAtomBondRange = OBRange; + using OBAtomAtomRange = OBRange; + +#if __cplusplus >= 202002L + static_assert(std::forward_iterator); + static_assert(std::ranges::range); +#endif + // Class OBAtom // class introduction in atom.cpp #define OBATOM_TYPE_LEN 6 @@ -269,12 +325,16 @@ namespace OpenBabel //! \return An iterator to the end of the bonds to this atom OBBondIterator EndBonds() { return(_vbond.end()); } + //! \return A range over the bonds to this atom. This range can be used in a range-based for loop. + OBAtomBondRange GetBonds() const { return {_vbond.begin(), _vbond.end()}; } //! Set the iterator @p i to the beginning of the bonds //! \return The first bond to this atom (or NULL if none exist) OBBond *BeginBond(OBBondIterator &i); //! Increment the iterator @p i //! \return The next bond to this atom (or NULL if none exist) OBBond *NextBond(OBBondIterator &i); + //! \return A range over the neighbors of this atom. This range can be used in a range-based for loop. + OBAtomAtomRange GetNbrs() const { return { {_vbond.begin(), this}, {_vbond.end()} }; } //! Set the iterator @p i to the beginning of the bonds //! \return The first neighboring atom (or NULL if none exist) OBAtom *BeginNbrAtom(OBBondIterator &i); diff --git a/include/openbabel/base.h b/include/openbabel/base.h index c814ed0ca..e88fcb6d2 100644 --- a/include/openbabel/base.h +++ b/include/openbabel/base.h @@ -340,6 +340,22 @@ class OBConversion; //used only as pointer }; + template::const_iterator> + class OBAPI OBRange + { + public: + OBRange(Iter begin, Iter end) : m_begin{begin}, m_end{end} + { + } + + Iter begin() const { return m_begin; } + Iter end() const { return m_end; } + + private: + Iter m_begin; + Iter m_end; + }; + } //namespace OpenBabel #endif // OB_BASE_H diff --git a/include/openbabel/bond.h b/include/openbabel/bond.h index 1dca40033..54ab7d8b6 100644 --- a/include/openbabel/bond.h +++ b/include/openbabel/bond.h @@ -260,6 +260,12 @@ namespace OpenBabel }; // class OBBond + inline OBAtom* OBAtomAtomIterAdaptor::operator*() const + { + auto bond = *m_iter; + return m_atom != bond->GetBeginAtom() ? bond->GetBeginAtom() : bond->GetEndAtom(); + } + //! A standard iterator over a vector of bonds typedef std::vector::iterator OBBondIterator; diff --git a/include/openbabel/mol.h b/include/openbabel/mol.h index 5599072b4..41c33c690 100644 --- a/include/openbabel/mol.h +++ b/include/openbabel/mol.h @@ -117,6 +117,14 @@ namespace OpenBabel enum HydrogenType { AllHydrogen, PolarHydrogen, NonPolarHydrogen }; + using OBMolAtomRange = OBRange; + using OBMolBondRange = OBRange; + +#if __cplusplus >= 202002L + static_assert(std::ranges::range); + static_assert(std::ranges::range); +#endif + // class introduction in mol.cpp class OBAPI OBMol: public OBBase { @@ -652,10 +660,14 @@ enum HydrogenType { AllHydrogen, PolarHydrogen, NonPolarHydrogen }; OBAtomIterator EndAtoms() { return _vatom.begin() + NumAtoms() ; } //! \return A constant atom iterator pointing to the end of the atom list OBAtomConstIterator CEndAtoms() const { return _vatom.cbegin() + NumAtoms(); } + //! \return A range over the atoms. This range can be used in a range-based for loop. + OBMolAtomRange GetAtoms() const { return {_vatom.begin(), _vatom.begin() + NumAtoms()}; } //! \return A bond iterator pointing to the beginning of the bond list OBBondIterator BeginBonds() { return _vbond.begin(); } //! \return A bond iterator pointing to the end of the bond list OBBondIterator EndBonds() { return _vbond.begin() + NumBonds() ; } + //! \return A range over the bonds. This range can be used in a range-based for loop. + OBMolBondRange GetBonds() const { return {_vbond.begin(), _vbond.begin() + NumBonds()}; } //! \return A residue iterator pointing to the beginning of the residue list OBResidueIterator BeginResidues() { return _residue.begin(); } //! \return A residue iterator pointing to the end of the residue list diff --git a/include/openbabel/obiter.h b/include/openbabel/obiter.h index a4b969de0..bba169f6c 100644 --- a/include/openbabel/obiter.h +++ b/include/openbabel/obiter.h @@ -22,6 +22,9 @@ GNU General Public License for more details. #include #include +#include +#include +#include #include #include @@ -395,10 +398,26 @@ namespace OpenBabel OBRing& operator*() const { return *_ptr;} }; -#define FOR_ATOMS_OF_MOL(a,m) for( OpenBabel::OBMolAtomIter a(m); a; ++a ) -#define FOR_BONDS_OF_MOL(b,m) for( OpenBabel::OBMolBondIter b(m); b; ++b ) -#define FOR_NBORS_OF_ATOM(a,p) for( OpenBabel::OBAtomAtomIter a(p); a; ++a ) -#define FOR_BONDS_OF_ATOM(b,p) for( OpenBabel::OBAtomBondIter b(p); b; ++b ) + namespace impl { + + inline OBMolAtomRange MolGetAtoms(const OpenBabel::OBMol &mol) { return mol.GetAtoms(); } + inline OBMolAtomRange MolGetAtoms(const OpenBabel::OBMol *mol) { return mol->GetAtoms(); } + + inline OBMolBondRange MolGetBonds(const OpenBabel::OBMol &mol) { return mol.GetBonds(); } + inline OBMolBondRange MolGetBonds(const OpenBabel::OBMol *mol) { return mol->GetBonds(); } + + inline OBAtomBondRange AtomGetBonds(const OpenBabel::OBAtom &atom) { return atom.GetBonds(); } + inline OBAtomBondRange AtomGetBonds(const OpenBabel::OBAtom *atom) { return atom->GetBonds(); } + + inline OBAtomAtomRange AtomGetNbrs(const OpenBabel::OBAtom &atom) { return atom.GetNbrs(); } + inline OBAtomAtomRange AtomGetNbrs(const OpenBabel::OBAtom *atom) { return atom->GetNbrs(); } + + } + +#define FOR_ATOMS_OF_MOL(a,m) for (auto a : impl::MolGetAtoms(m)) +#define FOR_BONDS_OF_MOL(b,m) for (auto b : impl::MolGetBonds(m)) +#define FOR_NBORS_OF_ATOM(a,p) for (auto a : impl::AtomGetNbrs(p)) +#define FOR_BONDS_OF_ATOM(b,p) for (auto b : impl::AtomGetBonds(p)) #define FOR_RESIDUES_OF_MOL(r,m) for( OpenBabel::OBResidueIter r(m); r; ++r ) #define FOR_ATOMS_OF_RESIDUE(a,r) for( OpenBabel::OBResidueAtomIter a(r); a; ++a ) #define FOR_DFS_OF_MOL(a,m) for( OpenBabel::OBMolAtomDFSIter a(m); a; ++a )