<commit_before>#ifndef STAN_MATH_REV_FUN_READ_VAR_HPP
#define STAN_MATH_REV_FUN_READ_VAR_HPP

#include <stan/math/prim/meta/require_generics.hpp>
#include <stan/math/rev/core/var.hpp>
#include <stan/math/rev/core/vari.hpp>

namespace stan {
namespace math {

/**
 * Functor for extracting the vari*, values, and adjoints from a matrix of var.
 * This functor is called using Eigen's NullaryExpr framework, which takes care
 * of the indexing. This removes the need to programmatically account for
 * whether the input is row- or column-major.
 */
template <typename EigRev, typename EigVari, typename EigDbl>
class vi_val_adj_functor {
  const EigRev& var_mat;
  EigVari& vi_mat;
  EigDbl& val_mat;

 public:
  vi_val_adj_functor(const EigRev& arg1, EigVari& arg2, EigDbl& arg3)
      : var_mat(arg1), vi_mat(arg2), val_mat(arg3) {}

  inline decltype(auto) operator()(Eigen::Index row, Eigen::Index col) const {
    vi_mat.coeffRef(row, col) = var_mat.coeffRef(row, col).vi_;
    val_mat.coeffRef(row, col) = var_mat.coeffRef(row, col).vi_->val_;
    return var_mat.coeffRef(row, col).vi_->adj_;
  }

  inline decltype(auto) operator()(Eigen::Index index) const {
    vi_mat.coeffRef(index) = var_mat.coeffRef(index).vi_;
    val_mat.coeffRef(index) = var_mat.coeffRef(index).vi_->val_;
    return var_mat.coeffRef(index).vi_->adj_;
  }
};

/**
 * Functor for extracting the values and adjoints from a matrix of var or vari.
 * This functor is called using Eigen's NullaryExpr framework.
 */
template <typename EigRev, typename EigDbl>
class val_adj_functor {
  const EigRev& var_mat;
  EigDbl& val_mat;

 public:
  val_adj_functor(const EigRev& arg1, EigDbl& arg2)
      : var_mat(arg1), val_mat(arg2) {}

  template <typename T = EigRev, require_st_same<T, var>* = nullptr>
  inline decltype(auto) operator()(Eigen::Index row, Eigen::Index col) const {
    val_mat.coeffRef(row, col) = var_mat.coeffRef(row, col).vi_->val_;
    return var_mat.coeffRef(row, col).vi_->adj_;
  }

  template <typename T = EigRev, require_st_same<T, var>* = nullptr>
  inline decltype(auto) operator()(Eigen::Index index) const {
    val_mat.coeffRef(index) = var_mat.coeffRef(index).vi_->val_;
    return var_mat.coeffRef(index).vi_->adj_;
  }

  template <typename T = EigRev, require_st_same<T, vari*>* = nullptr>
  inline decltype(auto) operator()(Eigen::Index row, Eigen::Index col) const {
    val_mat.coeffRef(row, col) = var_mat.coeffRef(row, col)->val_;
    return var_mat.coeffRef(row, col)->adj_;
  }

  template <typename T = EigRev, require_st_same<T, vari*>* = nullptr>
  inline decltype(auto) operator()(Eigen::Index index) const {
    val_mat.coeffRef(index) = var_mat.coeffRef(index)->val_;
    return var_mat.coeffRef(index)->adj_;
  }
};

/**
 * Functor for extracting the varis and values from a matrix of var.
 * This functor is called using Eigen's NullaryExpr framework.
 */
template <typename EigVar, typename EigVari>
class vi_val_functor {
  const EigVar& var_mat;
  EigVari& vi_mat;

 public:
  vi_val_functor(const EigVar& arg1, EigVari& arg2)
      : var_mat(arg1), vi_mat(arg2) {}

  inline decltype(auto) operator()(Eigen::Index row, Eigen::Index col) const {
    vi_mat.coeffRef(row, col) = var_mat.coeffRef(row, col).vi_;
    return var_mat.coeffRef(row, col).vi_->val_;
  }

  inline decltype(auto) operator()(Eigen::Index index) const {
    vi_mat.coeffRef(index) = var_mat.coeffRef(index).vi_;
    return var_mat.coeffRef(index).vi_->val_;
  }
};

/**
 * Functor for extracting the varis and adjoints from a matrix of var.
 * This functor is called using Eigen's NullaryExpr framework.
 */
template <typename EigVar, typename EigVari>
class vi_adj_functor {
  const EigVar& var_mat;
  EigVari& vi_mat;

 public:
  vi_adj_functor(const EigVar& arg1, EigVari& arg2)
      : var_mat(arg1), vi_mat(arg2) {}

  inline decltype(auto) operator()(Eigen::Index row, Eigen::Index col) const {
    vi_mat.coeffRef(row, col) = var_mat.coeffRef(row, col).vi_;
    return var_mat.coeffRef(row, col).vi_->adj_;
  }

  inline decltype(auto) operator()(Eigen::Index index) const {
    vi_mat.coeffRef(index) = var_mat.coeffRef(index).vi_;
    return var_mat.coeffRef(index).vi_->adj_;
  }
};

/**
 * Function applying the vi_val_adj_functor to extract the vari*, values,
 * and adjoints of a given var matrix into separate matrices.
 *
 * @tparam EigVar type of the Eigen container of var.
 * @tparam EigVari type of the Eigen container of vari to be copied to.
 * @tparam EigDbl type of the Eigen container of doubles to be copied to.
 * @param[in] VarMat Input Eigen container of var.
 * @param[in] VariMat Output Eigen container of vari.
 * @param[in] ValMat Output Eigen container of values.
 * @param[in] AdjMat Output Eigen container of tangents.
 */
template <typename EigVar, typename EigVari, typename EigDbl>
inline void read_vi_val_adj(const EigVar& VarMat, EigVari& VariMat,
                            EigDbl& ValMat, EigDbl& AdjMat) {
  AdjMat
      = EigDbl::NullaryExpr(VarMat.rows(), VarMat.cols(),
                            vi_val_adj_functor<const EigVar, EigVari, EigDbl>(
                                VarMat, VariMat, ValMat));
}

/**
 * Function applying the val_adj_functor to extract the values
 * and adjoints of a given var or vari matrix into separate matrices.
 *
 * @tparam EigRev type of the Eigen container of var or vari.
 * @tparam EigDbl type of the Eigen container of doubles to be copied to.
 * @param[in] VarMat Input Eigen container of var.
 * @param[in] ValMat Output Eigen container of values.
 * @param[in] AdjMat Output Eigen container of adjoints.
 */
template <typename EigRev, typename EigDbl>
inline void read_val_adj(const EigRev& VarMat, EigDbl& ValMat, EigDbl& AdjMat) {
  AdjMat = EigDbl::NullaryExpr(
      VarMat.rows(), VarMat.cols(),
      val_adj_functor<const EigRev, EigDbl>(VarMat, ValMat));
}

/**
 * Function applying the vi_val_functor to extract the varis and
 * and values of a given var matrix into separate matrices.
 *
 * @tparam EigVar type of the Eigen container of var.
 * @tparam EigDbl type of the Eigen container of doubles to be copied to.
 * @param[in] VarMat Input Eigen container of var.
 * @param[in] VariMat Output Eigen container of vari.
 * @param[in] ValMat Output Eigen container of values.
 */
template <typename EigVar, typename EigVari, typename EigDbl>
inline void read_vi_val(const EigVar& VarMat, EigVari& VariMat,
                        EigDbl& ValMat) {
  ValMat = EigDbl::NullaryExpr(
      VarMat.rows(), VarMat.cols(),
      vi_val_functor<const EigVar, EigVari>(VarMat, VariMat));
}

/**
 * Function applying the vi_adj_functor to extract the varis and
 * and adjoints of a given var matrix into separate matrices.
 *
 * @tparam EigVar type of the Eigen container of var.
 * @tparam EigDbl type of the Eigen container of doubles to be copied to.
 * @param[in] VarMat Input Eigen container of var.
 * @param[in] VariMat Output Eigen container of vari.
 * @param[in] ValMat Output Eigen container of adjoints.
 */
template <typename EigVar, typename EigVari, typename EigDbl>
inline void read_vi_adj(const EigVar& VarMat, EigVari& VariMat,
                        EigDbl& AdjMat) {
  AdjMat = EigDbl::NullaryExpr(
      VarMat.rows(), VarMat.cols(),
      vi_adj_functor<const EigVar, EigVari>(VarMat, VariMat));
}

}  // namespace math
}  // namespace stan
#endif
<commit_msg>Fix doc<commit_after>#ifndef STAN_MATH_REV_FUN_READ_VAR_HPP
#define STAN_MATH_REV_FUN_READ_VAR_HPP

#include <stan/math/prim/meta/require_generics.hpp>
#include <stan/math/rev/core/var.hpp>
#include <stan/math/rev/core/vari.hpp>

namespace stan {
namespace math {

/**
 * Functor for extracting the vari*, values, and adjoints from a matrix of var.
 * This functor is called using Eigen's NullaryExpr framework, which takes care
 * of the indexing. This removes the need to programmatically account for
 * whether the input is row- or column-major.
 */
template <typename EigRev, typename EigVari, typename EigDbl>
class vi_val_adj_functor {
  const EigRev& var_mat;
  EigVari& vi_mat;
  EigDbl& val_mat;

 public:
  vi_val_adj_functor(const EigRev& arg1, EigVari& arg2, EigDbl& arg3)
      : var_mat(arg1), vi_mat(arg2), val_mat(arg3) {}

  inline decltype(auto) operator()(Eigen::Index row, Eigen::Index col) const {
    vi_mat.coeffRef(row, col) = var_mat.coeffRef(row, col).vi_;
    val_mat.coeffRef(row, col) = var_mat.coeffRef(row, col).vi_->val_;
    return var_mat.coeffRef(row, col).vi_->adj_;
  }

  inline decltype(auto) operator()(Eigen::Index index) const {
    vi_mat.coeffRef(index) = var_mat.coeffRef(index).vi_;
    val_mat.coeffRef(index) = var_mat.coeffRef(index).vi_->val_;
    return var_mat.coeffRef(index).vi_->adj_;
  }
};

/**
 * Functor for extracting the values and adjoints from a matrix of var or vari.
 * This functor is called using Eigen's NullaryExpr framework.
 */
template <typename EigRev, typename EigDbl>
class val_adj_functor {
  const EigRev& var_mat;
  EigDbl& val_mat;

 public:
  val_adj_functor(const EigRev& arg1, EigDbl& arg2)
      : var_mat(arg1), val_mat(arg2) {}

  template <typename T = EigRev, require_st_same<T, var>* = nullptr>
  inline decltype(auto) operator()(Eigen::Index row, Eigen::Index col) const {
    val_mat.coeffRef(row, col) = var_mat.coeffRef(row, col).vi_->val_;
    return var_mat.coeffRef(row, col).vi_->adj_;
  }

  template <typename T = EigRev, require_st_same<T, var>* = nullptr>
  inline decltype(auto) operator()(Eigen::Index index) const {
    val_mat.coeffRef(index) = var_mat.coeffRef(index).vi_->val_;
    return var_mat.coeffRef(index).vi_->adj_;
  }

  template <typename T = EigRev, require_st_same<T, vari*>* = nullptr>
  inline decltype(auto) operator()(Eigen::Index row, Eigen::Index col) const {
    val_mat.coeffRef(row, col) = var_mat.coeffRef(row, col)->val_;
    return var_mat.coeffRef(row, col)->adj_;
  }

  template <typename T = EigRev, require_st_same<T, vari*>* = nullptr>
  inline decltype(auto) operator()(Eigen::Index index) const {
    val_mat.coeffRef(index) = var_mat.coeffRef(index)->val_;
    return var_mat.coeffRef(index)->adj_;
  }
};

/**
 * Functor for extracting the varis and values from a matrix of var.
 * This functor is called using Eigen's NullaryExpr framework.
 */
template <typename EigVar, typename EigVari>
class vi_val_functor {
  const EigVar& var_mat;
  EigVari& vi_mat;

 public:
  vi_val_functor(const EigVar& arg1, EigVari& arg2)
      : var_mat(arg1), vi_mat(arg2) {}

  inline decltype(auto) operator()(Eigen::Index row, Eigen::Index col) const {
    vi_mat.coeffRef(row, col) = var_mat.coeffRef(row, col).vi_;
    return var_mat.coeffRef(row, col).vi_->val_;
  }

  inline decltype(auto) operator()(Eigen::Index index) const {
    vi_mat.coeffRef(index) = var_mat.coeffRef(index).vi_;
    return var_mat.coeffRef(index).vi_->val_;
  }
};

/**
 * Functor for extracting the varis and adjoints from a matrix of var.
 * This functor is called using Eigen's NullaryExpr framework.
 */
template <typename EigVar, typename EigVari>
class vi_adj_functor {
  const EigVar& var_mat;
  EigVari& vi_mat;

