text:
// $Id$
//
//  Copyright (C) 2007-2011 Greg Landrum
//
//   @@ All Rights Reserved @@
//  This file is part of the RDKit.
//  The contents are covered by the terms of the BSD license
//  which is included in the file license.txt, found at the root
//  of the RDKit source tree.
//
#include <RDBoost/Wrap.h>
#include <GraphMol/Atom.h>
#include <GraphMol/GraphMol.h>

#include <RDGeneral/BoostStartInclude.h>
#include <boost/foreach.hpp>
#include <RDGeneral/BoostEndInclude.h>

#include <GraphMol/Descriptors/MolDescriptors.h>
#include <GraphMol/Fingerprints/AtomPairs.h>
#include <GraphMol/Fingerprints/MorganFingerprints.h>
#include <GraphMol/Fingerprints/MACCS.h>
#include <DataStructs/BitVects.h>

#include <vector>

namespace python = boost::python;

namespace {
std::vector<unsigned int> atomPairTypes(
    RDKit::AtomPairs::atomNumberTypes,
    RDKit::AtomPairs::atomNumberTypes +
        sizeof(RDKit::AtomPairs::atomNumberTypes) / sizeof(unsigned int));
python::tuple computeASAContribs(const RDKit::ROMol &mol, bool includeHs = true,
                                 bool force = false) {
  std::vector<double> contribs(mol.getNumAtoms());
  double hContrib = 0.0;
  RDKit::Descriptors::getLabuteAtomContribs(mol, contribs, hContrib, includeHs,
                                            force);
  python::tuple pycontribs(contribs);
  return python::make_tuple(contribs, hContrib);
}
python::tuple computeTPSAContribs(const RDKit::ROMol &mol, bool force = false) {
  std::vector<double> contribs(mol.getNumAtoms());
  RDKit::Descriptors::getTPSAAtomContribs(mol, contribs, force);
  python::tuple pycontribs(contribs);
  return pycontribs;
}

python::list computeCrippenContribs(
    const RDKit::ROMol &mol, bool force = false,
    python::list atomTypes = python::list(),
    python::list atomTypeLabels = python::list()) {
  std::vector<unsigned int> *tAtomTypes = 0;
  std::vector<std::string> *tAtomTypeLabels = 0;
  if (python::extract<unsigned int>(atomTypes.attr("__len__")()) != 0) {
    if (python::extract<unsigned int>(atomTypes.attr("__len__")()) !=
        mol.getNumAtoms()) {
      throw_value_error(
          "if atomTypes vector is provided, it must be as long as the number "
          "of atoms");
    } else {
      tAtomTypes = new std::vector<unsigned int>(mol.getNumAtoms(), 0);
    }
  }
  if (python::extract<unsigned int>(atomTypeLabels.attr("__len__")()) != 0) {
    if (python::extract<unsigned int>(atomTypeLabels.attr("__len__")()) !=
        mol.getNumAtoms()) {
      throw_value_error(
          "if atomTypeLabels vector is provided, it must be as long as the "
          "number of atoms");
    } else {
      tAtomTypeLabels = new std::vector<std::string>(mol.getNumAtoms(), "");
    }
  }

  std::vector<double> logpContribs(mol.getNumAtoms());
  std::vector<double> mrContribs(mol.getNumAtoms());

  RDKit::Descriptors::getCrippenAtomContribs(
      mol, logpContribs, mrContribs, force, tAtomTypes, tAtomTypeLabels);
  python::list pycontribs;
  for (unsigned int i = 0; i < mol.getNumAtoms(); ++i) {
    pycontribs.append(python::make_tuple(logpContribs[i], mrContribs[i]));
  }
  if (tAtomTypes) {
    for (unsigned int i = 0; i < mol.getNumAtoms(); ++i) {
      atomTypes[i] = (*tAtomTypes)[i];
    }
    delete tAtomTypes;
  }
  if (tAtomTypeLabels) {
    for (unsigned int i = 0; i < mol.getNumAtoms(); ++i) {
      atomTypeLabels[i] = (*tAtomTypeLabels)[i];
    }
    delete tAtomTypeLabels;
  }
  return pycontribs;
}
python::tuple calcCrippenDescriptors(const RDKit::ROMol &mol,
                                     bool includeHs = true,
                                     bool force = false) {
  double logp, mr;
  RDKit::Descriptors::calcCrippenDescriptors(mol, logp, mr, includeHs, force);
  return python::make_tuple(logp, mr);
}

RDKit::SparseIntVect<boost::int32_t> *GetAtomPairFingerprint(
    const RDKit::ROMol &mol, unsigned int minLength, unsigned int maxLength,
    python::object fromAtoms, python::object ignoreAtoms,
    python::object atomInvariants, bool includeChirality, bool use2D,
    int confId) {
  rdk_auto_ptr<std::vector<boost::uint32_t> > fvect =
      pythonObjectToVect(fromAtoms, mol.getNumAtoms());
  rdk_auto_ptr<std::vector<boost::uint32_t> > ivect =
      pythonObjectToVect(ignoreAtoms, mol.getNumAtoms());
  rdk_auto_ptr<std::vector<boost::uint32_t> > invvect = pythonObjectToVect(
      atomInvariants,
      static_cast<unsigned int>(1 << RDKit::AtomPairs::codeSize));
  RDKit::SparseIntVect<boost::int32_t> *res;
  res = RDKit::AtomPairs::getAtomPairFingerprint(
      mol, minLength, maxLength, fvect.get(), ivect.get(), invvect.get(),
      includeChirality, use2D, confId);
  return res;
}
RDKit::SparseIntVect<boost::int32_t> *GetHashedAtomPairFingerprint(
    const RDKit::ROMol &mol, unsigned int nBits, unsigned int minLength,
    unsigned int maxLength, python::object fromAtoms,
    python::object ignoreAtoms, python::object atomInvariants,
    bool includeChirality, bool use2D, int confId) {
  rdk_auto_ptr<std::vector<boost::uint32_t> > fvect =
      pythonObjectToVect(fromAtoms, mol.getNumAtoms());
  rdk_auto_ptr<std::vector<boost::uint32_t> > ivect =
      pythonObjectToVect(ignoreAtoms, mol.getNumAtoms());
  rdk_auto_ptr<std::vector<boost::uint32_t> > invvect = pythonObjectToVect(
      atomInvariants,
      static_cast<unsigned int>(1 << RDKit::AtomPairs::codeSize));
  RDKit::SparseIntVect<boost::int32_t> *res;
  res = RDKit::AtomPairs::getHashedAtomPairFingerprint(
      mol, nBits, minLength, maxLength, fvect.get(), ivect.get(), invvect.get(),
      includeChirality, use2D, confId);
  return res;
}

RDKit::SparseIntVect<boost::int64_t> *GetTopologicalTorsionFingerprint(
    const RDKit::ROMol &mol, unsigned int targetSize, python::object fromAtoms,
    python::object ignoreAtoms, python::object atomInvariants,
    bool includeChirality) {
  rdk_auto_ptr<std::vector<boost::uint32_t> > fvect =
      pythonObjectToVect(fromAtoms, mol.getNumAtoms());
  rdk_auto_ptr<std::vector<boost::uint32_t> > ivect =
      pythonObjectToVect(ignoreAtoms, mol.getNumAtoms());
  rdk_auto_ptr<std::vector<boost::uint32_t> > invvect = pythonObjectToVect(
      atomInvariants,
      static_cast<unsigned int>(1 << RDKit::AtomPairs::codeSize));
  if (targetSize * RDKit::AtomPairs::codeSize > 64) {
    std::ostringstream errout;
    errout << "Maximum supported topological torsion path length is "
           << 64 / RDKit::AtomPairs::codeSize << std::endl;
    throw_value_error(errout.str());
  }

  RDKit::SparseIntVect<boost::int64_t> *res;
  res = RDKit::AtomPairs::getTopologicalTorsionFingerprint(
      mol, targetSize, fvect.get(), ivect.get(), invvect.get(),
      includeChirality);
  return res;
}

RDKit::SparseIntVect<boost::int64_t> *GetHashedTopologicalTorsionFingerprint(
    const RDKit::ROMol &mol, unsigned int nBits, unsigned int targetSize,
    python::object fromAtoms, python::object ignoreAtoms,
    python::object atomInvariants, bool includeChirality) {
  rdk_auto_ptr<std::vector<boost::uint32_t> > fvect =
      pythonObjectToVect(fromAtoms, mol.getNumAtoms());
  rdk_auto_ptr<std::vector<boost::uint32_t> > ivect =
      pythonObjectToVect(ignoreAtoms, mol.getNumAtoms());
  rdk_auto_ptr<std::vector<boost::uint32_t> > invvect = pythonObjectToVect(
      atomInvariants,
      static_cast<unsigned int>(1 << RDKit::AtomPairs::codeSize));
  RDKit::SparseIntVect<boost::int64_t> *res;
  res = RDKit::AtomPairs::getHashedTopologicalTorsionFingerprint(
      mol, nBits, targetSize, fvect.get(), ivect.get(), invvect.get(),
      includeChirality);
  return res;
}

ExplicitBitVect *GetHashedTopologicalTorsionFingerprintAsBitVect(
    const RDKit::ROMol &mol, unsigned int nBits, unsigned int targetSize,
    python::object fromAtoms, python::object ignoreAtoms,
    python::object atomInvariants, unsigned int nBitsPerEntry,
    bool includeChirality) {
  rdk_auto_ptr<std::vector<boost::uint32_t> > fvect =
      pythonObjectToVect(fromAtoms, mol.getNumAtoms());
  rdk_auto_ptr<std::vector<boost::uint32_t> > ivect =
      pythonObjectToVect(ignoreAtoms, mol.getNumAtoms());
  rdk_auto_ptr<std::vector<boost::uint32_t> > invvect = pythonObjectToVect(
      atomInvariants,
      static_cast<unsigned int>(1 << RDKit::AtomPairs::codeSize));
  ExplicitBitVect *res;
  res = RDKit::AtomPairs::getHashedTopologicalTorsionFingerprintAsBitVect(
      mol, nBits, targetSize, fvect.get(), ivect.get(), invvect.get(),
      nBitsPerEntry, includeChirality);
  return res;
}

ExplicitBitVect *GetHashedAtomPairFingerprintAsBitVect(
    const RDKit::ROMol &mol, unsigned int nBits, unsigned int minLength,
    unsigned int maxLength, python::object fromAtoms,
    python::object ignoreAtoms, python::object atomInvariants,
    unsigned int nBitsPerEntry, bool includeChirality, bool use2D, int confId) {
  rdk_auto_ptr<std::vector<boost::uint32_t> > fvect =
      pythonObjectToVect(fromAtoms, mol.getNumAtoms());
  rdk_auto_ptr<std::vector<boost::uint32_t> > ivect =
      pythonObjectToVect(ignoreAtoms, mol.getNumAtoms());
  rdk_auto_ptr<std::vector<boost::uint32_t> > invvect = pythonObjectToVect(
      atomInvariants,
      static_cast<unsigned int>(1 << RDKit::AtomPairs::codeSize));
  ExplicitBitVect *res;
  res = RDKit::AtomPairs::getHashedAtomPairFingerprintAsBitVect(
      mol, nBits, minLength, maxLength, fvect.get(), ivect.get(), invvect.get(),
      nBitsPerEntry, includeChirality, use2D, confId);
  return res;
}

namespace {
double kappaHelper(double (*fn)(const RDKit::ROMol &, std::vector<double> *),
                   const RDKit::ROMol &mol, python::object atomContribs) {
  std::vector<double> *lContribs = 0;
  if (atomContribs != python::object()) {
    // make sure the optional argument actually was a list
    python::list typecheck = python::extract<python::list>(atomContribs);

    if (python::extract<unsigned int>(typecheck.attr("__len__")()) !=
        mol.getNumAtoms()) {
      throw_value_error("length of atomContribs list != number of atoms");
    }

    lContribs = new std::vector<double>(mol.getNumAtoms());
  }
  double res = fn(mol, lContribs);
  if (lContribs) {
    python::list acl = python::extract<python::list>(atomContribs);
    for (unsigned int i = 0; i < mol.getNumAtoms(); ++i) {
      acl[i] = (*lContribs)[i];
    }
    delete lContribs;
  }
  return res;
}
double hkAlphaHelper(const RDKit::ROMol &mol, python::object atomContribs) {
  return kappaHelper(RDKit::Descriptors::calcHallKierAlpha, mol, atomContribs);
}

RDKit::SparseIntVect<boost::uint32_t> *MorganFingerprintHelper(
    const RDKit::ROMol &mol, int radius, int nBits, python::object invariants,
    python::object fromAtoms, bool useChirality, bool useBondTypes,
    bool useFeatures, bool useCounts, python::object bitInfo) {
  std::vector<boost::uint32_t> *invars = 0;
  if (invariants) {
    unsigned int nInvar =
        python::extract<unsigned int>(invariants.attr("__len__")());
    if (nInvar) {
      if (nInvar != mol.getNumAtoms()) {
        throw_value_error("length of invariant vector != number of atoms");
      }
      invars = new std::vector<boost::uint32_t>(mol.getNumAtoms());
      for (unsigned int i = 0; i < mol.getNumAtoms(); ++i) {
        (*invars)[i] = python::extract<boost::uint32_t>(invariants[i]);
      }
    }
  } else if (useFeatures) {
    invars = new std::vector<boost::uint32_t>(mol.getNumAtoms());
    RDKit::MorganFingerprints::getFeatureInvariants(mol, *invars);
  }
  std::vector<boost::uint32_t> *froms = 0;
  if (fromAtoms) {
    unsigned int nFrom =
        python::extract<unsigned int>(fromAtoms.attr("__len__")());
    if (nFrom) {
      froms = new std::vector<boost::uint32_t>();
      for (unsigned int i = 0; i < nFrom; ++i) {
        froms->push_back(python::extract<boost::uint32_t>(fromAtoms[i]));
      }
    }
  }
  RDKit::MorganFingerprints::BitInfoMap *bitInfoMap = 0;
  if (bitInfo != python::object()) {
    // make sure the optional argument actually was a dictionary
    python::dict typecheck = python::extract<python::dict>(bitInfo);
    bitInfoMap = new RDKit::MorganFingerprints::BitInfoMap();
  }
  RDKit::SparseIntVect<boost::uint32_t> *res;
  if (nBits < 0) {
    res = RDKit::MorganFingerprints::getFingerprint(
        mol, static_cast<unsigned int>(radius), invars, froms, useChirality,
        useBondTypes, useCounts, false, bitInfoMap);
  } else {
    res = RDKit::MorganFingerprints::getHashedFingerprint(
        mol, static_cast<unsigned int>(radius),
        static_cast<unsigned int>(nBits), invars, froms, useChirality,
        useBondTypes, false, bitInfoMap);
  }
  if (bitInfoMap) {
    bitInfo.attr("clear")();
    for (RDKit::MorganFingerprints::BitInfoMap::const_iterator iter =
             bitInfoMap->begin();
         iter != bitInfoMap->end(); ++iter) {
      const std::vector<std::pair<boost::uint32_t, boost::uint32_t> > &v =
          iter->second;
      python::list localL;
      for (std::vector<std::pair<boost::uint32_t,
                                 boost::uint32_t> >::const_iterator vIt =
               v.begin();
           vIt != v.end(); ++vIt) {
        localL.append(python::make_tuple(vIt->first, vIt->second));
      }
      bitInfo[iter->first] = python::tuple(localL);
    }
    delete bitInfoMap;
  }
  if (invars) delete invars;
  if (froms) delete froms;
  return res;
}
}
RDKit::SparseIntVect<boost::uint32_t> *GetMorganFingerprint(
    const RDKit::ROMol &mol, int radius, python::object invariants,
    python::object fromAtoms, bool useChirality, bool useBondTypes,
    bool useFeatures, bool useCounts, python::object bitInfo) {
  return MorganFingerprintHelper(mol, radius, -1, invariants, fromAtoms,
                                 useChirality, useBondTypes, useFeatures,
                                 useCounts, bitInfo);
}
RDKit::SparseIntVect<boost::uint32_t> *GetHashedMorganFingerprint(
    const RDKit::ROMol &mol, int radius, int nBits, python::object invariants,
    python::object fromAtoms, bool useChirality, bool useBondTypes,
    bool useFeatures, python::object bitInfo) {
  return MorganFingerprintHelper(mol, radius, nBits, invariants, fromAtoms,
                                 useChirality, useBondTypes, useFeatures, true,
                                 bitInfo);
}

ExplicitBitVect *GetMorganFingerprintBV(
    const RDKit::ROMol &mol, int radius, unsigned int nBits,
    python::object invariants, python::object fromAtoms, bool useChirality,
    bool useBondTypes, bool useFeatures, python::object bitInfo) {
  std::vector<boost::uint32_t> *invars = 0;
  if (invariants) {
    unsigned int nInvar =
        python::extract<unsigned int>(invariants.attr("__len__")());
    if (nInvar) {
      if (nInvar != mol.getNumAtoms()) {
        throw_value_error("length of invariant vector != number of atoms");
      }
      invars = new std::vector<boost::uint32_t>(mol.getNumAtoms());
      for (unsigned int i = 0; i < mol.getNumAtoms(); ++i) {
        (*invars)[i] = python::extract<boost::uint32_t>(invariants[i]);
      }
    }
  } else if (useFeatures) {
    invars = new std::vector<boost::uint32_t>(mol.getNumAtoms());
    RDKit::MorganFingerprints::getFeatureInvariants(mol, *invars);
  }

  std::vector<boost::uint32_t> *froms = 0;
  if (fromAtoms) {
    unsigned int nFrom =
        python::extract<unsigned int>(fromAtoms.attr("__len__")());
    if (nFrom) {
      froms = new std::vector<boost::uint32_t>();
      for (unsigned int i = 0; i < nFrom; ++i) {
        froms->push_back(python::extract<boost::uint32_t>(fromAtoms[i]));
      }
    }
  }
  RDKit::MorganFingerprints::BitInfoMap *bitInfoMap = 0;
  if (bitInfo != python::object()) {
    // make sure the optional argument actually was a dictionary
    python::dict typecheck = python::extract<python::dict>(bitInfo);
    bitInfoMap = new RDKit::MorganFingerprints::BitInfoMap();
  }
  ExplicitBitVect *res;
  res = RDKit::MorganFingerprints::getFingerprintAsBitVect(
      mol, static_cast<unsigned int>(radius), nBits, invars, froms,
      useChirality, useBondTypes, false, bitInfoMap);
  if (bitInfoMap) {
    bitInfo.attr("clear")();
    for (RDKit::MorganFingerprints::BitInfoMap::const_iterator iter =
             bitInfoMap->begin();
         iter != bitInfoMap->end(); ++iter) {
      const std::vector<std::pair<boost::uint32_t, boost::uint32_t> > &v =
          iter->second;
      python::list localL;
      for (std::vector<std::pair<boost::uint32_t,
                                 boost::uint32_t> >::const_iterator vIt =
               v.begin();
           vIt != v.end(); ++vIt) {
        localL.append(python::make_tuple(vIt->first, vIt->second));
      }
      bitInfo[iter->first] = python::tuple(localL);
    }
    delete bitInfoMap;
  }
  if (invars) delete invars;
  if (froms) delete froms;
  return res;
}

python::list GetConnectivityInvariants(const RDKit::ROMol &mol,
                                       bool includeRingMembership) {
  std::vector<boost::uint32_t> invars(mol.getNumAtoms());
  RDKit::MorganFingerprints::getConnectivityInvariants(mol, invars,
                                                       includeRingMembership);
  python::list res;
  BOOST_FOREACH (boost::uint32_t iv, invars) { res.append(python::long_(iv)); }
  return res;
}
python::list GetFeatureInvariants(const RDKit::ROMol &mol) {
  std::vector<boost::uint32_t> invars(mol.getNumAtoms());
  RDKit::MorganFingerprints::getFeatureInvariants(mol, invars);
  python::list res;
  BOOST_FOREACH (boost::uint32_t iv, invars) { res.append(python::long_(iv)); }
  return res;
}

python::list CalcSlogPVSA(const RDKit::ROMol &mol, python::object bins,
                          bool force) {
  std::vector<double> *lbins = 0;
  if (bins) {
    unsigned int nBins = python::extract<unsigned int>(bins.attr("__len__")());
    if (nBins) {
      lbins = new std::vector<double>(nBins, 0.0);
      for (unsigned int i = 0; i < nBins; ++i) {
        (*lbins)[i] = python::extract<double>(bins[i]);
      }
    }
  }
  std::vector<double> res;
  res = RDKit::Descriptors::calcSlogP_VSA(mol, lbins, force);

  python::list pyres;
  BOOST_FOREACH (double dv, res) { pyres.append(dv); }
  return pyres;
}
python::list CalcSMRVSA(const RDKit::ROMol &mol, python::object bins,
                        bool force) {
  std::vector<double> *lbins = 0;
  if (bins) {
    unsigned int nBins = python::extract<unsigned int>(bins.attr("__len__")());
    if (nBins) {
      lbins = new std::vector<double>(nBins, 0.0);
      for (unsigned int i = 0; i < nBins; ++i) {
        (*lbins)[i] = python::extract<double>(bins[i]);
      }
    }
  }
  std::vector<double> res;
  res = RDKit::Descriptors::calcSMR_VSA(mol, lbins, force);

  python::list pyres;
  BOOST_FOREACH (double dv, res) { pyres.append(dv); }
  return pyres;
}
python::list CalcPEOEVSA(const RDKit::ROMol &mol, python::object bins,
                         bool force) {
  std::vector<double> *lbins = 0;
  if (bins) {
    unsigned int nBins = python::extract<unsigned int>(bins.attr("__len__")());
    if (nBins) {
      lbins = new std::vector<double>(nBins, 0.0);
      for (unsigned int i = 0; i < nBins; ++i) {
        (*lbins)[i] = python::extract<double>(bins[i]);
      }
    }
  }
  std::vector<double> res;
  res = RDKit::Descriptors::calcPEOE_VSA(mol, lbins, force);

  python::list pyres;
  BOOST_FOREACH (double dv, res) { pyres.append(dv); }
  return pyres;
}
python::list CalcMQNs(const RDKit::ROMol &mol, bool force) {
  std::vector<unsigned int> res;
  res = RDKit::Descriptors::calcMQNs(mol, force);

  python::list pyres;
  BOOST_FOREACH (unsigned int iv, res) { pyres.append(iv); }
  return pyres;
}
unsigned int numSpiroAtoms(const RDKit::ROMol &mol, python::object pyatoms) {
  std::vector<unsigned int> ats;
  unsigned int res = RDKit::Descriptors::calcNumSpiroAtoms(
      mol, pyatoms != python::object() ? &ats : NULL);
  if (pyatoms != python::object()) {
    python::list pyres = python::extract<python::list>(pyatoms);
    BOOST_FOREACH (unsigned int iv, ats) { pyres.append(iv); }
  }
  return res;
}
unsigned int numBridgeheadAtoms(const RDKit::ROMol &mol,
                                python::object pyatoms) {
  std::vector<unsigned int> ats;
  unsigned int res = RDKit::Descriptors::calcNumBridgeheadAtoms(
      mol, pyatoms != python::object() ? &ats : NULL);
  if (pyatoms != python::object()) {
    python::list pyres = python::extract<python::list>(pyatoms);
    BOOST_FOREACH (unsigned int iv, ats) { pyres.append(iv); }
  }
  return res;
}

/// Awesome StackOverflow response:
/// http://stackoverflow.com/questions/15842126/feeding-a-python-list-into-a-function-taking-in-a-vector-with-boost-python
/// I know a lot more about how boost works.
/// @brief Type that allows for registration of conversions from
///        python iterable types.
struct iterable_converter
{
  /// @note Registers converter from a python interable type to the
  ///       provided type.
  template <typename Container>
  iterable_converter&
  from_python()
  {
    boost::python::converter::registry::push_back(
      &iterable_converter::convertible,
      &iterable_converter::construct<Container>,
      boost::python::type_id<Container>());

    // Support chaining.
    return *this;
  }

