<commit_before>#ifndef STAN_MATH_PRIM_PROB_INV_CHI_SQUARE_LPDF_HPP
#define STAN_MATH_PRIM_PROB_INV_CHI_SQUARE_LPDF_HPP

#include <stan/math/prim/meta.hpp>
#include <stan/math/prim/err.hpp>
#include <stan/math/prim/fun/constants.hpp>
#include <stan/math/prim/fun/digamma.hpp>
#include <stan/math/prim/fun/gamma_q.hpp>
#include <stan/math/prim/fun/lgamma.hpp>
#include <stan/math/prim/fun/log.hpp>
#include <stan/math/prim/fun/max_size.hpp>
#include <stan/math/prim/fun/promote_scalar.hpp>
#include <stan/math/prim/fun/size.hpp>
#include <stan/math/prim/fun/size_zero.hpp>
#include <stan/math/prim/fun/value_of.hpp>
#include <stan/math/prim/functor/operands_and_partials.hpp>
#include <cmath>

namespace stan {
namespace math {

/** \ingroup prob_dists
 * The log of an inverse chi-squared density for y with the specified
 * degrees of freedom parameter.
 * The degrees of freedom parameter must be greater than 0.
 * y must be greater than 0.
 *
 \f{eqnarray*}{
 y &\sim& \mbox{\sf{Inv-}}\chi^2_\nu \\
 \log (p (y \, |\, \nu)) &=& \log \left( \frac{2^{-\nu / 2}}{\Gamma (\nu / 2)}
 y^{- (\nu / 2 + 1)} \exp^{-1 / (2y)} \right) \\
 &=& - \frac{\nu}{2} \log(2) - \log (\Gamma (\nu / 2)) - (\frac{\nu}{2} + 1)
 \log(y) - \frac{1}{2y} \\ & & \mathrm{ where } \; y > 0 \f}
 *
 * @tparam T_y type of scalar
 * @tparam T_dof type of degrees of freedom
 * @param y A scalar variable.
 * @param nu Degrees of freedom.
 * @throw std::domain_error if nu is not greater than or equal to 0
 * @throw std::domain_error if y is not greater than or equal to 0.
 */
template <bool propto, typename T_y, typename T_dof>
return_type_t<T_y, T_dof> inv_chi_square_lpdf(const T_y& y, const T_dof& nu) {
  using T_partials_return = partials_return_t<T_y, T_dof>;
  using T_y_ref = ref_type_if_t<!is_constant<T_y>::value, T_y>;
  using T_nu_ref = ref_type_if_t<!is_constant<T_dof>::value, T_dof>;
  static const char* function = "inv_chi_square_lpdf";
  check_consistent_sizes(function, "Random variable", y,
                         "Degrees of freedom parameter", nu);

  T_y_ref y_ref = y;
  T_nu_ref nu_ref = nu;

  const auto& y_col = as_column_vector_or_scalar(y_ref);
  const auto& nu_col = as_column_vector_or_scalar(nu_ref);

  const auto& y_arr = as_array_or_scalar(y_col);
  const auto& nu_arr = as_array_or_scalar(nu_col);

  ref_type_t<decltype(value_of(y_arr))> y_val = value_of(y_arr);
  ref_type_t<decltype(value_of(nu_arr))> nu_val = value_of(nu_arr);

  check_positive_finite(function, "Degrees of freedom parameter", nu_val);
  check_not_nan(function, "Random variable", y_val);

  if (size_zero(y, nu)) {
    return 0;
  }
  if (!include_summand<propto, T_y, T_dof>::value) {
    return 0;
  }

  if (sum(promote_scalar<int>(y_val <= 0))) {
    return LOG_ZERO;
  }

  operands_and_partials<T_y_ref, T_nu_ref> ops_partials(y_ref, nu_ref);

  const auto& log_y = to_ref_if<!is_constant_all<T_dof>::value>(log(y_val));
  const auto& half_nu = to_ref(0.5 * nu_val);

  size_t N = max_size(y, nu);
  T_partials_return logp = -sum((half_nu + 1.0) * log_y);
  if (include_summand<propto, T_dof>::value) {
    logp -= (sum(nu_val) * HALF_LOG_TWO + sum(lgamma(half_nu))) * N / size(nu);
  }
  if (include_summand<propto, T_y>::value) {
    const auto& inv_y = to_ref_if<!is_constant_all<T_y>::value>(inv(y_val));
    logp -= 0.5 * sum(inv_y) * N / size(y);
    if (!is_constant_all<T_y>::value) {
      ops_partials.edge1_.partials_ = (0.5 * inv_y - half_nu - 1.0) * inv_y;
    }
  }

  if (!is_constant_all<T_dof>::value) {
    ops_partials.edge2_.partials_
        = -HALF_LOG_TWO - (digamma(half_nu) + log_y) * 0.5;
  }
  return ops_partials.build(logp);
}

template <typename T_y, typename T_dof>
inline return_type_t<T_y, T_dof> inv_chi_square_lpdf(const T_y& y,
                                                     const T_dof& nu) {
  return inv_chi_square_lpdf<false>(y, nu);
}

}  // namespace math
}  // namespace stan
#endif
<commit_msg>another one<commit_after>#ifndef STAN_MATH_PRIM_PROB_INV_CHI_SQUARE_LPDF_HPP
#define STAN_MATH_PRIM_PROB_INV_CHI_SQUARE_LPDF_HPP

#include <stan/math/prim/meta.hpp>
#include <stan/math/prim/err.hpp>
#include <stan/math/prim/fun/constants.hpp>
#include <stan/math/prim/fun/digamma.hpp>
#include <stan/math/prim/fun/gamma_q.hpp>
#include <stan/math/prim/fun/lgamma.hpp>
#include <stan/math/prim/fun/log.hpp>
#include <stan/math/prim/fun/max_size.hpp>
#include <stan/math/prim/fun/promote_scalar.hpp>
#include <stan/math/prim/fun/size.hpp>
#include <stan/math/prim/fun/size_zero.hpp>
#include <stan/math/prim/fun/to_ref.hpp>
#include <stan/math/prim/fun/value_of.hpp>
#include <stan/math/prim/functor/operands_and_partials.hpp>
#include <cmath>

namespace stan {
namespace math {

/** \ingroup prob_dists
 * The log of an inverse chi-squared density for y with the specified
 * degrees of freedom parameter.
 * The degrees of freedom parameter must be greater than 0.
 * y must be greater than 0.
 *
 \f{eqnarray*}{
 y &\sim& \mbox{\sf{Inv-}}\chi^2_\nu \\
 \log (p (y \, |\, \nu)) &=& \log \left( \frac{2^{-\nu / 2}}{\Gamma (\nu / 2)}
 y^{- (\nu / 2 + 1)} \exp^{-1 / (2y)} \right) \\
 &=& - \frac{\nu}{2} \log(2) - \log (\Gamma (\nu / 2)) - (\frac{\nu}{2} + 1)
 \log(y) - \frac{1}{2y} \\ & & \mathrm{ where } \; y > 0 \f}
 *
 * @tparam T_y type of scalar
 * @tparam T_dof type of degrees of freedom
 * @param y A scalar variable.
 * @param nu Degrees of freedom.
 * @throw std::domain_error if nu is not greater than or equal to 0
 * @throw std::domain_error if y is not greater than or equal to 0.
 */
template <bool propto, typename T_y, typename T_dof>
return_type_t<T_y, T_dof> inv_chi_square_lpdf(const T_y& y, const T_dof& nu) {
  using T_partials_return = partials_return_t<T_y, T_dof>;
  using T_y_ref = ref_type_if_t<!is_constant<T_y>::value, T_y>;
  using T_nu_ref = ref_type_if_t<!is_constant<T_dof>::value, T_dof>;
  static const char* function = "inv_chi_square_lpdf";
  check_consistent_sizes(function, "Random variable", y,
                         "Degrees of freedom parameter", nu);

  T_y_ref y_ref = y;
  T_nu_ref nu_ref = nu;

  const auto& y_col = as_column_vector_or_scalar(y_ref);
  const auto& nu_col = as_column_vector_or_scalar(nu_ref);

  const auto& y_arr = as_array_or_scalar(y_col);
  const auto& nu_arr = as_array_or_scalar(nu_col);

  ref_type_t<decltype(value_of(y_arr))> y_val = value_of(y_arr);
  ref_type_t<decltype(value_of(nu_arr))> nu_val = value_of(nu_arr);

  check_positive_finite(function, "Degrees of freedom parameter", nu_val);
  check_not_nan(function, "Random variable", y_val);

  if (size_zero(y, nu)) {
    return 0;
  }
  if (!include_summand<propto, T_y, T_dof>::value) {
    return 0;
  }

  if (sum(promote_scalar<int>(y_val <= 0))) {
    return LOG_ZERO;
  }

  operands_and_partials<T_y_ref, T_nu_ref> ops_partials(y_ref, nu_ref);

  const auto& log_y = to_ref_if<!is_constant_all<T_dof>::value>(log(y_val));
  const auto& half_nu = to_ref(0.5 * nu_val);

  size_t N = max_size(y, nu);
  T_partials_return logp = -sum((half_nu + 1.0) * log_y);
  if (include_summand<propto, T_dof>::value) {
    logp -= (sum(nu_val) * HALF_LOG_TWO + sum(lgamma(half_nu))) * N / size(nu);
  }
  if (include_summand<propto, T_y>::value) {
    const auto& inv_y = to_ref_if<!is_constant_all<T_y>::value>(inv(y_val));
    logp -= 0.5 * sum(inv_y) * N / size(y);
    if (!is_constant_all<T_y>::value) {
      ops_partials.edge1_.partials_ = (0.5 * inv_y - half_nu - 1.0) * inv_y;
    }
  }

  if (!is_constant_all<T_dof>::value) {
    ops_partials.edge2_.partials_
        = -HALF_LOG_TWO - (digamma(half_nu) + log_y) * 0.5;
  }
  return ops_partials.build(logp);
}

template <typename T_y, typename T_dof>
inline return_type_t<T_y, T_dof> inv_chi_square_lpdf(const T_y& y,
                                                     const T_dof& nu) {
  return inv_chi_square_lpdf<false>(y, nu);
}

}  // namespace math
}  // namespace stan
#endif
<|endoftext|>


<commit_before>#ifndef STAN_MATH_REV_CORE_OPERATOR_SUBTRACTION_HPP
#define STAN_MATH_REV_CORE_OPERATOR_SUBTRACTION_HPP

#include <stan/math/rev/meta.hpp>
#include <stan/math/rev/core/var.hpp>
#include <stan/math/rev/core/arena_matrix.hpp>
#include <stan/math/rev/core/callback_vari.hpp>
#include <stan/math/prim/fun/constants.hpp>
#include <stan/math/prim/fun/is_any_nan.hpp>