 public:
  vi_adj_functor(const EigVar& arg1, EigVari& arg2)
      : var_mat(arg1), vi_mat(arg2) {}

  inline decltype(auto) operator()(Eigen::Index row, Eigen::Index col) const {
    vi_mat.coeffRef(row, col) = var_mat.coeffRef(row, col).vi_;
    return var_mat.coeffRef(row, col).vi_->adj_;
  }

  inline decltype(auto) operator()(Eigen::Index index) const {
    vi_mat.coeffRef(index) = var_mat.coeffRef(index).vi_;
    return var_mat.coeffRef(index).vi_->adj_;
  }
};

/**
 * Function applying the vi_val_adj_functor to extract the vari*, values,
 * and adjoints of a given var matrix into separate matrices.
 *
 * @tparam EigVar type of the Eigen container of var.
 * @tparam EigVari type of the Eigen container of vari to be copied to.
 * @tparam EigDbl type of the Eigen container of doubles to be copied to.
 * @param[in] VarMat Input Eigen container of var.
 * @param[in] VariMat Output Eigen container of vari.
 * @param[in] ValMat Output Eigen container of values.
 * @param[in] AdjMat Output Eigen container of tangents.
 */
template <typename EigVar, typename EigVari, typename EigDbl>
inline void read_vi_val_adj(const EigVar& VarMat, EigVari& VariMat,
                            EigDbl& ValMat, EigDbl& AdjMat) {
  AdjMat
      = EigDbl::NullaryExpr(VarMat.rows(), VarMat.cols(),
                            vi_val_adj_functor<const EigVar, EigVari, EigDbl>(
                                VarMat, VariMat, ValMat));
}

/**
 * Function applying the val_adj_functor to extract the values
 * and adjoints of a given var or vari matrix into separate matrices.
 *
 * @tparam EigRev type of the Eigen container of var or vari.
 * @tparam EigDbl type of the Eigen container of doubles to be copied to.
 * @param[in] VarMat Input Eigen container of var.
 * @param[in] ValMat Output Eigen container of values.
 * @param[in] AdjMat Output Eigen container of adjoints.
 */
template <typename EigRev, typename EigDbl>
inline void read_val_adj(const EigRev& VarMat, EigDbl& ValMat, EigDbl& AdjMat) {
  AdjMat = EigDbl::NullaryExpr(
      VarMat.rows(), VarMat.cols(),
      val_adj_functor<const EigRev, EigDbl>(VarMat, ValMat));
}

/**
 * Function applying the vi_val_functor to extract the varis and
 * and values of a given var matrix into separate matrices.
 *
 * @tparam EigVar type of the Eigen container of var.
 * @tparam EigDbl type of the Eigen container of doubles to be copied to.
 * @param[in] VarMat Input Eigen container of var.
 * @param[in] VariMat Output Eigen container of vari.
 * @param[in] ValMat Output Eigen container of values.
 */
template <typename EigVar, typename EigVari, typename EigDbl>
inline void read_vi_val(const EigVar& VarMat, EigVari& VariMat,
                        EigDbl& ValMat) {
  ValMat = EigDbl::NullaryExpr(
      VarMat.rows(), VarMat.cols(),
      vi_val_functor<const EigVar, EigVari>(VarMat, VariMat));
}

/**
 * Function applying the vi_adj_functor to extract the varis and
 * and adjoints of a given var matrix into separate matrices.
 *
 * @tparam EigVar type of the Eigen container of var.
 * @tparam EigDbl type of the Eigen container of doubles to be copied to.
 * @param[in] VarMat Input Eigen container of var.
 * @param[in] VariMat Output Eigen container of vari.
 * @param[in] AdjMat Output Eigen container of adjoints.
 */
template <typename EigVar, typename EigVari, typename EigDbl>
inline void read_vi_adj(const EigVar& VarMat, EigVari& VariMat,
                        EigDbl& AdjMat) {
  AdjMat = EigDbl::NullaryExpr(
      VarMat.rows(), VarMat.cols(),
      vi_adj_functor<const EigVar, EigVari>(VarMat, VariMat));
}

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


<commit_before>/*
Copyright (c) 2014 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.

Author: Leonardo de Moura
*/
#include "library/sorry.h"
#include <string>
#include <kernel/find_fn.h>
#include "kernel/type_checker.h"
#include "kernel/environment.h"
#include "library/module.h"
#include "kernel/for_each_fn.h"
#include "library/kernel_serializer.h"

namespace lean {
static name * g_sorry_name = nullptr;
static std::string * g_sorry_opcode = nullptr;

class sorry_macro_cell : public macro_definition_cell {
    bool m_synthetic;

public:
    sorry_macro_cell(bool synthetic) : m_synthetic(synthetic) {}

    bool is_synthetic() const { return m_synthetic; }

    virtual name get_name() const override { return *g_sorry_name; }

    unsigned int trust_level() const override { return 1; }

    virtual expr check_type(expr const & sry, abstract_type_context & ctx, bool infer_only) const override {
        if (!is_sorry(sry)) throw exception("invalid sorry macro");
        auto sort = ctx.whnf(ctx.check(sorry_type(sry), infer_only));
        if (!is_sort(sort)) throw exception("type of sorry macro is not a sort");
        return sorry_type(sry);
    }

    virtual optional<expr> expand(expr const &, abstract_type_context &) const override {
        return {};
    }