  /// @brief Check if PyObject is iterable.
  static void* convertible(PyObject* object)
  {
    return PyObject_GetIter(object) ? object : NULL;
  }

  /// @brief Convert iterable PyObject to C++ container type.
  ///
  /// Container Concept requirements:
  ///
  ///   * Container::value_type is CopyConstructable.
  ///   * Container can be constructed and populated with two iterators.
  ///     I.e. Container(begin, end)
  template <typename Container>
  static void construct(
    PyObject* object,
    boost::python::converter::rvalue_from_python_stage1_data* data)
  {
    namespace python = boost::python;
    // Object is a borrowed reference, so create a handle indicting it is
    // borrowed for proper reference counting.
    python::handle<> handle(python::borrowed(object));

    // Obtain a handle to the memory block that the converter has allocated
    // for the C++ type.
    typedef python::converter::rvalue_from_python_storage<Container>
                                                                storage_type;
    void* storage = reinterpret_cast<storage_type*>(data)->storage.bytes;

    typedef python::stl_input_iterator<typename Container::value_type>
                                                                    iterator;

    // Allocate the C++ type into the converter's memory block, and assign
    // its handle to the converter's convertible variable.  The C++
    // container is populated by passing the begin and end iterators of
    // the python object to the container's constructor.
    new (storage) Container(
      iterator(python::object(handle)), // begin
      iterator());                      // end
    data->convertible = storage;
  }
};

struct PythonPropertyFunctor : public RDKit::Descriptors::PropertyFunctor {
  PyObject *self;