namespace stan {
namespace math {

/**
 * Subtraction operator for variables.
 *
 * The partial derivatives are defined by
 *
 * \f$\frac{\partial}{\partial x} (x-y) = 1\f$, and
 *
 * \f$\frac{\partial}{\partial y} (x-y) = -1\f$.
 *
   \f[
   \mbox{operator-}(x, y) =
   \begin{cases}
     x-y & \mbox{if } -\infty\leq x, y \leq \infty \\[6pt]
     \textrm{NaN} & \mbox{if } x = \textrm{NaN or } y = \textrm{NaN}
   \end{cases}
   \f]

   \f[
   \frac{\partial\, \mbox{operator-}(x, y)}{\partial x} =
   \begin{cases}
     1 & \mbox{if } -\infty\leq x, y \leq \infty \\[6pt]
     \textrm{NaN} & \mbox{if } x = \textrm{NaN or } y = \textrm{NaN}
   \end{cases}
   \f]

   \f[
   \frac{\partial\, \mbox{operator-}(x, y)}{\partial y} =
   \begin{cases}
     -1 & \mbox{if } -\infty\leq x, y \leq \infty \\[6pt]
     \textrm{NaN} & \mbox{if } x = \textrm{NaN or } y = \textrm{NaN}
   \end{cases}
   \f]
 *
 * @tparam Var1 value type of a var
 * @tparam Var2 value type of a var
 * @param a First variable operand.
 * @param b Second variable operand.
 * @return Variable result of subtracting the second variable from
 * the first.
 */
inline var operator-(const var& a, const var& b) {
  return make_callback_vari(a.vi_->val_ - b.vi_->val_,
                            [avi = a.vi_, bvi = b.vi_](const auto& vi) mutable {
                              if (unlikely(is_nan(vi.val_))) {
                                avi->adj_ = NOT_A_NUMBER;
                                bvi->adj_ = NOT_A_NUMBER;
                              } else {
                                avi->adj_ += vi.adj_;
                                bvi->adj_ -= vi.adj_;
                              }
                            });
}

/**
 * Subtraction operator for variable and scalar.
 *
 * The derivative for the variable is
 *
 * \f$\frac{\partial}{\partial x} (x-c) = 1\f$, and
 *
 * @tparam Var value type of a var
 * @tparam Arith An arithmetic type
 * @param a First variable operand.
 * @param b Second scalar operand.
 * @return Result of subtracting the scalar from the variable.
 */
template <typename Arith, require_arithmetic_t<Arith>* = nullptr>
inline var operator-(const var& a, Arith b) {
  if (unlikely(b == 0.0)) {
    return a;
  }
  return make_callback_vari(a.vi_->val_ - b,
                            [avi = a.vi_, b](const auto& vi) mutable {
                              if (unlikely(is_nan(vi.val_))) {
                                avi->adj_ = NOT_A_NUMBER;
                              } else {
                                avi->adj_ += vi.adj_;
                              }
                            });
}

/**
 * Subtraction operator for scalar and variable.
 *
 * The derivative for the variable is
 *
 * \f$\frac{\partial}{\partial y} (c-y) = -1\f$, and
 *
 * @tparam Var value type of a var
 * @tparam Arith An arithmetic type
 * @param a First scalar operand.
 * @param b Second variable operand.
 * @return Result of subtracting a variable from a scalar.
 */
template <typename Arith, require_arithmetic_t<Arith>* = nullptr>
inline var operator-(Arith a, const var& b) {
  return make_callback_vari(a - b.vi_->val_,
                            [bvi = b.vi_, a](const auto& vi) mutable {
                              if (unlikely(is_nan(vi.val_))) {
                                bvi->adj_ = NOT_A_NUMBER;
                              } else {
                                bvi->adj_ -= vi.adj_;
                              }
                            });
}

/**
 * Subtraction operator for matrix variables.
 *
 * @tparam VarMat1 A matrix of vars or a var with an underlying matrix type.
 * @tparam VarMat2 A matrix of vars or a var with an underlying matrix type.
 * @param a First variable operand.
 * @param b Second variable operand.
 * @return Variable result of subtracting two variables.
 */
template <typename VarMat1, typename VarMat2,
          require_all_rev_matrix_t<VarMat1, VarMat2>* = nullptr>
inline auto subtract(const VarMat1& a, const VarMat2& b) {
  check_matching_dims("subtract", "a", a, "b", b);
  using op_ret_type = decltype(a.val() - b.val());
  using ret_type = return_var_matrix_t<op_ret_type, VarMat1, VarMat2>;
  arena_t<VarMat1> arena_a = a;
  arena_t<VarMat2> arena_b = b;
  arena_t<ret_type> ret((arena_a.val() - arena_b.val()));
  reverse_pass_callback([ret, arena_a, arena_b]() mutable {
    for (Eigen::Index j = 0; j < ret.cols(); ++j) {
      for (Eigen::Index i = 0; i < ret.rows(); ++i) {
        const auto ref_adj = ret.adj().coeffRef(i, j);
        arena_a.adj().coeffRef(i, j) += ref_adj;
        arena_b.adj().coeffRef(i, j) -= ref_adj;
      }
    }
  });
  return ret_type(ret);
}

/**
 * Subtraction operator for a matrix variable and arithmetic.
 *
 * @tparam VarMat A matrix of vars or a var with an underlying matrix type.
 * @tparam Arith A type with an arithmetic Scalar type.
 * @param a First variable operand.
 * @param b Second variable operand.
 * @return Variable result of subtracting two variables.
 */
template <typename Arith, typename VarMat,
          require_st_arithmetic<Arith>* = nullptr,
          require_rev_matrix_t<VarMat>* = nullptr>
inline auto subtract(const VarMat& a, const Arith& b) {
  if (is_eigen<Arith>::value) {
    check_matching_dims("subtract", "a", a, "b", b);
  }
  using op_ret_type = plain_type_t<decltype(
      (a.val().array() - as_array_or_scalar(b)).matrix())>;
  using ret_type = return_var_matrix_t<op_ret_type, VarMat>;
  arena_t<VarMat> arena_a = a;
  arena_t<ret_type> ret(arena_a.val().array() - as_array_or_scalar(b));
  reverse_pass_callback(
      [ret, arena_a]() mutable { arena_a.adj() += ret.adj(); });
  return ret_type(ret);
}

/**
 * Subtraction operator for an arithmetic type and matrix variable.
 *
 * @tparam VarMat A matrix of vars or a var with an underlying matrix type.
 * @tparam Arith A type with an arithmetic Scalar type.
 * @param a First variable operand.
 * @param b Second variable operand.
 * @return Variable result of subtracting two variables.
 */
template <typename Arith, typename VarMat,
          require_st_arithmetic<Arith>* = nullptr,
          require_rev_matrix_t<VarMat>* = nullptr>
inline auto subtract(const Arith& a, const VarMat& b) {
  if (is_eigen<Arith>::value) {
    check_matching_dims("subtract", "a", a, "b", b);
  }
  using op_ret_type = plain_type_t<decltype(
      (as_array_or_scalar(a) - b.val().array()).matrix())>;
  using ret_type = return_var_matrix_t<op_ret_type, VarMat>;
  arena_t<VarMat> arena_b = b;
  arena_t<ret_type> ret(as_array_or_scalar(a) - arena_b.val().array());
  reverse_pass_callback(
      [ret, arena_b]() mutable { arena_b.adj() -= ret.adj_op(); });
  return ret_type(ret);
}

/**
 * Subtraction operator for an arithmetic matrix and variable.
 *
 * @tparam Var A `var_value` with an underlying arithmetic type.
 * @tparam EigMat An Eigen Matrix type with an arithmetic Scalar type.
 * @param a First variable operand.
 * @param b Second variable operand.
 * @return Variable result of subtracting two variables.
 */
template <typename Var, typename EigMat,
          require_var_vt<std::is_arithmetic, Var>* = nullptr,
          require_eigen_vt<std::is_arithmetic, EigMat>* = nullptr>
inline auto subtract(const Var& a, const EigMat& b) {
  using ret_type = return_var_matrix_t<EigMat>;
  arena_t<ret_type> ret(a.val() - b.array());
  reverse_pass_callback([ret, a]() mutable { a.adj() += ret.adj().sum(); });
  return ret_type(ret);
}

/**
 * Subtraction operator for a variable and arithmetic matrix.
 *
 * @tparam EigMat An Eigen Matrix type with an arithmetic Scalar type.
 * @tparam Var A `var_value` with an underlying arithmetic type.
 * @param a First variable operand.
 * @param b Second variable operand.
 * @return Variable result of subtracting two variables.
 */
template <typename EigMat, typename Var,
          require_eigen_vt<std::is_arithmetic, EigMat>* = nullptr,
          require_var_vt<std::is_arithmetic, Var>* = nullptr>
inline auto subtract(const EigMat& a, const Var& b) {
  using ret_type = return_var_matrix_t<EigMat>;
  arena_t<plain_type_t<ret_type>> ret(a.array() - b.val());
  reverse_pass_callback([ret, b]() mutable { b.adj() -= ret.adj().sum(); });
  return plain_type_t<ret_type>(ret);
}

/**
 * Subtraction operator for a variable and variable matrix.
 *
 * @tparam VarMat An Eigen Matrix type with a variable Scalar type or a
 * `var_value` with an underlying matrix type.
 * @tparam Var A `var_value` with an underlying arithmetic type.
 * @param a First variable operand.
 * @param b Second variable operand.
 * @return Variable result of subtracting two variables.
 */
template <typename Var, typename VarMat,
          require_var_vt<std::is_arithmetic, Var>* = nullptr,
          require_rev_matrix_t<VarMat>* = nullptr>
inline auto subtract(const Var& a, const VarMat& b) {
  using ret_type = return_var_matrix_t<VarMat>;
  arena_t<VarMat> arena_b(b);
  arena_t<ret_type> ret(a.val() - arena_b.val().array());
  reverse_pass_callback([ret, a, arena_b]() mutable {
    for (Eigen::Index j = 0; j < ret.cols(); ++j) {
      for (Eigen::Index i = 0; i < ret.rows(); ++i) {
        auto ret_adj = ret.adj().coeff(i, j);
        a.adj() += ret_adj;
        arena_b.adj().coeffRef(i, j) -= ret_adj;
      }
    }
  });
  return ret_type(ret);
}

/**
 * Subtraction operator for a variable matrix and variable.
 *
 * @tparam VarMat An Eigen Matrix type with a variable Scalar type or a
 * `var_value` with an underlying matrix type.
 * @tparam Var A `var_value` with an underlying arithmetic type.
 * @param a First variable operand.
 * @param b Second variable operand.
 * @return Variable result of subtracting two variables.
 */
template <typename Var, typename VarMat,
          require_rev_matrix_t<VarMat>* = nullptr,
          require_var_vt<std::is_arithmetic, Var>* = nullptr>
inline auto subtract(const VarMat& a, const Var& b) {
  using ret_type = return_var_matrix_t<VarMat>;
  arena_t<VarMat> arena_a(a);
  arena_t<ret_type> ret(arena_a.val().array() - b.val());
  reverse_pass_callback([ret, b, arena_a]() mutable {
    for (Eigen::Index j = 0; j < ret.cols(); ++j) {
      for (Eigen::Index i = 0; i < ret.rows(); ++i) {
        const auto ret_adj = ret.adj().coeff(i, j);
        arena_a.adj().coeffRef(i, j) += ret_adj;
        b.adj() -= ret_adj;
      }
    }
  });
  return ret_type(ret);
}

template <typename T1, typename T2,
          require_any_var_vt<std::is_arithmetic, T1, T2>* = nullptr,
          require_any_arithmetic_t<T1, T2>* = nullptr>
inline auto subtract(const T1& a, const T2& b) {
  return a - b;
}

template <typename T1, typename T2,
          require_all_var_vt<std::is_arithmetic, T1, T2>* = nullptr>
inline auto subtract(const T1& a, const T2& b) {
  return a - b;
}

/**
 * Addition operator for matrix variables.
 *
 * @tparam VarMat1 A matrix of vars or a var with an underlying matrix type.
 * @tparam VarMat2 A matrix of vars or a var with an underlying matrix type.
 * @param a First variable operand.
 * @param b Second variable operand.
 * @return Variable result of adding two variables.
 */
template <typename VarMat1, typename VarMat2,
          require_any_var_matrix_t<VarMat1, VarMat2>* = nullptr>
inline auto operator-(const VarMat1& a, const VarMat2& b) {
  return subtract(a, b);
}

}  // namespace math
}  // namespace stan
#endif
<commit_msg>remove plain_type from operator subtract<commit_after>#ifndef STAN_MATH_REV_CORE_OPERATOR_SUBTRACTION_HPP
#define STAN_MATH_REV_CORE_OPERATOR_SUBTRACTION_HPP

#include <stan/math/rev/meta.hpp>
#include <stan/math/rev/core/var.hpp>
#include <stan/math/rev/core/arena_matrix.hpp>
#include <stan/math/rev/core/callback_vari.hpp>
#include <stan/math/prim/fun/constants.hpp>
#include <stan/math/prim/fun/is_any_nan.hpp>