    virtual void write(serializer & s) const override {
        s.write_string(*g_sorry_opcode);
        s.write_bool(m_synthetic);
    }
};

void initialize_sorry() {
    g_sorry_name = new name{"sorry"};
    g_sorry_opcode = new std::string("Sorry");

    register_macro_deserializer(*g_sorry_opcode,
        [] (deserializer & d, unsigned num, expr const * args) {
            if (num != 1) throw corrupted_stream_exception();
            bool synthetic = d.read_bool();
            return mk_sorry(args[0], synthetic);
        });
}

void finalize_sorry() {
    delete g_sorry_opcode;
    delete g_sorry_name;
}

expr mk_sorry(expr const & ty, bool synthetic) {
    return mk_macro(macro_definition(new sorry_macro_cell(synthetic)), 1, &ty);
}
bool is_sorry(expr const & e) {
    return is_macro(e) && macro_num_args(e) == 1 && dynamic_cast<sorry_macro_cell const *>(macro_def(e).raw());
}
bool is_synthetic_sorry(expr const & e) {
    return is_sorry(e) && static_cast<sorry_macro_cell const *>(macro_def(e).raw())->is_synthetic();
}

bool has_synthetic_sorry(expr const & ex) {
    return !!find(ex, [] (expr const & e, unsigned) { return is_synthetic_sorry(e); });
}

bool has_sorry(expr const & ex) {
    return !!find(ex, [] (expr const & e, unsigned) { return is_sorry(e); });
}

bool has_sorry(declaration const & decl) {
    return has_sorry(decl.get_type()) || (decl.is_definition() && has_sorry(decl.get_value()));
}

expr const & sorry_type(expr const & sry) {
    return macro_arg(sry, 0);
}

bool has_sorry(environment const & env) {
    bool found_sorry = false;
    env.for_each_declaration([&] (declaration const & decl) {
        if (!found_sorry && has_sorry(decl)) found_sorry = true;
    });
    return found_sorry;
}
}
<commit_msg>feat: allow sorry macro to textualize (#602)<commit_after>/*
Copyright (c) 2014 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.

Author: Leonardo de Moura
*/
#include "library/sorry.h"
#include <string>
#include <kernel/find_fn.h>
#include "kernel/type_checker.h"
#include "kernel/environment.h"
#include "library/module.h"
#include "kernel/for_each_fn.h"
#include "library/kernel_serializer.h"

namespace lean {
static name * g_sorry_name = nullptr;
static std::string * g_sorry_opcode = nullptr;

class sorry_macro_cell : public macro_definition_cell {
    bool m_synthetic;

public:
    sorry_macro_cell(bool synthetic) : m_synthetic(synthetic) {}

    bool is_synthetic() const { return m_synthetic; }

    virtual name get_name() const override { return *g_sorry_name; }

    unsigned int trust_level() const override { return 1; }

    virtual expr check_type(expr const & sry, abstract_type_context & ctx, bool infer_only) const override {
        if (!is_sorry(sry)) throw exception("invalid sorry macro");
        auto sort = ctx.whnf(ctx.check(sorry_type(sry), infer_only));
        if (!is_sort(sort)) throw exception("type of sorry macro is not a sort");
        return sorry_type(sry);
    }

    virtual bool can_textualize() const { return true; }

    virtual void textualize(tlean_exporter & x) const {
        x.out() << "#SORRY_MACRO";
    }

    virtual optional<expr> expand(expr const &, abstract_type_context &) const override {
        return {};
    }

    virtual void write(serializer & s) const override {
        s.write_string(*g_sorry_opcode);
        s.write_bool(m_synthetic);
    }
};

void initialize_sorry() {
    g_sorry_name = new name{"sorry"};
    g_sorry_opcode = new std::string("Sorry");

    register_macro_deserializer(*g_sorry_opcode,
        [] (deserializer & d, unsigned num, expr const * args) {
            if (num != 1) throw corrupted_stream_exception();
            bool synthetic = d.read_bool();
            return mk_sorry(args[0], synthetic);
        });
}

void finalize_sorry() {
    delete g_sorry_opcode;
    delete g_sorry_name;
}

expr mk_sorry(expr const & ty, bool synthetic) {
    return mk_macro(macro_definition(new sorry_macro_cell(synthetic)), 1, &ty);
}
bool is_sorry(expr const & e) {
    return is_macro(e) && macro_num_args(e) == 1 && dynamic_cast<sorry_macro_cell const *>(macro_def(e).raw());
}
bool is_synthetic_sorry(expr const & e) {
    return is_sorry(e) && static_cast<sorry_macro_cell const *>(macro_def(e).raw())->is_synthetic();
}

bool has_synthetic_sorry(expr const & ex) {
    return !!find(ex, [] (expr const & e, unsigned) { return is_synthetic_sorry(e); });
}

bool has_sorry(expr const & ex) {
    return !!find(ex, [] (expr const & e, unsigned) { return is_sorry(e); });
}

bool has_sorry(declaration const & decl) {
    return has_sorry(decl.get_type()) || (decl.is_definition() && has_sorry(decl.get_value()));
}

expr const & sorry_type(expr const & sry) {
    return macro_arg(sry, 0);
}

bool has_sorry(environment const & env) {
    bool found_sorry = false;
    env.for_each_declaration([&] (declaration const & decl) {
        if (!found_sorry && has_sorry(decl)) found_sorry = true;
    });
    return found_sorry;
}
}
<|endoftext|>


<commit_before>/*
 *            Copyright 2009-2020 The VOTCA Development Team
 *                       (http://www.votca.org)
 *
 *      Licensed under the Apache License, Version 2.0 (the "License")
 *
 * You may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *              http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

// Standard includes
#include <vector>

// Local VOTCA includes
#include "votca/xtp/aobasis.h"
#include "votca/xtp/basisset.h"
#include "votca/xtp/qmmolecule.h"
#include "votca/xtp/qmpackage.h"

namespace votca {
namespace xtp {

AOShell& AOBasis::addShell(const Shell& shell, const QMAtom& atom,
                           Index startIndex) {
  _aoshells.push_back(AOShell(shell, atom, startIndex));
  return _aoshells.back();
}

const std::vector<const AOShell*> AOBasis::getShellsofAtom(Index AtomId) const {
  std::vector<const AOShell*> result;
  for (const auto& aoshell : _aoshells) {
    if (aoshell.getAtomIndex() == AtomId) {
      result.push_back(&aoshell);
    }
  }
  return result;
}

void AOBasis::Fill(const BasisSet& bs, const QMMolecule& atoms) {
  _AOBasisSize = 0;
  _aoshells.clear();
  _FuncperAtom.clear();
  // loop over atoms
  for (const QMAtom& atom : atoms) {
    Index atomfunc = 0;
    const std::string& name = atom.getElement();
    const Element& element = bs.getElement(name);
    for (const Shell& shell : element) {
      Index numfuncshell = NumFuncShell(shell.getL());
      AOShell& aoshell = addShell(shell, atom, _AOBasisSize);
      _AOBasisSize += numfuncshell;
      atomfunc += numfuncshell;
      for (const GaussianPrimitive& gaussian : shell) {
        aoshell.addGaussian(gaussian);
      }
      aoshell.CalcMinDecay();
      aoshell.normalizeContraction();
    }
    _FuncperAtom.push_back(atomfunc);
  }
  GenerateLibintBasis();
  return;
}

void AOBasis::GenerateLibintBasis() {
  _libintshells.resize(0);
  _libintshells.reserve(_aoshells.size());

  for (const auto& shell : _aoshells) {
    libint2::svector<libint2::Shell::real_t> decays;
    libint2::svector<libint2::Shell::Contraction> contractions;
    const Eigen::Vector3d& pos = shell.getPos();
    libint2::Shell::Contraction contr;
    for (const auto& primitive : shell) {
      decays.push_back(primitive.getDecay());
      contr.l = static_cast<int>(shell.getL());
      contr.pure = true;
      contr.coeff.push_back(primitive.getContraction());
    }
    contractions.push_back(contr);
    std::array<libint2::Shell::real_t, 3> libintpos = {pos[0], pos[1], pos[2]};
    libint2::Shell libintshell(decays, contractions, libintpos);
    _libintshells.push_back(libintshell);
  }
}

}  // namespace xtp
}  // namespace votca
<commit_msg>minor update<commit_after>/*
 *            Copyright 2009-2020 The VOTCA Development Team
 *                       (http://www.votca.org)
 *
 *      Licensed under the Apache License, Version 2.0 (the "License")
 *
 * You may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *              http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

// Standard includes
#include <vector>

// Local VOTCA includes
#include "votca/xtp/aobasis.h"
#include "votca/xtp/basisset.h"
#include "votca/xtp/qmmolecule.h"
#include "votca/xtp/qmpackage.h"

namespace votca {
namespace xtp {

AOShell& AOBasis::addShell(const Shell& shell, const QMAtom& atom,
                           Index startIndex) {
  _aoshells.push_back(AOShell(shell, atom, startIndex));
  return _aoshells.back();
}

const std::vector<const AOShell*> AOBasis::getShellsofAtom(Index AtomId) const {
  std::vector<const AOShell*> result;
  for (const auto& aoshell : _aoshells) {
    if (aoshell.getAtomIndex() == AtomId) {
      result.push_back(&aoshell);
    }
  }
  return result;
}

void AOBasis::Fill(const BasisSet& bs, const QMMolecule& atoms) {
  _AOBasisSize = 0;
  _aoshells.clear();
  _FuncperAtom.clear();
  // loop over atoms
  for (const QMAtom& atom : atoms) {
    Index atomfunc = 0;
    const std::string& name = atom.getElement();
    const Element& element = bs.getElement(name);
    for (const Shell& shell : element) {
      Index numfuncshell = NumFuncShell(shell.getL());
      AOShell& aoshell = addShell(shell, atom, _AOBasisSize);
      _AOBasisSize += numfuncshell;
      atomfunc += numfuncshell;
      for (const GaussianPrimitive& gaussian : shell) {
        aoshell.addGaussian(gaussian);
      }
      aoshell.CalcMinDecay();
      aoshell.normalizeContraction();
    }
    _FuncperAtom.push_back(atomfunc);
  }
  GenerateLibintBasis();
  return;
}

void AOBasis::GenerateLibintBasis() {
  _libintshells.resize(0);
  _libintshells.reserve(_aoshells.size());

  for (const auto& shell : _aoshells) {
    libint2::svector<libint2::Shell::real_t> decays;
    libint2::svector<libint2::Shell::Contraction> contractions;
    const Eigen::Vector3d& pos = shell.getPos();
    libint2::Shell::Contraction contr;
    contr.l = static_cast<int>(shell.getL());
    contr.pure = true;
    for (const auto& primitive : shell) {
      decays.push_back(primitive.getDecay());
      contr.coeff.push_back(primitive.getContraction());
    }
    contractions.push_back(contr);
    std::array<libint2::Shell::real_t, 3> libintpos = {pos[0], pos[1], pos[2]};
    libint2::Shell libintshell(decays, contractions, libintpos);
    _libintshells.push_back(libintshell);
  }
}

}  // namespace xtp
}  // namespace votca
<|endoftext|>


<commit_before>#include <listformatter.h>
#include <utils.h>
#include <stflpp.h>

namespace newsbeuter {

listformatter::listformatter() : refresh_cache(true) { }

listformatter::~listformatter() { }

void listformatter::add_line(const std::string& text, unsigned int id, unsigned int width) {
	if (width > 0 && text.length() > 0) {
		std::wstring temp = utils::str2wstr(text);
		// clean up the string
		std::wstring mytext;
		for(size_t idx=0; idx < temp.size(); ++idx)
			if (iswprint(temp[idx]))
				mytext += temp[idx];
			else
				mytext += L'?';

		while (mytext.length() > 0) {
			size_t size = mytext.length();
			size_t w = wcswidth(mytext.c_str(), size);
			if (w > width) {
				while (size && (w = wcswidth(mytext.c_str(), size)) > width) {
					size--;
				}
			}
			lines.push_back(line_id_pair(utils::wstr2str(mytext.substr(0, size)), id));
			mytext.erase(0, size);
		}
	} else {
		lines.push_back(line_id_pair(text, id));
	}
	LOG(LOG_DEBUG, "listformatter::add_line: `%s'", text.c_str());
	refresh_cache = true;
}

void listformatter::add_lines(const std::vector<std::string>& thelines, unsigned int width) {
	for (std::vector<std::string>::const_iterator it=thelines.begin();it!=thelines.end();++it) {
		add_line(utils::replace_all(*it, "\t", "        "), UINT_MAX, width);
	}
}

std::string listformatter::format_list(regexmanager * rxman, const std::string& location) {
	format_cache = "{list";
	for (std::vector<line_id_pair>::iterator it=lines.begin();it!=lines.end();++it) {
		std::string str = it->first;
		if (rxman)
			rxman->quote_and_highlight(str, location);
		if (it->second == UINT_MAX) {
			format_cache.append(utils::strprintf("{listitem text:%s}", stfl::quote(str).c_str()));
		} else {
			format_cache.append(utils::strprintf("{listitem[%u] text:%s}", it->second, stfl::quote(str).c_str()));
		}
	}
	format_cache.append(1, '}');
	refresh_cache = false;
	return format_cache;
}

}
<commit_msg>use U+FFFD instead of ? to indicate invalid character.<commit_after>#include <listformatter.h>
#include <utils.h>
#include <stflpp.h>

namespace newsbeuter {

listformatter::listformatter() : refresh_cache(true) { }

listformatter::~listformatter() { }

void listformatter::add_line(const std::string& text, unsigned int id, unsigned int width) {
	if (width > 0 && text.length() > 0) {
		std::wstring temp = utils::str2wstr(text);
		// clean up the string
		std::wstring mytext;
		for(size_t idx=0; idx < temp.size(); ++idx)
			if (iswprint(temp[idx]))
				mytext += temp[idx];
			else
				mytext += L'\uFFFD';

		while (mytext.length() > 0) {
			size_t size = mytext.length();
			size_t w = wcswidth(mytext.c_str(), size);
			if (w > width) {
				while (size && (w = wcswidth(mytext.c_str(), size)) > width) {
					size--;
				}
			}
			lines.push_back(line_id_pair(utils::wstr2str(mytext.substr(0, size)), id));
			mytext.erase(0, size);
		}
	} else {
		lines.push_back(line_id_pair(text, id));
	}
	LOG(LOG_DEBUG, "listformatter::add_line: `%s'", text.c_str());
	refresh_cache = true;
}

void listformatter::add_lines(const std::vector<std::string>& thelines, unsigned int width) {
	for (std::vector<std::string>::const_iterator it=thelines.begin();it!=thelines.end();++it) {
		add_line(utils::replace_all(*it, "\t", "        "), UINT_MAX, width);
	}
}

std::string listformatter::format_list(regexmanager * rxman, const std::string& location) {
	format_cache = "{list";
	for (std::vector<line_id_pair>::iterator it=lines.begin();it!=lines.end();++it) {
		std::string str = it->first;
		if (rxman)
			rxman->quote_and_highlight(str, location);
		if (it->second == UINT_MAX) {
			format_cache.append(utils::strprintf("{listitem text:%s}", stfl::quote(str).c_str()));
		} else {
			format_cache.append(utils::strprintf("{listitem[%u] text:%s}", it->second, stfl::quote(str).c_str()));
		}
	}
	format_cache.append(1, '}');
	refresh_cache = false;
	return format_cache;
}

}
<|endoftext|>


<commit_before>//
//  main.cpp
//  lab2
//
//  Created by Dylan Brown on 2/5/14.
//  Copyright (c) 2014 Dylan Brown. All rights reserved.
//

#include <iostream>

#define N 1024

class BitMap {
public:
    BitMap();
private:
    unsigned char bitmap[N];
};

BitMap::BitMap(void) {
    srand((unsigned int)time(NULL));
    for (int i = 0; i < N; i++) {
        bitmap[i] = rand();
    }
}

int main(int argc, const char * argv[])
{
    /* Create a BitMap object */
    BitMap();

    return 0;
}
<commit_msg>Working search method for BitMap class.<commit_after>//
//  main.cpp
//  lab2
//
//  Created by Dylan Brown on 2/5/14.
//  Copyright (c) 2014 Dylan Brown. All rights reserved.
//

#include <iostream>

#define N 1024

class BitMap {

public:
    BitMap();
    bool search(int n, unsigned int blocks[]);
    void freeBlocks(int n, unsigned int blocks[]);
    bool searchConsecutive(int n,
                           unsigned int startAddress,
                           unsigned int blockAddress);

private:
    unsigned char bitmap[N];
};

BitMap::BitMap(void) {

    /* Initialize the bitmap with random binary values */
    srand((unsigned int)time(NULL));
    for (int i = 0; i < N; i++) {
        bitmap[i] = rand()%256;
    }

    /* Reset the bitmap[0][0] address. Mark as used. */
    bitmap[0] = bitmap[0] & 0xFE;
}

bool BitMap::search(int n, unsigned int blocks[]) {

    unsigned char testBit;
    int address;
    int k = 0;

    /* Find the free blocks by testing each address in the bitmap */
    for (int i = 0; i < N; i++) {
        testBit = 0x01;
        for (int j = 0; j < 8; j++) {
            address = i * 8 + j;
            if (address > (N * 8)) return false;
            if ((bitmap[i] & testBit) > 0) {
                blocks[k++] = address;
                if (--n == 0) return true;
            }
            testBit = testBit << 1;
        }
    }
    return false;
}

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

    /* Create a BitMap object and blocks array */
    BitMap map = BitMap();
    const int numBlocks = 10;
    unsigned int blocks[numBlocks];

    /* Output the blocks array, or error if search failed */
    if (map.search(numBlocks, blocks)) {
        std::cout << "List of " << numBlocks << " available blocks: ";
        for (int i = 0; i < numBlocks; i++) {
            std::cout << blocks[i] << " ";
        }
        std::cout << "\n";
    } else {
        std::cout << "Insufficient disk space available!\n";
    }

