This minor clean-up provides a negligible performance improvement
to OBAtom::GetValence(), but addresses a commonly occurring but
poor C++/STL programming idiom in the OpenBabel source tree.

The inefficient idiom that's currently used looks like:

       return _vbond.empty() ? 0 : _vbond.size();

Whilst it is true for many STL data structures that testing
empty() is often more efficient than testing size() == 0, it is
rarely beneficial to use empty() purely to avoid calling size()
as a special case.  This is certainly the case with std::vector
implementations on modern hardware.

To demonstrate this, consider the following test code

#include <vector>

std::vector<void*> v;

unsigned int oldway() {
 return v.empty() ? 0 : static_cast<unsigned int>(v.size());
}

unsigned int newway() {
 return (unsigned int)v.size();
}


Using g++ v4.6.0 on x86_64, the original implementation requires
10 (9) instructions including a conditional jump

oldway: movq    v+8(%rip), %rcx
       movq    v(%rip), %rdx
       xorl    %eax, %eax
       cmpq    %rdx, %rcx
       je      done
       movq    %rcx, %rax
       subq    %rdx, %rax
       shrq    $3, %rax
done:   rep ; ret

whereas the obvious simpler idiom requires only 4 instructions

newway: movq    v+8(%rip), %rax
       subq    v(%rip), %rax
       sarq    $3, %rax
       ret


It turns out that this idiom/misunderstanding occurs in various places
throughout the source tree. In the attached patch I've fixed GetValence() [as I was investigating a valence-related SMARTS bug] and rotor.h as another
occurrence in the same directory.  However many examples still remain in
the main src/ directories including

typer.cpp:        if (vs.empty() || vs.size() < 3)
rotor.cpp:    if (!vs.empty() && vs.size() > 5)
phmodel.cpp:        if (vs.empty() || vs.size() < 5)
mol.cpp: if (_vatom.empty() || _natoms+1 >= (signed)_vatom.size())

and so on.  There was once a time I'd have fixed this is g++, but I'm
getting old. Hopefully, there's a willing volunteer to audit and fix the
source tree.

The following has been tested with "make test" with no regressions.

Index: include/openbabel/atom.h
===================================================================
*** include/openbabel/atom.h    (revision 4680)
--- include/openbabel/atom.h    (working copy)
*************** namespace OpenBabel
*** 227,236 ****
        //! \deprecated Use GetCoordinateIdx() instead
        unsigned int GetCIdx()          const { return((int)_cidx); }
        //! \return The current number of explicit connections
!       unsigned int GetValence()       const
!         {
!           return((_vbond.empty()) ? 0 : static_cast<unsigned int> 
(_vbond.size()));
!         }
        //! \return The hybridization of this atom: 1 for sp, 2 for sp2, 3 for 
sp3, 4 for sq. planar, 5 for trig. bipy, 6 for octahedral
        unsigned int GetHyb()             const;
        //! \return The implicit valence of this atom type (i.e. maximum number 
of connections expected)
--- 227,233 ----
        //! \deprecated Use GetCoordinateIdx() instead
        unsigned int GetCIdx()          const { return((int)_cidx); }
        //! \return The current number of explicit connections
!       unsigned int GetValence() const { return (unsigned int)_vbond.size(); }
        //! \return The hybridization of this atom: 1 for sp, 2 for sp2, 3 for 
sp3, 4 for sq. planar, 5 for trig. bipy, 6 for octahedral
        unsigned int GetHyb()             const;
        //! \return The implicit valence of this atom type (i.e. maximum number 
of connections expected)
Index: include/openbabel/rotor.h
===================================================================
*** include/openbabel/rotor.h   (revision 4680)
--- include/openbabel/rotor.h   (working copy)
*************** namespace OpenBabel
*** 467,473 ****
       */
      size_t Size()
      {
!       return((_rotor.empty()) ? (size_t)0: _rotor.size());
      }
      /**
       * When no atoms/bonds are fixed or when bonds are fixed, this function 
will
--- 467,473 ----
       */
      size_t Size()
      {
!       return _rotor.size();
      }
      /**
       * When no atoms/bonds are fixed or when bonds are fixed, this function 
will


Thanks in advance,

Roger
--
Roger Sayle, Ph.D.
CEO and founder
NextMove Software Ltd
Cambridge, UK

------------------------------------------------------------------------------
Cloud Services Checklist: Pricing and Packaging Optimization
This white paper is intended to serve as a reference, checklist and point of 
discussion for anyone considering optimizing the pricing and packaging model 
of a cloud services business. Read Now!
http://www.accelacomm.com/jaw/sfnl/114/51491232/
_______________________________________________
OpenBabel-Devel mailing list
OpenBabel-Devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/openbabel-devel

Reply via email to