namespace stan {
namespace math {

/**
 * Subtraction operator for variables.
 *
 * The partial derivatives are defined by
 *
 * \f$\frac{\partial}{\partial x} (x-y) = 1\f$, and
 *
 * \f$\frac{\partial}{\partial y} (x-y) = -1\f$.
 *
   \f[
   \mbox{operator-}(x, y) =
   \begin{cases}
     x-y & \mbox{if } -\infty\leq x, y \leq \infty \\[6pt]
     \textrm{NaN} & \mbox{if } x = \textrm{NaN or } y = \textrm{NaN}
   \end{cases}
   \f]

   \f[
   \frac{\partial\, \mbox{operator-}(x, y)}{\partial x} =
   \begin{cases}
     1 & \mbox{if } -\infty\leq x, y \leq \infty \\[6pt]
     \textrm{NaN} & \mbox{if } x = \textrm{NaN or } y = \textrm{NaN}
   \end{cases}
   \f]

   \f[
   \frac{\partial\, \mbox{operator-}(x, y)}{\partial y} =
   \begin{cases}
     -1 & \mbox{if } -\infty\leq x, y \leq \infty \\[6pt]
     \textrm{NaN} & \mbox{if } x = \textrm{NaN or } y = \textrm{NaN}
   \end{cases}
   \f]
 *
 * @tparam Var1 value type of a var
 * @tparam Var2 value type of a var
 * @param a First variable operand.
 * @param b Second variable operand.
 * @return Variable result of subtracting the second variable from
 * the first.
 */
inline var operator-(const var& a, const var& b) {
  return make_callback_vari(a.vi_->val_ - b.vi_->val_,
                            [avi = a.vi_, bvi = b.vi_](const auto& vi) mutable {
                              if (unlikely(is_nan(vi.val_))) {
                                avi->adj_ = NOT_A_NUMBER;
                                bvi->adj_ = NOT_A_NUMBER;
                              } else {
                                avi->adj_ += vi.adj_;
                                bvi->adj_ -= vi.adj_;
                              }
                            });
}

/**
 * Subtraction operator for variable and scalar.
 *
 * The derivative for the variable is
 *
 * \f$\frac{\partial}{\partial x} (x-c) = 1\f$, and
 *
 * @tparam Var value type of a var
 * @tparam Arith An arithmetic type
 * @param a First variable operand.
 * @param b Second scalar operand.
 * @return Result of subtracting the scalar from the variable.
 */
template <typename Arith, require_arithmetic_t<Arith>* = nullptr>
inline var operator-(const var& a, Arith b) {
  if (unlikely(b == 0.0)) {
    return a;
  }
  return make_callback_vari(a.vi_->val_ - b,
                            [avi = a.vi_, b](const auto& vi) mutable {
                              if (unlikely(is_nan(vi.val_))) {
                                avi->adj_ = NOT_A_NUMBER;
                              } else {
                                avi->adj_ += vi.adj_;
                              }
                            });
}

/**
 * Subtraction operator for scalar and variable.
 *
 * The derivative for the variable is
 *
 * \f$\frac{\partial}{\partial y} (c-y) = -1\f$, and
 *
 * @tparam Var value type of a var
 * @tparam Arith An arithmetic type
 * @param a First scalar operand.
 * @param b Second variable operand.
 * @return Result of subtracting a variable from a scalar.
 */
template <typename Arith, require_arithmetic_t<Arith>* = nullptr>
inline var operator-(Arith a, const var& b) {
  return make_callback_vari(a - b.vi_->val_,
                            [bvi = b.vi_, a](const auto& vi) mutable {
                              if (unlikely(is_nan(vi.val_))) {
                                bvi->adj_ = NOT_A_NUMBER;
                              } else {
                                bvi->adj_ -= vi.adj_;
                              }
                            });
}

/**
 * Subtraction operator for matrix variables.
 *
 * @tparam VarMat1 A matrix of vars or a var with an underlying matrix type.
 * @tparam VarMat2 A matrix of vars or a var with an underlying matrix type.
 * @param a First variable operand.
 * @param b Second variable operand.
 * @return Variable result of subtracting two variables.
 */
template <typename VarMat1, typename VarMat2,
          require_all_rev_matrix_t<VarMat1, VarMat2>* = nullptr>
inline auto subtract(const VarMat1& a, const VarMat2& b) {
  check_matching_dims("subtract", "a", a, "b", b);
  using op_ret_type = decltype(a.val() - b.val());
  using ret_type = return_var_matrix_t<op_ret_type, VarMat1, VarMat2>;
  arena_t<VarMat1> arena_a = a;
  arena_t<VarMat2> arena_b = b;
  arena_t<ret_type> ret((arena_a.val() - arena_b.val()));
  reverse_pass_callback([ret, arena_a, arena_b]() mutable {
    for (Eigen::Index j = 0; j < ret.cols(); ++j) {
      for (Eigen::Index i = 0; i < ret.rows(); ++i) {
        const auto ref_adj = ret.adj().coeffRef(i, j);
        arena_a.adj().coeffRef(i, j) += ref_adj;
        arena_b.adj().coeffRef(i, j) -= ref_adj;
      }
    }
  });
  return ret_type(ret);
}

/**
 * Subtraction operator for a matrix variable and arithmetic.
 *
 * @tparam VarMat A matrix of vars or a var with an underlying matrix type.
 * @tparam Arith A type with an arithmetic Scalar type.
 * @param a First variable operand.
 * @param b Second variable operand.
 * @return Variable result of subtracting two variables.
 */
template <typename Arith, typename VarMat,
          require_st_arithmetic<Arith>* = nullptr,
          require_rev_matrix_t<VarMat>* = nullptr>
inline auto subtract(const VarMat& a, const Arith& b) {
  if (is_eigen<Arith>::value) {
    check_matching_dims("subtract", "a", a, "b", b);
  }
  using op_ret_type = plain_type_t<decltype(
      (a.val().array() - as_array_or_scalar(b)).matrix())>;
  using ret_type = return_var_matrix_t<op_ret_type, VarMat>;
  arena_t<VarMat> arena_a = a;
  arena_t<ret_type> ret(arena_a.val().array() - as_array_or_scalar(b));
  reverse_pass_callback(
      [ret, arena_a]() mutable { arena_a.adj() += ret.adj(); });
  return ret_type(ret);
}

/**
 * Subtraction operator for an arithmetic type and matrix variable.
 *
 * @tparam VarMat A matrix of vars or a var with an underlying matrix type.
 * @tparam Arith A type with an arithmetic Scalar type.
 * @param a First variable operand.
 * @param b Second variable operand.
 * @return Variable result of subtracting two variables.
 */
template <typename Arith, typename VarMat,
          require_st_arithmetic<Arith>* = nullptr,
          require_rev_matrix_t<VarMat>* = nullptr>
inline auto subtract(const Arith& a, const VarMat& b) {
  if (is_eigen<Arith>::value) {
    check_matching_dims("subtract", "a", a, "b", b);
  }
  using op_ret_type = plain_type_t<decltype(
      (as_array_or_scalar(a) - b.val().array()).matrix())>;
  using ret_type = return_var_matrix_t<op_ret_type, VarMat>;
  arena_t<VarMat> arena_b = b;
  arena_t<ret_type> ret(as_array_or_scalar(a) - arena_b.val().array());
  reverse_pass_callback(
      [ret, arena_b]() mutable { arena_b.adj() -= ret.adj_op(); });
  return ret_type(ret);
}

/**
 * Subtraction operator for an arithmetic matrix and variable.
 *
 * @tparam Var A `var_value` with an underlying arithmetic type.
 * @tparam EigMat An Eigen Matrix type with an arithmetic Scalar type.
 * @param a First variable operand.
 * @param b Second variable operand.
 * @return Variable result of subtracting two variables.
 */
template <typename Var, typename EigMat,
          require_var_vt<std::is_arithmetic, Var>* = nullptr,
          require_eigen_vt<std::is_arithmetic, EigMat>* = nullptr>
inline auto subtract(const Var& a, const EigMat& b) {
  using ret_type = return_var_matrix_t<EigMat>;
  arena_t<ret_type> ret(a.val() - b.array());
  reverse_pass_callback([ret, a]() mutable { a.adj() += ret.adj().sum(); });
  return ret_type(ret);
}

/**
 * Subtraction operator for a variable and arithmetic matrix.
 *
 * @tparam EigMat An Eigen Matrix type with an arithmetic Scalar type.
 * @tparam Var A `var_value` with an underlying arithmetic type.
 * @param a First variable operand.
 * @param b Second variable operand.
 * @return Variable result of subtracting two variables.
 */
template <typename EigMat, typename Var,
          require_eigen_vt<std::is_arithmetic, EigMat>* = nullptr,
          require_var_vt<std::is_arithmetic, Var>* = nullptr>
inline auto subtract(const EigMat& a, const Var& b) {
  using ret_type = return_var_matrix_t<EigMat>;
  arena_t<ret_type> ret(a.array() - b.val());
  reverse_pass_callback([ret, b]() mutable { b.adj() -= ret.adj().sum(); });
  return ret_type(ret);
}

/**
 * Subtraction operator for a variable and variable matrix.
 *
 * @tparam VarMat An Eigen Matrix type with a variable Scalar type or a
 * `var_value` with an underlying matrix type.
 * @tparam Var A `var_value` with an underlying arithmetic type.
 * @param a First variable operand.
 * @param b Second variable operand.
 * @return Variable result of subtracting two variables.
 */
template <typename Var, typename VarMat,
          require_var_vt<std::is_arithmetic, Var>* = nullptr,
          require_rev_matrix_t<VarMat>* = nullptr>
inline auto subtract(const Var& a, const VarMat& b) {
  using ret_type = return_var_matrix_t<VarMat>;
  arena_t<VarMat> arena_b(b);
  arena_t<ret_type> ret(a.val() - arena_b.val().array());
  reverse_pass_callback([ret, a, arena_b]() mutable {
    for (Eigen::Index j = 0; j < ret.cols(); ++j) {
      for (Eigen::Index i = 0; i < ret.rows(); ++i) {
        auto ret_adj = ret.adj().coeff(i, j);
        a.adj() += ret_adj;
        arena_b.adj().coeffRef(i, j) -= ret_adj;
      }
    }
  });
  return ret_type(ret);
}

/**
 * Subtraction operator for a variable matrix and variable.
 *
 * @tparam VarMat An Eigen Matrix type with a variable Scalar type or a
 * `var_value` with an underlying matrix type.
 * @tparam Var A `var_value` with an underlying arithmetic type.
 * @param a First variable operand.
 * @param b Second variable operand.
 * @return Variable result of subtracting two variables.
 */
template <typename Var, typename VarMat,
          require_rev_matrix_t<VarMat>* = nullptr,
          require_var_vt<std::is_arithmetic, Var>* = nullptr>
inline auto subtract(const VarMat& a, const Var& b) {
  using ret_type = return_var_matrix_t<VarMat>;
  arena_t<VarMat> arena_a(a);
  arena_t<ret_type> ret(arena_a.val().array() - b.val());
  reverse_pass_callback([ret, b, arena_a]() mutable {
    for (Eigen::Index j = 0; j < ret.cols(); ++j) {
      for (Eigen::Index i = 0; i < ret.rows(); ++i) {
        const auto ret_adj = ret.adj().coeff(i, j);
        arena_a.adj().coeffRef(i, j) += ret_adj;
        b.adj() -= ret_adj;
      }
    }
  });
  return ret_type(ret);
}

template <typename T1, typename T2,
          require_any_var_vt<std::is_arithmetic, T1, T2>* = nullptr,
          require_any_arithmetic_t<T1, T2>* = nullptr>
inline auto subtract(const T1& a, const T2& b) {
  return a - b;
}

template <typename T1, typename T2,
          require_all_var_vt<std::is_arithmetic, T1, T2>* = nullptr>
inline auto subtract(const T1& a, const T2& b) {
  return a - b;
}

/**
 * Addition operator for matrix variables.
 *
 * @tparam VarMat1 A matrix of vars or a var with an underlying matrix type.
 * @tparam VarMat2 A matrix of vars or a var with an underlying matrix type.
 * @param a First variable operand.
 * @param b Second variable operand.
 * @return Variable result of adding two variables.
 */
template <typename VarMat1, typename VarMat2,
          require_any_var_matrix_t<VarMat1, VarMat2>* = nullptr>
inline auto operator-(const VarMat1& a, const VarMat2& b) {
  return subtract(a, b);
}

}  // namespace math
}  // namespace stan
#endif
<|endoftext|>