    return 0;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <boost/tokenizer.hpp>

using namespace boost;
using namespace std;

void displayPrompt(){
    char *user = getlogin(); //I assign the login name to a user pointer
    if(user == NULL){
        perror("getlogin");
        exit(1);
    }

    char hostname[100]; //I allocate space for the hostname
    if(gethostname(hostname, sizeof(hostname)) == -1){ //checking for errors withostname
        perror("gethostname");
        exit(1);
    }

    cout << user << '@' << hostname << '$' << ' '; //here I output the user and hostanme to the screen.

}

void parseCommand(string &cmd){
    char_separator<char> delim;
    tokenizer< char_separator<char> > mytok(cmd, delim);
}

/*void executeCommand(char **argv){
    int pid = fork();

    if(pid == -1){
        perror("There was some error with fork()");
        exit(1);
    }
    else if(pid == 0){
        cout << "We are in the child process!";
        if(-1 == execvp(*argv, argv)){
            perror("There was an error with execvp");
            exit(1);
        }
    }
    else if(pid > 0){
        if(-1 == wait(0)){
            perror("There was an error with wait()");
        }
    }
}*/

int main(void){
        string cmd;

        while(cmd != "exit"){
            displayPrompt(); //display the username and hostname
            getline(cin, cmd);
        }

        return 0;
}

//notes to try
//------------
// if(strcmp(argv[0], "exit") == 0){
//              exit(0);
//         }
//------------
//execute command needs work
<commit_msg>started parsing<commit_after>#include <iostream>
#include <vector>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <boost/tokenizer.hpp>

using namespace boost;
using namespace std;

void displayPrompt(){
    char *user = getlogin(); //I assign the login name to a user pointer
    if(user == NULL){
        perror("getlogin");
        exit(1);
    }

    char hostname[100]; //I allocate space for the hostname
    if(gethostname(hostname, sizeof(hostname)) == -1){ //checking for errors withostname
        perror("gethostname");
        exit(1);
    }

    cout << user << '@' << hostname << '$' << ' '; //here I output the user and hostanme to the screen.

}

/*void parseCommands(char &commands[]){
    vector<char*> single_commands; //vector that stores each command

    char_separator<char> delim(";");
    tokenizer< char_separator<char> > mytok(commands, delim);
}*/

/*void executeCommand(char **argv){
    int pid = fork();

    if(pid == -1){
        perror("There was some error with fork()");
        exit(1);
    }
    else if(pid == 0){
        cout << "We are in the child process!";
        if(-1 == execvp(*argv, argv)){
            perror("There was an error with execvp");
            exit(1);
        }
    }
    else if(pid > 0){
        if(-1 == wait(0)){
            perror("There was an error with wait()");
        }
    }
}*/

int main(void){
        string cmd;

        //char commandLine[1000]; //user's command

        while(cmd != "exit"){
            displayPrompt(); //display the username and hostname
            getline(cin, cmd);
        }

        return 0;
}

//notes to try
//------------
// if(strcmp(argv[0], "exit") == 0){
//              exit(0);
//         }
//------------
//execute command needs work
<|endoftext|>


<commit_before>/*******************************************************************************
Copyright (c) 2014, Jan Koester jan.koester@gmx.net
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of the <organization> nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/

#include <fcntl.h>
#include <sys/sysinfo.h>
#include <cstdlib>
#include <config.h>
#include <errno.h>
#include <signal.h>
#include "os/os.h"

#define READEVENT 0
#define SENDEVENT 1

#define DEBUG_MUTEX

#include "../event.h"

libhttppp::Event::Event(ServerSocket *serversocket) {
    _ServerSocket=serversocket;
    _ServerSocket->setnonblocking();
    _ServerSocket->listenSocket();
    _EventEndloop =true;
    _Cpool= new ConnectionPool(_ServerSocket);
    _Events = new epoll_event[(_ServerSocket->getMaxconnections())];
    _Mutex = new Mutex;
    _firstConnectionContext=NULL;
    _lastConnectionContext=NULL;
}

libhttppp::Event::~Event() {
  delete   _Cpool;
  delete[] _Events;
  delete _firstConnectionContext;
  delete _Mutex;
  _lastConnectionContext=NULL;
}

libhttppp::Event* _EventIns=NULL;

void libhttppp::Event::CtrlHandler(int signum) {
    _EventIns->_EventEndloop=false;
}

void libhttppp::Event::runEventloop() {
    _setEvent = (struct epoll_event){0};
    for(int i=0; i<_ServerSocket->getMaxconnections(); i++)
        _Events[i].data.fd = -1;
    _epollFD = epoll_create1(0);

    if (_epollFD == -1) {
        _httpexception.Critical("can't create epoll");
        throw _httpexception;
    }

    _setEvent.events = EPOLLIN;
    _setEvent.data.fd = _ServerSocket->getSocket();

    if (epoll_ctl(_epollFD, EPOLL_CTL_ADD, _ServerSocket->getSocket(), &_setEvent) < 0) {
        _httpexception.Critical("can't create epoll");
        throw _httpexception;
    }

    int srvssocket=_ServerSocket->getSocket();
    int maxconnets=_ServerSocket->getMaxconnections();
    while(_EventEndloop) {
        int n = epoll_wait(_epollFD,_Events,maxconnets, EPOLLWAIT);
        if(n<0){
            if(errno== EINTR){
                continue;
            }else{
                 _httpexception.Critical("epoll wait failure");
                 throw _httpexception;
            }

        }
        for(int i=0; i<n; i++) {
            ConnectionContext *curct=NULL;
            if(_Events[i].data.fd == srvssocket) {
              try {
              /*will create warning debug mode that normally because the check already connection
               * with this socket if getconnection throw they will be create a new one
               */
#ifdef DEBUG_MUTEX
                _httpexception.Note("runeventloop","Lock MainMutex");
#endif
                _Mutex->lock();
                curct=addConnection();
#ifdef DEBUG_MUTEX
                _httpexception.Note("runeventloop","Unlock MainMutex");
#endif
                _Mutex->unlock();
#ifdef DEBUG_MUTEX
                _httpexception.Note("runeventloop","Lock ConnectionMutex");
#endif
                curct->_Mutex->lock();
                ClientSocket *clientsocket=curct->_CurConnection->getClientSocket();
                int fd=_ServerSocket->acceptEvent(clientsocket);
                clientsocket->setnonblocking();
                if(fd>0) {
                  _setEvent.data.ptr = (void*) curct;
                  _setEvent.events = EPOLLIN|EPOLLET;
                  if(epoll_ctl(_epollFD, EPOLL_CTL_ADD, fd, &_setEvent)==-1 && errno==EEXIST)
                    epoll_ctl(_epollFD, EPOLL_CTL_MOD,fd, &_setEvent);
                  ConnectEvent(curct->_CurConnection);
#ifdef DEBUG_MUTEX
                _httpexception.Note("runeventloop","Unlock ConnectionMutex");
#endif
                  curct->_Mutex->unlock();
                } else {
#ifdef DEBUG_MUTEX
                _httpexception.Note("runeventloop","Unlock ConnectionMutex");
#endif
                   curct->_Mutex->unlock();
#ifdef DEBUG_MUTEX
                _httpexception.Note("runeventloop","Lock MainMutex");
#endif
                  _Mutex->lock();
                  delConnection(curct->_CurConnection);
#ifdef DEBUG_MUTEX
                _httpexception.Note("runeventloop","Unlock MainMutex");
#endif
                  _Mutex->unlock();
                }

              } catch(HTTPException &e) {
#ifdef DEBUG_MUTEX
                _httpexception.Note("runeventloop","Lock MainMutex");
#endif
                _Mutex->lock();
#ifdef DEBUG_MUTEX
                _httpexception.Note("runeventloop","Unlock ConnectionMutex");
#endif
                curct->_Mutex->unlock();
                delConnection(curct->_CurConnection);
#ifdef DEBUG_MUTEX
                _httpexception.Note("runeventloop","Unlock MainMutex");
#endif
                _Mutex->unlock();
                if(e.isCritical())
                  throw e;
              }
            } else {
                curct=(ConnectionContext*)_Events[i].data.ptr;
                if(_Events[i].events & EPOLLIN) {
                    Thread(ReadEvent,curct);
                }else{
#ifdef DEBUG_MUTEX
                _httpexception.Note("runeventloop","Lock MainMutex");
#endif
                    _Mutex->lock();
                    CloseEvent(curct);
#ifdef DEBUG_MUTEX
                _httpexception.Note("runeventloop","Unlock MainMutex");
#endif
                    _Mutex->unlock();
                }
            }
        }
        _EventIns=this;
        signal(SIGINT, CtrlHandler);
    }
}

libhttppp::Event::ConnectionContext::ConnectionContext(){
  _CurConnection=NULL;
  _CurCPool=NULL;
  _CurEvent=NULL;
  _Mutex=new Mutex;
  _nextConnectionContext=NULL;
}

libhttppp::Event::ConnectionContext::~ConnectionContext(){
  delete _Mutex;
  delete _nextConnectionContext;
}

libhttppp::Event::ConnectionContext * libhttppp::Event::ConnectionContext::nextConnectionContext(){
  return _nextConnectionContext;
}

libhttppp::Event::ConnectionContext * libhttppp::Event::addConnection(){
  if(!_firstConnectionContext){
    _firstConnectionContext=new ConnectionContext();
#ifdef DEBUG_MUTEX
    _httpexception.Note("addConnection","Lock ConnectionMutex");
#endif
    _firstConnectionContext->_Mutex->lock();
    _lastConnectionContext=_firstConnectionContext;
#ifdef DEBUG_MUTEX
    _httpexception.Note("addConnection","Unlock ConnectionMutex");
#endif
    _firstConnectionContext->_Mutex->unlock();
  }else{
#ifdef DEBUG_MUTEX
    _httpexception.Note("addConnection","Lock ConnectionMutex");
#endif
    _lastConnectionContext->_Mutex->lock();
    _lastConnectionContext->_nextConnectionContext=new ConnectionContext();
    _lastConnectionContext=_lastConnectionContext->_nextConnectionContext;
#ifdef DEBUG_MUTEX
    _httpexception.Note("addConnection","Unlock ConnectionMutex");
#endif
    _lastConnectionContext->_Mutex->unlock();
  }
  _lastConnectionContext->_CurConnection=_Cpool->addConnection();
  _lastConnectionContext->_CurCPool=_Cpool;
  _lastConnectionContext->_CurEvent=this;

  return _lastConnectionContext;
}

libhttppp::Event::ConnectionContext * libhttppp::Event::delConnection(libhttppp::Connection* delcon){
  ConnectionContext *prevcontext=NULL;
  for(ConnectionContext *curcontext=_firstConnectionContext; curcontext;
      curcontext=curcontext->nextConnectionContext()){
    if(curcontext->_CurConnection==delcon){
#ifdef DEBUG_MUTEX
      _httpexception.Note("delConnection","Lock ConnectionMutex");
#endif
      curcontext->_Mutex->lock();
      _Cpool->delConnection(delcon);
      if(prevcontext){
#ifdef DEBUG_MUTEX
        _httpexception.Note("delConnection","Lock prevConnectionMutex");
#endif
        prevcontext->_Mutex->lock();
        prevcontext->_nextConnectionContext=curcontext->_nextConnectionContext;
        if(_lastConnectionContext==curcontext){
          _lastConnectionContext=prevcontext;
        }
#ifdef DEBUG_MUTEX
     _httpexception.Note("delConnection","unlock prevConnectionMutex");
#endif
        prevcontext->_Mutex->unlock();
      }else{
#ifdef DEBUG_MUTEX
        _httpexception.Note("delConnection","lock firstConnectionMutex");
#endif
        _firstConnectionContext->_Mutex->lock();
#ifdef DEBUG_MUTEX
        _httpexception.Note("delConnection","lock lastConnectionMutex");
#endif
        _lastConnectionContext->_Mutex->lock();
        _firstConnectionContext=curcontext->_nextConnectionContext;
        if(_lastConnectionContext->_CurConnection==delcon)
          _lastConnectionContext=_firstConnectionContext;
        if(_firstConnectionContext){
#ifdef DEBUG_MUTEX
        _httpexception.Note("delConnection","unlock firstConnectionMutex");
#endif
        _firstConnectionContext->_Mutex->unlock();
        }
        if(_lastConnectionContext){
#ifdef DEBUG_MUTEX
     _httpexception.Note("delConnection","unlock lastConnectionMutex");
#endif
        _lastConnectionContext->_Mutex->unlock();
        }
      }
      curcontext->_nextConnectionContext=NULL;
      delete curcontext;
      break;
    }
    prevcontext=curcontext;
  }
  if(prevcontext && prevcontext->_nextConnectionContext){
    return prevcontext->_nextConnectionContext;
  }else{
    ConnectionContext *fcontext=_firstConnectionContext;
    return fcontext;
  }
}

/*Workers*/
void *libhttppp::Event::ReadEvent(void *curcon){
  ConnectionContext *ccon=(ConnectionContext*)curcon;
  Event *eventins=ccon->_CurEvent;
#ifdef DEBUG_MUTEX
  eventins->_httpexception.Note("ReadEvent","lock ConnectionMutex");
#endif
  ccon->_Mutex->lock();
  Connection *con=(Connection*)ccon->_CurConnection;
  try {
    char buf[BLOCKSIZE];
    int rcvsize=0;
    do{
      rcvsize=eventins->_ServerSocket->recvData(con->getClientSocket(),buf,BLOCKSIZE);
      if(rcvsize>0)
        con->addRecvQueue(buf,rcvsize);
    }while(rcvsize>0);
    eventins->RequestEvent(con);
#ifdef DEBUG_MUTEX
  eventins->_httpexception.Note("ReadEvent","unlock ConnectionMutex");
#endif
    ccon->_Mutex->unlock();
    WriteEvent(ccon);
  } catch(HTTPException &e) {
#ifdef DEBUG_MUTEX
      eventins->_httpexception.Note("ReadEvent","unlock ConnectionMutex");
#endif
      ccon->_Mutex->unlock();
       if(e.isCritical()) {
         throw e;
       }
       if(e.isError()){
          CloseEvent(ccon);
       }
  }
  return NULL;
}

