// Autogenerated by tools\build\make_containers.py
// from tools\build\container_templates\kernel\classname_macros.h
// Do not edit - any changes will be lost!

/**
 *  \file IMP/quad_macros.h
 *  \brief Macros for various classes.
 *
 *  Copyright 2007-2021 IMP Inventors. All rights reserved.
 */

#ifndef IMPKERNEL_QUAD_MACROS_H
#define IMPKERNEL_QUAD_MACROS_H

#include "internal/TupleRestraint.h"
#include "internal/functors.h"
#include "container_macros.h"
#include <IMP/object_macros.h>
#include <algorithm>

/** Define
    - IMP::QuadScore::evaluate_indexes()
    - IMP::QuadScore::evaluate_if_good_indexes()
 */
#define IMP_QUAD_SCORE_METHODS(Name)                                      \
  double evaluate_indexes(Model *m, const ParticleIndexQuads &p,                  \
                          DerivativeAccumulator *da, unsigned int lower_bound, \
                          unsigned int upper_bound) const IMP_FINAL {          \
    double ret = 0;                                                            \
    for (unsigned int i = lower_bound; i < upper_bound; ++i) {                 \
      ret += evaluate_index(m, p[i], da);                                      \
    }                                                                          \
    return ret;                                                                \
  }                                                                            \
  double evaluate_if_good_indexes(                                             \
      Model *m, const ParticleIndexQuads &p, DerivativeAccumulator *da,           \
      double max, unsigned int lower_bound, unsigned int upper_bound) const {  \
    double ret = 0;                                                            \
    for (unsigned int i = lower_bound; i < upper_bound; ++i) {                 \
      ret += evaluate_if_good_index(m, p[i], da, max - ret);                   \
      if (ret > max) return std::numeric_limits<double>::max();                \
    }                                                                          \
    return ret;                                                                \
  }

//! Define extra the functions needed for a QuadPredicate
#define IMP_QUAD_PREDICATE_METHODS(Name)                                  \
  int get_value(const ParticleQuad& a) const {                                        \
    return get_value_index(IMP::internal::get_model(a),                        \
                           IMP::internal::get_index(a));                       \
  }                                                                            \
  Ints get_value(const ParticleQuadsTemp &o) const {                          \
    Ints ret(o.size());                                                        \
    for (unsigned int i = 0; i < o.size(); ++i) {                              \
      ret[i] += Name::get_value(o[i]);                                         \
    }                                                                          \
    return ret;                                                                \
  }                                                                            \
  Ints get_value_index(Model *m, const ParticleIndexQuads &o) const {             \
    Ints ret(o.size());                                                        \
    for (unsigned int i = 0; i < o.size(); ++i) {                              \
      ret[i] += Name::get_value_index(m, o[i]);                                \
    }                                                                          \
    return ret;                                                                \
  }                                                                            \
  IMP_IMPLEMENT_INLINE_NO_SWIG(                                                \
      void remove_if_equal(Model *m, ParticleIndexQuads &ps,                      \
                           int value) const,                                   \
  {                                                                            \
        ps.erase(                                                              \
            std::remove_if(ps.begin(), ps.end(),                               \
                           IMP::internal::PredicateEquals<Name, true>(         \
                               this, m, value)),                               \
            ps.end());                                                         \
      });                                                                      \
  IMP_IMPLEMENT_INLINE_NO_SWIG(void remove_if_not_equal(Model *m,              \
                                                        ParticleIndexQuads &ps,   \
                                                        int value) const,      \
  {                                                                            \
    ps.erase(                                                                  \
        std::remove_if(ps.begin(), ps.end(),                                   \
                       IMP::internal::PredicateEquals<Name, false>(            \
                           this, m, value)),                                   \
        ps.end());                                                             \
  });

//! Use IMP_QUAD_MODIFIER() instead
#define IMP_QUAD_DERIVATIVE_MODIFIER(Name) IMP_QUAD_MODIFIER(Name)

/** Define
    - IMP::QuadModifier::apply_indexes()
*/
#define IMP_QUAD_MODIFIER_METHODS(Name)                             \
  virtual void apply_indexes(Model *m, const ParticleIndexQuads &o,         \
                             unsigned int lower_bound,                   \
                             unsigned int upper_bound) const IMP_FINAL { \
    for (unsigned int i = lower_bound; i < upper_bound; ++i) {           \
      apply_index(m, o[i]);                                              \
    }                                                                    \
  }

//! Use IMP_INDEX_QUAD_MODIFIER instead
#define IMP_INDEX_QUAD_DERIVATIVE_MODIFIER(Name) \
  IMP_INDEX_QUAD_MODIFIER(Name)

#ifndef IMP_DOXYGEN
#define IMP_IMPLEMENT_QUAD_CONTAINER(Name)                          \
  IMP_IMPLEMENT_INLINE(void do_apply(const QuadModifier *sm) const, \
  { apply_generic(sm); });                                               \
  virtual ParticleIndexes get_all_possible_indexes() const IMP_OVERRIDE; \
  IMP_OBJECT_METHODS(Name)
#endif

/** Use this to fill in container methods
    IMP::QuadContainer::do_apply()
*/
#define IMP_QUAD_CONTAINER_METHODS(Name) \
  void do_apply(const QuadModifier *sm) const { apply_generic(sm); }

#endif /* IMPKERNEL_QUAD_MACROS_H */