<commit_before>#include "itkSCIFIOImageIO.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include "itkImage.h"
#include "itkRGBPixel.h"
#include "itkMetaDataObject.h"
#include "itkStreamingImageFilter.h"

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

  if( argc < 2 )
    {
    std::cerr << "Missing command line arguments" << std::endl;
    std::cerr << "Usage :  Test input-ome-tiff-ImageFileName " << std::endl;
    return -1;
    }

  typedef unsigned int       PixelType;
  const unsigned int          Dimension = 2;
  typedef itk::Image<PixelType, Dimension > ImageType;

  typedef typename itk::ImageFileReader< ImageType > ReaderType;
  itk::SCIFIOImageIO::Pointer io = itk::SCIFIOImageIO::New();
  io->DebugOn();
  typename ReaderType::Pointer reader = ReaderType::New();
  std::cout << "reader->GetUseStreaming(): " << reader->GetUseStreaming() << std::endl;
  std::cout << "done checking streaming usage" << std::endl;
  reader->SetImageIO( io );
  const char * inputFileName  = argv[1];
  reader->SetFileName( inputFileName );

  typedef itk::StreamingImageFilter< ImageType, ImageType > StreamingFilter;
  typename StreamingFilter::Pointer streamer = StreamingFilter::New();
  streamer->SetInput( reader->GetOutput() );
  streamer->SetNumberOfStreamDivisions( 4 );

  try
    {
    streamer->Update();
    }
  catch( itk::ExceptionObject & excp )
    {
    std::cerr << "Problem encoutered while reading image file : " << argv[1] << std::endl;
    std::cerr << excp << std::endl;
    return -1;
    }
}
<commit_msg>read 3D<commit_after>#include "itkSCIFIOImageIO.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include "itkImage.h"
#include "itkRGBPixel.h"
#include "itkMetaDataObject.h"
#include "itkStreamingImageFilter.h"

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

  if( argc < 2 )
    {
    std::cerr << "Missing command line arguments" << std::endl;
    std::cerr << "Usage :  Test input-ome-tiff-ImageFileName " << std::endl;
    return -1;
    }

  typedef unsigned short PixelComponentType;
  const unsigned int Dimension = 3;
  const unsigned int Channels = 3;
  typedef itk::Vector<PixelComponentType, Channels> PixelType;
  typedef itk::Image<PixelType, Dimension> ImageType;

  typedef typename itk::ImageFileReader< ImageType > ReaderType;
  itk::SCIFIOImageIO::Pointer io = itk::SCIFIOImageIO::New();
  io->DebugOn();
  typename ReaderType::Pointer reader = ReaderType::New();
  std::cout << "reader->GetUseStreaming(): " << reader->GetUseStreaming() << std::endl;
  std::cout << "done checking streaming usage" << std::endl;
  reader->SetImageIO( io );
  const char * inputFileName  = argv[1];
  reader->SetFileName( inputFileName );

  typedef itk::StreamingImageFilter< ImageType, ImageType > StreamingFilter;
  typename StreamingFilter::Pointer streamer = StreamingFilter::New();
  streamer->SetInput( reader->GetOutput() );
  streamer->SetNumberOfStreamDivisions( 4 );

  try
    {
    streamer->Update();
    }
  catch( itk::ExceptionObject & excp )
    {
    std::cerr << "Problem encoutered while reading image file : " << argv[1] << std::endl;
    std::cerr << excp << std::endl;
    return -1;
    }
}
<|endoftext|>


<commit_before>#pragma once

#include <set>
#include <stdlib.h>
#include <stdint.h>
#include <assert.h>

#include <stdio.h>

#include "channel9.hpp"
#include "memcheck.h"

namespace Channel9
{
	class GC::Semispace : protected GC
	{
	public:
		typedef unsigned char uchar;

		struct Data
		{
			uint16_t m_type;
			uint8_t  m_forward; //forwarding pointer?
			uint8_t  m_pool; //which pool
			uint32_t m_count; //number of bytes of memory in this allocation
			uchar    m_data[0]; //the actual data, 8 byte aligned

			Data *next() const { return (Data*)((uchar*)(this + 1) + m_count); }
			static Data *ptr_for(const void *ptr) { return (Data*)ptr - 1; }
		};

	private:

		static const double   GC_GROWTH_LIMIT = 2.0;
		static const uint64_t CHUNK_SIZE = 2<<20; // 2mb

		struct Chunk
		{
			Chunk *  m_next; //linked list of chunks
			uint32_t m_capacity; //in bytes
			uint32_t m_used;     //in bytes
			uchar    m_data[0];  //actual memory

			void init(uint32_t capacity)
			{
				m_next = NULL;
				m_capacity = capacity;
				m_used = 0;
				DO_DEBUG VALGRIND_CREATE_MEMPOOL(m_data, 0, false);
			}

			Data * alloc(size_t size)
			{
				if(m_used + size <= m_capacity)
				{
					Data * ret = (Data*)(m_data + m_used);
					m_used += size;
					DO_DEBUG VALGRIND_MEMPOOL_ALLOC(m_data, ret, size);
					return ret;
				}
				return NULL;
			}
			Data * begin(){ return (Data *) m_data; }
			Data * end()  { return (Data *) (m_data + m_used); }
			void deadbeef()
			{
				uint32_t * i = (uint32_t *) m_data,
				         * e = (uint32_t *) (m_data + m_capacity);
				for(; i < e; ++i)
					*i = 0xDEADBEEF;
			}
		};

		Chunk * m_pools[2]; //two sets of pools, each garbage collection swaps between them, active is stored in m_cur_pool
		int     m_cur_pool; //which of the two pools are we using now
		Chunk * m_cur_chunk; //which chunk are we allocating from
		bool    m_in_gc;     //are we garbage collecting now? if so, just allocate a new chunk if the last one is full
		uint64_t m_alloced;  //how much memory are in all pools (active or not) combined
		uint64_t m_used;     //how much memory is used by data blocks, not including the header
		uint64_t m_data_blocks; //how many data allocations are in the current pool
		uint64_t m_next_gc;  //garbage collect when m_next_gc < m_used

		std::set<GCRoot*> m_roots;

		void collect();

		uchar *next(size_t size, uint32_t type)
		{
			assert(size < 10000);

			if(!m_in_gc)
				DO_TRACEGC printf("Alloc %u type %x ... ", (unsigned)size, type);

			size += (8 - size % 8) % 8; //8 byte align

			while(1){
				Data * data = m_cur_chunk->alloc(size + sizeof(Data));

				if(data){
					m_used += size;
					m_data_blocks++;

					data->m_type = type;
					data->m_forward = 0;
					data->m_pool = m_cur_pool;
					data->m_count = size;

					if(!m_in_gc)
						DO_TRACEGC printf("alloc return %p\n", data->m_data);

					return data->m_data;
				}

				if(m_cur_chunk->m_next)
				{ //advance
					m_cur_chunk = m_cur_chunk->m_next;
					m_cur_chunk->init(m_cur_chunk->m_capacity);
				} else {
					//allocate a new chunk
					Chunk * c = new_chunk();

					m_cur_chunk->m_next = c;
					m_cur_chunk = c;
				}
			}
			return NULL;
		}

		Chunk * new_chunk()
		{
			Chunk * c = (Chunk *)malloc(CHUNK_SIZE);
			c->init(CHUNK_SIZE - sizeof(Chunk));
			DO_DEBUG VALGRIND_MAKE_MEM_NOACCESS(c->m_data, CHUNK_SIZE);
			m_alloced += CHUNK_SIZE;
			return c;
		}

	public:
		Semispace()
		 : m_cur_pool(0), m_in_gc(false), m_alloced(0), m_used(0), m_data_blocks(0), m_next_gc(1<<20)
		{
			m_pools[0] = new_chunk();
			m_pools[1] = NULL;

			m_cur_chunk = m_pools[m_cur_pool];
		}

		template <typename tObj>
		tObj *alloc(size_t extra, uint32_t type)
		{
			return reinterpret_cast<tObj*>(next(sizeof(tObj) + extra, type));
		}

		template <typename tObj>
		bool validate(tObj * from)
		{
			if(m_in_gc)
				return true;
			else
				return (Data::ptr_for(from)->m_pool == m_cur_pool);
		}

		template <typename tObj>
		bool mark(tObj **from_ptr)
		{
			tObj *from = *from_ptr;
			Data * old = (Data*)(from) - 1;

			if(old->m_pool == m_cur_pool){
				DO_TRACEGC printf("Move %p, type %X already moved\n", from, old->m_type);
				return from;
			}

			if(old->m_forward){
				DO_TRACEGC printf("Move %p, type %X => %p\n", from, old->m_type, (*(tObj**)from));
				*from_ptr = *(tObj**)from;
				return true;
			}

			tObj * n = (tObj*)next(old->m_count, old->m_type);
			memcpy(n, from, old->m_count);

			DO_TRACEGC printf("Move %p, type %X <= %p\n", from, old->m_type, n);

			old->m_forward = 1;
			// put the new location in the old object's space
			*(tObj**)from = n;
			// change the marked pointer
			*from_ptr = n;
			return true;
		}

		// make sure this object is ready to be read from
		template <typename tObj>
		void read_barrier(tObj * obj) { }

		// tell the GC that obj will contain a reference to the object pointed to by ptr
		template <typename tObj, typename tPtr>
		void write_barrier(tObj * obj, tPtr * ptr) { }

		// now is a valid time to stop the world
		void safe_point() {
			if(m_next_gc < m_used)
				collect();
		}

		void register_root(GCRoot *root);
		void unregister_root(GCRoot *root);
	};
}

<commit_msg>Relax the maximum allocation size a bit, but still set a hard limit as no large-object allocation strategy has been defined yet<commit_after>#pragma once

#include <set>
#include <stdlib.h>
#include <stdint.h>
#include <assert.h>

#include <stdio.h>

#include "channel9.hpp"
#include "memcheck.h"

namespace Channel9
{
	class GC::Semispace : protected GC
	{
	public:
		typedef unsigned char uchar;

		struct Data
		{
			uint16_t m_type;
			uint8_t  m_forward; //forwarding pointer?
			uint8_t  m_pool; //which pool
			uint32_t m_count; //number of bytes of memory in this allocation
			uchar    m_data[0]; //the actual data, 8 byte aligned

			Data *next() const { return (Data*)((uchar*)(this + 1) + m_count); }
			static Data *ptr_for(const void *ptr) { return (Data*)ptr - 1; }
		};

	private:

		static const double   GC_GROWTH_LIMIT = 2.0;
		static const uint64_t CHUNK_SIZE = 2<<20; // 2mb

		struct Chunk
		{
			Chunk *  m_next; //linked list of chunks
			uint32_t m_capacity; //in bytes
			uint32_t m_used;     //in bytes
			uchar    m_data[0];  //actual memory

			void init(uint32_t capacity)
			{
				m_next = NULL;
				m_capacity = capacity;
				m_used = 0;
				DO_DEBUG VALGRIND_CREATE_MEMPOOL(m_data, 0, false);
			}

			Data * alloc(size_t size)
			{
				if(m_used + size <= m_capacity)
				{
					Data * ret = (Data*)(m_data + m_used);
					m_used += size;
					DO_DEBUG VALGRIND_MEMPOOL_ALLOC(m_data, ret, size);
					return ret;
				}
				return NULL;
			}
			Data * begin(){ return (Data *) m_data; }
			Data * end()  { return (Data *) (m_data + m_used); }
			void deadbeef()
			{
				uint32_t * i = (uint32_t *) m_data,
				         * e = (uint32_t *) (m_data + m_capacity);
				for(; i < e; ++i)
					*i = 0xDEADBEEF;
			}
		};

		Chunk * m_pools[2]; //two sets of pools, each garbage collection swaps between them, active is stored in m_cur_pool
		int     m_cur_pool; //which of the two pools are we using now
		Chunk * m_cur_chunk; //which chunk are we allocating from
		bool    m_in_gc;     //are we garbage collecting now?
		uint64_t m_alloced;  //how much memory are in all pools (active or not) combined
		uint64_t m_used;     //how much memory is used by data blocks, not including the header
		uint64_t m_data_blocks; //how many data allocations are in the current pool
		uint64_t m_next_gc;  //garbage collect when m_next_gc < m_used

		std::set<GCRoot*> m_roots;

		void collect();