  // n.b. until we switch the query d_dataFunc over to boost::function
  //  we can't use python props in functions.
  PythonPropertyFunctor(PyObject *self, const std::string &name, const std::string &version) :
      PropertyFunctor(name, version), self(self) {
    python::incref(self);

  }

  ~PythonPropertyFunctor() {
    python::decref(self);
  }

  double operator()(const RDKit::ROMol &mol) const {
    return python::call_method<double>(self, "__call__", boost::ref(mol));
  }
};

}

BOOST_PYTHON_MODULE(rdMolDescriptors) {
  python::scope().attr("__doc__") =
      "Module containing functions to compute molecular descriptors";

  std::string docString = "";

  python::class_<python::object>("AtomPairsParameters")
      .setattr("version", RDKit::AtomPairs::atomPairsVersion)
      .setattr("numTypeBits", RDKit::AtomPairs::numTypeBits)
      .setattr("numPiBits", RDKit::AtomPairs::numPiBits)
      .setattr("numBranchBits", RDKit::AtomPairs::numBranchBits)
      .setattr("codeSize", RDKit::AtomPairs::codeSize)
      .setattr("atomTypes", atomPairTypes)
      .setattr("numPathBits", RDKit::AtomPairs::numPathBits)
      .setattr("numAtomPairFingerprintBits",
               RDKit::AtomPairs::numAtomPairFingerprintBits);
  docString = "Returns the atom code (hash) for an atom";
  python::def("GetAtomPairAtomCode", RDKit::AtomPairs::getAtomCode,
              (python::arg("atom"), python::arg("branchSubtract") = 0,
               python::arg("includeChirality") = false),
              docString.c_str());
  docString =
      "Returns the atom-pair fingerprint for a molecule as an IntSparseIntVect";
  python::def("GetAtomPairFingerprint", GetAtomPairFingerprint,
              (python::arg("mol"), python::arg("minLength") = 1,
               python::arg("maxLength") = RDKit::AtomPairs::maxPathLen - 1,
               python::arg("fromAtoms") = 0, python::arg("ignoreAtoms") = 0,
               python::arg("atomInvariants") = 0,
               python::arg("includeChirality") = false,
               python::arg("use2D") = true, python::arg("confId") = -1),
              docString.c_str(),
              python::return_value_policy<python::manage_new_object>());

  docString =
      "Returns the hashed atom-pair fingerprint for a molecule as an "
      "IntSparseIntVect";
  python::def("GetHashedAtomPairFingerprint", GetHashedAtomPairFingerprint,
              (python::arg("mol"), python::arg("nBits") = 2048,
               python::arg("minLength") = 1,
               python::arg("maxLength") = RDKit::AtomPairs::maxPathLen - 1,
               python::arg("fromAtoms") = 0, python::arg("ignoreAtoms") = 0,
               python::arg("atomInvariants") = 0,
               python::arg("includeChirality") = false,
               python::arg("use2D") = true, python::arg("confId") = -1),
              docString.c_str(),
              python::return_value_policy<python::manage_new_object>());

  docString =
      "Returns the atom-pair fingerprint for a molecule as an ExplicitBitVect";
  python::def(
      "GetHashedAtomPairFingerprintAsBitVect",
      GetHashedAtomPairFingerprintAsBitVect,
      (python::arg("mol"), python::arg("nBits") = 2048,
       python::arg("minLength") = 1,
       python::arg("maxLength") = RDKit::AtomPairs::maxPathLen - 1,
       python::arg("fromAtoms") = 0, python::arg("ignoreAtoms") = 0,
       python::arg("atomInvariants") = 0, python::arg("nBitsPerEntry") = 4,
       python::arg("includeChirality") = false, python::arg("use2D") = true,
       python::arg("confId") = -1),
      docString.c_str(),
      python::return_value_policy<python::manage_new_object>());

  docString =
      "Returns the topological-torsion fingerprint for a molecule as a "
      "LongIntSparseIntVect";
  python::def("GetTopologicalTorsionFingerprint",
              GetTopologicalTorsionFingerprint,
              (python::arg("mol"), python::arg("targetSize") = 4,
               python::arg("fromAtoms") = 0, python::arg("ignoreAtoms") = 0,
               python::arg("atomInvariants") = 0,
               python::arg("includeChirality") = false),
              docString.c_str(),
              python::return_value_policy<python::manage_new_object>());
  docString =
      "Returns the hashed topological-torsion fingerprint for a molecule as a "
      "LongIntSparseIntVect";
  python::def(
      "GetHashedTopologicalTorsionFingerprint",
      GetHashedTopologicalTorsionFingerprint,
      (python::arg("mol"), python::arg("nBits") = 2048,
       python::arg("targetSize") = 4, python::arg("fromAtoms") = 0,
       python::arg("ignoreAtoms") = 0, python::arg("atomInvariants") = 0,
       python::arg("includeChirality") = false),
      docString.c_str(),
      python::return_value_policy<python::manage_new_object>());
  docString =
      "Returns the topological-torsion fingerprint for a molecule as an "
      "ExplicitBitVect";
  python::def(
      "GetHashedTopologicalTorsionFingerprintAsBitVect",
      GetHashedTopologicalTorsionFingerprintAsBitVect,
      (python::arg("mol"), python::arg("nBits") = 2048,
       python::arg("targetSize") = 4, python::arg("fromAtoms") = 0,
       python::arg("ignoreAtoms") = 0, python::arg("atomInvariants") = 0,
       python::arg("nBitsPerEntry") = 4,
       python::arg("includeChirality") = false),
      docString.c_str(),
      python::return_value_policy<python::manage_new_object>());

  docString = "Returns a Morgan fingerprint for a molecule";
  python::def(
      "GetMorganFingerprint", GetMorganFingerprint,
      (python::arg("mol"), python::arg("radius"),
       python::arg("invariants") = python::list(),
       python::arg("fromAtoms") = python::list(),
       python::arg("useChirality") = false, python::arg("useBondTypes") = true,
       python::arg("useFeatures") = false, python::arg("useCounts") = true,
       python::arg("bitInfo") = python::object()),
      docString.c_str(),
      python::return_value_policy<python::manage_new_object>());
  docString = "Returns a hashed Morgan fingerprint for a molecule";
  python::def(
      "GetHashedMorganFingerprint", GetHashedMorganFingerprint,
      (python::arg("mol"), python::arg("radius"), python::arg("nBits") = 2048,
       python::arg("invariants") = python::list(),
       python::arg("fromAtoms") = python::list(),
       python::arg("useChirality") = false, python::arg("useBondTypes") = true,
       python::arg("useFeatures") = false,
       python::arg("bitInfo") = python::object()),
      docString.c_str(),
      python::return_value_policy<python::manage_new_object>());
  docString = "Returns a Morgan fingerprint for a molecule as a bit vector";
  python::def(
      "GetMorganFingerprintAsBitVect", GetMorganFingerprintBV,
      (python::arg("mol"), python::arg("radius"), python::arg("nBits") = 2048,
       python::arg("invariants") = python::list(),
       python::arg("fromAtoms") = python::list(),
       python::arg("useChirality") = false, python::arg("useBondTypes") = true,
       python::arg("useFeatures") = false,
       python::arg("bitInfo") = python::object()),
      docString.c_str(),
      python::return_value_policy<python::manage_new_object>());
  python::scope().attr("_MorganFingerprint_version") =
      RDKit::MorganFingerprints::morganFingerprintVersion;
  docString = "Returns connectivity invariants (ECFP-like) for a molecule.";
  python::def("GetConnectivityInvariants", GetConnectivityInvariants,
              (python::arg("mol"), python::arg("includeRingMembership") = true),
              docString.c_str());
  python::scope().attr("_ConnectivityInvariants_version") =
      RDKit::MorganFingerprints::morganConnectivityInvariantVersion;

  docString = "Returns feature invariants (FCFP-like) for a molecule.";
  python::def("GetFeatureInvariants", GetFeatureInvariants,
              (python::arg("mol")), docString.c_str());
  python::scope().attr("_FeatureInvariants_version") =
      RDKit::MorganFingerprints::morganFeatureInvariantVersion;

  docString =
      "returns (as a list of 2-tuples) the contributions of each atom to\n"
      "the Wildman-Cripppen logp and mr value";
  python::def("_CalcCrippenContribs", computeCrippenContribs,
              (python::arg("mol"), python::arg("force") = false,
               python::arg("atomTypes") = python::list(),
               python::arg("atomTypeLabels") = python::list()),
              docString.c_str());
  docString = "returns a 2-tuple with the Wildman-Crippen logp,mr values";
  python::def("CalcCrippenDescriptors", calcCrippenDescriptors,
              (python::arg("mol"), python::arg("includeHs") = true,
               python::arg("force") = false),
              docString.c_str());
  python::scope().attr("_CalcCrippenDescriptors_version") =
      RDKit::Descriptors::crippenVersion;

  docString = "returns the Labute ASA value for a molecule";
  python::def("CalcLabuteASA", RDKit::Descriptors::calcLabuteASA,
              (python::arg("mol"), python::arg("includeHs") = true,
               python::arg("force") = false),
              docString.c_str());
  python::scope().attr("_CalcLabuteASA_version") =
      RDKit::Descriptors::labuteASAVersion;

  docString = "returns a list of atomic contributions to the Labute ASA";
  python::def("_CalcLabuteASAContribs", computeASAContribs,
              (python::arg("mol"), python::arg("includeHs") = true,
               python::arg("force") = false),
              docString.c_str());

  docString = "returns the TPSA value for a molecule";
  python::def("CalcTPSA", RDKit::Descriptors::calcTPSA,
              (python::arg("mol"), python::arg("force") = false),
              docString.c_str());
  python::scope().attr("_CalcTPSA_version") = RDKit::Descriptors::tpsaVersion;

  docString = "returns a list of atomic contributions to the TPSA";
  python::def("_CalcTPSAContribs", computeTPSAContribs,
              (python::arg("mol"), python::arg("force") = false),
              docString.c_str());

  docString = "returns the molecule's molecular weight";
  python::def("_CalcMolWt", RDKit::Descriptors::calcAMW,
              (python::arg("mol"), python::arg("onlyHeavy") = false),
              docString.c_str());
  python::scope().attr("_CalcMolWt_version") = "1.0.0";

  docString = "returns the molecule's exact molecular weight";
  python::def("CalcExactMolWt", RDKit::Descriptors::calcExactMW,
              (python::arg("mol"), python::arg("onlyHeavy") = false),
              docString.c_str());
  python::scope().attr("_CalcExactMolWt_version") = "1.0.0";

  docString = "returns the molecule's formula";
  python::def("CalcMolFormula", RDKit::Descriptors::calcMolFormula,
              (python::arg("mol"), python::arg("separateIsotopes") = false,
               python::arg("abbreviateHIsotopes") = true),
              docString.c_str());
  python::scope().attr("_CalcMolFormula_version") = "1.3.0";

  docString = "returns the number of Lipinski H-bond donors for a molecule";
  python::def("CalcNumLipinskiHBD", RDKit::Descriptors::calcLipinskiHBD,
              (python::arg("mol")), docString.c_str());
  python::scope().attr("_CalcNumLipinskiHBD_version") =
      RDKit::Descriptors::lipinskiHBDVersion;
  docString = "returns the number of Lipinski H-bond acceptors for a molecule";
  python::def("CalcNumLipinskiHBA", RDKit::Descriptors::calcLipinskiHBA,
              (python::arg("mol")), docString.c_str());
  python::scope().attr("_CalcNumLipinskiHBA_version") =
      RDKit::Descriptors::lipinskiHBAVersion;
  docString = "returns the number of H-bond donors for a molecule";
  python::def("CalcNumHBD", RDKit::Descriptors::calcNumHBD,
              (python::arg("mol")), docString.c_str());
  python::scope().attr("_CalcNumHBD_version") =
      RDKit::Descriptors::NumHBDVersion;
  docString = "returns the number of H-bond acceptors for a molecule";
  python::def("CalcNumHBA", RDKit::Descriptors::calcNumHBA,
              (python::arg("mol")), docString.c_str());
  python::scope().attr("_CalcNumHBA_version") =
      RDKit::Descriptors::NumHBAVersion;

  // exposes calcNumRotatableBondOptions (must be a better way!)

  docString = "Options for generating rotatble bonds\n\
 NonStrict - standard loose definitions\n\
 Strict - stricter definition excluding amides, esters, etc\n\
 StrictLinkages - adds rotors between rotatable bonds\n\
 Default - Current RDKit default\n";

  python::enum_<RDKit::Descriptors::NumRotatableBondsOptions>("NumRotatableBondsOptions", docString.c_str())
      .value("NonStrict", RDKit::Descriptors::NonStrict)
      .value("Strict", RDKit::Descriptors::Strict)
      .value("StrictLinkages", RDKit::Descriptors::StrictLinkages)
      .value("Default", RDKit::Descriptors::Default)
       ;

#ifdef RDK_USE_STRICT_ROTOR_DEFINITION
    docString=
        "returns the number of rotatable bonds for a molecule.\n\
   strict = NumRotatableBondsOptions.NonStrict - Simple rotatable bond definition.\n\
   strict = NumRotatableBondsOptions.Strict - (default) does not count things like\n\
            amide or ester bonds\n\
   strict = NumRotatableBondsOptions.StrictLinkages - handles linkages between ring\n\
      systems.\n\
      - Single bonds between aliphatic ring Cs are always rotatable. This\n\
        means that the central bond in CC1CCCC(C)C1-C1C(C)CCCC1C is now \n\
        considered rotatable; it was not before\n\
      - Heteroatoms in the linked rings no longer affect whether or not\n\
        the linking bond is rotatable\n\
      - the linking bond in systems like Cc1cccc(C)c1-c1c(C)cccc1 is now\n\
         considered non-rotatable";
#else
    docString=
        "returns the number of rotatable bonds for a molecule.\n\
   strict = NumRotatableBondsOptions.NonStrict - (default) Simple rotatable bond definition.\n\
   strict = NumRotatableBondsOptions.Strict - does not count things like\n\
            amide or ester bonds\n\
   strict = NumRotatableBondsOptions.StrictLinkages - handles linkages between ring\n\
      systems.\n\
      - Single bonds between aliphatic ring Cs are always rotatable. This\n\
        means that the central bond in CC1CCCC(C)C1-C1C(C)CCCC1C is now \n\
        considered rotatable; it was not before\n\
      - Heteroatoms in the linked rings no longer affect whether or not\n\
        the linking bond is rotatable\n\
      - the linking bond in systems like Cc1cccc(C)c1-c1c(C)cccc1 is now\n\
         considered non-rotatable";
#endif

  python::def(
      "CalcNumRotatableBonds", (unsigned int (*)(const RDKit::ROMol&, bool))
                                RDKit::Descriptors::calcNumRotatableBonds,
      (python::arg("mol"),
       python::arg("strict")),
      docString.c_str());

  python::def(
      "CalcNumRotatableBonds", (unsigned int (*)(const RDKit::ROMol&,
                                                 RDKit::Descriptors::NumRotatableBondsOptions))
                                RDKit::Descriptors::calcNumRotatableBonds,
      (python::arg("mol"),
       python::arg("strict") = RDKit::Descriptors::Default),
      docString.c_str());
  python::scope().attr("_CalcNumRotatableBonds_version") =
      RDKit::Descriptors::NumRotatableBondsVersion;

  docString = "returns the number of rings for a molecule";
  python::def("CalcNumRings", RDKit::Descriptors::calcNumRings,
              (python::arg("mol")), docString.c_str());
  python::scope().attr("_CalcNumRings_version") =
      RDKit::Descriptors::NumRingsVersion;

  docString = "returns the number of aromatic rings for a molecule";
  python::def("CalcNumAromaticRings", RDKit::Descriptors::calcNumAromaticRings,
              (python::arg("mol")), docString.c_str());
  python::scope().attr("_CalcNumAromaticRings_version") =
      RDKit::Descriptors::NumAromaticRingsVersion;

  docString = "returns the number of saturated rings for a molecule";
  python::def("CalcNumSaturatedRings",
              RDKit::Descriptors::calcNumSaturatedRings, (python::arg("mol")),
              docString.c_str());
  python::scope().attr("_CalcNumSaturatedRings_version") =
      RDKit::Descriptors::NumSaturatedRingsVersion;

  docString = "returns the number of heterocycles for a molecule";
  python::def("CalcNumHeterocycles", RDKit::Descriptors::calcNumHeterocycles,
              (python::arg("mol")), docString.c_str());
  python::scope().attr("_CalcNumHeterocycles_version") =
      RDKit::Descriptors::NumHeterocyclesVersion;

  docString = "returns the number of aromatic heterocycles for a molecule";
  python::def("CalcNumAromaticHeterocycles",
              RDKit::Descriptors::calcNumAromaticHeterocycles,
              (python::arg("mol")), docString.c_str());
  python::scope().attr("_CalcNumAromaticHeterocycles_version") =
      RDKit::Descriptors::NumAromaticHeterocyclesVersion;

  docString = "returns the number of aromatic carbocycles for a molecule";
  python::def("CalcNumAromaticCarbocycles",
              RDKit::Descriptors::calcNumAromaticCarbocycles,
              (python::arg("mol")), docString.c_str());
  python::scope().attr("_CalcNumAromaticCarbocycles_version") =
      RDKit::Descriptors::NumAromaticCarbocyclesVersion;

  docString = "returns the number of saturated heterocycles for a molecule";
  python::def("CalcNumSaturatedHeterocycles",
              RDKit::Descriptors::calcNumSaturatedHeterocycles,
              (python::arg("mol")), docString.c_str());
  python::scope().attr("_CalcNumSaturatedHeterocycles_version") =
      RDKit::Descriptors::NumSaturatedHeterocyclesVersion;

  docString = "returns the number of saturated carbocycles for a molecule";
  python::def("CalcNumSaturatedCarbocycles",
              RDKit::Descriptors::calcNumSaturatedCarbocycles,
              (python::arg("mol")), docString.c_str());
  python::scope().attr("_CalcNumSaturatedCarbocycles_version") =
      RDKit::Descriptors::NumSaturatedCarbocyclesVersion;

  docString =
      "returns the number of aliphatic (containing at least one non-aromatic "
      "bond) rings for a molecule";
  python::def("CalcNumAliphaticRings",
              RDKit::Descriptors::calcNumAliphaticRings, (python::arg("mol")),
              docString.c_str());
  python::scope().attr("_CalcNumAliphaticRings_version") =
      RDKit::Descriptors::NumAliphaticRingsVersion;

  docString =
      "returns the number of aliphatic (containing at least one non-aromatic "
      "bond) heterocycles for a molecule";
  python::def("CalcNumAliphaticHeterocycles",
              RDKit::Descriptors::calcNumAliphaticHeterocycles,
              (python::arg("mol")), docString.c_str());
  python::scope().attr("_CalcNumAliphaticHeterocycles_version") =
      RDKit::Descriptors::NumAliphaticHeterocyclesVersion;

  docString =
      "returns the number of aliphatic (containing at least one non-aromatic "
      "bond) carbocycles for a molecule";
  python::def("CalcNumAliphaticCarbocycles",
              RDKit::Descriptors::calcNumAliphaticCarbocycles,
              (python::arg("mol")), docString.c_str());
  python::scope().attr("_CalcNumAliphaticCarbocycles_version") =
      RDKit::Descriptors::NumAliphaticCarbocyclesVersion;

  docString = "returns the number of heteroatoms for a molecule";
  python::def("CalcNumHeteroatoms", RDKit::Descriptors::calcNumHeteroatoms,
              (python::arg("mol")), docString.c_str());
  python::scope().attr("_CalcNumHeteroatoms_version") =
      RDKit::Descriptors::NumHeteroatomsVersion;
  docString = "returns the number of amide bonds in a molecule";
  python::def("CalcNumAmideBonds", RDKit::Descriptors::calcNumAmideBonds,
              (python::arg("mol")), docString.c_str());
  python::scope().attr("_CalcNumAmideBonds_version") =
      RDKit::Descriptors::NumAmideBondsVersion;

  docString = "returns the fraction of C atoms that are SP3 hybridized";
  python::def("CalcFractionCSP3", RDKit::Descriptors::calcFractionCSP3,
              (python::arg("mol")), docString.c_str());
  python::scope().attr("_CalcFractionCSP3_version") =
      RDKit::Descriptors::FractionCSP3Version;

  docString = "returns the SlogP VSA contributions for a molecule";
  python::def("SlogP_VSA_", CalcSlogPVSA,
              (python::arg("mol"), python::arg("bins") = python::list(),
               python::arg("force") = false));
  docString = "returns the SMR VSA contributions for a molecule";
  python::def("SMR_VSA_", CalcSMRVSA,
              (python::arg("mol"), python::arg("bins") = python::list(),
               python::arg("force") = false));
  docString = "returns the PEOE VSA contributions for a molecule";
  python::def("PEOE_VSA_", CalcPEOEVSA,
              (python::arg("mol"), python::arg("bins") = python::list(),
               python::arg("force") = false));
  docString = "returns the MQN descriptors for a molecule";
  python::def("MQNs_", CalcMQNs,
              (python::arg("mol"), python::arg("force") = false));

  docString =
      "From equations (5),(9) and (10) of Rev. Comp. Chem. vol 2, 367-422, "
      "(1991)";
  python::def(
      "CalcChiNv", RDKit::Descriptors::calcChiNv,
      (python::arg("mol"), python::arg("n"), python::arg("force") = false));
  python::scope().attr("_CalcChiNv_version") = RDKit::Descriptors::chiNvVersion;
  docString =
      "From equations (5),(9) and (10) of Rev. Comp. Chem. vol 2, 367-422, "
      "(1991)";
  python::def("CalcChi0v", RDKit::Descriptors::calcChi0v,
              (python::arg("mol"), python::arg("force") = false));
  python::scope().attr("_CalcChi0v_version") = RDKit::Descriptors::chi0vVersion;
  docString =
      "From equations (5),(9) and (10) of Rev. Comp. Chem. vol 2, 367-422, "
      "(1991)";
  python::def("CalcChi1v", RDKit::Descriptors::calcChi1v,
              (python::arg("mol"), python::arg("force") = false));
  python::scope().attr("_CalcChi1v_version") = RDKit::Descriptors::chi1vVersion;
  docString =
      "From equations (5),(9) and (10) of Rev. Comp. Chem. vol 2, 367-422, "
      "(1991)";
  python::def("CalcChi2v", RDKit::Descriptors::calcChi2v,
              (python::arg("mol"), python::arg("force") = false));
  python::scope().attr("_CalcChi2v_version") = RDKit::Descriptors::chi2vVersion;
  docString =
      "From equations (5),(9) and (10) of Rev. Comp. Chem. vol 2, 367-422, "
      "(1991)";
  python::def("CalcChi3v", RDKit::Descriptors::calcChi3v,
              (python::arg("mol"), python::arg("force") = false));
  python::scope().attr("_CalcChi3v_version") = RDKit::Descriptors::chi3vVersion;
  docString =
      "From equations (5),(9) and (10) of Rev. Comp. Chem. vol 2, 367-422, "
      "(1991)";
  python::def("CalcChi4v", RDKit::Descriptors::calcChi4v,
              (python::arg("mol"), python::arg("force") = false));
  python::scope().attr("_CalcChi4v_version") = RDKit::Descriptors::chi4vVersion;
  docString =
      "Similar to ChiXv, but uses uses nVal instead of valence. This makes a "
      "big difference after we get out of the first row.";
  python::def(
      "CalcChiNn", RDKit::Descriptors::calcChiNn,
      (python::arg("mol"), python::arg("n"), python::arg("force") = false));
  python::scope().attr("_CalcChiNn_version") = RDKit::Descriptors::chiNnVersion;

  docString =
      "Similar to ChiXv, but uses uses nVal instead of valence. This makes a "
      "big difference after we get out of the first row.";
  python::def("CalcChi0n", RDKit::Descriptors::calcChi0n,
              (python::arg("mol"), python::arg("force") = false));
  python::scope().attr("_CalcChi0n_version") = RDKit::Descriptors::chi0nVersion;

  docString =
      "Similar to ChiXv, but uses uses nVal instead of valence. This makes a "
      "big difference after we get out of the first row.";
  python::def("CalcChi1n", RDKit::Descriptors::calcChi1n,
              (python::arg("mol"), python::arg("force") = false));
  python::scope().attr("_CalcChi1n_version") = RDKit::Descriptors::chi1nVersion;

  docString =
      "Similar to ChiXv, but uses uses nVal instead of valence. This makes a "
      "big difference after we get out of the first row.";
  python::def("CalcChi2n", RDKit::Descriptors::calcChi2n,
              (python::arg("mol"), python::arg("force") = false));
  python::scope().attr("_CalcChi2n_version") = RDKit::Descriptors::chi2nVersion;

  docString =
      "Similar to ChiXv, but uses uses nVal instead of valence. This makes a "
      "big difference after we get out of the first row.";
  python::def("CalcChi3n", RDKit::Descriptors::calcChi3n,
              (python::arg("mol"), python::arg("force") = false));
  python::scope().attr("_CalcChi3n_version") = RDKit::Descriptors::chi3nVersion;

  docString =
      "Similar to ChiXv, but uses uses nVal instead of valence. This makes a "
      "big difference after we get out of the first row.";
  python::def("CalcChi4n", RDKit::Descriptors::calcChi4n,
              (python::arg("mol"), python::arg("force") = false));
  python::scope().attr("_CalcChi4n_version") = RDKit::Descriptors::chi4nVersion;

  docString = "From equation (58) of Rev. Comp. Chem. vol 2, 367-422, (1991)";
  python::def(
      "CalcHallKierAlpha", hkAlphaHelper,
      (python::arg("mol"), python::arg("atomContribs") = python::object()));
  python::scope().attr("_CalcHallKierAlpha_version") =
      RDKit::Descriptors::hallKierAlphaVersion;

  docString =
      "From equations (58) and (59) of Rev. Comp. Chem. vol 2, 367-422, (1991)";
  python::def("CalcKappa1", RDKit::Descriptors::calcKappa1,
              (python::arg("mol")));
  python::scope().attr("_CalcKappa1_version") =
      RDKit::Descriptors::kappa1Version;
  docString =
      "From equations (58) and (60) of Rev. Comp. Chem. vol 2, 367-422, (1991)";
  python::def("CalcKappa2", RDKit::Descriptors::calcKappa2,
              (python::arg("mol")));
  python::scope().attr("_CalcKappa2_version") =
      RDKit::Descriptors::kappa2Version;
  docString =
      "From equations (58), (61) and (62) of Rev. Comp. Chem. vol 2, 367-422, "
      "(1991)";
  python::def("CalcKappa3", RDKit::Descriptors::calcKappa3,
              (python::arg("mol")));
  python::scope().attr("_CalcKappa3_version") =
      RDKit::Descriptors::kappa3Version;

  docString = "Returns the MACCS keys for a molecule as an ExplicitBitVect";
  python::def("GetMACCSKeysFingerprint",
              RDKit::MACCSFingerprints::getFingerprintAsBitVect,
              (python::arg("mol")), docString.c_str(),
              python::return_value_policy<python::manage_new_object>());

  python::scope().attr("_CalcNumSpiroAtoms_version") =
      RDKit::Descriptors::NumSpiroAtomsVersion;
  docString =
      "Returns the number of spiro atoms (atoms shared between rings that "
      "share exactly one atom)";
  python::def("CalcNumSpiroAtoms", numSpiroAtoms,
              (python::arg("mol"), python::arg("atoms") = python::object()),
              docString.c_str());

  python::scope().attr("_CalcNumBridgeheadAtoms_version") =
      RDKit::Descriptors::NumBridgeheadAtomsVersion;
  docString =
      "Returns the number of bridgehead atoms (atoms shared between rings that "
      "share at least two bonds)";
  python::def("CalcNumBridgeheadAtoms", numBridgeheadAtoms,
              (python::arg("mol"), python::arg("atoms") = python::object()),
              docString.c_str());

  docString = "Property computation class stored in the property registry.\n"
      "See rdkit.Chem.rdMolDescriptor.Properties.GetProperty and \n"
      "rdkit.Chem.Descriptor.Properties.PropertyFunctor for creating new ones";
  python::class_<RDKit::Descriptors::PropertyFunctor,
                 RDKit::Descriptors::PropertyFunctor*,
                 boost::shared_ptr<RDKit::Descriptors::PropertyFunctor>,
                 boost::noncopyable>("PropertyFunctor", docString.c_str(), python::no_init)
      .def("__call__", &RDKit::Descriptors::PropertyFunctor::operator(),
           "Compute the property for the specified molecule")
      .def("GetName", &RDKit::Descriptors::PropertyFunctor::getName,
           "Return the name of the property to calculate")
      .def("GetVersion", &RDKit::Descriptors::PropertyFunctor::getVersion,
           "Return the version of the calculated property");

  iterable_converter().from_python<std::vector<std::string> >();

  docString = "Property computation and registry system.  To compute all registered properties:\n"
      "mol = Chem.MolFromSmiles('c1ccccc1')\n"
      "properties = rdMolDescriptors.Properties()\n"
      "for name, value in zip(properties.GetPropertyNames(), properties.ComputeProperties(mol)):\n"
      "  print(name, value)\n\n"
      "To compute a subset\n"
      "properties = rdMolDescriptors.Properties(['exactmw', 'lipinskiHBA'])\n"
      "for name, value in zip(properties.GetPropertyNames(), properties.ComputeProperties(mol)):\n"
      "  print(name, value)\n\n"
      "";

  python::class_<RDKit::Descriptors::Properties,
                 RDKit::Descriptors::Properties*>("Properties", docString.c_str(), python::init<>() )
      .def(python::init<const std::vector<std::string>&>())
      .def("GetPropertyNames", &RDKit::Descriptors::Properties::getPropertyNames,
           "Return the property names computed by this instance")
      .def("ComputeProperties", &RDKit::Descriptors::Properties::computeProperties,
           (python::arg("mol"), python::arg("annotateMol")=false),
           "Return a list of computed properties, if annotateMol==True, annotate the molecule with "
           "the computed properties.")
      .def("AnnotateProperties",
           &RDKit::Descriptors::Properties::annotateProperties,
           python::arg("mol"),
           "Annotate the molecule with the computed properties.  These properties will be available "
           "as SDData or from mol.GetProp(prop)")
      .def("GetAvailableProperties", &RDKit::Descriptors::Properties::getAvailableProperties,
           "Return all available property names that can be computed").staticmethod("GetAvailableProperties")
      .def("GetProperty", &RDKit::Descriptors::Properties::getProperty,
           python::arg("propName"),
           "Return the named property if it exists").staticmethod("GetProperty")
      .def("RegisterProperty", &RDKit::Descriptors::Properties::registerProperty,
           python::arg("propertyFunctor"),
           "Register a new property object (not thread safe)").staticmethod("RegisterProperty");

  python::class_<PythonPropertyFunctor, boost::noncopyable,
                 python::bases<RDKit::Descriptors::PropertyFunctor> >(
                     "PythonPropertyFunctor","",python::init<
                     PyObject*, const std::string &, const std::string &>())
      .def("__call__", &PythonPropertyFunctor::operator(),
           "Compute the property for the specified molecule");

  docString = "Property Range Query for a molecule.  Match(mol) -> true if in range";
  python::class_<Queries::RangeQuery<double, RDKit::ROMol const&, true>,
                 Queries::RangeQuery<double, RDKit::ROMol const&, true>*,
                 boost::noncopyable>(
                     "PropertyRangeQuery",
                     docString.c_str(),
                     python::no_init)
      .def("Match", &Queries::RangeQuery<double, RDKit::ROMol const&, true>::Match);

  docString = "Generates a Range property for the specified property, between min and max\n"
      "query = MakePropertyRangeQuery('exactmw', 0, 500)\n"
      "query.Match( mol )";

  python::def("MakePropertyRangeQuery",
              RDKit::Descriptors::makePropertyRangeQuery,
              (python::arg("name"), python::arg("min"), python::arg("max")), docString.c_str(),
              python::return_value_policy<python::manage_new_object>());

}