void *libhttppp::Event::WriteEvent(void* curcon){
  ConnectionContext *ccon=(ConnectionContext*)curcon;
  Event *eventins=ccon->_CurEvent;
#ifdef DEBUG_MUTEX
  eventins->_httpexception.Note("WriteEvent","lock ConnectionMutex");
#endif
  ccon->_Mutex->lock();
  Connection *con=(Connection*)ccon->_CurConnection;
  try {
    ssize_t sended=0;
    while(con->getSendData()){
      sended=eventins->_ServerSocket->sendData(con->getClientSocket(),
                                    (void*)con->getSendData()->getData(),
                                    con->getSendData()->getDataSize());
      if(sended>0)
        con->resizeSendQueue(sended);
      eventins->ResponseEvent(con);
    }
  } catch(HTTPException &e) {
    con->cleanSendData();
    CloseEvent(ccon);
  }
#ifdef DEBUG_MUTEX
  eventins->_httpexception.Note("WriteEvent","unlock ConnectionMutex");
#endif
  ccon->_Mutex->unlock();
  return NULL;
}

void *libhttppp::Event::CloseEvent(void *curcon){
  ConnectionContext *ccon=(ConnectionContext*)curcon;
  Event *eventins=ccon->_CurEvent;
#ifdef DEBUG_MUTEX
  eventins->_httpexception.Note("CloseEvent","MainMutex");
#endif
  ccon->_Mutex->lock();
  Connection *con=(Connection*)ccon->_CurConnection;
  eventins->DisconnectEvent(con);
#ifdef DEBUG_MUTEX
  eventins->_httpexception.Note("CloseEvent","unlock MainMutex");
#endif
  ccon->_Mutex->unlock();
  try {
    epoll_ctl(eventins->_epollFD, EPOLL_CTL_DEL, con->getClientSocket()->getSocket(), &eventins->_setEvent);
    eventins->delConnection(con);
    curcon=NULL;
    eventins->_httpexception.Note("Connection shutdown!");
  } catch(HTTPException &e) {
    eventins->_httpexception.Note("Can't do Connection shutdown!");
  }
  return NULL;
}

/*Event Handlers*/
void libhttppp::Event::RequestEvent(libhttppp::Connection *curcon) {
    return;
}

void libhttppp::Event::ResponseEvent(libhttppp::Connection *curcon) {
    return;
}

void libhttppp::Event::ConnectEvent(libhttppp::Connection *curcon) {
    return;
}

void libhttppp::Event::DisconnectEvent(libhttppp::Connection *curcon) {
    return;
}
<commit_msg>small optimations<commit_after>/*******************************************************************************
Copyright (c) 2014, Jan Koester jan.koester@gmx.net
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of the <organization> nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/

#include <fcntl.h>
#include <sys/sysinfo.h>
#include <cstdlib>
#include <config.h>
#include <errno.h>
#include <signal.h>
#include "os/os.h"

#define READEVENT 0
#define SENDEVENT 1

#define DEBUG_MUTEX

#include "../event.h"

libhttppp::Event::Event(ServerSocket *serversocket) {
    _ServerSocket=serversocket;
    _ServerSocket->setnonblocking();
    _ServerSocket->listenSocket();
    _EventEndloop =true;
    _Cpool= new ConnectionPool(_ServerSocket);
    _Events = new epoll_event[(_ServerSocket->getMaxconnections())];
    _Mutex = new Mutex;
    _firstConnectionContext=NULL;
    _lastConnectionContext=NULL;
}

libhttppp::Event::~Event() {
  delete   _Cpool;
  delete[] _Events;
  delete _firstConnectionContext;
  delete _Mutex;
  _lastConnectionContext=NULL;
}

libhttppp::Event* _EventIns=NULL;

void libhttppp::Event::CtrlHandler(int signum) {
    _EventIns->_EventEndloop=false;
}

void libhttppp::Event::runEventloop() {
    _setEvent = (struct epoll_event){0};
    for(int i=0; i<_ServerSocket->getMaxconnections(); i++)
        _Events[i].data.fd = -1;
    _epollFD = epoll_create1(0);

    if (_epollFD == -1) {
        _httpexception.Critical("can't create epoll");
        throw _httpexception;
    }

    _setEvent.events = EPOLLIN;
    _setEvent.data.fd = _ServerSocket->getSocket();

    if (epoll_ctl(_epollFD, EPOLL_CTL_ADD, _ServerSocket->getSocket(), &_setEvent) < 0) {
        _httpexception.Critical("can't create epoll");
        throw _httpexception;
    }

    int srvssocket=_ServerSocket->getSocket();
    int maxconnets=_ServerSocket->getMaxconnections();
    while(_EventEndloop) {
        int n = epoll_wait(_epollFD,_Events,maxconnets, EPOLLWAIT);
        if(n<0){
            if(errno== EINTR){
                continue;
            }else{
                 _httpexception.Critical("epoll wait failure");
                 throw _httpexception;
            }

        }
        for(int i=0; i<n; i++) {
            ConnectionContext *curct=NULL;
            if(_Events[i].data.fd == srvssocket) {
              try {
              /*will create warning debug mode that normally because the check already connection
               * with this socket if getconnection throw they will be create a new one
               */
#ifdef DEBUG_MUTEX
                _httpexception.Note("runeventloop","Lock MainMutex");
#endif
                _Mutex->lock();
                curct=addConnection();
#ifdef DEBUG_MUTEX
                _httpexception.Note("runeventloop","Unlock MainMutex");
#endif
                _Mutex->unlock();
#ifdef DEBUG_MUTEX
                _httpexception.Note("runeventloop","Lock ConnectionMutex");
#endif
                curct->_Mutex->lock();
                ClientSocket *clientsocket=curct->_CurConnection->getClientSocket();
                int fd=_ServerSocket->acceptEvent(clientsocket);
                clientsocket->setnonblocking();
                if(fd>0) {
                  _setEvent.data.ptr = (void*) curct;
                  _setEvent.events = EPOLLIN|EPOLLET;
                  if(epoll_ctl(_epollFD, EPOLL_CTL_ADD, fd, &_setEvent)==-1 && errno==EEXIST)
                    epoll_ctl(_epollFD, EPOLL_CTL_MOD,fd, &_setEvent);
                  ConnectEvent(curct->_CurConnection);
#ifdef DEBUG_MUTEX
                _httpexception.Note("runeventloop","Unlock ConnectionMutex");
#endif
                  curct->_Mutex->unlock();
                } else {
#ifdef DEBUG_MUTEX
                _httpexception.Note("runeventloop","Unlock ConnectionMutex");
#endif
                   curct->_Mutex->unlock();
#ifdef DEBUG_MUTEX
                _httpexception.Note("runeventloop","Lock MainMutex");
#endif
                  _Mutex->lock();
                  delConnection(curct->_CurConnection);
#ifdef DEBUG_MUTEX
                _httpexception.Note("runeventloop","Unlock MainMutex");
#endif
                  _Mutex->unlock();
                }

              } catch(HTTPException &e) {
#ifdef DEBUG_MUTEX
                _httpexception.Note("runeventloop","Lock MainMutex");
#endif
                _Mutex->lock();
#ifdef DEBUG_MUTEX
                _httpexception.Note("runeventloop","Unlock ConnectionMutex");
#endif
                curct->_Mutex->unlock();
                delConnection(curct->_CurConnection);
#ifdef DEBUG_MUTEX
                _httpexception.Note("runeventloop","Unlock MainMutex");
#endif
                _Mutex->unlock();
                if(e.isCritical())
                  throw e;
              }
            } else {
                curct=(ConnectionContext*)_Events[i].data.ptr;
                if(_Events[i].events & EPOLLIN) {
                    Thread(ReadEvent,curct);
                }else{
                    CloseEvent(curct);
                }
            }
        }
        _EventIns=this;
        signal(SIGINT, CtrlHandler);
    }
}

libhttppp::Event::ConnectionContext::ConnectionContext(){
  _CurConnection=NULL;
  _CurCPool=NULL;
  _CurEvent=NULL;
  _Mutex=new Mutex;
  _nextConnectionContext=NULL;
}

libhttppp::Event::ConnectionContext::~ConnectionContext(){
  delete _Mutex;
  delete _nextConnectionContext;
}

libhttppp::Event::ConnectionContext * libhttppp::Event::ConnectionContext::nextConnectionContext(){
  return _nextConnectionContext;
}

libhttppp::Event::ConnectionContext * libhttppp::Event::addConnection(){
  if(!_firstConnectionContext){
    _firstConnectionContext=new ConnectionContext();
#ifdef DEBUG_MUTEX
    _httpexception.Note("addConnection","Lock ConnectionMutex");
#endif
    _firstConnectionContext->_Mutex->lock();
    _lastConnectionContext=_firstConnectionContext;
#ifdef DEBUG_MUTEX
    _httpexception.Note("addConnection","Unlock ConnectionMutex");
#endif
    _firstConnectionContext->_Mutex->unlock();
  }else{
#ifdef DEBUG_MUTEX
    _httpexception.Note("addConnection","Lock ConnectionMutex");
#endif
    _lastConnectionContext->_Mutex->lock();
    _lastConnectionContext->_nextConnectionContext=new ConnectionContext();
    _lastConnectionContext=_lastConnectionContext->_nextConnectionContext;
#ifdef DEBUG_MUTEX
    _httpexception.Note("addConnection","Unlock ConnectionMutex");
#endif
    _lastConnectionContext->_Mutex->unlock();
  }
  _lastConnectionContext->_CurConnection=_Cpool->addConnection();
  _lastConnectionContext->_CurCPool=_Cpool;
  _lastConnectionContext->_CurEvent=this;

  return _lastConnectionContext;
}

libhttppp::Event::ConnectionContext * libhttppp::Event::delConnection(libhttppp::Connection* delcon){
  ConnectionContext *prevcontext=NULL;
  for(ConnectionContext *curcontext=_firstConnectionContext; curcontext;
      curcontext=curcontext->nextConnectionContext()){
    if(curcontext->_CurConnection==delcon){
#ifdef DEBUG_MUTEX
      _httpexception.Note("delConnection","Lock ConnectionMutex");
#endif
      curcontext->_Mutex->lock();
      _Cpool->delConnection(delcon);
      if(prevcontext){
#ifdef DEBUG_MUTEX
        _httpexception.Note("delConnection","Lock prevConnectionMutex");
#endif
        prevcontext->_Mutex->lock();
        prevcontext->_nextConnectionContext=curcontext->_nextConnectionContext;
        if(_lastConnectionContext==curcontext){
          _lastConnectionContext=prevcontext;
        }
#ifdef DEBUG_MUTEX
        _httpexception.Note("delConnection","unlock prevConnectionMutex");
#endif
        prevcontext->_Mutex->unlock();
      }else{
#ifdef DEBUG_MUTEX
        _httpexception.Note("delConnection","lock firstConnectionMutex");
#endif
        _firstConnectionContext->_Mutex->lock();
#ifdef DEBUG_MUTEX
        _httpexception.Note("delConnection","lock lastConnectionMutex");
#endif
        _lastConnectionContext->_Mutex->lock();
        _firstConnectionContext=curcontext->_nextConnectionContext;
        if(_lastConnectionContext->_CurConnection==delcon)
          _lastConnectionContext=_firstConnectionContext;
        if(_firstConnectionContext){
#ifdef DEBUG_MUTEX
        _httpexception.Note("delConnection","unlock firstConnectionMutex");
#endif
        _firstConnectionContext->_Mutex->unlock();
        }
        if(_lastConnectionContext){
#ifdef DEBUG_MUTEX
     _httpexception.Note("delConnection","unlock lastConnectionMutex");
#endif
        _lastConnectionContext->_Mutex->unlock();
        }
      }
      curcontext->_nextConnectionContext=NULL;
      delete curcontext;
      break;
    }
    prevcontext=curcontext;
  }
  if(prevcontext && prevcontext->_nextConnectionContext){
    return prevcontext->_nextConnectionContext;
  }else{
    ConnectionContext *fcontext=_firstConnectionContext;
    return fcontext;
  }
}

/*Workers*/
void *libhttppp::Event::ReadEvent(void *curcon){
  ConnectionContext *ccon=(ConnectionContext*)curcon;
  Event *eventins=ccon->_CurEvent;
#ifdef DEBUG_MUTEX
  eventins->_httpexception.Note("ReadEvent","lock ConnectionMutex");
#endif
  ccon->_Mutex->lock();
  Connection *con=(Connection*)ccon->_CurConnection;
  try {
    char buf[BLOCKSIZE];
    int rcvsize=0;
    do{
      rcvsize=eventins->_ServerSocket->recvData(con->getClientSocket(),buf,BLOCKSIZE);
      if(rcvsize>0)
        con->addRecvQueue(buf,rcvsize);
    }while(rcvsize>0);
    eventins->RequestEvent(con);
#ifdef DEBUG_MUTEX
  eventins->_httpexception.Note("ReadEvent","unlock ConnectionMutex");
#endif
    ccon->_Mutex->unlock();
    WriteEvent(ccon);
  } catch(HTTPException &e) {
#ifdef DEBUG_MUTEX
      eventins->_httpexception.Note("ReadEvent","unlock ConnectionMutex");
#endif
      ccon->_Mutex->unlock();
       if(e.isCritical()) {
         throw e;
       }
       if(e.isError()){
          con->cleanRecvData();
          CloseEvent(ccon);
       }
  }
  return NULL;
}