		uchar *next(size_t size, uint32_t type)
		{
			assert(size < (CHUNK_SIZE >> 4));

			if(!m_in_gc)
				DO_TRACEGC printf("Alloc %u type %x ... ", (unsigned)size, type);

			size += (8 - size % 8) % 8; //8 byte align

			while(1){
				Data * data = m_cur_chunk->alloc(size + sizeof(Data));

				if(data){
					m_used += size;
					m_data_blocks++;

					data->m_type = type;
					data->m_forward = 0;
					data->m_pool = m_cur_pool;
					data->m_count = size;

					if(!m_in_gc)
						DO_TRACEGC printf("alloc return %p\n", data->m_data);

					return data->m_data;
				}

				if(m_cur_chunk->m_next)
				{ //advance
					m_cur_chunk = m_cur_chunk->m_next;
					m_cur_chunk->init(m_cur_chunk->m_capacity);
				} else {
					//allocate a new chunk
					Chunk * c = new_chunk();

					m_cur_chunk->m_next = c;
					m_cur_chunk = c;
				}
			}
			return NULL;
		}

		Chunk * new_chunk()
		{
			Chunk * c = (Chunk *)malloc(CHUNK_SIZE);
			c->init(CHUNK_SIZE - sizeof(Chunk));
			DO_DEBUG VALGRIND_MAKE_MEM_NOACCESS(c->m_data, CHUNK_SIZE);
			m_alloced += CHUNK_SIZE;
			return c;
		}

	public:
		Semispace()
		 : m_cur_pool(0), m_in_gc(false), m_alloced(0), m_used(0), m_data_blocks(0), m_next_gc(1<<20)
		{
			m_pools[0] = new_chunk();
			m_pools[1] = NULL;

			m_cur_chunk = m_pools[m_cur_pool];
		}

		template <typename tObj>
		tObj *alloc(size_t extra, uint32_t type)
		{
			return reinterpret_cast<tObj*>(next(sizeof(tObj) + extra, type));
		}

		template <typename tObj>
		bool validate(tObj * from)
		{
			if(m_in_gc)
				return true;
			else
				return (Data::ptr_for(from)->m_pool == m_cur_pool);
		}

		template <typename tObj>
		bool mark(tObj **from_ptr)
		{
			tObj *from = *from_ptr;
			Data * old = (Data*)(from) - 1;

			if(old->m_pool == m_cur_pool){
				DO_TRACEGC printf("Move %p, type %X already moved\n", from, old->m_type);
				return from;
			}

			if(old->m_forward){
				DO_TRACEGC printf("Move %p, type %X => %p\n", from, old->m_type, (*(tObj**)from));
				*from_ptr = *(tObj**)from;
				return true;
			}

			tObj * n = (tObj*)next(old->m_count, old->m_type);
			memcpy(n, from, old->m_count);

			DO_TRACEGC printf("Move %p, type %X <= %p\n", from, old->m_type, n);

			old->m_forward = 1;
			// put the new location in the old object's space
			*(tObj**)from = n;
			// change the marked pointer
			*from_ptr = n;
			return true;
		}

		// make sure this object is ready to be read from
		template <typename tObj>
		void read_barrier(tObj * obj) { }

		// tell the GC that obj will contain a reference to the object pointed to by ptr
		template <typename tObj, typename tPtr>
		void write_barrier(tObj * obj, tPtr * ptr) { }

		// now is a valid time to stop the world
		void safe_point() {
			if(m_next_gc < m_used)
				collect();
		}

		void register_root(GCRoot *root);
		void unregister_root(GCRoot *root);
	};
}

<|endoftext|>


<commit_before>// ** DON'T INCLUDE <iostream>! THINGS WILL BREAK! **
#include <ctime>
#include <string>
#include <array>

#include <rtos.h>

#include <helper-funcs.hpp>
#include <watchdog.hpp>
#include <logger.hpp>
#include <assert.hpp>

#include "robot-devices.hpp"
#include "task-signals.hpp"
#include "commands.hpp"
#include "fpga.hpp"
#include "io-expander.hpp"
#include "neostrip.hpp"

void Task_Controller(void const* args);

/**
 * @brief      { Sets the hardware configurations for the status LEDs & places
 * into the given state }
 *
 * @param[in]  state  { the next state of the LEDs }
 */
void statusLights(bool state) {
    DigitalInOut init_leds[] = {{RJ_BALL_LED, PIN_OUTPUT, OpenDrain, !state},
                                {RJ_RX_LED, PIN_OUTPUT, OpenDrain, !state},
                                {RJ_TX_LED, PIN_OUTPUT, OpenDrain, !state},
                                {RJ_RDY_LED, PIN_OUTPUT, OpenDrain, !state}};

    for (int i = 0; i < 4; i++) init_leds[i].mode(PullUp);
}

/**
 * @brief      { Turn all status LEDs on }
 */
void statusLightsON(void const* args) { statusLights(1); }

/**
 * @brief      { Turn all status LEDs off }
 */
void statusLightsOFF(void const* args) { statusLights(0); }

/**
 * [main Main The entry point of the system where each submodule's thread is
 * started.]
 * @return  [none]
 */
int main() {
    // Store the thread's ID
    static const osThreadId mainID = Thread::gettid();
    ASSERT(mainID != nullptr);

    // clear any extraneous rx serial bytes
    if (1) {
        Serial s(RJ_SERIAL_RXTX);
        // flush rx queue?
        while (s.readable()) s.getc();

        // print out the baudrate we're using as a last resort
        // to let the user know they may or may not see it
        // depending on many factors.
        s.baud(9600);
        std::printf("BAUDRATE: 57600\n");
        s.baud(57600);
        fflush(stdout);
    }

    // Turn on some startup LEDs to show they're working, they are turned off
    // before we hit the while loop
    statusLightsON(nullptr);

    // Set the default logging configurations
    isLogging = RJ_LOGGING_EN;
    rjLogLevel = INIT;

    /* Always send out an empty line at startup for keeping the console
     * clean on after a 'reboot' command is called;
     */
    if (isLogging) {
        // reset the console's default settings and enable the cursor
        printf("\033[0m\033[?25h");
        fflush(stdout);
    }

    // Setup the interrupt priorities before launching each subsystem's task
    // thread.
    setISRPriorities();

    // Start a periodic blinking LED to show system activity
    DigitalOut ledOne(LED1, 0);
    RtosTimer live_light(imAlive, osTimerPeriodic, (void*)&ledOne);
    live_light.start(RJ_LIFELIGHT_TIMEOUT_MS);

    // Flip off the startup LEDs after a timeout period
    RtosTimer init_leds_off(statusLightsOFF, osTimerOnce);
    init_leds_off.start(RJ_STARTUP_LED_TIMEOUT_MS);

    // This is where the FPGA is actually configured with the bitfile's name
    // passed in
    bool fpga_ready = FPGA::Instance()->Init("/local/rj-fpga.nib");

    /* We MUST wait for the FPGA to COMPLETELY configure before moving on
     * because of
     * threading with the shared the SPI. If we don't explicitly halt main (it's
     * just
     * considered another thread), then the chip select lines will not be in the
     * correct
     * states for communicating between devices exclusively. Many bus faults
     * occured on the
     * road to finding this problem and then determining how to fix it.
     */
    if (fpga_ready == true) {
        LOG(INIT, "FPGA Configuration Successful!");
        osSignalSet(mainID, MAIN_TASK_CONTINUE);
    } else {
        LOG(FATAL, "FPGA Configuration Failed!");
        osSignalSet(mainID, MAIN_TASK_CONTINUE);
    }

    Thread::signal_wait(MAIN_TASK_CONTINUE, osWaitForever);

    motors_Init();

    // Start the thread task for the on-board control loop
    Thread controller_task(Task_Controller, mainID, osPriorityHigh);

    // Start the thread task for handling radio communications
    Thread comm_task(Task_CommCtrl, mainID, osPriorityAboveNormal);

    // Start the thread task for the serial console
    Thread console_task(Task_SerialConsole, mainID, osPriorityBelowNormal);

#if RJ_WATCHDOG_TIMER_EN
    // Enable the watchdog timer if it's set in configurations.
    Watchdog::Set(RJ_WATCHDOG_TIMER_VALUE);
#endif

    DigitalOut rdy_led(RJ_RDY_LED, !fpga_ready);

    NeoStrip rgbLED(RJ_NEOPIXEL, 2);
    rgbLED.clear();
    rgbLED.brightness(0.1);
    rgbLED.setPixel(0, 0x00, 0xFF, 0x00);
    rgbLED.setPixel(1, 0x00, 0xFF, 0x00);
    rgbLED.write();

    if (fpga_ready) {
        // TODO: set RGB LED to green, otherwise set it to red.
    }

    // Make sure all of the motors are enabled
    FPGA::Instance()->motors_en(true);

    // Wait for all threads to get to their ready state
    for (size_t i = 0; i < 3; ++i)
        Thread::signal_wait(MAIN_TASK_CONTINUE, osWaitForever);

    // Release each thread into its operations in a structured manner
    controller_task.signal_set(SUB_TASK_CONTINUE);
    comm_task.signal_set(SUB_TASK_CONTINUE);
    console_task.signal_set(SUB_TASK_CONTINUE);

    while (true) {
        // make sure we can always reach back to main by
        // renewing the watchdog timer periodicly
        rdy_led = !fpga_ready;
        Watchdog::Renew();
        Thread::wait(2 * RJ_WATCHDOG_TIMER_VALUE);
    }
}

#define _EXTERN extern "C"

_EXTERN void HardFault_Handler() {
    __asm volatile(
        " tst lr, #4                                                \n"
        " ite eq                                                    \n"
        " mrseq r0, msp                                             \n"
        " mrsne r0, psp                                             \n"
        " ldr r1, [r0, #24]                                         \n"
        " ldr r2, hard_fault_handler_2_const                        \n"
        " bx r2                                                     \n"
        " hard_fault_handler_2_const: .word HARD_FAULT_HANDLER    	\n");
}

_EXTERN void HARD_FAULT_HANDLER(uint32_t* stackAddr) {
    /* These are volatile to try and prevent the compiler/linker optimising them
     * away as the variables never actually get used.  If the debugger won't
     * show the values of the variables, make them global my moving their
     * declaration outside of this function. */
    volatile uint32_t r0;
    volatile uint32_t r1;
    volatile uint32_t r2;
    volatile uint32_t r3;
    volatile uint32_t r12;
    volatile uint32_t lr;  /* Link register. */
    volatile uint32_t pc;  /* Program counter. */
    volatile uint32_t psr; /* Program status register. */

    r0 = stackAddr[0];
    r1 = stackAddr[1];
    r2 = stackAddr[2];
    r3 = stackAddr[3];
    r12 = stackAddr[4];
    lr = stackAddr[5];
    pc = stackAddr[6];
    psr = stackAddr[7];

    LOG(FATAL,
        "\r\n"
        "================================\r\n"
        "========== HARD FAULT ==========\r\n"
        "\r\n"
        "  MSP:\t0x%08X\r\n"
        "  HFSR:\t0x%08X\r\n"
        "  CFSR:\t0x%08X\r\n"
        "\r\n"
        "  r0:\t0x%08X\r\n"
        "  r1:\t0x%08X\r\n"
        "  r2:\t0x%08X\r\n"
        "  r3:\t0x%08X\r\n"
        "  r12:\t0x%08X\r\n"
        "  lr:\t0x%08X\r\n"
        "  pc:\t0x%08X\r\n"
        "  psr:\t0x%08X\r\n"
        "\r\n"
        "========== HARD FAULT ==========\r\n"
        "================================",
        __get_MSP, SCB->HFSR, SCB->CFSR, r0, r1, r2, r3, r12, lr, pc, psr);

    // do nothing so everything remains unchanged for debugging
    while (true)
        ;
}

_EXTERN void NMI_Handler() { std::printf("NMI Fault!\n"); }

_EXTERN void MemManage_Handler() { std::printf("MemManage Fault!\n"); }

_EXTERN void BusFault_Handler() { std::printf("BusFault Fault!\n"); }

_EXTERN void UsageFault_Handler() { std::printf("UsageFault Fault!\n"); }
<commit_msg>adding neopixel activity<commit_after>// ** DON'T INCLUDE <iostream>! THINGS WILL BREAK! **
#include <ctime>
#include <string>
#include <array>

#include <rtos.h>

#include <helper-funcs.hpp>
#include <watchdog.hpp>
#include <logger.hpp>
#include <assert.hpp>

#include "robot-devices.hpp"
#include "task-signals.hpp"
#include "commands.hpp"
#include "fpga.hpp"
#include "io-expander.hpp"
#include "neostrip.hpp"