max_stars_repo_name: darkreactions/rdkit

max_issues_repo_name: darkreactions/rdkit

max_forks_repo_name: darkreactions/rdkit


text:
#pragma once

#include <wise.kernel/net/protocol/bits/bits_packet.hpp>
#include <boost/system/error_code.hpp>

namespace wise {
namespace kernel {

struct bits_topic
{
	static const uint8_t category = 1;
	static const uint8_t group = 1;

	enum class type : uint16_t
	{
		connected = 1,
		connect_failed,
		accepted,
		disconnected,
	};

	static topic accepted()
	{
		return topic(category, group, (uint16_t)type::accepted);
	}

	static topic disconnected()
	{
		return topic(category, group, (uint16_t)type::disconnected);
	}
};

// naming convention:
// - syn : notification wo/ response
// - req : request expecting a response
// - res : response for a req packet

struct bits_syn_connected : public bits_packet
{
	static topic get_topic()
	{
		return topic(
			bits_topic::category,
			bits_topic::group,
			(uint16_t)bits_topic::type::connected);
	}

	bits_syn_connected()
		: bits_packet(get_topic())
	{
	}
};

struct bits_syn_connect_failed : public bits_packet
{
	static topic get_topic()
	{
		return topic(
			bits_topic::category,
			bits_topic::group,
			(uint16_t)bits_topic::type::connect_failed);
	}