void *libhttppp::Event::WriteEvent(void* curcon){
  ConnectionContext *ccon=(ConnectionContext*)curcon;
  Event *eventins=ccon->_CurEvent;
#ifdef DEBUG_MUTEX
  eventins->_httpexception.Note("WriteEvent","lock ConnectionMutex");
#endif
  ccon->_Mutex->lock();
  Connection *con=(Connection*)ccon->_CurConnection;
  try {
    ssize_t sended=0;
    while(con->getSendData()){
      sended=eventins->_ServerSocket->sendData(con->getClientSocket(),
                                    (void*)con->getSendData()->getData(),
                                    con->getSendData()->getDataSize());
      if(sended>0)
        con->resizeSendQueue(sended);
      eventins->ResponseEvent(con);
    }
  } catch(HTTPException &e) {
    CloseEvent(ccon);
  }
#ifdef DEBUG_MUTEX
  eventins->_httpexception.Note("WriteEvent","unlock ConnectionMutex");
#endif
  ccon->_Mutex->unlock();
  return NULL;
}

void *libhttppp::Event::CloseEvent(void *curcon){
  ConnectionContext *ccon=(ConnectionContext*)curcon;
  Event *eventins=ccon->_CurEvent;
#ifdef DEBUG_MUTEX
  eventins->_httpexception.Note("CloseEvent","ConnectionMutex");
#endif
  ccon->_Mutex->lock();
  Connection *con=(Connection*)ccon->_CurConnection;
  eventins->DisconnectEvent(con);
#ifdef DEBUG_MUTEX
  eventins->_httpexception.Note("CloseEvent","unlock ConnectionMutex");
#endif
  ccon->_Mutex->unlock();
  try {
    epoll_ctl(eventins->_epollFD, EPOLL_CTL_DEL, con->getClientSocket()->getSocket(), &eventins->_setEvent);
    eventins->delConnection(con);
    curcon=NULL;
    eventins->_httpexception.Note("Connection shutdown!");
  } catch(HTTPException &e) {
    eventins->_httpexception.Note("Can't do Connection shutdown!");
  }
  return NULL;
}

/*Event Handlers*/
void libhttppp::Event::RequestEvent(libhttppp::Connection *curcon) {
    return;
}

void libhttppp::Event::ResponseEvent(libhttppp::Connection *curcon) {
    return;
}

void libhttppp::Event::ConnectEvent(libhttppp::Connection *curcon) {
    return;
}

void libhttppp::Event::DisconnectEvent(libhttppp::Connection *curcon) {
    return;
}
<|endoftext|>


<commit_before>// Copyright 2015 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <algorithm>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <numeric>
#include <sched.h>
#include <string.h>
#include <sstream>
#include <sys/mman.h>
#include <vector>

#include <rttest.h>

// Global variables
struct rttest_params _rttest_params;
struct rttest_sample_buffer _rttest_sample_buffer;
struct rttest_results _rttest_results;

static inline bool timespec_gt(const struct timespec *t1,
    const struct timespec *t2)
{
  if (t1->tv_sec > t2->tv_sec)
  {
    return true;
  }
  if (t1->tv_sec < t2->tv_sec)
  {
    return false;
  }
  return t1->tv_nsec > t2->tv_nsec;
}

static inline void normalize_timespec(struct timespec *t)
{
  // TODO: maybe could use some work
  while (t->tv_nsec >= NSEC_PER_SEC) {
    t->tv_nsec -= NSEC_PER_SEC;
    t->tv_sec++;
  }
}

static inline void add_timespecs(const struct timespec *t1,
    const struct timespec *t2,
    struct timespec *dst)
{
  dst->tv_sec = t1->tv_sec + t2->tv_sec;
  dst->tv_nsec = t1->tv_nsec + t2->tv_nsec;
  normalize_timespec(dst);
}

static inline bool subtract_timespecs(const struct timespec *t1,
    const struct timespec *t2,
    struct timespec *dst)
{
  if (timespec_gt(t2, t1))
  {
    return subtract_timespecs(t2, t1, dst);
  }

  dst->tv_sec = t1->tv_sec - t2->tv_sec;
  dst->tv_nsec = t1->tv_nsec - t2->tv_nsec;

  normalize_timespec(dst);
  return true;
}

static inline unsigned long timespec_to_long(const struct timespec *t)
{
  return t->tv_sec * NSEC_PER_SEC + t->tv_nsec;
}

int rttest_record_missed_deadline(struct timespec *deadline,
    struct timespec *result_time, int iteration)
{
  struct timespec jitter;
  subtract_timespecs(result_time, deadline, &jitter);
  // Record jitter
  if (iteration > _rttest_sample_buffer.buffer_size)
  {
    return -1;
  }
  _rttest_sample_buffer.missed_deadlines[iteration] = true;
  _rttest_sample_buffer.latency_samples[iteration] = -timespec_to_long(&jitter);
  return 0;
}

int rttest_record_jitter(struct timespec *deadline,
    struct timespec *result_time, int iteration)
{
  if (timespec_gt(result_time, deadline))
  {
    // missed a deadline
    return rttest_record_missed_deadline(deadline, result_time, iteration);
  }
  struct timespec jitter;
  subtract_timespecs(deadline, result_time, &jitter);
  // Record jitter
  if (iteration > _rttest_sample_buffer.buffer_size)
  {
    return -1;
  }
  _rttest_sample_buffer.missed_deadlines[iteration] = false;
  _rttest_sample_buffer.latency_samples[iteration] = timespec_to_long(&jitter);
  return 0;
}

int rttest_read_args(int argc, char** argv)
{
  //parse arguments
}

int rttest_init(unsigned long iterations, struct timespec update_period,
    size_t sched_policy, int sched_priority, int lock_memory, size_t stack_size,
    int plot, int write, char *filename)
{
  _rttest_params.iterations = iterations;
  _rttest_params.update_period = update_period;
  _rttest_params.sched_policy = sched_policy;
  _rttest_params.sched_priority = sched_priority;
  _rttest_params.lock_memory = lock_memory;
  _rttest_params.stack_size = stack_size;
  _rttest_params.plot = plot;
  _rttest_params.write = write;
  _rttest_params.filename = filename;

  _rttest_sample_buffer.latency_samples =
      (long *) std::malloc(iterations*sizeof(unsigned long));
  memset(_rttest_sample_buffer.latency_samples, 0,
      iterations*sizeof(long));
  _rttest_sample_buffer.missed_deadlines =
      (bool *) std::malloc(iterations*sizeof(bool));
  memset(_rttest_sample_buffer.missed_deadlines, 0, iterations*sizeof(bool));
  _rttest_sample_buffer.buffer_size = iterations;
}

int rttest_spin(void *(*user_function)(void *), void *args)
{
  return rttest_spin_period(user_function, args, &_rttest_params.update_period,
      _rttest_params.iterations);
}

int rttest_spin_period(void *(*user_function)(void *), void *args,
    const struct timespec *update_period, const unsigned long iterations)
{
  struct timespec wakeup_time, current_time;
  clock_gettime(0, &current_time);
  wakeup_time = current_time;

  for (int i = 0; i < iterations; i++)
  {
    // Plan the next shot
    add_timespecs(&wakeup_time, update_period, &wakeup_time);
    clock_gettime(0, &current_time);
    if (timespec_gt(&current_time, &wakeup_time))
    {
      // Missed a deadline before we could sleep! Record it
      rttest_record_missed_deadline(&wakeup_time, &current_time, i);
    }
    else
    {
      clock_nanosleep(0, TIMER_ABSTIME, &wakeup_time, NULL);
      clock_gettime(0, &current_time);

      rttest_record_jitter(&wakeup_time, &current_time, i);
    }

    user_function(args);
  }

  return 0;
}

int rttest_schedule_wakeup(void *(*user_function)(void *), void *args,
    struct timespec absolute_wakeup)
{
  struct timespec current_time;
  clock_gettime(0, &current_time);
  if (timespec_gt(&current_time, &absolute_wakeup))
  {
    // Missed a deadline before we could sleep! Record it
    rttest_record_missed_deadline(&absolute_wakeup, &current_time, -1);
  }
  else
  {
    clock_nanosleep(0, TIMER_ABSTIME, &absolute_wakeup, NULL);
    clock_gettime(0, &current_time);

    rttest_record_jitter(&absolute_wakeup, &current_time, -1);
  }

  user_function(args);

  return 0;
}

int rttest_lock_memory()
{
  return mlockall(MCL_CURRENT | MCL_FUTURE);
}

int rttest_prefault_stack_size(const size_t stack_size)
{
  unsigned char stack[stack_size];
  memset(stack, 0, stack_size);
  // TODO: catch errors, maybe verify memset return value points to stack?
  return 0;
}

int rttest_prefault_stack()
{
  return rttest_prefault_stack_size(_rttest_params.stack_size);
}

int rttest_set_thread_default_priority()
{
  return rttest_set_sched_priority(_rttest_params.sched_priority,
      _rttest_params.sched_policy);
}

int rttest_set_sched_priority(size_t sched_priority, int policy)
{
  struct sched_param param;

  param.sched_priority = sched_priority;

  // note that sched_setscheduler can set the priority of an arbitrary process
  return sched_setscheduler(0, policy, &param);
}

int rttest_calculate_statistics(struct rttest_results *results)
{
  if (results == NULL)
  {
    return -1;
  }

  std::vector<long> jitter_dataset;
  jitter_dataset.assign(_rttest_sample_buffer.latency_samples,
      _rttest_sample_buffer.latency_samples + _rttest_sample_buffer.buffer_size);

  std::vector<long> latency_dataset(jitter_dataset.size());
  std::copy_if(jitter_dataset.begin(), jitter_dataset.end(),
      latency_dataset.begin(),
      [](long sample){ return sample < 0; } );

  std::vector<bool> missed_deadlines_data;
  missed_deadlines_data.assign(_rttest_sample_buffer.missed_deadlines,
      _rttest_sample_buffer.missed_deadlines + _rttest_sample_buffer.buffer_size);

  results->min_latency = *std::min_element(latency_dataset.begin(), latency_dataset.end());
  results->max_latency = *std::max_element(latency_dataset.begin(), latency_dataset.end());
  results->mean_latency = std::accumulate(latency_dataset.begin(),
      latency_dataset.end(), 0.0) / latency_dataset.size();
  double sq_sum = std::inner_product(latency_dataset.begin(), latency_dataset.end(),
      latency_dataset.begin(), 0.0);
  results->latency_stddev =
      std::sqrt(sq_sum / latency_dataset.size() - results->mean_latency * results->mean_latency);

  results->min_jitter = *std::min_element(jitter_dataset.begin(), jitter_dataset.end());
  results->max_jitter = *std::max_element(jitter_dataset.begin(), jitter_dataset.end());
  results->mean_jitter = std::accumulate(jitter_dataset.begin(),
      jitter_dataset.end(), 0.0) / jitter_dataset.size();
  sq_sum = std::inner_product(jitter_dataset.begin(), jitter_dataset.end(),
      jitter_dataset.begin(), 0.0);
  results->jitter_stddev =
      std::sqrt(sq_sum / jitter_dataset.size() - results->mean_jitter * results->mean_jitter);

  results->missed_deadlines = std::count(missed_deadlines_data.begin(),
      missed_deadlines_data.end(), true);
  results->early_deadlines = missed_deadlines_data.size() - results->missed_deadlines;
  return 0;
}

std::string rttest_results_to_string(struct rttest_results *results)
{
  if (!results)
  {
    return "ERROR: rttest got NULL results string!";
  }
  std::stringstream sstring;

  sstring << "rttest statistics:" << std::endl;
  sstring << "  - Missed deadlines: " << results->missed_deadlines << std::endl;
  sstring << "  - Early deadlines: " << results->early_deadlines << std::endl;
  sstring << std::endl;
  sstring << "  Latency (time after deadline was missed):" << std::endl;
  sstring << "    - Min: " << results->min_latency << std::endl;
  sstring << "    - Max: " << results->max_latency << std::endl;
  sstring << "    - Mean: " << results->mean_latency << std::endl;
  sstring << "    - Standard deviation: " << results->latency_stddev << std::endl;
  sstring << std::endl;
  sstring << "  Jitter (scheduling variation for early or missed deadlines):" << std::endl;
  sstring << "    - Min: " << results->min_jitter << std::endl;
  sstring << "    - Max: " << results->max_jitter << std::endl;
  sstring << "    - Mean: " << results->mean_jitter << std::endl;
  sstring << "    - Standard deviation: " << results->jitter_stddev << std::endl;

  return sstring.str();
}