void Task_Controller(void const* args);

/**
 * @brief      { Sets the hardware configurations for the status LEDs & places
 * into the given state }
 *
 * @param[in]  state  { the next state of the LEDs }
 */
void statusLights(bool state) {
    DigitalInOut init_leds[] = {{RJ_BALL_LED, PIN_OUTPUT, OpenDrain, !state},
                                {RJ_RX_LED, PIN_OUTPUT, OpenDrain, !state},
                                {RJ_TX_LED, PIN_OUTPUT, OpenDrain, !state},
                                {RJ_RDY_LED, PIN_OUTPUT, OpenDrain, !state}};

    for (int i = 0; i < 4; i++) init_leds[i].mode(PullUp);
}

/**
 * @brief      { Turn all status LEDs on }
 */
void statusLightsON(void const* args) { statusLights(1); }

/**
 * @brief      { Turn all status LEDs off }
 */
void statusLightsOFF(void const* args) { statusLights(0); }

/**
 * [main Main The entry point of the system where each submodule's thread is
 * started.]
 * @return  [none]
 */
int main() {
    // Store the thread's ID
    static const osThreadId mainID = Thread::gettid();
    ASSERT(mainID != nullptr);

    // clear any extraneous rx serial bytes
    if (1) {
        Serial s(RJ_SERIAL_RXTX);
        // flush rx queue?
        while (s.readable()) s.getc();

        // print out the baudrate we're using as a last resort
        // to let the user know they may or may not see it
        // depending on many factors.
        s.baud(9600);
        std::printf("BAUDRATE: 57600\n");
        s.baud(57600);
        fflush(stdout);
    }

    // Turn on some startup LEDs to show they're working, they are turned off
    // before we hit the while loop
    statusLightsON(nullptr);

    // Set the default logging configurations
    isLogging = RJ_LOGGING_EN;
    rjLogLevel = INIT;

    /* Always send out an empty line at startup for keeping the console
     * clean on after a 'reboot' command is called;
     */
    if (isLogging) {
        // reset the console's default settings and enable the cursor
        printf("\033[0m\033[?25h");
        fflush(stdout);
    }

    // Setup the interrupt priorities before launching each subsystem's task
    // thread.
    setISRPriorities();

    // Start a periodic blinking LED to show system activity
    DigitalOut ledOne(LED1, 0);
    RtosTimer live_light(imAlive, osTimerPeriodic, (void*)&ledOne);
    live_light.start(RJ_LIFELIGHT_TIMEOUT_MS);

    // Flip off the startup LEDs after a timeout period
    RtosTimer init_leds_off(statusLightsOFF, osTimerOnce);
    init_leds_off.start(RJ_STARTUP_LED_TIMEOUT_MS);

    // This is where the FPGA is actually configured with the bitfile's name
    // passed in
    bool fpga_ready = FPGA::Instance()->Init("/local/rj-fpga.nib");

    /* We MUST wait for the FPGA to COMPLETELY configure before moving on
     * because of
     * threading with the shared the SPI. If we don't explicitly halt main (it's
     * just
     * considered another thread), then the chip select lines will not be in the
     * correct
     * states for communicating between devices exclusively. Many bus faults
     * occured on the
     * road to finding this problem and then determining how to fix it.
     */
    if (fpga_ready == true) {
        LOG(INIT, "FPGA Configuration Successful!");
        osSignalSet(mainID, MAIN_TASK_CONTINUE);
    } else {
        LOG(FATAL, "FPGA Configuration Failed!");
        osSignalSet(mainID, MAIN_TASK_CONTINUE);
    }

    Thread::signal_wait(MAIN_TASK_CONTINUE, osWaitForever);

    motors_Init();

    // Start the thread task for the on-board control loop
    Thread controller_task(Task_Controller, mainID, osPriorityHigh);

    // Start the thread task for handling radio communications
    Thread comm_task(Task_CommCtrl, mainID, osPriorityAboveNormal);

    // Start the thread task for the serial console
    Thread console_task(Task_SerialConsole, mainID, osPriorityBelowNormal);

#if RJ_WATCHDOG_TIMER_EN
    // Enable the watchdog timer if it's set in configurations.
    Watchdog::Set(RJ_WATCHDOG_TIMER_VALUE);
#endif

    DigitalOut rdy_led(RJ_RDY_LED, !fpga_ready);

    NeoStrip rgbLED(RJ_NEOPIXEL, 2);
    rgbLED.clear();
    rgbLED.brightness(0.1);
    rgbLED.setPixel(0, 0x00, 0xFF, 0x00);
    rgbLED.setPixel(1, 0x00, 0xFF, 0x00);
    rgbLED.write();

    if (fpga_ready) {
        // TODO: set RGB LED to green, otherwise set it to red.
    }

    // Make sure all of the motors are enabled
    FPGA::Instance()->motors_en(true);

    // Wait for all threads to get to their ready state
    for (size_t i = 0; i < 3; ++i)
        Thread::signal_wait(MAIN_TASK_CONTINUE, osWaitForever);

    // Release each thread into its operations in a structured manner
    controller_task.signal_set(SUB_TASK_CONTINUE);
    comm_task.signal_set(SUB_TASK_CONTINUE);
    console_task.signal_set(SUB_TASK_CONTINUE);

    while (true) {
        // make sure we can always reach back to main by
        // renewing the watchdog timer periodicly
        rdy_led = !fpga_ready;
        Watchdog::Renew();
        // toggle the neopixel between green & blue
        rgbLED.setPixel(0, 0x00, 0xFF, 0x00);
        rgbLED.write();
        Thread::wait(RJ_WATCHDOG_TIMER_VALUE * 1000);
        rgbLED.setPixel(0, 0x00, 0x00, 0xFF);
        rgbLED.write();
        Thread::wait(RJ_WATCHDOG_TIMER_VALUE * 1000);
    }
}

#define _EXTERN extern "C"

_EXTERN void HardFault_Handler() {
    __asm volatile(
        " tst lr, #4                                                \n"
        " ite eq                                                    \n"
        " mrseq r0, msp                                             \n"
        " mrsne r0, psp                                             \n"
        " ldr r1, [r0, #24]                                         \n"
        " ldr r2, hard_fault_handler_2_const                        \n"
        " bx r2                                                     \n"
        " hard_fault_handler_2_const: .word HARD_FAULT_HANDLER    	\n");
}

_EXTERN void HARD_FAULT_HANDLER(uint32_t* stackAddr) {
    /* These are volatile to try and prevent the compiler/linker optimising them
     * away as the variables never actually get used.  If the debugger won't
     * show the values of the variables, make them global my moving their
     * declaration outside of this function. */
    volatile uint32_t r0;
    volatile uint32_t r1;
    volatile uint32_t r2;
    volatile uint32_t r3;
    volatile uint32_t r12;
    volatile uint32_t lr;  /* Link register. */
    volatile uint32_t pc;  /* Program counter. */
    volatile uint32_t psr; /* Program status register. */

    r0 = stackAddr[0];
    r1 = stackAddr[1];
    r2 = stackAddr[2];
    r3 = stackAddr[3];
    r12 = stackAddr[4];
    lr = stackAddr[5];
    pc = stackAddr[6];
    psr = stackAddr[7];

    LOG(FATAL,
        "\r\n"
        "================================\r\n"
        "========== HARD FAULT ==========\r\n"
        "\r\n"
        "  MSP:\t0x%08X\r\n"
        "  HFSR:\t0x%08X\r\n"
        "  CFSR:\t0x%08X\r\n"
        "\r\n"
        "  r0:\t0x%08X\r\n"
        "  r1:\t0x%08X\r\n"
        "  r2:\t0x%08X\r\n"
        "  r3:\t0x%08X\r\n"
        "  r12:\t0x%08X\r\n"
        "  lr:\t0x%08X\r\n"
        "  pc:\t0x%08X\r\n"
        "  psr:\t0x%08X\r\n"
        "\r\n"
        "========== HARD FAULT ==========\r\n"
        "================================",
        __get_MSP, SCB->HFSR, SCB->CFSR, r0, r1, r2, r3, r12, lr, pc, psr);

    // do nothing so everything remains unchanged for debugging
    while (true)
        ;
}

_EXTERN void NMI_Handler() { std::printf("NMI Fault!\n"); }

_EXTERN void MemManage_Handler() { std::printf("MemManage Fault!\n"); }

_EXTERN void BusFault_Handler() { std::printf("BusFault Fault!\n"); }

_EXTERN void UsageFault_Handler() { std::printf("UsageFault Fault!\n"); }
<|endoftext|>


<commit_before>#include <cstring>
#include <cassert>
#include <boost/lexical_cast.hpp>
#include <boost/regex.hpp>
#include <string>
#include <atomic>
#include <memory>
#include <set>
#include <boost/asio.hpp>
#include <mutex>

#include "I2PService.h"
#include "Destination.h"
#include "HTTPProxy.h"
#include "util.h"
#include "Identity.h"
#include "Streaming.h"
#include "Destination.h"
#include "ClientContext.h"
#include "I2PEndian.h"
#include "I2PTunnel.h"
#include "Config.h"
#include "HTTP.h"

namespace i2p {
namespace proxy {
	bool str_rmatch(std::string & str, const char *suffix) {
		auto pos = str.rfind (suffix);
		if (pos == std::string::npos)
			return false; /* not found */
		if (str.length() == (pos + std::strlen(suffix)))
			return true; /* match */
		return false;
	}

	static const size_t http_buffer_size = 8192;
	class HTTPReqHandler: public i2p::client::I2PServiceHandler, public std::enable_shared_from_this<HTTPReqHandler>
	{
		private:
			enum state
			{
				GET_METHOD,
				GET_HOSTNAME,
				GET_HTTPV,
				GET_HTTPVNL, //TODO: fallback to finding HOst: header if needed
				DONE
			};

			void EnterState(state nstate);
			bool HandleData(uint8_t *http_buff, std::size_t len);
			void HandleSockRecv(const boost::system::error_code & ecode, std::size_t bytes_transfered);
			void Terminate();
			void AsyncSockRead();
			void HTTPRequestFailed(const char *message);
			void RedirectToJumpService(std::string & host);
			void ExtractRequest();
			bool ValidateHTTPRequest();
			void HandleJumpServices();
			bool CreateHTTPRequest(uint8_t *http_buff, std::size_t len);
			void SentHTTPFailed(const boost::system::error_code & ecode);
			void HandleStreamRequestComplete (std::shared_ptr<i2p::stream::Stream> stream);

			uint8_t m_http_buff[http_buffer_size];
			std::shared_ptr<boost::asio::ip::tcp::socket> m_sock;
			std::string m_request; //Data left to be sent
			std::string m_Response;
			std::string m_url; //URL
			std::string m_method; //Method
			std::string m_version; //HTTP version
			std::string m_address; //Address
			std::string m_path; //Path
			int m_port; //Port
			state m_state;//Parsing state

		public:

			HTTPReqHandler(HTTPProxy * parent, std::shared_ptr<boost::asio::ip::tcp::socket> sock) :
				I2PServiceHandler(parent), m_sock(sock)
				{ EnterState(GET_METHOD); }
			~HTTPReqHandler() { Terminate(); }
			void Handle () { AsyncSockRead(); }
	};

	void HTTPReqHandler::AsyncSockRead()
	{
		LogPrint(eLogDebug, "HTTPProxy: async sock read");
		if(m_sock) {
			m_sock->async_receive(boost::asio::buffer(m_http_buff, http_buffer_size),
						std::bind(&HTTPReqHandler::HandleSockRecv, shared_from_this(),
								std::placeholders::_1, std::placeholders::_2));
		} else {
			LogPrint(eLogError, "HTTPProxy: no socket for read");
		}
	}

	void HTTPReqHandler::Terminate() {
		if (Kill()) return;
		if (m_sock)
		{
			LogPrint(eLogDebug, "HTTPProxy: close sock");
			m_sock->close();
			m_sock = nullptr;
		}
		Done(shared_from_this());
	}

	/* All hope is lost beyond this point */
	//TODO: handle this apropriately
	void HTTPReqHandler::HTTPRequestFailed(const char *message)
	{
		i2p::http::HTTPRes res;
		res.code = 500;
		res.add_header("Content-Type", "text/plain");
		res.add_header("Connection", "close");
		res.body = message;
		res.body += "\r\n";
		std::string response = res.to_string();
		boost::asio::async_write(*m_sock, boost::asio::buffer(response, response.size()),
					 std::bind(&HTTPReqHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1));
	}