	std::string remote_addr;
	boost::system::error_code ec;

	bits_syn_connect_failed()
		: bits_packet(get_topic())
	{
	}
};

struct bits_syn_accepted : public bits_packet
{
	static topic get_topic()
	{
		return topic(
			bits_topic::category,
			bits_topic::group,
			(uint16_t)bits_topic::type::accepted);
	}

	bits_syn_accepted()
		: bits_packet(get_topic())
	{
	}
};

struct bits_syn_disconnected: public bits_packet
{
	static topic get_topic()
	{
		return topic(
			bits_topic::category,
			bits_topic::group,
			(uint16_t)bits_topic::type::disconnected);
	}

	boost::system::error_code ec;

	bits_syn_disconnected()
		: bits_packet(get_topic())
	{
	}
};

} // kernel
} // wise

ext: hpp


text:
//
// Created by Chao Shu on 16/4/5.
//

#include <gtest/gtest.h>

#include <boost/bind.hpp>
#include <boost/make_shared.hpp>

#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/transport/TSocket.h>
#include <thrift/transport/TTransportUtils.h>

#include <muduo/base/AsyncLogging.h>
#include <muduo/base/Logging.h>
#include <muduo/base/TimeZone.h>
#include <muduo/net/EventLoopThread.h>
#include <muduo/net/InetAddress.h>
#include <thrift/async/TAsyncChannel.h>
#include <cthrift/cthrift_client_channel.h>
#include <cthrift/cthrift_async_callback.h>

#define private public
#define protected public
#include <cthrift/cthrift_svr.h>
#include <cthrift/cthrift_client.h>
#undef private
#undef protected

#include "Echo.h"

using namespace std;

using namespace apache::thrift;
using namespace apache::thrift::protocol;
using namespace apache::thrift::transport;
using namespace apache::thrift::async;

using namespace echo;
using namespace meituan_cthrift;

using namespace muduo;
using namespace muduo::net;
using namespace boost;

using testing::Types;

boost::shared_ptr<muduo::Thread> g_sp_thread_svr;
boost::shared_ptr<muduo::Thread> g_sp_thread_cli;
boost::shared_ptr<muduo::Thread> g_sp_thread_asyc_cli;

muduo::AsyncLogging *g_asyncLog = NULL;
muduo::net::EventLoop event_loop;

void asyncOutput(const char *msg, int len) {
  g_asyncLog->append(msg, len);
}

void Quit(void) {
  event_loop.quit();
  g_sp_thread_asyc_cli.reset();

  CTHRIFT_LOG_INFO("exit");
}

//callback函数，业务代码实际逻辑。
void my_echo(EchoCobClient *client) {
  std::string pong = "";
  //这行必不可少，请业务参考idl产生的源代码，填写revc函数
  client->recv_echo(pong);
  //业务实际的处理逻辑
  std::cout << pong << std::endl;
}