int rttest_finish()
{
  // Print statistics to screen
  rttest_calculate_statistics(&_rttest_results);
  std::cout << rttest_results_to_string(&_rttest_results);

  if (_rttest_sample_buffer.latency_samples != NULL)
  {
    free(_rttest_sample_buffer.latency_samples);
  }

  if (_rttest_sample_buffer.missed_deadlines != NULL)
  {
    free(_rttest_sample_buffer.missed_deadlines);
  }
  return 0;
}

int rttest_write_results()
{
  // Format:
  // iteration  timestamp  latency  missed_deadline? (1/0)

  if (!_rttest_params.write)
  {
    return -1;
  }

  if (_rttest_sample_buffer.latency_samples == NULL)
  {
    return -1;
  }

  if (_rttest_sample_buffer.missed_deadlines == NULL)
  {
    return -1;
  }

  return 0;
}

int rttest_plot()
{
  if (!_rttest_params.plot)
  {
    return -1;
  }
  return 0;
}
<commit_msg>adding pagefaults<commit_after>// Copyright 2015 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <algorithm>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <numeric>
#include <sched.h>
#include <string.h>
#include <sstream>
#include <sys/mman.h>
#include <sys/rusage.h>
#include <vector>

#include <rttest.h>

// Global variables
struct rttest_params _rttest_params;
struct rttest_sample_buffer _rttest_sample_buffer;
struct rttest_results _rttest_results;

static inline bool timespec_gt(const struct timespec *t1,
    const struct timespec *t2)
{
  if (t1->tv_sec > t2->tv_sec)
  {
    return true;
  }
  if (t1->tv_sec < t2->tv_sec)
  {
    return false;
  }
  return t1->tv_nsec > t2->tv_nsec;
}

static inline void normalize_timespec(struct timespec *t)
{
  // TODO: maybe could use some work
  while (t->tv_nsec >= NSEC_PER_SEC) {
    t->tv_nsec -= NSEC_PER_SEC;
    t->tv_sec++;
  }
}

static inline void add_timespecs(const struct timespec *t1,
    const struct timespec *t2,
    struct timespec *dst)
{
  dst->tv_sec = t1->tv_sec + t2->tv_sec;
  dst->tv_nsec = t1->tv_nsec + t2->tv_nsec;
  normalize_timespec(dst);
}

static inline bool subtract_timespecs(const struct timespec *t1,
    const struct timespec *t2,
    struct timespec *dst)
{
  if (timespec_gt(t2, t1))
  {
    return subtract_timespecs(t2, t1, dst);
  }

  dst->tv_sec = t1->tv_sec - t2->tv_sec;
  dst->tv_nsec = t1->tv_nsec - t2->tv_nsec;

  normalize_timespec(dst);
  return true;
}

static inline unsigned long timespec_to_long(const struct timespec *t)
{
  return t->tv_sec * NSEC_PER_SEC + t->tv_nsec;
}

int rttest_record_missed_deadline(struct timespec *deadline,
    struct timespec *result_time, int iteration)
{
  struct timespec jitter;
  subtract_timespecs(result_time, deadline, &jitter);
  // Record jitter
  if (iteration > _rttest_sample_buffer.buffer_size)
  {
    return -1;
  }
  _rttest_sample_buffer.missed_deadlines[iteration] = true;
  _rttest_sample_buffer.latency_samples[iteration] = -timespec_to_long(&jitter);
  return 0;
}

int rttest_record_jitter(struct timespec *deadline,
    struct timespec *result_time, int iteration)
{
  if (timespec_gt(result_time, deadline))
  {
    // missed a deadline
    return rttest_record_missed_deadline(deadline, result_time, iteration);
  }
  struct timespec jitter;
  subtract_timespecs(deadline, result_time, &jitter);
  // Record jitter
  if (iteration > _rttest_sample_buffer.buffer_size)
  {
    return -1;
  }
  _rttest_sample_buffer.missed_deadlines[iteration] = false;
  _rttest_sample_buffer.latency_samples[iteration] = timespec_to_long(&jitter);
  return 0;
}

int rttest_read_args(int argc, char** argv)
{
  //parse arguments
}

int rttest_init(unsigned long iterations, struct timespec update_period,
    size_t sched_policy, int sched_priority, int lock_memory, size_t stack_size,
    int plot, int write, char *filename)
{
  _rttest_params.iterations = iterations;
  _rttest_params.update_period = update_period;
  _rttest_params.sched_policy = sched_policy;
  _rttest_params.sched_priority = sched_priority;
  _rttest_params.lock_memory = lock_memory;
  _rttest_params.stack_size = stack_size;
  _rttest_params.plot = plot;
  _rttest_params.write = write;
  _rttest_params.filename = filename;

  _rttest_sample_buffer.latency_samples =
      (long *) std::malloc(iterations*sizeof(unsigned long));
  memset(_rttest_sample_buffer.latency_samples, 0,
      iterations*sizeof(long));
  _rttest_sample_buffer.missed_deadlines =
      (bool *) std::malloc(iterations*sizeof(bool));
  memset(_rttest_sample_buffer.missed_deadlines, 0, iterations*sizeof(bool));
  _rttest_sample_buffer.buffer_size = iterations;
}

int rttest_spin(void *(*user_function)(void *), void *args)
{
  return rttest_spin_period(user_function, args, &_rttest_params.update_period,
      _rttest_params.iterations);
}

int rttest_spin_period(void *(*user_function)(void *), void *args,
    const struct timespec *update_period, const unsigned long iterations)
{
  struct timespec wakeup_time, current_time;
  clock_gettime(0, &current_time);
  wakeup_time = current_time;

  for (int i = 0; i < iterations; i++)
  {
    // Plan the next shot
    add_timespecs(&wakeup_time, update_period, &wakeup_time);
    clock_gettime(0, &current_time);
    if (timespec_gt(&current_time, &wakeup_time))
    {
      // Missed a deadline before we could sleep! Record it
      rttest_record_missed_deadline(&wakeup_time, &current_time, i);
    }
    else
    {
      clock_nanosleep(0, TIMER_ABSTIME, &wakeup_time, NULL);
      clock_gettime(0, &current_time);

      rttest_record_jitter(&wakeup_time, &current_time, i);
    }

    user_function(args);
  }

  return 0;
}

int rttest_schedule_wakeup(void *(*user_function)(void *), void *args,
    struct timespec absolute_wakeup)
{
  struct timespec current_time;
  clock_gettime(0, &current_time);
  if (timespec_gt(&current_time, &absolute_wakeup))
  {
    // Missed a deadline before we could sleep! Record it
    rttest_record_missed_deadline(&absolute_wakeup, &current_time, -1);
  }
  else
  {
    clock_nanosleep(0, TIMER_ABSTIME, &absolute_wakeup, NULL);
    clock_gettime(0, &current_time);

    rttest_record_jitter(&absolute_wakeup, &current_time, -1);
  }

  user_function(args);

  return 0;
}

int rttest_lock_memory()
{
  return mlockall(MCL_CURRENT | MCL_FUTURE);
}

int rttest_prefault_stack_size(const size_t stack_size)
{
  unsigned char stack[stack_size];
  memset(stack, 0, stack_size);
  // TODO: catch errors, maybe verify memset return value points to stack?
  return 0;
}

int rttest_prefault_stack()
{
  return rttest_prefault_stack_size(_rttest_params.stack_size);
}

int rttest_set_thread_default_priority()
{
  return rttest_set_sched_priority(_rttest_params.sched_priority,
      _rttest_params.sched_policy);
}

int rttest_set_sched_priority(size_t sched_priority, int policy)
{
  struct sched_param param;

  param.sched_priority = sched_priority;

  // note that sched_setscheduler can set the priority of an arbitrary process
  return sched_setscheduler(0, policy, &param);
}

int rttest_calculate_statistics(struct rttest_results *results)
{
  if (results == NULL)
  {
    return -1;
  }

  std::vector<long> jitter_dataset;
  jitter_dataset.assign(_rttest_sample_buffer.latency_samples,
      _rttest_sample_buffer.latency_samples + _rttest_sample_buffer.buffer_size);

  std::vector<long> latency_dataset(jitter_dataset.size());
  std::copy_if(jitter_dataset.begin(), jitter_dataset.end(),
      latency_dataset.begin(),
      [](long sample){ return sample < 0; } );

  std::vector<bool> missed_deadlines_data;
  missed_deadlines_data.assign(_rttest_sample_buffer.missed_deadlines,
      _rttest_sample_buffer.missed_deadlines + _rttest_sample_buffer.buffer_size);

  results->min_latency = *std::min_element(latency_dataset.begin(), latency_dataset.end());
  results->max_latency = *std::max_element(latency_dataset.begin(), latency_dataset.end());
  results->mean_latency = std::accumulate(latency_dataset.begin(),
      latency_dataset.end(), 0.0) / latency_dataset.size();
  double sq_sum = std::inner_product(latency_dataset.begin(), latency_dataset.end(),
      latency_dataset.begin(), 0.0);
  results->latency_stddev =
      std::sqrt(sq_sum / latency_dataset.size() - results->mean_latency * results->mean_latency);

  results->min_jitter = *std::min_element(jitter_dataset.begin(), jitter_dataset.end());
  results->max_jitter = *std::max_element(jitter_dataset.begin(), jitter_dataset.end());
  results->mean_jitter = std::accumulate(jitter_dataset.begin(),
      jitter_dataset.end(), 0.0) / jitter_dataset.size();
  sq_sum = std::inner_product(jitter_dataset.begin(), jitter_dataset.end(),
      jitter_dataset.begin(), 0.0);
  results->jitter_stddev =
      std::sqrt(sq_sum / jitter_dataset.size() - results->mean_jitter * results->mean_jitter);

  results->missed_deadlines = std::count(missed_deadlines_data.begin(),
      missed_deadlines_data.end(), true);
  results->early_deadlines = missed_deadlines_data.size() - results->missed_deadlines;
  return 0;
}

std::string rttest_results_to_string(struct rttest_results *results)
{
  if (!results)
  {
    return "ERROR: rttest got NULL results string!";
  }
  std::stringstream sstring;

  sstring << "rttest statistics:" << std::endl;
  sstring << "  - Missed deadlines: " << results->missed_deadlines << std::endl;
  sstring << "  - Early deadlines: " << results->early_deadlines << std::endl;
  sstring << std::endl;
  sstring << "  Latency (time after deadline was missed):" << std::endl;
  sstring << "    - Min: " << results->min_latency << std::endl;
  sstring << "    - Max: " << results->max_latency << std::endl;
  sstring << "    - Mean: " << results->mean_latency << std::endl;
  sstring << "    - Standard deviation: " << results->latency_stddev << std::endl;
  sstring << std::endl;
  sstring << "  Jitter (scheduling variation for early or missed deadlines):" << std::endl;
  sstring << "    - Min: " << results->min_jitter << std::endl;
  sstring << "    - Max: " << results->max_jitter << std::endl;
  sstring << "    - Mean: " << results->mean_jitter << std::endl;
  sstring << "    - Standard deviation: " << results->jitter_stddev << std::endl;

  return sstring.str();
}

int rttest_finish()
{
  // Print statistics to screen
  rttest_calculate_statistics(&_rttest_results);
  std::cout << rttest_results_to_string(&_rttest_results);

  if (_rttest_sample_buffer.latency_samples != NULL)
  {
    free(_rttest_sample_buffer.latency_samples);
  }

  if (_rttest_sample_buffer.missed_deadlines != NULL)
  {
    free(_rttest_sample_buffer.missed_deadlines);
  }
  return 0;
}

int rttest_write_results()
{
  // Format:
  // iteration  timestamp  latency  missed_deadline? (1/0)

  if (!_rttest_params.write)
  {
    return -1;
  }

  if (_rttest_sample_buffer.latency_samples == NULL)
  {
    return -1;
  }

  if (_rttest_sample_buffer.missed_deadlines == NULL)
  {
    return -1;
  }

  return 0;
}