	void HTTPReqHandler::RedirectToJumpService(std::string & host)
	{
		i2p::http::HTTPRes res;
		i2p::http::URL url;

		i2p::config::GetOption("http.address", url.host);
		i2p::config::GetOption("http.port",    url.port);
		url.path  = "/";
		url.query = "page=jumpservices&address=";
		url.query += host;

		res.code = 302; /* redirect */
		res.add_header("Location", url.to_string().c_str());

		std::string response = res.to_string();
		boost::asio::async_write(*m_sock, boost::asio::buffer(response, response.length()),
					 std::bind(&HTTPReqHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1));
	}

	void HTTPReqHandler::EnterState(HTTPReqHandler::state nstate)
	{
		m_state = nstate;
	}

	void HTTPReqHandler::ExtractRequest()
	{
		LogPrint(eLogDebug, "HTTPProxy: request: ", m_method, " ", m_url);
		std::string server="";
		std::string port="80";
		boost::regex rHTTP("http://(.*?)(:(\\d+))?(/.*)");
		boost::smatch m;
		std::string path;
		if(boost::regex_search(m_url, m, rHTTP, boost::match_extra))
		{
			server=m[1].str();
			if (m[2].str() != "")  port=m[3].str();
			path=m[4].str();
		}
		LogPrint(eLogDebug, "HTTPProxy: server: ", server, ", port: ", port, ", path: ", path);
		m_address = server;
		m_port = boost::lexical_cast<int>(port);
		m_path = path;
	}

	bool HTTPReqHandler::ValidateHTTPRequest()
	{
		if ( m_version != "HTTP/1.0" && m_version != "HTTP/1.1" )
		{
			LogPrint(eLogError, "HTTPProxy: unsupported version: ", m_version);
			HTTPRequestFailed("unsupported HTTP version");
			return false;
		}
		return true;
	}

	void HTTPReqHandler::HandleJumpServices()
	{
		static const char * helpermark1 = "?i2paddresshelper=";
		static const char * helpermark2 = "&i2paddresshelper=";
		size_t addressHelperPos1 = m_path.rfind (helpermark1);
		size_t addressHelperPos2 = m_path.rfind (helpermark2);
		size_t addressHelperPos;
		if (addressHelperPos1 == std::string::npos)
		{
			if (addressHelperPos2 == std::string::npos)
				return; //Not a jump service
			else
				addressHelperPos = addressHelperPos2;
		}
		else
		{
			if (addressHelperPos2 == std::string::npos)
				addressHelperPos = addressHelperPos1;
			else if ( addressHelperPos1 > addressHelperPos2 )
				addressHelperPos = addressHelperPos1;
			else
				addressHelperPos = addressHelperPos2;
		}
		auto base64 = m_path.substr (addressHelperPos + strlen(helpermark1));
		base64 = i2p::util::http::urlDecode(base64); //Some of the symbols may be urlencoded
		LogPrint (eLogInfo, "HTTPProxy: jump service for ", m_address, ", inserting to address book");
		//TODO: this is very dangerous and broken. We should ask the user before doing anything see http://pastethis.i2p/raw/pn5fL4YNJL7OSWj3Sc6N/
		//TODO: we could redirect the user again to avoid dirtiness in the browser
		i2p::client::context.GetAddressBook ().InsertAddress (m_address, base64);
		m_path.erase(addressHelperPos);
	}

	bool HTTPReqHandler::CreateHTTPRequest(uint8_t *http_buff, std::size_t len)
	{
		ExtractRequest(); //TODO: parse earlier
		if (!ValidateHTTPRequest()) return false;
		HandleJumpServices();

		i2p::data::IdentHash identHash;
		if (str_rmatch(m_address, ".i2p"))
		{
			if (!i2p::client::context.GetAddressBook ().GetIdentHash (m_address, identHash)){
				RedirectToJumpService(m_address);
				return false;
			}
		}

		m_request = m_method;
		m_request.push_back(' ');
		m_request += m_path;
		m_request.push_back(' ');
		m_request += m_version;
		m_request.push_back('\r');
		m_request.push_back('\n');
		m_request.append("Connection: close\r\n");
		// TODO: temporary shortcut. Must be implemented properly
		uint8_t * eol = nullptr;
		bool isEndOfHeader = false;
		while (!isEndOfHeader && len && (eol = (uint8_t *)memchr (http_buff, '\r', len)))
		{
			if (eol)
			{
				*eol = 0; eol++;
				if (strncmp ((const char *)http_buff, "Referer", 7) && strncmp ((const char *)http_buff, "Connection", 10)) // strip out referer and connection
				{
					if (!strncmp ((const char *)http_buff, "User-Agent", 10)) // replace UserAgent
						m_request.append("User-Agent: MYOB/6.66 (AN/ON)");
					else
						m_request.append ((const char *)http_buff);
					m_request.append ("\r\n");
				}
				isEndOfHeader = !http_buff[0];
				auto l = eol - http_buff;
				http_buff = eol;
				len -= l;
				if (len > 0) // \r
				{
					http_buff++;
					len--;
				}
			}
		}
		m_request.append(reinterpret_cast<const char *>(http_buff),len);
		return true;
	}

	bool HTTPReqHandler::HandleData(uint8_t *http_buff, std::size_t len)
	{
		while (len > 0)
		{
			//TODO: fallback to finding HOst: header if needed
			switch (m_state)
			{
				case GET_METHOD:
					switch (*http_buff)
					{
						case ' ': EnterState(GET_HOSTNAME); break;
						default: m_method.push_back(*http_buff); break;
					}
				break;
				case GET_HOSTNAME:
					switch (*http_buff)
					{
						case ' ': EnterState(GET_HTTPV); break;
						default: m_url.push_back(*http_buff); break;
					}
				break;
				case GET_HTTPV:
					switch (*http_buff)
					{
						case '\r': EnterState(GET_HTTPVNL); break;
						default: m_version.push_back(*http_buff); break;
					}
				break;
				case GET_HTTPVNL:
					switch (*http_buff)
					{
						case '\n': EnterState(DONE); break;
						default:
							LogPrint(eLogError, "HTTPProxy: rejected invalid request ending with: ", ((int)*http_buff));
							HTTPRequestFailed("rejected invalid request");
							return false;
					}
				break;
				default:
					LogPrint(eLogError, "HTTPProxy: invalid state: ", m_state);
					HTTPRequestFailed("invalid parser state");
					return false;
			}
			http_buff++;
			len--;
			if (m_state == DONE)
				return CreateHTTPRequest(http_buff,len);
		}
		return true;
	}

	void HTTPReqHandler::HandleSockRecv(const boost::system::error_code & ecode, std::size_t len)
	{
		LogPrint(eLogDebug, "HTTPProxy: sock recv: ", len, " bytes");
		if(ecode)
		{
			LogPrint(eLogWarning, "HTTPProxy: sock recv got error: ", ecode);
			Terminate();
			return;
		}

		if (HandleData(m_http_buff, len))
		{
			if (m_state == DONE)
			{
				LogPrint(eLogDebug, "HTTPProxy: requested: ", m_url);
				GetOwner()->CreateStream (std::bind (&HTTPReqHandler::HandleStreamRequestComplete,
						shared_from_this(), std::placeholders::_1), m_address, m_port);
			}
			else
				AsyncSockRead();
		}
	}

	void HTTPReqHandler::SentHTTPFailed(const boost::system::error_code & ecode)
	{
		if (ecode)
			LogPrint (eLogError, "HTTPProxy: Closing socket after sending failure because: ", ecode.message ());
		Terminate();
	}

	void HTTPReqHandler::HandleStreamRequestComplete (std::shared_ptr<i2p::stream::Stream> stream)
	{
		if (stream)
		{
			if (Kill()) return;
			LogPrint (eLogInfo, "HTTPProxy: New I2PTunnel connection");
			auto connection = std::make_shared<i2p::client::I2PTunnelConnection>(GetOwner(), m_sock, stream);
			GetOwner()->AddHandler (connection);
			connection->I2PConnect (reinterpret_cast<const uint8_t*>(m_request.data()), m_request.size());
			Done(shared_from_this());
		}
		else
		{
			LogPrint (eLogError, "HTTPProxy: error when creating the stream, check the previous warnings for more info");
			HTTPRequestFailed("error when creating the stream, check logs");
		}
	}

	HTTPProxy::HTTPProxy(const std::string& address, int port, std::shared_ptr<i2p::client::ClientDestination> localDestination):
		TCPIPAcceptor(address, port, localDestination ? localDestination : i2p::client::context.GetSharedLocalDestination ())
	{
	}

	std::shared_ptr<i2p::client::I2PServiceHandler> HTTPProxy::CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket)
	{
		return std::make_shared<HTTPReqHandler> (this, socket);
	}
} // http
} // i2p
<commit_msg>* HTTPProxy.cpp : kill ExtractRequest(), drop boost::regex<commit_after>#include <cstring>
#include <cassert>
#include <string>
#include <atomic>
#include <memory>
#include <set>
#include <boost/asio.hpp>
#include <mutex>

#include "I2PService.h"
#include "Destination.h"
#include "HTTPProxy.h"
#include "util.h"
#include "Identity.h"
#include "Streaming.h"
#include "Destination.h"
#include "ClientContext.h"
#include "I2PEndian.h"
#include "I2PTunnel.h"
#include "Config.h"
#include "HTTP.h"

namespace i2p {
namespace proxy {
	bool str_rmatch(std::string & str, const char *suffix) {
		auto pos = str.rfind (suffix);
		if (pos == std::string::npos)
			return false; /* not found */
		if (str.length() == (pos + std::strlen(suffix)))
			return true; /* match */
		return false;
	}

	static const size_t http_buffer_size = 8192;
	class HTTPReqHandler: public i2p::client::I2PServiceHandler, public std::enable_shared_from_this<HTTPReqHandler>
	{
		private:
			enum state
			{
				GET_METHOD,
				GET_HOSTNAME,
				GET_HTTPV,
				GET_HTTPVNL, //TODO: fallback to finding HOst: header if needed
				DONE
			};

			void EnterState(state nstate);
			bool HandleData(uint8_t *http_buff, std::size_t len);
			void HandleSockRecv(const boost::system::error_code & ecode, std::size_t bytes_transfered);
			void Terminate();
			void AsyncSockRead();
			void HTTPRequestFailed(const char *message);
			void RedirectToJumpService(std::string & host);
			bool ValidateHTTPRequest();
			void HandleJumpServices();
			bool CreateHTTPRequest(uint8_t *http_buff, std::size_t len);
			void SentHTTPFailed(const boost::system::error_code & ecode);
			void HandleStreamRequestComplete (std::shared_ptr<i2p::stream::Stream> stream);

			uint8_t m_http_buff[http_buffer_size];
			std::shared_ptr<boost::asio::ip::tcp::socket> m_sock;
			std::string m_request; //Data left to be sent
			std::string m_Response;
			std::string m_url; //URL
			std::string m_method; //Method
			std::string m_version; //HTTP version
			std::string m_address; //Address
			std::string m_path; //Path
			int m_port; //Port
			state m_state;//Parsing state

		public:

			HTTPReqHandler(HTTPProxy * parent, std::shared_ptr<boost::asio::ip::tcp::socket> sock) :
				I2PServiceHandler(parent), m_sock(sock)
				{ EnterState(GET_METHOD); }
			~HTTPReqHandler() { Terminate(); }
			void Handle () { AsyncSockRead(); }
	};

	void HTTPReqHandler::AsyncSockRead()
	{
		LogPrint(eLogDebug, "HTTPProxy: async sock read");
		if(m_sock) {
			m_sock->async_receive(boost::asio::buffer(m_http_buff, http_buffer_size),
						std::bind(&HTTPReqHandler::HandleSockRecv, shared_from_this(),
								std::placeholders::_1, std::placeholders::_2));
		} else {
			LogPrint(eLogError, "HTTPProxy: no socket for read");
		}
	}

	void HTTPReqHandler::Terminate() {
		if (Kill()) return;
		if (m_sock)
		{
			LogPrint(eLogDebug, "HTTPProxy: close sock");
			m_sock->close();
			m_sock = nullptr;
		}
		Done(shared_from_this());
	}