void TestAsyncSvrList(const string &str_svr_appkey,
                      const string &str_cli_appkey,
                      const int32_t &i32_loop_num) {
  //建议CthriftClient生命期也和线程保持一致，不要一次请求创建销毁一次
  boost::shared_ptr<CthriftClient>
      cthrift_client = boost::make_shared<CthriftClient>(str_svr_appkey, 30);

  //开启异步化，并设置异步场景下队列阈值，任务超过阈值后会被丢弃，并且向该业务线程抛出异常
  cthrift_client->SetAsync(true);
  cthrift_client->SetThreshold(100);
  //设置client appkey，方便服务治理识别来源
  if (SUCCESS != cthrift_client->SetClientAppkey(str_cli_appkey)) {
    return;
  }
  if (SUCCESS != cthrift_client->Init()) {
    return;
  }
  /* 注意：72行～84行关键代码段的Cthrift Client的初始化流程，请保证线程安全问题；
 *   避免多线程同时初始化，同一个cthrift client场景
 * */

  boost::shared_ptr<TAsyncChannel>
      channel = boost::make_shared<CthriftClientChannel>(cthrift_client);
  EchoCobClient client(channel, new CthriftTAsyncProtocolFactory());

  //业务借助AsyncCallback<class type>模版, 传入业务自己的回调处理callback: Success、Timeout ...
  function<void(EchoCobClient *client)> echo_cob = boost::bind(&my_echo, _1);
  AsyncCallback <EchoCobClient> *pecho = new AsyncCallback<EchoCobClient>();
  //传入成功处理callback
  pecho->Success(echo_cob);
  function<void(EchoCobClient *client)>
      cob = boost::bind(&AsyncCallback<EchoCobClient>::Callback, pecho, _1);

  string strRet;
  string str_tmp;
  size_t sz;
  char buf[1025];  //1K数据
  memset(buf, 1, sizeof(buf));

  std::string arg = "arg";

  test arg_all;
  arg_all.__set_arg("arg1");
  arg_all.__set_arg2(10.0);

  std::vector<std::string> arg3;
  arg3.push_back(arg);
  arg3.push_back(arg);
  arg3.push_back(arg);

  arg_all.__set_arg3(arg3);

  std::map<std::string, std::string> arg4;
  arg4["1"] = arg;
  arg4["2"] = arg;
  arg4["3"] = arg;

  arg_all.__set_arg4(arg4);

  arg_all.__set_arg5(false);

  std::set<int64_t> arg6;
  arg6.insert(1);
  arg6.insert(2);
  arg6.insert(3);

  arg_all.__set_arg6(arg6);

  arg_all.__set_arg7(7);

  arg_all.__set_arg8(TweetType::REPLY);

  for (int i = muduo::CurrentThread::tid() * 1000;
       i < muduo::CurrentThread::tid() * 1000 + 100; i++) {

    try {
      str_tmp = boost::lexical_cast<std::string>(i);
    } catch (boost::bad_lexical_cast &e) {

      cerr << "boost::bad_lexical_cast :" << e.what()
           << "i : " << i;
      continue;
    }

    sz = str_tmp.size();
    str_tmp += string(buf, 0, sizeof(buf) - 1 - sz);

    retry:
    try {
      //thrift标准的异步化
      client.echo(cob, str_tmp, arg_all);
    } catch (TException &tx) {
      cerr << "ERROR: " << tx.what() << endl;
      sleep(1);
      //抛出超出发送队列阈值异常，业务线程应该减速，并且重试本次数据发送操作
      goto retry;
    }

  }

  //等待异步回调线程排空数据
  sleep(20);
}

class EchoHandler : virtual public EchoIf {
 public:
  EchoHandler() {
  }

  void echo(std::string &_return, const std::string &arg, const test &arg2) {
    CTHRIFT_LOG_DEBUG("EchoHandler::echo:" << arg);
    _return = arg;
  }
};

void TestRegSvr(muduo::net::EventLoop *p_event_loop) {
  boost::shared_ptr<EchoHandler> handler(new EchoHandler());
  boost::shared_ptr<TProcessor> processor(new EchoProcessor(handler));

  try {
    CthriftSvr svr(processor);

    if (svr.Init() != 0) {
      CTHRIFT_LOG_ERROR("CthriftSvr init failed: ");
      return;
    }

    svr.serve();
  } catch (TException &tx) {
    EXPECT_EQ(tx.what(), "str_app_key empty, reason ");
    CTHRIFT_LOG_ERROR("CthriftSvr failed: " << tx.what());
    cerr << "CthriftSvr failed: " << tx.what() << endl;
    FAIL();

    p_event_loop->runInLoop(boost::bind(&Quit));
  }
}

int main(int argc, char **argv) {

  testing::InitGoogleTest(&argc, argv);

  log4cplus::PropertyConfigurator::doConfigure(LOG4CPLUS_TEXT("log4cplus.conf"));

  if (CTHRIFT_UNLIKELY(4 < argc)) {
    CTHRIFT_LOG_ERROR(
        "prog <appkey,default \"com.sankuai.inf.newct\"> <echo loop time, default 100> <port, defalut 6666>");
    cerr
        << "prog <appkey,default \"com.sankuai.inf.newct\"> <echo loop time, default 100> <port, defalut 6666>"
        << endl;
    exit(-1);
  }

  string str_svr_appkey("com.sankuai.inf.newct");
  string str_cli_appkey("com.sankuai.inf.newct.client");
  int32_t i32_echo_time = 100;

  if (2 <= argc) {
    str_svr_appkey.assign(argv[1]);
    if (3 <= argc) {
      i32_echo_time = atoi(argv[2]);
    }
  }

  CTHRIFT_LOG_DEBUG(
      "str_svr_appkey: " << str_svr_appkey << " i32_echo_time: " <<
                         i32_echo_time);

  g_sp_thread_svr =
      boost::make_shared<muduo::Thread>(boost::bind(&TestRegSvr, &event_loop));
  g_sp_thread_svr->start();

  muduo::CurrentThread::sleepUsec(3000 * 1000); //wait 3s for reg svr

  g_sp_thread_asyc_cli =
      boost::make_shared<muduo::Thread>(boost::bind(&TestAsyncSvrList,
                                                    str_svr_appkey,
                                                    str_cli_appkey,
                                                    i32_echo_time));
  g_sp_thread_asyc_cli->start();

  event_loop.runAfter(60.0, boost::bind(&Quit));

  event_loop.loop();

  CTHRIFT_LOG_INFO("EXIT loop");

  return RUN_ALL_TESTS();;
}

ext: cc


text:
//  Copyright (c) 2009 Hartmut Kaiser
//
//  Distributed under the Boost Software License, Version 1.0. (See accompanying
//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#include <boost/detail/lightweight_test.hpp>

#include <saga/saga.hpp>
#include <iostream>

int main ()
{
    // serialize session
    try {
        saga::session s;
        saga::context ctx("default_advert_db");
        ctx.set_attribute(saga::attributes::context_userid, "SAGA");
        ctx.set_attribute(saga::attributes::context_userpass, "Example");
        s.add_context(ctx);

        std::vector<saga::context> ctxs = s.list_contexts();
        BOOST_TEST(ctxs.size() == 1 &&
            ctxs[0].get_attribute(saga::attributes::context_type) == "default_advert_db");

        saga::advert::entry e("advert://localhost/session_test?dbname=session_test.db&dbtype=sqlite3",
            saga::advert::Create|saga::advert::Overwrite|saga::advert::ReadWrite);
        e.store_object(s);
    }
    catch (saga::exception const& e)
    {
        std::cerr << e.what () << std::endl;
        BOOST_TEST(false);
    }

    // deserialize session
    try {
        saga::advert::entry e("advert://localhost/session_test?dbname=session_test.db&dbtype=sqlite3",
            saga::advert::ReadWrite);

        saga::session s(e.retrieve_object());
        std::vector<saga::context> ctxs = s.list_contexts();
        BOOST_TEST(ctxs.size() == 1 &&
            ctxs[0].get_attribute(saga::attributes::context_type) == "default_advert_db");
    }
    catch (saga::exception const& e)
    {
        std::cerr << e.what () << std::endl;
        BOOST_TEST(false);
    }

    // serialize context
    try {
        saga::session s;
        saga::context ctx("default_advert_db");
        ctx.set_attribute(saga::attributes::context_userid, "SAGA");
        ctx.set_attribute(saga::attributes::context_userpass, "Example");
        s.add_context(ctx);

        saga::advert::entry e("advert://localhost/context_test?dbname=session_test.db&dbtype=sqlite3",
            saga::advert::Create|saga::advert::Overwrite|saga::advert::ReadWrite);
        e.store_object(ctx);
    }
    catch (saga::exception const& e)
    {
        std::cerr << e.what () << std::endl;
        BOOST_TEST(false);
    }

    // deserialize session
    try {
        saga::advert::entry e("advert://localhost/context_test?dbname=session_test.db&dbtype=sqlite3",
            saga::advert::ReadWrite);

        saga::context ctx(e.retrieve_object());
        BOOST_TEST(ctx.get_attribute(saga::attributes::context_type) == "default_advert_db");
        BOOST_TEST(ctx.get_attribute(saga::attributes::context_userid) == "SAGA");
        BOOST_TEST(ctx.get_attribute(saga::attributes::context_userpass) == "Example");
    }
    catch (saga::exception const& e)
    {
        std::cerr << e.what () << std::endl;
        BOOST_TEST(false);
    }

    return boost::report_errors();
}

ext: cpp

max_stars_repo_name: saga-project/saga-cpp

max_issues_repo_name: saga-project/saga-cpp

max_forks_repo_name: saga-project/saga-cpp


text:
// Boost.Bimap
//
// Copyright (c) 2006-2007 Matias Capeletto
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

//  VC++ 8.0 warns on usage of certain Standard Library and API functions that
//  can be cause buffer overruns or other possible security issues if misused.
//  See https://web.archive.org/web/20071014014301/http://msdn.microsoft.com/msdnmag/issues/05/05/SafeCandC/default.aspx
//  But the wording of the warning is misleading and unsettling, there are no
//  portable alternative functions, and VC++ 8.0's own libraries use the
//  functions in question. So turn off the warnings.
#define _CRT_SECURE_NO_DEPRECATE
#define _SCL_SECURE_NO_DEPRECATE

#include <boost/config.hpp>

// Boost.Test
#include <boost/test/minimal.hpp>

// Boost.Bimap
#include <boost/bimap/support/lambda.hpp>
#include <boost/bimap/bimap.hpp>

void test_bimap_unconstrained()
{
    using namespace boost::bimaps;

    {
        typedef bimap<int,double,unconstrained_set_of_relation> bm;
        bm b;
        b.left.insert( bm::left_value_type(2,34.4) );
        b.right.insert( bm::right_value_type(2.2,3) );
    }

    {
        typedef bimap<int,unconstrained_set_of<double> > bm;
        bm b;
        b.insert( bm::value_type(2,34.4) );
        BOOST_CHECK( b.size() == 1 );
    }

    {
        typedef bimap<unconstrained_set_of<int>, double > bm;
        bm b;
        b.right[2.4] = 34;
        BOOST_CHECK( b.right.size() == 1 );
    }

    {
        typedef bimap<unconstrained_set_of<int>, double, right_based > bm;
        bm b;
        b.right[2.4] = 34;
        BOOST_CHECK( b.right.size() == 1 );
    }

    {
        typedef bimap
        <
            int,
            unconstrained_set_of<double>,
            unconstrained_set_of_relation

        > bm;

        bm b;
        b.left[2] = 34.4;
        BOOST_CHECK( b.left.size() == 1 );
    }

    {
        typedef bimap
        <
            unconstrained_set_of<int>,
            double,
            unconstrained_set_of_relation

        > bm;

        bm b;
        b.right[2.4] = 34;
        BOOST_CHECK( b.right.size() == 1 );
    }

    {
        typedef bimap
        <
            unconstrained_set_of<int>,
            unconstrained_set_of<double>,
            set_of_relation<>

        > bm;

        bm b;
        b.insert( bm::value_type(1,2.3) );
        BOOST_CHECK( b.size() == 1 );
    }
}

int test_main( int, char* [] )
{
    test_bimap_unconstrained();
    return 0;
}

max_issues_repo_name: qingkouwei/mediaones

max_forks_repo_name: qingkouwei/mediaones


text: #include <boost/parameter/aux_/set.hpp>

max_stars_repo_name: miathedev/BoostForArduino

max_issues_repo_name: miathedev/BoostForArduino

max_forks_repo_name: miathedev/BoostForArduino