int rttest_plot()
{
  if (!_rttest_params.plot)
  {
    return -1;
  }
  return 0;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <llvm/ADT/StringRef.h>
#include <llvm/IR/Module.h>
#include <llvm/IR/LegacyPassManager.h>
#include <llvm/Target/TargetMachine.h>
#include <llvm/Support/TargetRegistry.h>
#include <llvm/Support/TargetSelect.h>
#include <llvm/Support/FileSystem.h>
#include <llvm/Support/Program.h>
#include <llvm/Support/Path.h>
#include "repl.h"
#include "../ast/ast_printer.h"
#include "../ast/decl.h"
#include "../ast/module.h"
#include "../irgen/irgen.h"
#include "../parser/parse.h"
#include "../sema/typecheck.h"
#include "../support/utility.h"

using namespace delta;

namespace {

/// If `args` contains `flag`, removes it and returns true, otherwise returns false.
bool checkFlag(llvm::StringRef flag, std::vector<llvm::StringRef>& args) {
    const auto it = std::find(args.begin(), args.end(), flag);
    const bool contains = it != args.end();
    if (contains) args.erase(it);
    return contains;
}

std::vector<llvm::StringRef> collectStringOptionValues(llvm::StringRef flagPrefix,
                                                       std::vector<llvm::StringRef>& args) {
    std::vector<llvm::StringRef> values;
    for (auto arg = args.begin(); arg != args.end();) {
        if (arg->startswith(flagPrefix)) {
            values.push_back(arg->substr(flagPrefix.size()));
            arg = args.erase(arg);
        } else {
            ++arg;
        }
    }
    return values;
}

void emitMachineCode(llvm::Module& module, llvm::StringRef fileName,
                     llvm::TargetMachine::CodeGenFileType fileType,
                     llvm::Reloc::Model relocModel) {
    llvm::InitializeNativeTarget();
    llvm::InitializeNativeTargetAsmPrinter();
    llvm::InitializeNativeTargetAsmParser();

    std::string targetTriple = llvm::sys::getDefaultTargetTriple();
    module.setTargetTriple(targetTriple);

    std::string errorMessage;
    auto* target = llvm::TargetRegistry::lookupTarget(targetTriple, errorMessage);
    if (!target) printErrorAndExit(errorMessage);

    llvm::TargetOptions options;
    auto* targetMachine = target->createTargetMachine(targetTriple, "generic", "", options,
                                                      relocModel);
    module.setDataLayout(targetMachine->createDataLayout());

    std::error_code error;
    llvm::raw_fd_ostream file(fileName, error, llvm::sys::fs::F_None);
    if (error) printErrorAndExit(error.message());

    llvm::legacy::PassManager passManager;
    if (targetMachine->addPassesToEmitFile(passManager, file, fileType)) {
        printErrorAndExit("TargetMachine can't emit a file of this type");
    }

    passManager.run(module);
    file.flush();
}

void printHelp() {
    llvm::outs() <<
        "OVERVIEW: Delta compiler\n"
        "\n"
        "USAGE: delta [options] <inputs>\n"
        "\n"
        "OPTIONS:\n"
        "  -c                    - Compile only, generating an .o file; don't link\n"
        "  -emit-assembly        - Emit assembly code\n"
        "  -fPIC                 - Emit position-independent code\n"
        "  -parse                - Perform parsing\n"
        "  -typecheck            - Perform parsing and type checking\n"
        "  -help                 - Display this help\n"
        "  -I<directory>         - Add a search path for module and C header import\n"
        "  -print-ast            - Print the abstract syntax tree to stdout\n"
        "  -print-ir             - Print the generated LLVM IR to stdout\n";
}

} // anonymous namespace

int main(int argc, char** argv) try {
    if (argc == 1) return replMain();

    std::vector<llvm::StringRef> args(argv + 1, argv + argc);

    if (checkFlag("-help", args) || checkFlag("--help", args) || checkFlag("-h", args)) {
        printHelp();
        return 0;
    }

    const bool parseFlag = checkFlag("-parse", args);
    const bool typecheckFlag = checkFlag("-typecheck", args);
    const bool compileOnly = checkFlag("-c", args);
    const bool printAST = checkFlag("-print-ast", args);
    const bool printIR = checkFlag("-print-ir", args);
    const bool emitAssembly = checkFlag("-emit-assembly", args) || checkFlag("-S", args);
    const bool emitPositionIndependentCode = checkFlag("-fPIC", args);
    std::vector<llvm::StringRef> importSearchPaths = collectStringOptionValues("-I", args);
    importSearchPaths.push_back(".");
    importSearchPaths.push_back(DELTA_ROOT_DIR); // For development.

    for (llvm::StringRef arg : args) {
        if (arg.startswith("-")) {
            printErrorAndExit("unsupported option '", arg, "'");
        }
    }

    if (args.empty()) {
        printErrorAndExit("no input files");
    }

    Module module("main");

    for (llvm::StringRef filePath : args) {
        parse(filePath, module);
        importSearchPaths.push_back(llvm::sys::path::parent_path(filePath)); // TODO: Don't add duplicates.
    }

    if (printAST) {
        std::cout << module;
        return 0;
    }

    if (parseFlag) return 0;

    for (auto& importedModule : module.getImportedModules()) {
        typecheckModule(*importedModule, importSearchPaths, parse);
    }
    typecheckModule(module, importSearchPaths, parse);

    if (typecheckFlag) return 0;

    IRGenerator irGenerator;
    for (auto& module : getAllImportedModules()) {
        irGenerator.compile(*module);
    }
    auto& irModule = irGenerator.compile(module);

    if (printIR) {
        irModule.print(llvm::outs(), nullptr);
        return 0;
    }

    std::string outputFile = emitAssembly ? "output.s" : "output.o";
    auto fileType = emitAssembly ? llvm::TargetMachine::CGFT_AssemblyFile
                                 : llvm::TargetMachine::CGFT_ObjectFile;
    auto relocModel = emitPositionIndependentCode ? llvm::Reloc::Model::PIC_
                                                  : llvm::Reloc::Model::Static;
    emitMachineCode(irModule, outputFile, fileType, relocModel);

    if (compileOnly || emitAssembly) return 0;

    // Link the output.

    llvm::ErrorOr<std::string> ccPath = llvm::sys::findProgramByName("cc");
    if (!ccPath) {
        printErrorAndExit("couldn't find C compiler");
    }

    const char* ccArgs[] = { ccPath->c_str(), outputFile.c_str(), nullptr };
    int ccExitStatus = llvm::sys::ExecuteAndWait(ccArgs[0], ccArgs);
    std::remove(outputFile.c_str());
    return ccExitStatus;
} catch (const CompileError& error) {
    error.print();
    exit(1);
}
<commit_msg>Add "run" command to compile and execute Delta code<commit_after>#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <llvm/ADT/StringRef.h>
#include <llvm/IR/Module.h>
#include <llvm/IR/LegacyPassManager.h>
#include <llvm/Target/TargetMachine.h>
#include <llvm/Support/TargetRegistry.h>
#include <llvm/Support/TargetSelect.h>
#include <llvm/Support/FileSystem.h>
#include <llvm/Support/Program.h>
#include <llvm/Support/Path.h>
#include "repl.h"
#include "../ast/ast_printer.h"
#include "../ast/decl.h"
#include "../ast/module.h"
#include "../irgen/irgen.h"
#include "../parser/parse.h"
#include "../sema/typecheck.h"
#include "../support/utility.h"

using namespace delta;

namespace {

/// If `args` contains `flag`, removes it and returns true, otherwise returns false.
bool checkFlag(llvm::StringRef flag, std::vector<llvm::StringRef>& args) {
    const auto it = std::find(args.begin(), args.end(), flag);
    const bool contains = it != args.end();
    if (contains) args.erase(it);
    return contains;
}

std::vector<llvm::StringRef> collectStringOptionValues(llvm::StringRef flagPrefix,
                                                       std::vector<llvm::StringRef>& args) {
    std::vector<llvm::StringRef> values;
    for (auto arg = args.begin(); arg != args.end();) {
        if (arg->startswith(flagPrefix)) {
            values.push_back(arg->substr(flagPrefix.size()));
            arg = args.erase(arg);
        } else {
            ++arg;
        }
    }
    return values;
}

void emitMachineCode(llvm::Module& module, llvm::StringRef fileName,
                     llvm::TargetMachine::CodeGenFileType fileType,
                     llvm::Reloc::Model relocModel) {
    llvm::InitializeNativeTarget();
    llvm::InitializeNativeTargetAsmPrinter();
    llvm::InitializeNativeTargetAsmParser();

    std::string targetTriple = llvm::sys::getDefaultTargetTriple();
    module.setTargetTriple(targetTriple);

    std::string errorMessage;
    auto* target = llvm::TargetRegistry::lookupTarget(targetTriple, errorMessage);
    if (!target) printErrorAndExit(errorMessage);

    llvm::TargetOptions options;
    auto* targetMachine = target->createTargetMachine(targetTriple, "generic", "", options,
                                                      relocModel);
    module.setDataLayout(targetMachine->createDataLayout());

    std::error_code error;
    llvm::raw_fd_ostream file(fileName, error, llvm::sys::fs::F_None);
    if (error) printErrorAndExit(error.message());

    llvm::legacy::PassManager passManager;
    if (targetMachine->addPassesToEmitFile(passManager, file, fileType)) {
        printErrorAndExit("TargetMachine can't emit a file of this type");
    }

    passManager.run(module);
    file.flush();
}

void printHelp() {
    llvm::outs() <<
        "OVERVIEW: Delta compiler\n"
        "\n"
        "USAGE: delta [options] <inputs>\n"
        "\n"
        "OPTIONS:\n"
        "  -c                    - Compile only, generating an .o file; don't link\n"
        "  -emit-assembly        - Emit assembly code\n"
        "  -fPIC                 - Emit position-independent code\n"
        "  -parse                - Perform parsing\n"
        "  -typecheck            - Perform parsing and type checking\n"
        "  -help                 - Display this help\n"
        "  -I<directory>         - Add a search path for module and C header import\n"
        "  -print-ast            - Print the abstract syntax tree to stdout\n"
        "  -print-ir             - Print the generated LLVM IR to stdout\n";
}

} // anonymous namespace

int main(int argc, char** argv) try {
    if (argc == 1) return replMain();

    bool run = strcmp(argv[1], "run") == 0;
    if (run) {
        ++argv;
        --argc;
    }

    std::vector<llvm::StringRef> args(argv + 1, argv + argc);

    if (checkFlag("-help", args) || checkFlag("--help", args) || checkFlag("-h", args)) {
        printHelp();
        return 0;
    }

    const bool parseFlag = checkFlag("-parse", args);
    const bool typecheckFlag = checkFlag("-typecheck", args);
    const bool compileOnly = checkFlag("-c", args);
    const bool printAST = checkFlag("-print-ast", args);
    const bool printIR = checkFlag("-print-ir", args);
    const bool emitAssembly = checkFlag("-emit-assembly", args) || checkFlag("-S", args);
    const bool emitPositionIndependentCode = checkFlag("-fPIC", args);
    std::vector<llvm::StringRef> importSearchPaths = collectStringOptionValues("-I", args);
    importSearchPaths.push_back(".");
    importSearchPaths.push_back(DELTA_ROOT_DIR); // For development.

    for (llvm::StringRef arg : args) {
        if (arg.startswith("-")) {
            printErrorAndExit("unsupported option '", arg, "'");
        }
    }

    if (args.empty()) {
        printErrorAndExit("no input files");
    }

    Module module("main");

    for (llvm::StringRef filePath : args) {
        parse(filePath, module);
        importSearchPaths.push_back(llvm::sys::path::parent_path(filePath)); // TODO: Don't add duplicates.
    }

    if (printAST) {
        std::cout << module;
        return 0;
    }

    if (parseFlag) return 0;

    for (auto& importedModule : module.getImportedModules()) {
        typecheckModule(*importedModule, importSearchPaths, parse);
    }
    typecheckModule(module, importSearchPaths, parse);

    if (typecheckFlag) return 0;

    IRGenerator irGenerator;
    for (auto& module : getAllImportedModules()) {
        irGenerator.compile(*module);
    }
    auto& irModule = irGenerator.compile(module);

    if (printIR) {
        irModule.print(llvm::outs(), nullptr);
        return 0;
    }

    std::string outputFile = emitAssembly ? "output.s" : "output.o";
    auto fileType = emitAssembly ? llvm::TargetMachine::CGFT_AssemblyFile
                                 : llvm::TargetMachine::CGFT_ObjectFile;
    auto relocModel = emitPositionIndependentCode ? llvm::Reloc::Model::PIC_
                                                  : llvm::Reloc::Model::Static;
    emitMachineCode(irModule, outputFile, fileType, relocModel);

    if (compileOnly || emitAssembly) return 0;

    // Link the output.

    llvm::ErrorOr<std::string> ccPath = llvm::sys::findProgramByName("cc");
    if (!ccPath) {
        printErrorAndExit("couldn't find C compiler");
    }

    const char* ccArgs[] = { ccPath->c_str(), outputFile.c_str(), nullptr };
    int ccExitStatus = llvm::sys::ExecuteAndWait(ccArgs[0], ccArgs);
    std::remove(outputFile.c_str());
    if (!run) return ccExitStatus;

    const char* programArgs[] = { "a.out", nullptr };
    return llvm::sys::ExecuteAndWait(programArgs[0], programArgs);
} catch (const CompileError& error) {
    error.print();
    exit(1);
}
<|endoftext|>