	/* All hope is lost beyond this point */
	//TODO: handle this apropriately
	void HTTPReqHandler::HTTPRequestFailed(const char *message)
	{
		i2p::http::HTTPRes res;
		res.code = 500;
		res.add_header("Content-Type", "text/plain");
		res.add_header("Connection", "close");
		res.body = message;
		res.body += "\r\n";
		std::string response = res.to_string();
		boost::asio::async_write(*m_sock, boost::asio::buffer(response, response.size()),
					 std::bind(&HTTPReqHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1));
	}

	void HTTPReqHandler::RedirectToJumpService(std::string & host)
	{
		i2p::http::HTTPRes res;
		i2p::http::URL url;

		i2p::config::GetOption("http.address", url.host);
		i2p::config::GetOption("http.port",    url.port);
		url.path  = "/";
		url.query = "page=jumpservices&address=";
		url.query += host;

		res.code = 302; /* redirect */
		res.add_header("Location", url.to_string().c_str());

		std::string response = res.to_string();
		boost::asio::async_write(*m_sock, boost::asio::buffer(response, response.length()),
					 std::bind(&HTTPReqHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1));
	}

	void HTTPReqHandler::EnterState(HTTPReqHandler::state nstate)
	{
		m_state = nstate;
	}

	bool HTTPReqHandler::ValidateHTTPRequest()
	{
		if ( m_version != "HTTP/1.0" && m_version != "HTTP/1.1" )
		{
			LogPrint(eLogError, "HTTPProxy: unsupported version: ", m_version);
			HTTPRequestFailed("unsupported HTTP version");
			return false;
		}
		return true;
	}

	void HTTPReqHandler::HandleJumpServices()
	{
		static const char * helpermark1 = "?i2paddresshelper=";
		static const char * helpermark2 = "&i2paddresshelper=";
		size_t addressHelperPos1 = m_path.rfind (helpermark1);
		size_t addressHelperPos2 = m_path.rfind (helpermark2);
		size_t addressHelperPos;
		if (addressHelperPos1 == std::string::npos)
		{
			if (addressHelperPos2 == std::string::npos)
				return; //Not a jump service
			else
				addressHelperPos = addressHelperPos2;
		}
		else
		{
			if (addressHelperPos2 == std::string::npos)
				addressHelperPos = addressHelperPos1;
			else if ( addressHelperPos1 > addressHelperPos2 )
				addressHelperPos = addressHelperPos1;
			else
				addressHelperPos = addressHelperPos2;
		}
		auto base64 = m_path.substr (addressHelperPos + strlen(helpermark1));
		base64 = i2p::util::http::urlDecode(base64); //Some of the symbols may be urlencoded
		LogPrint (eLogInfo, "HTTPProxy: jump service for ", m_address, ", inserting to address book");
		//TODO: this is very dangerous and broken. We should ask the user before doing anything see http://pastethis.i2p/raw/pn5fL4YNJL7OSWj3Sc6N/
		//TODO: we could redirect the user again to avoid dirtiness in the browser
		i2p::client::context.GetAddressBook ().InsertAddress (m_address, base64);
		m_path.erase(addressHelperPos);
	}

	bool HTTPReqHandler::CreateHTTPRequest(uint8_t *http_buff, std::size_t len)
	{
		i2p::http::URL url;
		url.parse(m_url);
		m_address = url.host; /* < compatibility */
		m_port    = url.port; /* < compatibility */
		m_path    = url.path; /* < compatibility */
		if (!ValidateHTTPRequest()) return false;
		HandleJumpServices();

		i2p::data::IdentHash identHash;
		if (str_rmatch(m_address, ".i2p"))
		{
			if (!i2p::client::context.GetAddressBook ().GetIdentHash (m_address, identHash)){
				RedirectToJumpService(m_address);
				return false;
			}
		}

		m_request = m_method;
		m_request.push_back(' ');
		m_request += m_path;
		m_request.push_back(' ');
		m_request += m_version;
		m_request.push_back('\r');
		m_request.push_back('\n');
		m_request.append("Connection: close\r\n");
		// TODO: temporary shortcut. Must be implemented properly
		uint8_t * eol = nullptr;
		bool isEndOfHeader = false;
		while (!isEndOfHeader && len && (eol = (uint8_t *)memchr (http_buff, '\r', len)))
		{
			if (eol)
			{
				*eol = 0; eol++;
				if (strncmp ((const char *)http_buff, "Referer", 7) && strncmp ((const char *)http_buff, "Connection", 10)) // strip out referer and connection
				{
					if (!strncmp ((const char *)http_buff, "User-Agent", 10)) // replace UserAgent
						m_request.append("User-Agent: MYOB/6.66 (AN/ON)");
					else
						m_request.append ((const char *)http_buff);
					m_request.append ("\r\n");
				}
				isEndOfHeader = !http_buff[0];
				auto l = eol - http_buff;
				http_buff = eol;
				len -= l;
				if (len > 0) // \r
				{
					http_buff++;
					len--;
				}
			}
		}
		m_request.append(reinterpret_cast<const char *>(http_buff),len);
		return true;
	}

	bool HTTPReqHandler::HandleData(uint8_t *http_buff, std::size_t len)
	{
		while (len > 0)
		{
			//TODO: fallback to finding HOst: header if needed
			switch (m_state)
			{
				case GET_METHOD:
					switch (*http_buff)
					{
						case ' ': EnterState(GET_HOSTNAME); break;
						default: m_method.push_back(*http_buff); break;
					}
				break;
				case GET_HOSTNAME:
					switch (*http_buff)
					{
						case ' ': EnterState(GET_HTTPV); break;
						default: m_url.push_back(*http_buff); break;
					}
				break;
				case GET_HTTPV:
					switch (*http_buff)
					{
						case '\r': EnterState(GET_HTTPVNL); break;
						default: m_version.push_back(*http_buff); break;
					}
				break;
				case GET_HTTPVNL:
					switch (*http_buff)
					{
						case '\n': EnterState(DONE); break;
						default:
							LogPrint(eLogError, "HTTPProxy: rejected invalid request ending with: ", ((int)*http_buff));
							HTTPRequestFailed("rejected invalid request");
							return false;
					}
				break;
				default:
					LogPrint(eLogError, "HTTPProxy: invalid state: ", m_state);
					HTTPRequestFailed("invalid parser state");
					return false;
			}
			http_buff++;
			len--;
			if (m_state == DONE)
				return CreateHTTPRequest(http_buff,len);
		}
		return true;
	}

	void HTTPReqHandler::HandleSockRecv(const boost::system::error_code & ecode, std::size_t len)
	{
		LogPrint(eLogDebug, "HTTPProxy: sock recv: ", len, " bytes");
		if(ecode)
		{
			LogPrint(eLogWarning, "HTTPProxy: sock recv got error: ", ecode);
			Terminate();
			return;
		}

		if (HandleData(m_http_buff, len))
		{
			if (m_state == DONE)
			{
				LogPrint(eLogDebug, "HTTPProxy: requested: ", m_url);
				GetOwner()->CreateStream (std::bind (&HTTPReqHandler::HandleStreamRequestComplete,
						shared_from_this(), std::placeholders::_1), m_address, m_port);
			}
			else
				AsyncSockRead();
		}
	}

	void HTTPReqHandler::SentHTTPFailed(const boost::system::error_code & ecode)
	{
		if (ecode)
			LogPrint (eLogError, "HTTPProxy: Closing socket after sending failure because: ", ecode.message ());
		Terminate();
	}

	void HTTPReqHandler::HandleStreamRequestComplete (std::shared_ptr<i2p::stream::Stream> stream)
	{
		if (stream)
		{
			if (Kill()) return;
			LogPrint (eLogInfo, "HTTPProxy: New I2PTunnel connection");
			auto connection = std::make_shared<i2p::client::I2PTunnelConnection>(GetOwner(), m_sock, stream);
			GetOwner()->AddHandler (connection);
			connection->I2PConnect (reinterpret_cast<const uint8_t*>(m_request.data()), m_request.size());
			Done(shared_from_this());
		}
		else
		{
			LogPrint (eLogError, "HTTPProxy: error when creating the stream, check the previous warnings for more info");
			HTTPRequestFailed("error when creating the stream, check logs");
		}
	}

	HTTPProxy::HTTPProxy(const std::string& address, int port, std::shared_ptr<i2p::client::ClientDestination> localDestination):
		TCPIPAcceptor(address, port, localDestination ? localDestination : i2p::client::context.GetSharedLocalDestination ())
	{
	}

	std::shared_ptr<i2p::client::I2PServiceHandler> HTTPProxy::CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket)
	{
		return std::make_shared<HTTPReqHandler> (this, socket);
	}
} // http
} // i2p
<|endoftext|>


<commit_before>#pragma once

#include "MatrixData.h"

namespace smurff
{
   template<typename YType>
   class MatrixDataTempl : public MatrixData
   {
   public:
      MatrixDataTempl(YType Y) : Y(Y)
      {
      }

      //init and center
      void init_pre() override
      {
         assert(nrow() > 0 && ncol() > 0);

         Yc.push_back(Y);
         Yc.push_back(Y.transpose());

         cwise_mean = sum() / (size() - nna());
      }

      PVec   dim() const override { return PVec({ static_cast<int>(Y.cols()), static_cast<int>(Y.rows()) }); }
      int    nnz() const override { return Y.nonZeros(); }
      double sum() const override { return Y.sum(); }

      double offset_to_mean(const PVec& pos) const override
      {
              if (center_mode == CENTER_GLOBAL) return global_mean;
         else if (center_mode == CENTER_VIEW)   return cwise_mean;
         else if (center_mode == CENTER_ROWS)   return mean(1,pos.at(1));
         else if (center_mode == CENTER_COLS)   return mean(0,pos.at(0));
         else if (center_mode == CENTER_NONE)   return .0;
         assert(false);
         return .0;
      }

      double var_total() const override;
      double sumsq(const SubModel& model) const override;

      YType Y;
      std::vector<YType> Yc; // centered versions
   };

   template<>
   double MatrixDataTempl<Eigen::MatrixXd>::var_total() const;

   template<>
   double MatrixDataTempl<Eigen::SparseMatrix<double> >::var_total() const;

   template<>
   double MatrixDataTempl<Eigen::MatrixXd>::sumsq(const SubModel &model) const;

   template<>
   double MatrixDataTempl<Eigen::SparseMatrix<double> >::sumsq(const SubModel &model) const;
}<commit_msg>ENH?: first mode is now row i.o. col<commit_after>#pragma once

#include "MatrixData.h"

namespace smurff
{
   template<typename YType>
   class MatrixDataTempl : public MatrixData
   {
   public:
      MatrixDataTempl(YType Y) : Y(Y)
      {
      }

      //init and center
      void init_pre() override
      {
         assert(nrow() > 0 && ncol() > 0);

         Yc.push_back(Y.transpose());
         Yc.push_back(Y);

         cwise_mean = sum() / (size() - nna());
      }

      PVec   dim() const override { return PVec({ static_cast<int>(Y.rows()), static_cast<int>(Y.cols()) }); }
      int    nnz() const override { return Y.nonZeros(); }
      double sum() const override { return Y.sum(); }

      double offset_to_mean(const PVec& pos) const override
      {
              if (center_mode == CENTER_GLOBAL) return global_mean;
         else if (center_mode == CENTER_VIEW)   return cwise_mean;
         else if (center_mode == CENTER_ROWS)   return mean(1,pos.at(1));
         else if (center_mode == CENTER_COLS)   return mean(0,pos.at(0));
         else if (center_mode == CENTER_NONE)   return .0;
         assert(false);
         return .0;
      }

      double var_total() const override;
      double sumsq(const SubModel& model) const override;

      YType Y;
      std::vector<YType> Yc; // centered versions
   };

   template<>
   double MatrixDataTempl<Eigen::MatrixXd>::var_total() const;

   template<>
   double MatrixDataTempl<Eigen::SparseMatrix<double> >::var_total() const;

   template<>
   double MatrixDataTempl<Eigen::MatrixXd>::sumsq(const SubModel &model) const;

   template<>
   double MatrixDataTempl<Eigen::SparseMatrix<double> >::sumsq(const SubModel &model) const;
}
<|endoftext|>