text:
// Distributed under the MIT License.
// See LICENSE.txt for details.

#pragma once

#include <array>
#include <boost/functional/hash.hpp>
#include <cstddef>
#include <utility>

#include "DataStructures/DataBox/Prefixes.hpp"
#include "DataStructures/DataVector.hpp"
#include "DataStructures/FixedHashMap.hpp"
#include "DataStructures/Tensor/Slice.hpp"
#include "DataStructures/Tensor/Tensor.hpp"
#include "DataStructures/Variables.hpp"
#include "Domain/ElementMap.hpp"
#include "Domain/LogicalCoordinates.hpp"
#include "Domain/Structure/Direction.hpp"
#include "Domain/Structure/DirectionMap.hpp"
#include "Domain/Structure/Element.hpp"
#include "Domain/Structure/ElementId.hpp"
#include "Domain/Structure/MaxNumberOfNeighbors.hpp"
#include "Domain/Structure/Neighbors.hpp"
#include "Evolution/DgSubcell/NeighborData.hpp"
#include "Evolution/DgSubcell/SliceData.hpp"
#include "Evolution/Systems/ScalarAdvection/FiniteDifference/Reconstructor.hpp"
#include "Evolution/Systems/ScalarAdvection/Tags.hpp"
#include "NumericalAlgorithms/Spectral/Mesh.hpp"
#include "NumericalAlgorithms/Spectral/Spectral.hpp"
#include "Utilities/Gsl.hpp"
#include "Utilities/MakeArray.hpp"
#include "Utilities/TMPL.hpp"

namespace TestHelpers {
/*!
 * \brief Defines functions useful for testing advection subcell
 */
namespace ScalarAdvection::fd {
template <size_t Dim, typename F>
FixedHashMap<maximum_number_of_neighbors(Dim) + 1,
             std::pair<Direction<Dim>, ElementId<Dim>>,
             evolution::dg::subcell::NeighborData,
             boost::hash<std::pair<Direction<Dim>, ElementId<Dim>>>>
compute_neighbor_data(const Mesh<Dim>& subcell_mesh,
                      const tnsr::I<DataVector, Dim, Frame::ElementLogical>&
                          volume_logical_coords,
                      const DirectionMap<Dim, Neighbors<Dim>>& neighbors,
                      const size_t ghost_zone_size,
                      const F& compute_variables_of_neighbor_data) {
  FixedHashMap<maximum_number_of_neighbors(Dim) + 1,
               std::pair<Direction<Dim>, ElementId<Dim>>,
               evolution::dg::subcell::NeighborData,
               boost::hash<std::pair<Direction<Dim>, ElementId<Dim>>>>
      neighbor_data{};
  for (const auto& [direction, neighbors_in_direction] : neighbors) {
    REQUIRE(neighbors_in_direction.size() ==
            1);  // currently only support one neighbor in each direction
    const ElementId<Dim>& neighbor_id = *neighbors_in_direction.begin();

    auto neighbor_logical_coords = volume_logical_coords;
    neighbor_logical_coords.get(direction.dimension()) +=
        direction.sign() * 2.0;
    const auto neighbor_vars_for_reconstruction =
        compute_variables_of_neighbor_data(neighbor_logical_coords);

    DirectionMap<Dim, bool> directions_to_slice{};
    directions_to_slice[direction.opposite()] = true;
    const auto sliced_data = evolution::dg::subcell::detail::slice_data_impl(
        gsl::make_span(neighbor_vars_for_reconstruction.data(),
                       neighbor_vars_for_reconstruction.size()),
        subcell_mesh.extents(), ghost_zone_size, directions_to_slice);
    REQUIRE(sliced_data.size() == 1);
    REQUIRE(sliced_data.contains(direction.opposite()));
    neighbor_data[std::pair{direction, neighbor_id}].data_for_reconstruction =
        sliced_data.at(direction.opposite());
  }
  return neighbor_data;
}

template <size_t Dim, typename Reconstructor>
void test_reconstructor(const size_t points_per_dimension,
                        const Reconstructor& derived_reconstructor) {
  // 1. create the scalar field U to reconstruct being linear to coords
  // 2. send through reconstruction
  // 3. check if U was reconstructed correctly

  const ::ScalarAdvection::fd::Reconstructor<Dim>& reconstructor =
      derived_reconstructor;
  static_assert(
      tmpl::list_contains_v<
          typename ::ScalarAdvection::fd::Reconstructor<Dim>::creatable_classes,
          Reconstructor>);

  // create an element and its neighbor elements
  DirectionMap<Dim, Neighbors<Dim>> neighbors{};
  for (size_t i = 0; i < 2 * Dim; ++i) {
    neighbors[gsl::at(Direction<Dim>::all_directions(), i)] =
        Neighbors<Dim>{{ElementId<Dim>{i + 1, {}}}, {}};
  }
  const Element<Dim> element{ElementId<Dim>{0, {}}, neighbors};

  // a simple, linear form of the scalar field U for testing purpose
  //   * U(x)   = x + 1       (for 1D)
  //   * U(x,y) = x + 2y + 1  (for 2D)
  using scalar_u = ::ScalarAdvection::Tags::U;
  const auto compute_solution = [](const auto& coords) {
    Variables<tmpl::list<scalar_u>> vars{get<0>(coords).size(), 0.0};
    for (size_t i = 0; i < Dim; ++i) {
      get(get<scalar_u>(vars)) += (i + 1) * coords.get(i);
    }
    get(get<scalar_u>(vars)) += 1.0;
    return vars;
  };

  // compute neighbor data
  const Mesh<Dim> subcell_mesh{points_per_dimension,
                               Spectral::Basis::FiniteDifference,
                               Spectral::Quadrature::CellCentered};
  auto logical_coords = logical_coordinates(subcell_mesh);
  const FixedHashMap<maximum_number_of_neighbors(Dim) + 1,
                     std::pair<Direction<Dim>, ElementId<Dim>>,
                     evolution::dg::subcell::NeighborData,
                     boost::hash<std::pair<Direction<Dim>, ElementId<Dim>>>>
      neighbor_data = compute_neighbor_data(
          subcell_mesh, logical_coords, element.neighbors(),
          reconstructor.ghost_zone_size(), compute_solution);

  // create Variables on lower and upper faces to perform reconstruction
  using dg_package_data_argument_tags =
      tmpl::list<scalar_u,
                 ::Tags::Flux<scalar_u, tmpl::size_t<Dim>, Frame::Inertial>,
                 ::ScalarAdvection::Tags::VelocityField<Dim>>;
  const size_t reconstructed_num_pts =
      (subcell_mesh.extents(0) + 1) *
      subcell_mesh.extents().slice_away(0).product();
  std::array<Variables<dg_package_data_argument_tags>, Dim> vars_on_lower_face =
      make_array<Dim>(
          Variables<dg_package_data_argument_tags>(reconstructed_num_pts));
  std::array<Variables<dg_package_data_argument_tags>, Dim> vars_on_upper_face =
      make_array<Dim>(
          Variables<dg_package_data_argument_tags>(reconstructed_num_pts));

  Variables<tmpl::list<scalar_u>> volume_vars{
      subcell_mesh.number_of_grid_points()};
  volume_vars.assign_subset(compute_solution(logical_coords));

  // call the reconstruction
  dynamic_cast<const Reconstructor&>(reconstructor)
      .reconstruct(make_not_null(&vars_on_lower_face),
                   make_not_null(&vars_on_upper_face), volume_vars, element,
                   neighbor_data, subcell_mesh);

  for (size_t dim = 0; dim < Dim; ++dim) {
    // construct face-centered coordinates
    const auto basis = make_array<Dim>(Spectral::Basis::FiniteDifference);
    auto quadrature = make_array<Dim>(Spectral::Quadrature::CellCentered);
    auto extents = make_array<Dim>(points_per_dimension);
    gsl::at(extents, dim) = points_per_dimension + 1;
    gsl::at(quadrature, dim) = Spectral::Quadrature::FaceCentered;
    const Mesh<Dim> face_centered_mesh{extents, basis, quadrature};
    auto logical_coords_face_centered = logical_coordinates(face_centered_mesh);

    // check reconstructed values for reconstruct() function
    Variables<dg_package_data_argument_tags> expected_face_values{
        face_centered_mesh.number_of_grid_points()};
    expected_face_values.assign_subset(
        compute_solution(logical_coords_face_centered));

    CHECK_ITERABLE_APPROX(get<scalar_u>(gsl::at(vars_on_lower_face, dim)),
                          get<scalar_u>(expected_face_values));
    CHECK_ITERABLE_APPROX(get<scalar_u>(gsl::at(vars_on_upper_face, dim)),
                          get<scalar_u>(expected_face_values));

    // check reconstructed values for reconstruct_fd_neighbor() function
    Variables<dg_package_data_argument_tags> vars_on_mortar_face{0};
    Variables<dg_package_data_argument_tags> expected_mortar_face_values{0};

    for (size_t upper_or_lower = 0; upper_or_lower < 2; ++upper_or_lower) {
      // iterate over upper and lower direction
      Direction<Dim> direction =
          gsl::at(Direction<Dim>::all_directions(), 2 * dim + upper_or_lower);

      if constexpr (Dim == 1) {
        // 1D mortar has only one face point
        vars_on_mortar_face.initialize(1);
        expected_mortar_face_values.initialize(1);
      } else {
        const size_t num_mortar_face_pts =
            subcell_mesh.extents().slice_away(direction.dimension()).product();
        vars_on_mortar_face.initialize(num_mortar_face_pts);
        expected_mortar_face_values.initialize(num_mortar_face_pts);
      }

      // call the reconstruction
      dynamic_cast<const Reconstructor&>(reconstructor)
          .reconstruct_fd_neighbor(make_not_null(&vars_on_mortar_face),
                                   volume_vars, element, neighbor_data,
                                   subcell_mesh, direction);

      // slice face-centered variables to get the values on the mortar
      data_on_slice(make_not_null(&get<scalar_u>(expected_mortar_face_values)),
                    get<scalar_u>(expected_face_values),
                    face_centered_mesh.extents(), direction.dimension(),
                    direction.side() == Side::Lower
                        ? 0
                        : extents[direction.dimension()] - 1);

      CHECK_ITERABLE_APPROX(get<scalar_u>(vars_on_mortar_face),
                            get<scalar_u>(expected_mortar_face_values));
    }
  }
}

}  // namespace ScalarAdvection::fd
}  // namespace TestHelpers

max_stars_repo_name: kidder/spectre

max_issues_repo_name: kidder/spectre

max_forks_repo_name: kidder/spectre


text:
/*
 *
 * Copyright (c) 2004
 * John Maddock
 *
 * Use, modification and distribution are subject to the
 * Boost Software License, Version 1.0. (See accompanying file
 * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 *
 */

/*
 *   LOCATION:    see http://www.boost.org for most recent version.
 *   FILE         regex_traits_defaults.hpp
 *   VERSION      see <boost/version.hpp>
 *   DESCRIPTION: Declares API's for access to regex_traits default properties.
 */

#ifndef BOOST_REGEX_TRAITS_DEFAULTS_HPP_INCLUDED
#define BOOST_REGEX_TRAITS_DEFAULTS_HPP_INCLUDED

#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable : 4103)
#endif
#ifdef BOOST_HAS_ABI_HEADERS
#include BOOST_ABI_PREFIX
#endif
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif

#include <boost/regex/config.hpp>

#ifndef BOOST_REGEX_SYNTAX_TYPE_HPP
#include <boost/regex/v4/syntax_type.hpp>
#endif
#ifndef BOOST_REGEX_ERROR_TYPE_HPP
#include <boost/regex/v4/error_type.hpp>
#endif
#include <boost/type_traits/make_unsigned.hpp>
#include <boost/utility/enable_if.hpp>

#ifdef BOOST_NO_STDC_NAMESPACE
namespace std
{
using ::strlen;
}
#endif

namespace boost
{
namespace BOOST_REGEX_DETAIL_NS
{

//
// helpers to suppress warnings:
//
template <class charT>
inline bool is_extended(charT c)
{
    typedef typename make_unsigned<charT>::type unsigned_type;
    return (sizeof(charT) > 1) && (static_cast<unsigned_type>(c) >= 256u);
}
inline bool is_extended(char)
{
    return false;
}

BOOST_REGEX_DECL const char* BOOST_REGEX_CALL
    get_default_syntax(regex_constants::syntax_type n);
BOOST_REGEX_DECL const char* BOOST_REGEX_CALL
    get_default_error_string(regex_constants::error_type n);
BOOST_REGEX_DECL regex_constants::syntax_type BOOST_REGEX_CALL
    get_default_syntax_type(char c);
BOOST_REGEX_DECL regex_constants::escape_syntax_type BOOST_REGEX_CALL
    get_default_escape_syntax_type(char c);

// is charT c a combining character?
BOOST_REGEX_DECL bool BOOST_REGEX_CALL
    is_combining_implementation(uint_least16_t s);

template <class charT>
inline bool is_combining(charT c)
{
    return (c <= static_cast<charT>(0))
               ? false
               : ((c >= static_cast<charT>(
                            (std::numeric_limits<uint_least16_t>::max)()))
                      ? false
                      : is_combining_implementation(
                            static_cast<unsigned short>(c)));
}
template <>
inline bool is_combining<char>(char)
{
    return false;
}
template <>
inline bool is_combining<signed char>(signed char)
{
    return false;
}
template <>
inline bool is_combining<unsigned char>(unsigned char)
{
    return false;
}
#if !defined(__hpux) &&                                                        \
    !defined(__WINSCW__) // can't use WCHAR_MAX/MIN in pp-directives
#ifdef _MSC_VER
template <>
inline bool is_combining<wchar_t>(wchar_t c)
{
    return is_combining_implementation(static_cast<unsigned short>(c));
}
#elif !defined(__DECCXX) && !defined(__osf__) && !defined(__OSF__) &&          \
    defined(WCHAR_MIN) && (WCHAR_MIN == 0) &&                                  \
    !defined(BOOST_NO_INTRINSIC_WCHAR_T)
#if defined(WCHAR_MAX) && (WCHAR_MAX <= USHRT_MAX)
template <>
inline bool is_combining<wchar_t>(wchar_t c)
{
    return is_combining_implementation(static_cast<unsigned short>(c));
}
#else
template <>
inline bool is_combining<wchar_t>(wchar_t c)
{
    return (c >= (std::numeric_limits<uint_least16_t>::max)())
               ? false
               : is_combining_implementation(static_cast<unsigned short>(c));
}
#endif
#endif
#endif

//
// is a charT c a line separator?
//
template <class charT>
inline bool is_separator(charT c)
{
    return BOOST_REGEX_MAKE_BOOL((c == static_cast<charT>('\n')) ||
                                 (c == static_cast<charT>('\r')) ||
                                 (c == static_cast<charT>('\f')) ||
                                 (static_cast<boost::uint16_t>(c) == 0x2028u) ||
                                 (static_cast<boost::uint16_t>(c) == 0x2029u) ||
                                 (static_cast<boost::uint16_t>(c) == 0x85u));
}
template <>
inline bool is_separator<char>(char c)
{
    return BOOST_REGEX_MAKE_BOOL((c == '\n') || (c == '\r') || (c == '\f'));
}

//
// get a default collating element:
//
BOOST_REGEX_DECL std::string BOOST_REGEX_CALL
    lookup_default_collate_name(const std::string& name);

//
// get the state_id of a character clasification, the individual
// traits classes then transform that state_id into a bitmask:
//
template <class charT>
struct character_pointer_range
{
    const charT* p1;
    const charT* p2;

    bool operator<(const character_pointer_range& r) const
    {
        return std::lexicographical_compare(p1, p2, r.p1, r.p2);
    }
    bool operator==(const character_pointer_range& r) const
    {
        // Not only do we check that the ranges are of equal size before
        // calling std::equal, but there is no other algorithm available:
        // not even a non-standard MS one.  So forward to unchecked_equal
        // in the MS case.
        return ((p2 - p1) == (r.p2 - r.p1)) &&
               BOOST_REGEX_DETAIL_NS::equal(p1, p2, r.p1);
    }
};
template <class charT>
int get_default_class_id(const charT* p1, const charT* p2)
{
    static const charT data[73] = {
        'a', 'l', 'n', 'u', 'm', 'a', 'l', 'p', 'h', 'a', 'b', 'l', 'a',
        'n', 'k', 'c', 'n', 't', 'r', 'l', 'd', 'i', 'g', 'i', 't', 'g',
        'r', 'a', 'p', 'h', 'l', 'o', 'w', 'e', 'r', 'p', 'r', 'i', 'n',
        't', 'p', 'u', 'n', 'c', 't', 's', 'p', 'a', 'c', 'e', 'u', 'n',
        'i', 'c', 'o', 'd', 'e', 'u', 'p', 'p', 'e', 'r', 'v', 'w', 'o',
        'r', 'd', 'x', 'd', 'i', 'g', 'i', 't',
    };

    static const character_pointer_range<charT> ranges[21] = {
        {
            data + 0,
            data + 5,
        }, // alnum
        {
            data + 5,
            data + 10,
        }, // alpha
        {
            data + 10,
            data + 15,
        }, // blank
        {
            data + 15,
            data + 20,
        }, // cntrl
        {
            data + 20,
            data + 21,
        }, // d
        {
            data + 20,
            data + 25,
        }, // digit
        {
            data + 25,
            data + 30,
        }, // graph
        {
            data + 29,
            data + 30,
        }, // h
        {
            data + 30,
            data + 31,
        }, // l
        {
            data + 30,
            data + 35,
        }, // lower
        {
            data + 35,
            data + 40,
        }, // print
        {
            data + 40,
            data + 45,
        }, // punct
        {
            data + 45,
            data + 46,
        }, // s
        {
            data + 45,
            data + 50,
        }, // space
        {
            data + 57,
            data + 58,
        }, // u
        {
            data + 50,
            data + 57,
        }, // unicode
        {
            data + 57,
            data + 62,
        }, // upper
        {
            data + 62,
            data + 63,
        }, // v
        {
            data + 63,
            data + 64,
        }, // w
        {
            data + 63,
            data + 67,
        }, // word
        {
            data + 67,
            data + 73,
        }, // xdigit
    };
    static const character_pointer_range<charT>* ranges_begin = ranges;
    static const character_pointer_range<charT>* ranges_end =
        ranges + (sizeof(ranges) / sizeof(ranges[0]));

    character_pointer_range<charT> t = {
        p1,
        p2,
    };
    const character_pointer_range<charT>* p =
        std::lower_bound(ranges_begin, ranges_end, t);
    if ((p != ranges_end) && (t == *p))
        return static_cast<int>(p - ranges);
    return -1;
}

//
// helper functions:
//
template <class charT>
std::ptrdiff_t global_length(const charT* p)
{
    std::ptrdiff_t n = 0;
    while (*p)
    {
        ++p;
        ++n;
    }
    return n;
}
template <>
inline std::ptrdiff_t global_length<char>(const char* p)
{
    return (std::strlen)(p);
}
#ifndef BOOST_NO_WREGEX
template <>
inline std::ptrdiff_t global_length<wchar_t>(const wchar_t* p)
{
    return (std::ptrdiff_t)(std::wcslen)(p);
}
#endif
template <class charT>
inline charT BOOST_REGEX_CALL global_lower(charT c)
{
    return c;
}
template <class charT>
inline charT BOOST_REGEX_CALL global_upper(charT c)
{
    return c;
}

BOOST_REGEX_DECL char BOOST_REGEX_CALL do_global_lower(char c);
BOOST_REGEX_DECL char BOOST_REGEX_CALL do_global_upper(char c);
#ifndef BOOST_NO_WREGEX
BOOST_REGEX_DECL wchar_t BOOST_REGEX_CALL do_global_lower(wchar_t c);
BOOST_REGEX_DECL wchar_t BOOST_REGEX_CALL do_global_upper(wchar_t c);
#endif
#ifdef BOOST_REGEX_HAS_OTHER_WCHAR_T
BOOST_REGEX_DECL unsigned short BOOST_REGEX_CALL
    do_global_lower(unsigned short c);
BOOST_REGEX_DECL unsigned short BOOST_REGEX_CALL
    do_global_upper(unsigned short c);
#endif
//
// This sucks: declare template specialisations of global_lower/global_upper
// that just forward to the non-template implementation functions.  We do
// this because there is one compiler (Compaq Tru64 C++) that doesn't seem
// to differentiate between templates and non-template overloads....
// what's more, the primary template, plus all overloads have to be
// defined in the same translation unit (if one is inline they all must be)
// otherwise the "local template instantiation" compiler option can pick
// the wrong instantiation when linking:
//
template <>
inline char BOOST_REGEX_CALL global_lower<char>(char c)
{
    return do_global_lower(c);
}
template <>
inline char BOOST_REGEX_CALL global_upper<char>(char c)
{
    return do_global_upper(c);
}
#ifndef BOOST_NO_WREGEX
template <>
inline wchar_t BOOST_REGEX_CALL global_lower<wchar_t>(wchar_t c)
{
    return do_global_lower(c);
}
template <>
inline wchar_t BOOST_REGEX_CALL global_upper<wchar_t>(wchar_t c)
{
    return do_global_upper(c);
}
#endif
#ifdef BOOST_REGEX_HAS_OTHER_WCHAR_T
template <>
inline unsigned short BOOST_REGEX_CALL
    global_lower<unsigned short>(unsigned short c)
{
    return do_global_lower(c);
}
template <>
inline unsigned short BOOST_REGEX_CALL
    global_upper<unsigned short>(unsigned short c)
{
    return do_global_upper(c);
}
#endif

template <class charT>
int global_value(charT c)
{
    static const charT zero = '0';
    static const charT nine = '9';
    static const charT a = 'a';
    static const charT f = 'f';
    static const charT A = 'A';
    static const charT F = 'F';

    if (c > f)
        return -1;
    if (c >= a)
        return 10 + (c - a);
    if (c > F)
        return -1;
    if (c >= A)
        return 10 + (c - A);
    if (c > nine)
        return -1;
    if (c >= zero)
        return c - zero;
    return -1;
}
template <class charT, class traits>
boost::intmax_t global_toi(const charT*& p1, const charT* p2, int radix,
                           const traits& t)
{
    (void)t; // warning suppression
    boost::intmax_t limit =
        (std::numeric_limits<boost::intmax_t>::max)() / radix;
    boost::intmax_t next_value = t.value(*p1, radix);
    if ((p1 == p2) || (next_value < 0) || (next_value >= radix))
        return -1;
    boost::intmax_t result = 0;
    while (p1 != p2)
    {
        next_value = t.value(*p1, radix);
        if ((next_value < 0) || (next_value >= radix))
            break;
        result *= radix;
        result += next_value;
        ++p1;
        if (result > limit)
            return -1;
    }
    return result;
}

template <class charT>
inline typename boost::enable_if_c<(sizeof(charT) > 1), const charT*>::type
    get_escape_R_string()
{
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable : 4309 4245)
#endif
    static const charT e1[] = {'(',
                               '?',
                               '-',
                               'x',
                               ':',
                               '(',
                               '?',
                               '>',
                               '\x0D',
                               '\x0A',
                               '?',
                               '|',
                               '[',
                               '\x0A',
                               '\x0B',
                               '\x0C',
                               static_cast<charT>(0x85),
                               static_cast<charT>(0x2028),
                               static_cast<charT>(0x2029),
                               ']',
                               ')',
                               ')',
                               '\0'};
    static const charT e2[] = {'(',
                               '?',
                               '-',
                               'x',
                               ':',
                               '(',
                               '?',
                               '>',
                               '\x0D',
                               '\x0A',
                               '?',
                               '|',
                               '[',
                               '\x0A',
                               '\x0B',
                               '\x0C',
                               static_cast<charT>(0x85),
                               ']',
                               ')',
                               ')',
                               '\0'};

    charT c = static_cast<charT>(0x2029u);
    bool b = (static_cast<unsigned>(c) == 0x2029u);

    return (b ? e1 : e2);
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
}

template <class charT>
inline typename boost::disable_if_c<(sizeof(charT) > 1), const charT*>::type
    get_escape_R_string()
{
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable : 4309)
#endif
    static const charT e2[] = {'(',    '?',    '-',    'x', ':', '(', '?',
                               '>',    '\x0D', '\x0A', '?', '|', '[', '\x0A',
                               '\x0B', '\x0C', '\x85', ']', ')', ')', '\0'};
    return e2;
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
}

} // namespace BOOST_REGEX_DETAIL_NS
} // namespace boost

#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable : 4103)
#endif
#ifdef BOOST_HAS_ABI_HEADERS
#include BOOST_ABI_SUFFIX
#endif
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif

#endif

max_stars_repo_name: sotaoverride/backup

max_issues_repo_name: sotaoverride/backup

max_forks_repo_name: sotaoverride/backup