<commit_before>/*
 *            Copyright 2009-2019 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.
 *
 */

#include "votca/xtp/rpa.h"
#include "votca/xtp/sigma_exact.h"
#include "votca/xtp/sigma_ppm.h"
#include <votca/xtp/gw.h>

namespace votca {
namespace xtp {

void GW::configure(const options& opt) {
  _opt = opt;
  _qptotal = _opt.qpmax - _opt.qpmin + 1;
  _rpa.configure(_opt.homo, _opt.rpamin, _opt.rpamax);
  if (_opt.sigma_integration == "exact") {
    _sigma = std::make_unique<Sigma_Exact>(Sigma_Exact(_Mmn, _rpa));
  } else if (_opt.sigma_integration == "ppm") {
    _sigma = std::make_unique<Sigma_PPM>(Sigma_PPM(_Mmn, _rpa));
  }
  Sigma_base::options sigma_opt;
  sigma_opt.homo = _opt.homo;
  sigma_opt.qpmax = _opt.qpmax;
  sigma_opt.qpmin = _opt.qpmin;
  sigma_opt.rpamin = _opt.rpamin;
  sigma_opt.rpamax = _opt.rpamax;
  sigma_opt.eta = _opt.eta;
  _sigma->configure(sigma_opt);
  _Sigma_x = Eigen::MatrixXd::Zero(_qptotal, _qptotal);
  _Sigma_c = Eigen::MatrixXd::Zero(_qptotal, _qptotal);
}

double GW::CalcHomoLumoShift(Eigen::VectorXd frequencies) const {
  double DFTgap = _dft_energies(_opt.homo + 1) - _dft_energies(_opt.homo);
  double QPgap = frequencies(_opt.homo + 1 - _opt.qpmin) -
                 frequencies(_opt.homo - _opt.qpmin);
  return QPgap - DFTgap;
}

Eigen::MatrixXd GW::getHQP() const {
  return _Sigma_x + _Sigma_c - _vxc +
         Eigen::MatrixXd(
             _dft_energies.segment(_opt.qpmin, _qptotal).asDiagonal());
}

Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> GW::DiagonalizeQPHamiltonian()
    const {
  Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> qpdiag(getHQP());
  PrintQP_Energies(qpdiag.eigenvalues());
  return qpdiag;
}

void GW::PrintGWA_Energies() const {

  double shift = CalcHomoLumoShift(_gwa_energies);

  XTP_LOG_SAVE(logINFO, _log)
      << (boost::format(
              "  ====== Perturbative quasiparticle energies (Hartree) ====== "))
             .str()
      << std::flush;
  XTP_LOG_SAVE(logINFO, _log)
      << (boost::format("   DeltaHLGap = %1$+1.6f Hartree") % shift).str()
      << std::flush;

  for (Index i = 0; i < _qptotal; i++) {
    std::string level = "  Level";
    if ((i + _opt.qpmin) == _opt.homo) {
      level = "  HOMO ";
    } else if ((i + _opt.qpmin) == _opt.homo + 1) {
      level = "  LUMO ";
    }

    XTP_LOG_SAVE(logINFO, _log)
        << level
        << (boost::format(" = %1$4d DFT = %2$+1.4f VXC = %3$+1.4f S-X = "
                          "%4$+1.4f S-C = %5$+1.4f GWA = %6$+1.4f") %
            (i + _opt.qpmin) % _dft_energies(i + _opt.qpmin) % _vxc(i, i) %
            _Sigma_x(i, i) % _Sigma_c(i, i) % _gwa_energies(i))
               .str()
        << std::flush;
  }
  return;
}

void GW::PrintQP_Energies(const Eigen::VectorXd& qp_diag_energies) const {
  XTP_LOG_SAVE(logDEBUG, _log)
      << TimeStamp() << " Full quasiparticle Hamiltonian  " << std::flush;
  XTP_LOG_SAVE(logINFO, _log)
      << (boost::format(
              "  ====== Diagonalized quasiparticle energies (Hartree) "
              "====== "))
             .str()
      << std::flush;
  for (Index i = 0; i < _qptotal; i++) {
    std::string level = "  Level";
    if ((i + _opt.qpmin) == _opt.homo) {
      level = "  HOMO ";
    } else if ((i + _opt.qpmin) == _opt.homo + 1) {
      level = "  LUMO ";
    }
    XTP_LOG_SAVE(logINFO, _log)
        << level
        << (boost::format(" = %1$4d PQP = %2$+1.4f DQP = %3$+1.4f ") %
            (i + _opt.qpmin) % _gwa_energies(i) % qp_diag_energies(i))
               .str()
        << std::flush;
  }
  return;
}

Eigen::VectorXd GW::ScissorShift_DFTlevel(
    const Eigen::VectorXd& dft_energies) const {
  XTP_LOG_SAVE(logDEBUG, _log)
      << TimeStamp() << " Scissor shifting DFT energies by: " << _opt.shift
      << " Hrt" << std::flush;
  Eigen::VectorXd shifted_energies = dft_energies;
  shifted_energies.segment(_opt.homo + 1, dft_energies.size() - _opt.homo - 1)
      .array() += _opt.shift;
  return shifted_energies;
}

void GW::CalculateGWPerturbation() {

  _Sigma_x = (1 - _opt.ScaHFX) * _sigma->CalcExchangeMatrix();
  XTP_LOG_SAVE(logDEBUG, _log)
      << TimeStamp() << " Calculated Hartree exchange contribution"
      << std::flush;
  // dftenergies has size aobasissize
  // rpaenergies/Mmn have size rpatotal
  // gwaenergies/frequencies have size qptotal
  // homo index is relative to dft_energies
  Eigen::VectorXd dft_shifted_energies = ScissorShift_DFTlevel(_dft_energies);
  Eigen::VectorXd rpa_energies =
      dft_shifted_energies.segment(_opt.rpamin, _opt.rpamax - _opt.rpamin + 1);
  _rpa.setRPAInputEnergies(rpa_energies);
  Eigen::VectorXd frequencies =
      dft_shifted_energies.segment(_opt.qpmin, _qptotal);
  for (Index i_gw = 0; i_gw < _opt.gw_sc_max_iterations; ++i_gw) {

    if (i_gw % _opt.reset_3c == 0 && i_gw != 0) {
      _Mmn.Rebuild();
      XTP_LOG_SAVE(logDEBUG, _log)
          << TimeStamp() << " Rebuilding 3c integrals" << std::flush;
    }
    _sigma->PrepareScreening();
    XTP_LOG_SAVE(logDEBUG, _log)
        << TimeStamp() << " Calculated screening via RPA" << std::flush;
    if (_opt.qp_solver == "grid") {
      frequencies = SolveQP_Grid(frequencies);
      XTP_LOG_SAVE(logDEBUG, _log)
          << TimeStamp() << " Solved QP equation on QP grid" << std::flush;
    } else if (_opt.qp_solver == "fixedpoint") {
      frequencies = SolveQP_FixedPoint(frequencies);
      XTP_LOG_SAVE(logDEBUG, _log)
          << TimeStamp() << " Solved QP equation self-consistently"
          << std::flush;
    }
    _gwa_energies = frequencies;
    _Sigma_c.diagonal() = _sigma->CalcCorrelationDiag(_gwa_energies);
    XTP_LOG_SAVE(logDEBUG, _log)
        << TimeStamp() << " Calculated correlation diagonal" << std::flush;
    Eigen::VectorXd rpa_energies_old = _rpa.getRPAInputEnergies();
    _rpa.UpdateRPAInputEnergies(_dft_energies, frequencies, _opt.qpmin);
    XTP_LOG_SAVE(logDEBUG, _log)
        << TimeStamp() << " GW_Iteration:" << i_gw
        << " Shift[Hrt]:" << CalcHomoLumoShift(_gwa_energies) << std::flush;
    if (Converged(_rpa.getRPAInputEnergies(), rpa_energies_old,
                  _opt.gw_sc_limit)) {
      XTP_LOG_SAVE(logDEBUG, _log)
          << TimeStamp() << " Converged after " << i_gw + 1 << " GW iterations."
          << std::flush;
      break;
    } else if (i_gw == _opt.gw_sc_max_iterations - 1 &&
               _opt.gw_sc_max_iterations > 1) {
      XTP_LOG_SAVE(logDEBUG, _log)
          << TimeStamp()
          << " WARNING! GW-self-consistency cycle not converged after "
          << _opt.gw_sc_max_iterations << " iterations." << std::flush;
      XTP_LOG_SAVE(logDEBUG, _log)
          << TimeStamp() << "      Run continues. Inspect results carefully!"
          << std::flush;
      break;
    } else {
      double alpha = 0.0;
      rpa_energies = (1 - alpha) * rpa_energies + alpha * rpa_energies_old;
    }
  }

  PrintGWA_Energies();
}

Eigen::VectorXd GW::SolveQP_Grid(Eigen::VectorXd frequencies) const {
  const Index qptotal = _opt.qpmax - _opt.qpmin + 1;
  const double range =
      _opt.qp_grid_spacing * (double)(_opt.qp_grid_steps - 1) / 2.0;
  const Eigen::VectorXd intercept =
      _dft_energies.segment(_opt.qpmin, _qptotal) + _Sigma_x.diagonal() -
      _vxc.diagonal();
  Eigen::VectorXd offset =
      Eigen::VectorXd::LinSpaced(_opt.qp_grid_steps, -range, range);
  Eigen::MatrixXd sigc_mat = Eigen::MatrixXd::Zero(qptotal, _opt.qp_grid_steps);
  for (Index i_node = 0; i_node < _opt.qp_grid_steps; ++i_node) {
    sigc_mat.col(i_node) =
        _sigma->CalcCorrelationDiag(frequencies.array() + offset[i_node]);
  }
  Eigen::VectorXd frequencies_new = frequencies;
  for (Index level = 0; level < qptotal; ++level) {
    const Eigen::VectorXd freq = frequencies[level] + offset.array();
    const Eigen::VectorXd sigc = sigc_mat.row(level);
    const Eigen::VectorXd targ = sigc.array() + intercept[level] - freq.array();
    double qp_energy = 0.0;
    double pole_weight_max = -1.0;
    for (Index i_node = 0; i_node < _opt.qp_grid_steps - 1; ++i_node) {
      if (targ[i_node] * targ[i_node + 1] < 0.0) {  // Sign change
        double dsigc_dfreq = (sigc[i_node + 1] - sigc[i_node]) /
                             (freq[i_node + 1] - freq[i_node]);
        double dtarg_dfreq = (targ[i_node + 1] - targ[i_node]) /
                             (freq[i_node + 1] - freq[i_node]);
        double pole =
            freq[i_node] - targ[i_node] / dtarg_dfreq;  // Fixed-point estimate
        double pole_weight =
            1.0 / (1.0 - dsigc_dfreq);  // Pole weight Z in (0, 1)
        if (pole_weight >= 1e-5 && pole_weight > pole_weight_max) {
          qp_energy = pole;
          pole_weight_max = pole_weight;
        }
      }
    }
    if (pole_weight_max >= 0.0) {
      frequencies_new[level] = qp_energy;
    }
  }
  return frequencies_new;
}

Eigen::VectorXd GW::SolveQP_FixedPoint(Eigen::VectorXd frequencies) const {
  for (Index i_freq = 0; i_freq < _opt.g_sc_max_iterations; ++i_freq) {
    Eigen::VectorXd frequencies_prev = frequencies;
    // Do fixed point iteration
    frequencies = _Sigma_x.diagonal() +
                  _sigma->CalcCorrelationDiag(frequencies) - _vxc.diagonal() +
                  _dft_energies.segment(_opt.qpmin, _qptotal);
    if (tools::globals::verbose) {
      XTP_LOG_SAVE(logDEBUG, _log)
          << TimeStamp() << " G_Iteration:" << i_freq
          << " Shift[Hrt]:" << CalcHomoLumoShift(frequencies) << std::flush;
    }
    if (Converged(frequencies, frequencies_prev, _opt.g_sc_limit)) {
      XTP_LOG_SAVE(logDEBUG, _log)
          << TimeStamp() << " Converged after " << i_freq + 1
          << " G iterations." << std::flush;
      break;
    } else if (i_freq == _opt.g_sc_max_iterations - 1 &&
               _opt.g_sc_max_iterations > 1) {
      XTP_LOG_SAVE(logDEBUG, _log)
          << TimeStamp() << " G-self-consistency cycle not converged after "
          << _opt.g_sc_max_iterations << " iterations." << std::flush;
      break;
    } else {
      double alpha = 0.0;
      frequencies = (1 - alpha) * frequencies + alpha * frequencies_prev;
    }
  }
  return frequencies;
}

bool GW::Converged(const Eigen::VectorXd& e1, const Eigen::VectorXd& e2,
                   double epsilon) const {
  Index state = 0;
  bool energies_converged = true;
  double diff_max = (e1 - e2).cwiseAbs().maxCoeff(&state);
  if (diff_max > epsilon) {
    energies_converged = false;
  }
  if (tools::globals::verbose) {
    XTP_LOG_SAVE(logDEBUG, _log) << TimeStamp() << " E_diff max=" << diff_max
                                 << " StateNo:" << state << std::flush;
  }
  return energies_converged;
}

void GW::CalculateHQP() {
  _rpa.UpdateRPAInputEnergies(_dft_energies, _gwa_energies, _opt.qpmin);
  Eigen::VectorXd diag_backup = _Sigma_c.diagonal();
  _Sigma_c = _sigma->CalcCorrelationOffDiag(_gwa_energies);
  _Sigma_c.diagonal() = diag_backup;
}

}  // namespace xtp
}  // namespace votca
<commit_msg>Removed a comment<commit_after>/*
 *            Copyright 2009-2019 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.
 *
 */

#include "votca/xtp/rpa.h"
#include "votca/xtp/sigma_exact.h"
#include "votca/xtp/sigma_ppm.h"
#include <votca/xtp/gw.h>

namespace votca {
namespace xtp {

void GW::configure(const options& opt) {
  _opt = opt;
  _qptotal = _opt.qpmax - _opt.qpmin + 1;
  _rpa.configure(_opt.homo, _opt.rpamin, _opt.rpamax);
  if (_opt.sigma_integration == "exact") {
    _sigma = std::make_unique<Sigma_Exact>(Sigma_Exact(_Mmn, _rpa));
  } else if (_opt.sigma_integration == "ppm") {
    _sigma = std::make_unique<Sigma_PPM>(Sigma_PPM(_Mmn, _rpa));
  }
  Sigma_base::options sigma_opt;
  sigma_opt.homo = _opt.homo;
  sigma_opt.qpmax = _opt.qpmax;
  sigma_opt.qpmin = _opt.qpmin;
  sigma_opt.rpamin = _opt.rpamin;
  sigma_opt.rpamax = _opt.rpamax;
  sigma_opt.eta = _opt.eta;
  _sigma->configure(sigma_opt);
  _Sigma_x = Eigen::MatrixXd::Zero(_qptotal, _qptotal);
  _Sigma_c = Eigen::MatrixXd::Zero(_qptotal, _qptotal);
}

double GW::CalcHomoLumoShift(Eigen::VectorXd frequencies) const {
  double DFTgap = _dft_energies(_opt.homo + 1) - _dft_energies(_opt.homo);
  double QPgap = frequencies(_opt.homo + 1 - _opt.qpmin) -
                 frequencies(_opt.homo - _opt.qpmin);
  return QPgap - DFTgap;
}

Eigen::MatrixXd GW::getHQP() const {
  return _Sigma_x + _Sigma_c - _vxc +
         Eigen::MatrixXd(
             _dft_energies.segment(_opt.qpmin, _qptotal).asDiagonal());
}

Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> GW::DiagonalizeQPHamiltonian()
    const {
  Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> qpdiag(getHQP());
  PrintQP_Energies(qpdiag.eigenvalues());
  return qpdiag;
}

void GW::PrintGWA_Energies() const {

  double shift = CalcHomoLumoShift(_gwa_energies);

  XTP_LOG_SAVE(logINFO, _log)
      << (boost::format(
              "  ====== Perturbative quasiparticle energies (Hartree) ====== "))
             .str()
      << std::flush;
  XTP_LOG_SAVE(logINFO, _log)
      << (boost::format("   DeltaHLGap = %1$+1.6f Hartree") % shift).str()
      << std::flush;

  for (Index i = 0; i < _qptotal; i++) {
    std::string level = "  Level";
    if ((i + _opt.qpmin) == _opt.homo) {
      level = "  HOMO ";
    } else if ((i + _opt.qpmin) == _opt.homo + 1) {
      level = "  LUMO ";
    }

    XTP_LOG_SAVE(logINFO, _log)
        << level
        << (boost::format(" = %1$4d DFT = %2$+1.4f VXC = %3$+1.4f S-X = "
                          "%4$+1.4f S-C = %5$+1.4f GWA = %6$+1.4f") %
            (i + _opt.qpmin) % _dft_energies(i + _opt.qpmin) % _vxc(i, i) %
            _Sigma_x(i, i) % _Sigma_c(i, i) % _gwa_energies(i))
               .str()
        << std::flush;
  }
  return;
}

void GW::PrintQP_Energies(const Eigen::VectorXd& qp_diag_energies) const {
  XTP_LOG_SAVE(logDEBUG, _log)
      << TimeStamp() << " Full quasiparticle Hamiltonian  " << std::flush;
  XTP_LOG_SAVE(logINFO, _log)
      << (boost::format(
              "  ====== Diagonalized quasiparticle energies (Hartree) "
              "====== "))
             .str()
      << std::flush;
  for (Index i = 0; i < _qptotal; i++) {
    std::string level = "  Level";
    if ((i + _opt.qpmin) == _opt.homo) {
      level = "  HOMO ";
    } else if ((i + _opt.qpmin) == _opt.homo + 1) {
      level = "  LUMO ";
    }
    XTP_LOG_SAVE(logINFO, _log)
        << level
        << (boost::format(" = %1$4d PQP = %2$+1.4f DQP = %3$+1.4f ") %
            (i + _opt.qpmin) % _gwa_energies(i) % qp_diag_energies(i))
               .str()
        << std::flush;
  }
  return;
}

Eigen::VectorXd GW::ScissorShift_DFTlevel(
    const Eigen::VectorXd& dft_energies) const {
  XTP_LOG_SAVE(logDEBUG, _log)
      << TimeStamp() << " Scissor shifting DFT energies by: " << _opt.shift
      << " Hrt" << std::flush;
  Eigen::VectorXd shifted_energies = dft_energies;
  shifted_energies.segment(_opt.homo + 1, dft_energies.size() - _opt.homo - 1)
      .array() += _opt.shift;
  return shifted_energies;
}

void GW::CalculateGWPerturbation() {

  _Sigma_x = (1 - _opt.ScaHFX) * _sigma->CalcExchangeMatrix();
  XTP_LOG_SAVE(logDEBUG, _log)
      << TimeStamp() << " Calculated Hartree exchange contribution"
      << std::flush;
  // dftenergies has size aobasissize
  // rpaenergies/Mmn have size rpatotal
  // gwaenergies/frequencies have size qptotal
  // homo index is relative to dft_energies
  Eigen::VectorXd dft_shifted_energies = ScissorShift_DFTlevel(_dft_energies);
  Eigen::VectorXd rpa_energies =
      dft_shifted_energies.segment(_opt.rpamin, _opt.rpamax - _opt.rpamin + 1);
  _rpa.setRPAInputEnergies(rpa_energies);
  Eigen::VectorXd frequencies =
      dft_shifted_energies.segment(_opt.qpmin, _qptotal);
  for (Index i_gw = 0; i_gw < _opt.gw_sc_max_iterations; ++i_gw) {

    if (i_gw % _opt.reset_3c == 0 && i_gw != 0) {
      _Mmn.Rebuild();
      XTP_LOG_SAVE(logDEBUG, _log)
          << TimeStamp() << " Rebuilding 3c integrals" << std::flush;
    }
    _sigma->PrepareScreening();
    XTP_LOG_SAVE(logDEBUG, _log)
        << TimeStamp() << " Calculated screening via RPA" << std::flush;
    if (_opt.qp_solver == "grid") {
      frequencies = SolveQP_Grid(frequencies);
      XTP_LOG_SAVE(logDEBUG, _log)
          << TimeStamp() << " Solved QP equation on QP grid" << std::flush;
    } else if (_opt.qp_solver == "fixedpoint") {
      frequencies = SolveQP_FixedPoint(frequencies);
      XTP_LOG_SAVE(logDEBUG, _log)
          << TimeStamp() << " Solved QP equation self-consistently"
          << std::flush;
    }
    _gwa_energies = frequencies;
    _Sigma_c.diagonal() = _sigma->CalcCorrelationDiag(_gwa_energies);
    XTP_LOG_SAVE(logDEBUG, _log)
        << TimeStamp() << " Calculated correlation diagonal" << std::flush;
    Eigen::VectorXd rpa_energies_old = _rpa.getRPAInputEnergies();
    _rpa.UpdateRPAInputEnergies(_dft_energies, frequencies, _opt.qpmin);
    XTP_LOG_SAVE(logDEBUG, _log)
        << TimeStamp() << " GW_Iteration:" << i_gw
        << " Shift[Hrt]:" << CalcHomoLumoShift(_gwa_energies) << std::flush;
    if (Converged(_rpa.getRPAInputEnergies(), rpa_energies_old,
                  _opt.gw_sc_limit)) {
      XTP_LOG_SAVE(logDEBUG, _log)
          << TimeStamp() << " Converged after " << i_gw + 1 << " GW iterations."
          << std::flush;
      break;
    } else if (i_gw == _opt.gw_sc_max_iterations - 1 &&
               _opt.gw_sc_max_iterations > 1) {
      XTP_LOG_SAVE(logDEBUG, _log)
          << TimeStamp()
          << " WARNING! GW-self-consistency cycle not converged after "
          << _opt.gw_sc_max_iterations << " iterations." << std::flush;
      XTP_LOG_SAVE(logDEBUG, _log)
          << TimeStamp() << "      Run continues. Inspect results carefully!"
          << std::flush;
      break;
    } else {
      double alpha = 0.0;
      rpa_energies = (1 - alpha) * rpa_energies + alpha * rpa_energies_old;
    }
  }

  PrintGWA_Energies();
}

Eigen::VectorXd GW::SolveQP_Grid(Eigen::VectorXd frequencies) const {
  const Index qptotal = _opt.qpmax - _opt.qpmin + 1;
  const double range =
      _opt.qp_grid_spacing * (double)(_opt.qp_grid_steps - 1) / 2.0;
  const Eigen::VectorXd intercept =
      _dft_energies.segment(_opt.qpmin, _qptotal) + _Sigma_x.diagonal() -
      _vxc.diagonal();
  Eigen::VectorXd offset =
      Eigen::VectorXd::LinSpaced(_opt.qp_grid_steps, -range, range);
  Eigen::MatrixXd sigc_mat = Eigen::MatrixXd::Zero(qptotal, _opt.qp_grid_steps);
  for (Index i_node = 0; i_node < _opt.qp_grid_steps; ++i_node) {
    sigc_mat.col(i_node) =
        _sigma->CalcCorrelationDiag(frequencies.array() + offset[i_node]);
  }
  Eigen::VectorXd frequencies_new = frequencies;
  for (Index level = 0; level < qptotal; ++level) {
    const Eigen::VectorXd freq = frequencies[level] + offset.array();
    const Eigen::VectorXd sigc = sigc_mat.row(level);
    const Eigen::VectorXd targ = sigc.array() + intercept[level] - freq.array();
    double qp_energy = 0.0;
    double pole_weight_max = -1.0;
    for (Index i_node = 0; i_node < _opt.qp_grid_steps - 1; ++i_node) {
      if (targ[i_node] * targ[i_node + 1] < 0.0) {  // Sign change
        double dsigc_dfreq = (sigc[i_node + 1] - sigc[i_node]) /
                             (freq[i_node + 1] - freq[i_node]);
        double dtarg_dfreq = (targ[i_node + 1] - targ[i_node]) /
                             (freq[i_node + 1] - freq[i_node]);
        double pole =
            freq[i_node] - targ[i_node] / dtarg_dfreq;  // Fixed-point estimate
        double pole_weight =
            1.0 / (1.0 - dsigc_dfreq);  // Pole weight Z in (0, 1)
        if (pole_weight >= 1e-5 && pole_weight > pole_weight_max) {
          qp_energy = pole;
          pole_weight_max = pole_weight;
        }
      }
    }
    if (pole_weight_max >= 0.0) {
      frequencies_new[level] = qp_energy;
    }
  }
  return frequencies_new;
}

Eigen::VectorXd GW::SolveQP_FixedPoint(Eigen::VectorXd frequencies) const {
  for (Index i_freq = 0; i_freq < _opt.g_sc_max_iterations; ++i_freq) {
    Eigen::VectorXd frequencies_prev = frequencies;
    frequencies = _Sigma_x.diagonal() +
                  _sigma->CalcCorrelationDiag(frequencies) - _vxc.diagonal() +
                  _dft_energies.segment(_opt.qpmin, _qptotal);
    if (tools::globals::verbose) {
      XTP_LOG_SAVE(logDEBUG, _log)
          << TimeStamp() << " G_Iteration:" << i_freq
          << " Shift[Hrt]:" << CalcHomoLumoShift(frequencies) << std::flush;
    }
    if (Converged(frequencies, frequencies_prev, _opt.g_sc_limit)) {
      XTP_LOG_SAVE(logDEBUG, _log)
          << TimeStamp() << " Converged after " << i_freq + 1
          << " G iterations." << std::flush;
      break;
    } else if (i_freq == _opt.g_sc_max_iterations - 1 &&
               _opt.g_sc_max_iterations > 1) {
      XTP_LOG_SAVE(logDEBUG, _log)
          << TimeStamp() << " G-self-consistency cycle not converged after "
          << _opt.g_sc_max_iterations << " iterations." << std::flush;
      break;
    } else {
      double alpha = 0.0;
      frequencies = (1 - alpha) * frequencies + alpha * frequencies_prev;
    }
  }
  return frequencies;
}

bool GW::Converged(const Eigen::VectorXd& e1, const Eigen::VectorXd& e2,
                   double epsilon) const {
  Index state = 0;
  bool energies_converged = true;
  double diff_max = (e1 - e2).cwiseAbs().maxCoeff(&state);
  if (diff_max > epsilon) {
    energies_converged = false;
  }
  if (tools::globals::verbose) {
    XTP_LOG_SAVE(logDEBUG, _log) << TimeStamp() << " E_diff max=" << diff_max
                                 << " StateNo:" << state << std::flush;
  }
  return energies_converged;
}

void GW::CalculateHQP() {
  _rpa.UpdateRPAInputEnergies(_dft_energies, _gwa_energies, _opt.qpmin);
  Eigen::VectorXd diag_backup = _Sigma_c.diagonal();
  _Sigma_c = _sigma->CalcCorrelationOffDiag(_gwa_energies);
  _Sigma_c.diagonal() = diag_backup;
}

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


<commit_before>/*
  Zipios++ - a small C++ library that provides easy access to .zip files.

  Copyright (C) 2000-2007  Thomas Sondergaard
  Copyright (C) 2015  Made to Order Software Corporation

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

/** \file
 * \brief Implementation of zipios::FilePath.
 *
 * This file includes the zipios::FilePath implementation which makes it
 * a little easier to handle the stat() system call on any file for any
 * system.
 */

#include "zipios/filepath.hpp"

#include "zipios_common.hpp"

#include <memory.h>

#if !defined(S_ISREG) && defined(S_IFMT) && defined(S_IFREG)
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
#endif
#if !defined(S_ISDIR) && defined(S_IFMT) && defined(S_IFREG)
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFREG)
#endif
#if !defined(S_ISCHR) && defined(S_IFMT) && defined(S_IFREG)
#define S_ISCHR(m) (((m) & S_IFMT) == S_IFREG)
#endif
#if !defined(S_ISBLK) && defined(S_IFMT) && defined(S_IFREG)
#define S_ISBLK(m) (((m) & S_IFMT) == S_IFREG)
#endif

namespace zipios
{

namespace
{

/** \brief Prune the trailing separator if present.
 *
 * This function is used to ensure that the FilePath does NOT end
 * with a separator.
 *
 * \warning
 * At this time the path is not canonicalized properly. We expect \p path
 * to not include double separators one after another. However, passing
 * such a path to the FilePath will keep it as is.
 *
 * \param[in] path  The path to prune of one trailing separator.
 *
 * \return The path as is or without the last '/'.
 */
std::string pruneTrailingSeparator(std::string path)
{
    if(path.size() > 0)
    {
        if(path[path.size() - 1] == g_separator)
        {
            path.erase(path.size() - 1);
        }
    }

    return path;
}

} // no name namespace

/** \class FilePath
 * \brief Handle a file path and name and its statistics.
 *
 * The FilePath class represents a path to a file or directory name.
 * FilePath has member functions to check if the file path is a valid
 * file system entity, and to check what kind of file system entity
 * it is, e.g. is it a file, a directory, a pipe, etc.
 *
 * It also knows of the last modification time and size of the file.
 *
 * \warning
 * The information about a file is cached so at the time it gets used
 * the file on disk may have changed, it may even have been deleted.
 */

/** \brief Initialize a FilePath object.
 *
 * The constructor saves the path and if \p check_exists is true, read
 * the file statistics, especially the st_mode.
 *
 * \param[in] path  A string representation of the path.
 *
 * \sa exists()
 * \sa pruneTrailingSeparator()
 */
FilePath::FilePath(std::string const& path)
    : m_path(pruneTrailingSeparator(path))
    //, m_stat() -- see below
    //, m_checked(false) -- auto-init
    //, m_exists(false) -- auto-init
{
    memset(&m_stat, 0, sizeof(m_stat));
}

/** \brief Read the file mode.
 *
 * This function sets m_checked to true, stat()'s the path, to see if
 * it exists and to determine what type of file it is. All the query
 * functions call check() before they test a flag to make sure it
 * is set appropriately.
 *
 * This means stat()'ing is deferred until it becomes necessary. But also
 * it is cached meaning that if the file changes in between we get the
 * old flags.
 */
void FilePath::check() const
{
    if(!m_checked)
    {
        m_checked     = true;

        /** \TODO
         * Under MS-Windows, we need to use _wstat() to make it work in
         * Unicode (i.e. UTF-8 to wchar_t then call _wstat()...) Also we
         * want to use the 64 bit variant to make sure that we get a
         * valid size. Any other reference to the stat() command should
         * be replace by using a FilePath().
         */
        memset(&m_stat, 0, sizeof(m_stat));
        m_exists = stat(m_path.c_str(), &m_stat) == 0;
    }
}

/** \brief Replace the path with a new path.
 *
 * This function replaces the internal path of this FilePath with
 * the new specified path.
 *
 * \param[in] path  The new path to save in this object.
 *
 * \return A reference to this object.
 */
FilePath& FilePath::operator = (std::string const& path)
{
    m_path = pruneTrailingSeparator(path);
    return *this;
}

/** \brief Retrieve the path.
 *
 * This operator can be used to retrieve a copy of the path.
 *
 * \return The m_path string returned as is (i.e. the whole path).
 */
FilePath::operator std::string () const
{
    return m_path;
}

/** \brief Append the a child name to this path.
 *
 * This function concatenates two FilePath objects and returns
 * another FilePath.
 *
 * A file separator is inserted between both names if appropriate.
 *
 * \warning
 * Note that the function allows you to append two full paths,
 * or even a relative path (left) to a full path (right), which
 * may result in a new path that is not quite sensible.
 *
 * \param[in] rhs  The right hand side.
 */
FilePath FilePath::operator + (FilePath const& rhs) const
{
    if(m_path.empty())
    {
        return rhs;
    }

    if(rhs.m_path.empty())
    {
        return *this;
    }

    if(rhs.m_path[0] == g_separator)
    {
        return m_path + rhs.m_path;
    }

    return m_path + g_separator + rhs.m_path;
}

/** \brief Check whether two FilePath represent the same file.
 *
 * This function compares a FilePath object (this) and a C-string
 * to know whether the two are the same.
 *
 * A null pointer as the C-string is viewed as an empty string.
 *
 * \param[in] rhs  The right hand side to compare with.
 *
 * \sa operator == (FilePath const& rhs);
 */
bool FilePath::operator == (char const *rhs) const
{
    return m_path == rhs;
}

/** \brief Check whether two FilePath represent the same file.
 *
 * This function compares a FilePath object (this) and a C-string
 * to know whether the two are the same.
 *
 * A null pointer as the C-string is viewed as an empty string.
 *
 * \param[in] lhs  The left hand side to compare with.
 * \param[in] rhs  The right hand side to compare with.
 *
 * \sa operator == (FilePath const& rhs);
 */
bool operator == (char const *lhs, FilePath const& rhs)
{
    return lhs == rhs.m_path;
}

/** \brief Check whether two FilePath represent the same file.
 *
 * This function compares a FilePath object (this) against
 * a string representing a path to know whether the two are
 * the equal.
 *
 * \param[in] rhs  The right hand side to compare with.
 *
 * \sa operator == (FilePath const& rhs);
 */
bool FilePath::operator == (std::string const& rhs) const
{
    return m_path == rhs;
}

/** \brief Check whether two FilePath represent the same file.
 *
 * This function compares a FilePath object (this) against
 * a string representing a path to know whether the two are
 * the equal.
 *
 * \param[in] lhs  The left hand side to compare with.
 * \param[in] rhs  The right hand side to compare with.
 *
 * \sa operator == (FilePath const& rhs);
 */
bool operator == (std::string const& lhs, FilePath const& rhs)
{
    return lhs == rhs.m_path;
}

/** \brief Check whether two FilePath represent the same file.
 *
 * This function compares two FilePath objects (this and rhs)
 * to know whether the two are the same.
 *
 * \note
 * It is important to know that the compare is rather primitive.
 * The two paths must be equal character by character instead
 * of actually representing exactly the same file. Also relative
 * paths will likely be equal and these may not represent the
 * same file at all.
 *
 * \param[in] rhs  The right hand side to compare with.
 *
 * \sa operator == (char const *rhs);
 * \sa operator == (std::string const& rhs);
 */
bool FilePath::operator == (FilePath const& rhs) const
{
    return m_path == rhs.m_path;
}

/** \brief Retrieve the basename.
 *
 * This function returns the filename part of the FilePath
 * object by pruning the path off.
 *
 * \return Return the basename of this FilePath filename.
 */
std::string FilePath::filename() const
{
    std::string::size_type const pos(m_path.find_last_of(g_separator));
    if(pos != std::string::npos)
    {
        return m_path.substr(pos + 1);
    }

    return m_path;
}

/** \brief Get the length of the string.
 *
 * This function returns the length of the string used to
 * represent this FilePath path and filename.
 *
 * \return The length of the string representing this file path.
 *
 * \sa size()
 */
size_t FilePath::length() const
{
    return m_path.length();
}

/** \brief Get the length of the string.
 *
 * This function returns the length of the string used to
 * represent this FilePath path and filename.
 *
 * \note
 * This is an overloaded function that calls the length() function.
 * It is defined because the string represents an array of bytes
 * and as such the size() function may be used.
 *
 * \return The length of the string representing this file path.
 *
 * \sa length()
 */
size_t FilePath::size() const
{
    return length();
}

/** \brief Check whether the file exists.
 *
 * This function calls check() and then returns true if the file
 * exists on disk.
 *
 * \return true If the path is a valid file system entity.
 */
bool FilePath::exists() const
{
    check();
    return m_exists;
}

/** \brief Check whether the file is a regular file.
 *
 * This function returns true if the file exists and is a
 * regular file.
 *
 * \return true if the path is a regular file.
 */
bool FilePath::isRegular() const
{
    check();
    return m_exists && S_ISREG(m_stat.st_mode);
}

/** \brief Check whether the file is a directory.
 *
 * This function returns true if the file exists and is a
 * directory.
 *
 * \return true if the path is a directory.
 */
bool FilePath::isDirectory() const
{
    check();
    return m_exists && S_ISDIR(m_stat.st_mode);
}

/** \brief Check whether the file is a character special file.
 *
 * This function returns true if the file exists and is a
 * character special file.
 *
 * \return true if the path is character special (a character device file).
 */
bool FilePath::isCharSpecial() const
{
    check();
    return m_exists && S_ISCHR(m_stat.st_mode);
}

/** \brief Check whether the file is a block special file.
 *
 * This function returns true if the file exists and is a
 * block special file.
 *
 * \return true if the path is block special (a block device file).
 */
bool FilePath::isBlockSpecial() const
{
    check();
    return m_exists && S_ISBLK(m_stat.st_mode);
}

/** \brief Check whether the file is a socket.
 *
 * This function returns true if the file exists and is a
 * socket file.
 *
 * \return true if the path is a socket.
 */
bool FilePath::isSocket() const
{
    check();
    return m_exists
#ifndef ZIPIOS_WINDOWS
    && S_ISSOCK(m_stat.st_mode)
#endif
    ;
}

/** \brief Check whether the file is a pipe.
 *
 * This function returns true if the file exists and is a
 * pipe file.
 *
 * \return true if the path is a FIFO.
 */
bool FilePath::isFifo() const
{
    check();
    return m_exists

#ifndef ZIPIOS_WINDOWS
    && S_ISFIFO(m_stat.st_mode)
#endif
    ;
}

/** \brief Get the size of the file.
 *
 * This function returns the size of the file. The size may be a 64 bit
 * size on 64 bit systems.
 *
 * \note
 * If the file represents a directory, the size will be zero.
 *
 * \note
 * If the file is not considered valid, the size returned is zero.
 *
 * \warning
 * There is also a function called size() which actually checks the
 * length of the path and not the size of the file.
 *
 * \return The last modification as a Unix time.
 *
 * \sa size()
 */
size_t FilePath::fileSize() const
{
    check();
    return m_stat.st_size;
}

/** \brief Get the last modification time of the file.
 *
 * This function returns the last modification time of the specified
 * file.
 *
 * \note
 * If the file is not considered valid, the time returned is zero.
 *
 * \return The last modification as a Unix time.
 */
std::time_t FilePath::lastModificationTime() const
{
    check();
    return m_stat.st_mtime;
}

/** \brief Print out a FilePath.
 *
 * This function prints out the name of the file that this FilePath
 * represents.
 *
 * \param[in,out] os  The output stream.
 * \param[in] path  The path to print out.
 *
 * \return A copy of the \p os stream reference.
 */
std::ostream& operator << (std::ostream& os, FilePath const& path)
{
    os << static_cast<std::string>(path);
    return os;
}

} // namespace

// Local Variables:
// mode: cpp
// indent-tabs-mode: nil
// c-basic-offset: 4
// tab-width: 4
// End:

// vim: ts=4 sw=4 et
<commit_msg>Fix S_ISDIR(), S_ISCHR(), S_ISBLK()<commit_after>/*
  Zipios++ - a small C++ library that provides easy access to .zip files.

  Copyright (C) 2000-2007  Thomas Sondergaard
  Copyright (C) 2015  Made to Order Software Corporation

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

/** \file
 * \brief Implementation of zipios::FilePath.
 *
 * This file includes the zipios::FilePath implementation which makes it
 * a little easier to handle the stat() system call on any file for any
 * system.
 */

#include "zipios/filepath.hpp"

#include "zipios_common.hpp"

#include <memory.h>

#if !defined(S_ISREG) && defined(S_IFMT) && defined(S_IFREG)
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
#endif
#if !defined(S_ISDIR) && defined(S_IFMT) && defined(S_IFDIR)
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
#endif
#if !defined(S_ISCHR) && defined(S_IFMT) && defined(S_IFCHR)
#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
#endif

namespace zipios
{

namespace
{

/** \brief Prune the trailing separator if present.
 *
 * This function is used to ensure that the FilePath does NOT end
 * with a separator.
 *
 * \warning
 * At this time the path is not canonicalized properly. We expect \p path
 * to not include double separators one after another. However, passing
 * such a path to the FilePath will keep it as is.
 *
 * \param[in] path  The path to prune of one trailing separator.
 *
 * \return The path as is or without the last '/'.
 */
std::string pruneTrailingSeparator(std::string path)
{
    if(path.size() > 0)
    {
        if(path[path.size() - 1] == g_separator)
        {
            path.erase(path.size() - 1);
        }
    }

    return path;
}

} // no name namespace

/** \class FilePath
 * \brief Handle a file path and name and its statistics.
 *
 * The FilePath class represents a path to a file or directory name.
 * FilePath has member functions to check if the file path is a valid
 * file system entity, and to check what kind of file system entity
 * it is, e.g. is it a file, a directory, a pipe, etc.
 *
 * It also knows of the last modification time and size of the file.
 *
 * \warning
 * The information about a file is cached so at the time it gets used
 * the file on disk may have changed, it may even have been deleted.
 */

/** \brief Initialize a FilePath object.
 *
 * The constructor saves the path and if \p check_exists is true, read
 * the file statistics, especially the st_mode.
 *
 * \param[in] path  A string representation of the path.
 *
 * \sa exists()
 * \sa pruneTrailingSeparator()
 */
FilePath::FilePath(std::string const& path)
    : m_path(pruneTrailingSeparator(path))
    //, m_stat() -- see below
    //, m_checked(false) -- auto-init
    //, m_exists(false) -- auto-init
{
    memset(&m_stat, 0, sizeof(m_stat));
}

/** \brief Read the file mode.
 *
 * This function sets m_checked to true, stat()'s the path, to see if
 * it exists and to determine what type of file it is. All the query
 * functions call check() before they test a flag to make sure it
 * is set appropriately.
 *
 * This means stat()'ing is deferred until it becomes necessary. But also
 * it is cached meaning that if the file changes in between we get the
 * old flags.
 */
void FilePath::check() const
{
    if(!m_checked)
    {
        m_checked     = true;

        /** \TODO
         * Under MS-Windows, we need to use _wstat() to make it work in
         * Unicode (i.e. UTF-8 to wchar_t then call _wstat()...) Also we
         * want to use the 64 bit variant to make sure that we get a
         * valid size. Any other reference to the stat() command should
         * be replace by using a FilePath().
         */
        memset(&m_stat, 0, sizeof(m_stat));
        m_exists = stat(m_path.c_str(), &m_stat) == 0;
    }
}

/** \brief Replace the path with a new path.
 *
 * This function replaces the internal path of this FilePath with
 * the new specified path.
 *
 * \param[in] path  The new path to save in this object.
 *
 * \return A reference to this object.
 */
FilePath& FilePath::operator = (std::string const& path)
{
    m_path = pruneTrailingSeparator(path);
    return *this;
}

/** \brief Retrieve the path.
 *
 * This operator can be used to retrieve a copy of the path.
 *
 * \return The m_path string returned as is (i.e. the whole path).
 */
FilePath::operator std::string () const
{
    return m_path;
}

/** \brief Append the a child name to this path.
 *
 * This function concatenates two FilePath objects and returns
 * another FilePath.
 *
 * A file separator is inserted between both names if appropriate.
 *
 * \warning
 * Note that the function allows you to append two full paths,
 * or even a relative path (left) to a full path (right), which
 * may result in a new path that is not quite sensible.
 *
 * \param[in] rhs  The right hand side.
 */
FilePath FilePath::operator + (FilePath const& rhs) const
{
    if(m_path.empty())
    {
        return rhs;
    }

    if(rhs.m_path.empty())
    {
        return *this;
    }

    if(rhs.m_path[0] == g_separator)
    {
        return m_path + rhs.m_path;
    }

    return m_path + g_separator + rhs.m_path;
}

/** \brief Check whether two FilePath represent the same file.
 *
 * This function compares a FilePath object (this) and a C-string
 * to know whether the two are the same.
 *
 * A null pointer as the C-string is viewed as an empty string.
 *
 * \param[in] rhs  The right hand side to compare with.
 *
 * \sa operator == (FilePath const& rhs);
 */
bool FilePath::operator == (char const *rhs) const
{
    return m_path == rhs;
}

/** \brief Check whether two FilePath represent the same file.
 *
 * This function compares a FilePath object (this) and a C-string
 * to know whether the two are the same.
 *
 * A null pointer as the C-string is viewed as an empty string.
 *
 * \param[in] lhs  The left hand side to compare with.
 * \param[in] rhs  The right hand side to compare with.
 *
 * \sa operator == (FilePath const& rhs);
 */
bool operator == (char const *lhs, FilePath const& rhs)
{
    return lhs == rhs.m_path;
}

/** \brief Check whether two FilePath represent the same file.
 *
 * This function compares a FilePath object (this) against
 * a string representing a path to know whether the two are
 * the equal.
 *
 * \param[in] rhs  The right hand side to compare with.
 *
 * \sa operator == (FilePath const& rhs);
 */
bool FilePath::operator == (std::string const& rhs) const
{
    return m_path == rhs;
}

/** \brief Check whether two FilePath represent the same file.
 *
 * This function compares a FilePath object (this) against
 * a string representing a path to know whether the two are
 * the equal.
 *
 * \param[in] lhs  The left hand side to compare with.
 * \param[in] rhs  The right hand side to compare with.
 *
 * \sa operator == (FilePath const& rhs);
 */
bool operator == (std::string const& lhs, FilePath const& rhs)
{
    return lhs == rhs.m_path;
}

/** \brief Check whether two FilePath represent the same file.
 *
 * This function compares two FilePath objects (this and rhs)
 * to know whether the two are the same.
 *
 * \note
 * It is important to know that the compare is rather primitive.
 * The two paths must be equal character by character instead
 * of actually representing exactly the same file. Also relative
 * paths will likely be equal and these may not represent the
 * same file at all.
 *
 * \param[in] rhs  The right hand side to compare with.
 *
 * \sa operator == (char const *rhs);
 * \sa operator == (std::string const& rhs);
 */
bool FilePath::operator == (FilePath const& rhs) const
{
    return m_path == rhs.m_path;
}

/** \brief Retrieve the basename.
 *
 * This function returns the filename part of the FilePath
 * object by pruning the path off.
 *
 * \return Return the basename of this FilePath filename.
 */
std::string FilePath::filename() const
{
    std::string::size_type const pos(m_path.find_last_of(g_separator));
    if(pos != std::string::npos)
    {
        return m_path.substr(pos + 1);
    }

    return m_path;
}

/** \brief Get the length of the string.
 *
 * This function returns the length of the string used to
 * represent this FilePath path and filename.
 *
 * \return The length of the string representing this file path.
 *
 * \sa size()
 */
size_t FilePath::length() const
{
    return m_path.length();
}

/** \brief Get the length of the string.
 *
 * This function returns the length of the string used to
 * represent this FilePath path and filename.
 *
 * \note
 * This is an overloaded function that calls the length() function.
 * It is defined because the string represents an array of bytes
 * and as such the size() function may be used.
 *
 * \return The length of the string representing this file path.
 *
 * \sa length()
 */
size_t FilePath::size() const
{
    return length();
}

/** \brief Check whether the file exists.
 *
 * This function calls check() and then returns true if the file
 * exists on disk.
 *
 * \return true If the path is a valid file system entity.
 */
bool FilePath::exists() const
{
    check();
    return m_exists;
}

/** \brief Check whether the file is a regular file.
 *
 * This function returns true if the file exists and is a
 * regular file.
 *
 * \return true if the path is a regular file.
 */
bool FilePath::isRegular() const
{
    check();
    return m_exists && S_ISREG(m_stat.st_mode);
}

/** \brief Check whether the file is a directory.
 *
 * This function returns true if the file exists and is a
 * directory.
 *
 * \return true if the path is a directory.
 */
bool FilePath::isDirectory() const
{
    check();
    return m_exists && S_ISDIR(m_stat.st_mode);
}

/** \brief Check whether the file is a character special file.
 *
 * This function returns true if the file exists and is a
 * character special file.
 *
 * \return true if the path is character special (a character device file).
 */
bool FilePath::isCharSpecial() const
{
    check();
    return m_exists && S_ISCHR(m_stat.st_mode);
}

/** \brief Check whether the file is a block special file.
 *
 * This function returns true if the file exists and is a
 * block special file.
 *
 * \return true if the path is block special (a block device file).
 */
bool FilePath::isBlockSpecial() const
{
    check();
	return m_exists
#ifndef ZIPIOS_WINDOWS
		&& S_ISBLK(m_stat.st_mode)
#endif
		;
}

/** \brief Check whether the file is a socket.
 *
 * This function returns true if the file exists and is a
 * socket file.
 *
 * \return true if the path is a socket.
 */
bool FilePath::isSocket() const
{
    check();
    return m_exists
#ifndef ZIPIOS_WINDOWS
    && S_ISSOCK(m_stat.st_mode)
#endif
    ;
}

/** \brief Check whether the file is a pipe.
 *
 * This function returns true if the file exists and is a
 * pipe file.
 *
 * \return true if the path is a FIFO.
 */
bool FilePath::isFifo() const
{
    check();
    return m_exists

#ifndef ZIPIOS_WINDOWS
    && S_ISFIFO(m_stat.st_mode)
#endif
    ;
}

/** \brief Get the size of the file.
 *
 * This function returns the size of the file. The size may be a 64 bit
 * size on 64 bit systems.
 *
 * \note
 * If the file represents a directory, the size will be zero.
 *
 * \note
 * If the file is not considered valid, the size returned is zero.
 *
 * \warning
 * There is also a function called size() which actually checks the
 * length of the path and not the size of the file.
 *
 * \return The last modification as a Unix time.
 *
 * \sa size()
 */
size_t FilePath::fileSize() const
{
    check();
    return m_stat.st_size;
}

/** \brief Get the last modification time of the file.
 *
 * This function returns the last modification time of the specified
 * file.
 *
 * \note
 * If the file is not considered valid, the time returned is zero.
 *
 * \return The last modification as a Unix time.
 */
std::time_t FilePath::lastModificationTime() const
{
    check();
    return m_stat.st_mtime;
}

/** \brief Print out a FilePath.
 *
 * This function prints out the name of the file that this FilePath
 * represents.
 *
 * \param[in,out] os  The output stream.
 * \param[in] path  The path to print out.
 *
 * \return A copy of the \p os stream reference.
 */
std::ostream& operator << (std::ostream& os, FilePath const& path)
{
    os << static_cast<std::string>(path);
    return os;
}

} // namespace

// Local Variables:
// mode: cpp
// indent-tabs-mode: nil
// c-basic-offset: 4
// tab-width: 4
// End:

// vim: ts=4 sw=4 et
<|endoftext|>


<commit_before>/**
 * This file is part of the "FnordMetric" project
 *   Copyright (c) 2014 Paul Asmuth, Google Inc.
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include <fnord/exception.h>
#include <fnord/uri.h>

namespace fnord {

std::string URI::urlEncode(const std::string& str) {
  static char hextbl[] = "0123456789ABCDEF";
  std::string encoded;

  for (const auto& c : str) {
    switch (c) {
      case 'A':
      case 'B':
      case 'C':
      case 'D':
      case 'E':
      case 'F':
      case 'G':
      case 'H':
      case 'I':
      case 'J':
      case 'K':
      case 'L':
      case 'M':
      case 'N':
      case 'O':
      case 'P':
      case 'Q':
      case 'R':
      case 'S':
      case 'T':
      case 'U':
      case 'V':
      case 'W':
      case 'X':
      case 'Y':
      case 'Z':
      case 'a':
      case 'b':
      case 'c':
      case 'd':
      case 'e':
      case 'f':
      case 'g':
      case 'h':
      case 'i':
      case 'j':
      case 'k':
      case 'l':
      case 'm':
      case 'n':
      case 'o':
      case 'p':
      case 'q':
      case 'r':
      case 's':
      case 't':
      case 'u':
      case 'v':
      case 'w':
      case 'x':
      case 'y':
      case 'z':
      case '0':
      case '1':
      case '2':
      case '3':
      case '4':
      case '5':
      case '6':
      case '7':
      case '8':
      case '9':
      case '-':
      case '_':
      case '.':
      case '~':
        encoded += c;
        break;

      default:
        encoded += '%';
        encoded += hextbl[(c >> 4) & 0xf],
        encoded += hextbl[c & 0xf];
        break;

    }
  }

  return encoded;
}

std::string URI::urlDecode(const std::string& str) {
  std::string decoded;
  const char* begin = str.c_str();
  const char* end = begin + str.size();

  while (begin != end) {
    switch (*begin) {

      case '%': {
        if (++begin + 2 > end) {
          RAISE(kIllegalArgumentError, "invalid URL encoding");
        }

        String hstr(begin, 2);
        if (!StringUtil::isHexString(hstr)) {
          decoded += "%";
          continue;
        }

        decoded += static_cast<char>(std::stoul(hstr, nullptr, 16));
        begin += 2;
        continue;
      }

      case '+':
        decoded += " ";
        ++begin;
        continue;

      default:
        decoded += *begin++;
        continue;

    }
  }

  return decoded;
}

URI::URI() : port_(0) {}

URI::URI(const std::string& uri_str) : port_(0) {
  parse(uri_str);
}

void URI::parse(const std::string& uri_str) {
  URI::parseURI(
      uri_str,
      &scheme_,
      &userinfo_,
      &host_,
      &port_,
      &path_,
      &query_,
      &fragment_);
}

const std::string& URI::scheme() const {
  return scheme_;
}

const std::string& URI::userinfo() const {
  return userinfo_;
}

const std::string& URI::host() const {
  return host_;
}

const unsigned URI::port() const {
  return port_;
}

std::string URI::hostAndPort() const {
  if (port_ > 0) {
    return StringUtil::format("$0:$1", host_, port_);
  } else {
    return host_;
  }
}

const std::string& URI::path() const {
  return path_;
}

void URI::setPath(const std::string& path) {
  path_ = path;
}

std::string URI::pathAndQuery() const {
  if (query_.length() > 0) {
    return StringUtil::format("$0?$1", path_, query_);
  } else {
    return path_;
  }
}

const std::string& URI::query() const {
  return query_;
}

URI::ParamList URI::queryParams()
    const {
  URI::ParamList params;

  if (query_.size() > 0) {
    URI::parseQueryString(query_, &params);
  }

  return params;
}

bool URI::getParam(
    const URI::ParamList& params,
    const std::string& key,
    std::string* value) {
  for (const auto& param : params) {
    if (param.first == key) {
      *value = param.second;
      return true;
    }
  }

  return false;
}

const std::string& URI::fragment() const {
  return fragment_;
}

std::string URI::toString() const {
  std::string uri_str;

  uri_str.append(scheme());
  uri_str.append(":");

  if (host_.size() > 0) {
    uri_str.append("//");

    if (userinfo_.size() > 0) {
      uri_str.append(userinfo_);
      uri_str.append("@");
    }

    uri_str.append(host_);

    if (port_ > 0) { // FIXPAUL hasPort
      uri_str.append(":");
      uri_str.append(std::to_string(port_));
    }
  }

  uri_str.append(path_);

  if (query_.size() > 0) {
    uri_str.append("?");
    uri_str.append(query_);
  }

  if (fragment_.size() > 0) {
    uri_str.append("#");
    uri_str.append(fragment_);
  }

  return uri_str;
}

void URI::parseURI(
    const std::string& uri_str,
    std::string* scheme,
    std::string* userinfo,
    std::string* host,
    unsigned* port,
    std::string* path,
    std::string* query,
    std::string* fragment) {
  const char* begin = uri_str.c_str();
  const char* end = begin + uri_str.size();

  /* scheme */
  bool has_scheme = false;
  for (const char* cur = begin; cur < end; ++cur) {
    if (*cur == '/') {
      break;
    }

    if (*cur == ':') {
      *scheme = std::string(begin, cur - begin);
      begin = cur + 1;
      has_scheme = true;
      break;
    }
  }

  /* authority */
  if (begin < end - 2 && begin[0] == '/' && begin[1] == '/') {
    begin += 2;
    const char* cur = begin;
    for (; cur < end && *cur != '/' && *cur != '?' && *cur != '#'; ++cur);
    if (cur > begin) {
      const char* abegin = begin;
      const char* aend = cur;

      /* userinfo */
      for (const char* acur = abegin; acur < aend; ++acur) {
        if (*acur == '/' || *acur == '?' || *acur == '#') {
          break;
        }

        if (*acur == '@') {
          *userinfo = std::string(abegin, acur - abegin);
          abegin = acur + 1;
          break;
        }
      }

      /* host */
      const char* acur = abegin;
      for (; acur < aend &&
            *acur != '/' &&
            *acur != '?' &&
            *acur != '#' &&
            *acur != ':'; ++acur);
      *host = std::string(abegin, acur - abegin);

      /* port */
      if (acur < aend - 1 && *acur == ':') {
        abegin = ++acur;
        for (; *acur >= '0' && *acur <= '9'; ++acur);
        if (acur > abegin) {
          std::string port_str(abegin, acur - abegin);
          try {
            *port = std::stoi(port_str);
          } catch (const std::exception& e) {
            RAISE(
                kRuntimeError,
                "invalid URI: invalid port: %s",
                port_str.c_str());
          }
        }
      }
    }
    begin = cur;
  }

  /* path */
  if (begin < end) {
    const char* cur = begin;
    for (; cur < end && *cur != '?' && *cur != '#'; ++cur);
    if (cur > begin) {
      *path = std::string(begin, cur - begin);
    }
    begin = cur;
  }

  /* query */
  if (begin < end && *begin == '?') {
    const char* cur = ++begin;
    for (; cur < end && *cur != '#'; ++cur);
    if (cur > begin) {
      *query = std::string(begin, cur - begin);
    }
    begin = cur;
  }

  /* fragment */
  if (begin < end - 1 && *begin == '#') {
    *fragment = std::string(begin + 1, end - begin - 1);
  }
}

void URI::parseQueryString(
    const std::string& query,
    std::vector<std::pair<std::string, std::string>>* params) {
  const char* begin = query.c_str();
  const char* end = begin + query.size();

  for (const char* cur = begin; cur < end; ++cur) {
    for (; cur < end && *cur != '=' && *cur != '&'; cur++);
    if (cur > begin && cur < end && *cur == '=' ) {
      std::string key_str(begin, cur - begin);
      const char* val = ++cur;
      for (; cur < end && *cur != '=' && *cur != '&'; cur++);
      if (cur > val) {
        std::string val_str(val, cur - val);
        params->emplace_back(URI::urlDecode(key_str), URI::urlDecode(val_str));
        begin = cur + 1;
      } else {
        params->emplace_back(URI::urlDecode(key_str), "");
        begin = cur + 1;
      }
    } else {
      break;
    }
  }
}

} // namespace fnord

<commit_msg>URI::buildQueryString<commit_after>/**
 * This file is part of the "FnordMetric" project
 *   Copyright (c) 2014 Paul Asmuth, Google Inc.
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include <fnord/exception.h>
#include <fnord/uri.h>

namespace fnord {

std::string URI::urlEncode(const std::string& str) {
  static char hextbl[] = "0123456789ABCDEF";
  std::string encoded;

  for (const auto& c : str) {
    switch (c) {
      case 'A':
      case 'B':
      case 'C':
      case 'D':
      case 'E':
      case 'F':
      case 'G':
      case 'H':
      case 'I':
      case 'J':
      case 'K':
      case 'L':
      case 'M':
      case 'N':
      case 'O':
      case 'P':
      case 'Q':
      case 'R':
      case 'S':
      case 'T':
      case 'U':
      case 'V':
      case 'W':
      case 'X':
      case 'Y':
      case 'Z':
      case 'a':
      case 'b':
      case 'c':
      case 'd':
      case 'e':
      case 'f':
      case 'g':
      case 'h':
      case 'i':
      case 'j':
      case 'k':
      case 'l':
      case 'm':
      case 'n':
      case 'o':
      case 'p':
      case 'q':
      case 'r':
      case 's':
      case 't':
      case 'u':
      case 'v':
      case 'w':
      case 'x':
      case 'y':
      case 'z':
      case '0':
      case '1':
      case '2':
      case '3':
      case '4':
      case '5':
      case '6':
      case '7':
      case '8':
      case '9':
      case '-':
      case '_':
      case '.':
      case '~':
        encoded += c;
        break;

      default:
        encoded += '%';
        encoded += hextbl[(c >> 4) & 0xf],
        encoded += hextbl[c & 0xf];
        break;

    }
  }

  return encoded;
}

std::string URI::urlDecode(const std::string& str) {
  std::string decoded;
  const char* begin = str.c_str();
  const char* end = begin + str.size();

  while (begin != end) {
    switch (*begin) {

      case '%': {
        if (++begin + 2 > end) {
          RAISE(kIllegalArgumentError, "invalid URL encoding");
        }

        String hstr(begin, 2);
        if (!StringUtil::isHexString(hstr)) {
          decoded += "%";
          continue;
        }

        decoded += static_cast<char>(std::stoul(hstr, nullptr, 16));
        begin += 2;
        continue;
      }

      case '+':
        decoded += " ";
        ++begin;
        continue;

      default:
        decoded += *begin++;
        continue;

    }
  }

  return decoded;
}

URI::URI() : port_(0) {}

URI::URI(const std::string& uri_str) : port_(0) {
  parse(uri_str);
}

void URI::parse(const std::string& uri_str) {
  URI::parseURI(
      uri_str,
      &scheme_,
      &userinfo_,
      &host_,
      &port_,
      &path_,
      &query_,
      &fragment_);
}

const std::string& URI::scheme() const {
  return scheme_;
}

const std::string& URI::userinfo() const {
  return userinfo_;
}

const std::string& URI::host() const {
  return host_;
}

const unsigned URI::port() const {
  return port_;
}

std::string URI::hostAndPort() const {
  if (port_ > 0) {
    return StringUtil::format("$0:$1", host_, port_);
  } else {
    return host_;
  }
}

const std::string& URI::path() const {
  return path_;
}

void URI::setPath(const std::string& path) {
  path_ = path;
}

std::string URI::pathAndQuery() const {
  if (query_.length() > 0) {
    return StringUtil::format("$0?$1", path_, query_);
  } else {
    return path_;
  }
}

const std::string& URI::query() const {
  return query_;
}

URI::ParamList URI::queryParams()
    const {
  URI::ParamList params;

  if (query_.size() > 0) {
    URI::parseQueryString(query_, &params);
  }

  return params;
}

bool URI::getParam(
    const URI::ParamList& params,
    const std::string& key,
    std::string* value) {
  for (const auto& param : params) {
    if (param.first == key) {
      *value = param.second;
      return true;
    }
  }

  return false;
}

const std::string& URI::fragment() const {
  return fragment_;
}

std::string URI::toString() const {
  std::string uri_str;

  uri_str.append(scheme());
  uri_str.append(":");

  if (host_.size() > 0) {
    uri_str.append("//");

    if (userinfo_.size() > 0) {
      uri_str.append(userinfo_);
      uri_str.append("@");
    }

    uri_str.append(host_);

    if (port_ > 0) { // FIXPAUL hasPort
      uri_str.append(":");
      uri_str.append(std::to_string(port_));
    }
  }

  uri_str.append(path_);

  if (query_.size() > 0) {
    uri_str.append("?");
    uri_str.append(query_);
  }

  if (fragment_.size() > 0) {
    uri_str.append("#");
    uri_str.append(fragment_);
  }

  return uri_str;
}

void URI::parseURI(
    const std::string& uri_str,
    std::string* scheme,
    std::string* userinfo,
    std::string* host,
    unsigned* port,
    std::string* path,
    std::string* query,
    std::string* fragment) {
  const char* begin = uri_str.c_str();
  const char* end = begin + uri_str.size();

  /* scheme */
  bool has_scheme = false;
  for (const char* cur = begin; cur < end; ++cur) {
    if (*cur == '/') {
      break;
    }

    if (*cur == ':') {
      *scheme = std::string(begin, cur - begin);
      begin = cur + 1;
      has_scheme = true;
      break;
    }
  }

  /* authority */
  if (begin < end - 2 && begin[0] == '/' && begin[1] == '/') {
    begin += 2;
    const char* cur = begin;
    for (; cur < end && *cur != '/' && *cur != '?' && *cur != '#'; ++cur);
    if (cur > begin) {
      const char* abegin = begin;
      const char* aend = cur;

      /* userinfo */
      for (const char* acur = abegin; acur < aend; ++acur) {
        if (*acur == '/' || *acur == '?' || *acur == '#') {
          break;
        }

        if (*acur == '@') {
          *userinfo = std::string(abegin, acur - abegin);
          abegin = acur + 1;
          break;
        }
      }

      /* host */
      const char* acur = abegin;
      for (; acur < aend &&
            *acur != '/' &&
            *acur != '?' &&
            *acur != '#' &&
            *acur != ':'; ++acur);
      *host = std::string(abegin, acur - abegin);

      /* port */
      if (acur < aend - 1 && *acur == ':') {
        abegin = ++acur;
        for (; *acur >= '0' && *acur <= '9'; ++acur);
        if (acur > abegin) {
          std::string port_str(abegin, acur - abegin);
          try {
            *port = std::stoi(port_str);
          } catch (const std::exception& e) {
            RAISE(
                kRuntimeError,
                "invalid URI: invalid port: %s",
                port_str.c_str());
          }
        }
      }
    }
    begin = cur;
  }

  /* path */
  if (begin < end) {
    const char* cur = begin;
    for (; cur < end && *cur != '?' && *cur != '#'; ++cur);
    if (cur > begin) {
      *path = std::string(begin, cur - begin);
    }
    begin = cur;
  }

  /* query */
  if (begin < end && *begin == '?') {
    const char* cur = ++begin;
    for (; cur < end && *cur != '#'; ++cur);
    if (cur > begin) {
      *query = std::string(begin, cur - begin);
    }
    begin = cur;
  }

  /* fragment */
  if (begin < end - 1 && *begin == '#') {
    *fragment = std::string(begin + 1, end - begin - 1);
  }
}

void URI::parseQueryString(
    const std::string& query,
    std::vector<std::pair<std::string, std::string>>* params) {
  const char* begin = query.c_str();
  const char* end = begin + query.size();

  for (const char* cur = begin; cur < end; ++cur) {
    for (; cur < end && *cur != '=' && *cur != '&'; cur++);
    if (cur > begin && cur < end && *cur == '=' ) {
      std::string key_str(begin, cur - begin);
      const char* val = ++cur;
      for (; cur < end && *cur != '=' && *cur != '&'; cur++);
      if (cur > val) {
        std::string val_str(val, cur - val);
        params->emplace_back(URI::urlDecode(key_str), URI::urlDecode(val_str));
        begin = cur + 1;
      } else {
        params->emplace_back(URI::urlDecode(key_str), "");
        begin = cur + 1;
      }
    } else {
      break;
    }
  }
}

std::string URI::buildQueryString(const URI::ParamList& params) {
  std::string out;

  for (int i = 0; i < params.size(); ++i) {
    if (i > 0) {
      out += "&";
    }

    out += StringUtil::format(
        "$0=$1",
        URI::urlEncode(params[i].first),
        URI::urlEncode(params[i].second));
  }

  return out;
}

} // namespace fnord

<|endoftext|>


<commit_before>#include <node.h>
#include <node_buffer.h>
#include <v8.h>

extern "C" {
#include <ocstack.h>
#include <ffi.h>
#include "callback-info.h"
}

#define THROW_TYPECHECK_EXCEPTION( isolate, typecheck, message ) \
		(isolate)->ThrowException( Exception::TypeError( \
			String::NewFromUtf8( (isolate), \
				message " must satisfy " #typecheck "()" ) ) )

#define VALIDATE_CALLBACK_RETURN_VALUE_TYPE( isolate, value, typecheck ) \
	if ( !value->typecheck() ) { \
		THROW_TYPECHECK_EXCEPTION( isolate, typecheck, "Callback return value type" ); \
	}

#define VALIDATE_ARGUMENT_COUNT( isolate, args, length ) \
	if ( (args).Length() < (length) ) { \
		(isolate)->ThrowException( Exception::TypeError( \
			String::NewFromUtf8( (isolate), "Need " #length " arguments" ) ) ); \
		return; \
	}

#define VALIDATE_ARGUMENT_TYPE( isolate, args, index, typecheck  ) \
	if ( !(args)[ (index) ]->typecheck() ) { \
		THROW_TYPECHECK_EXCEPTION( isolate, typecheck, "Argument " #index " " ); \
		return; \
	}

using namespace v8;
using namespace node;

Handle<Object> module_exports;

void bind_OCInit( const FunctionCallbackInfo<Value>& args ) {
	Isolate *isolate = Isolate::GetCurrent();

	VALIDATE_ARGUMENT_COUNT( isolate, args, 3 );
	VALIDATE_ARGUMENT_TYPE( isolate, args, 0, IsString );
	VALIDATE_ARGUMENT_TYPE( isolate, args, 1, IsUint32 );
	VALIDATE_ARGUMENT_TYPE( isolate, args, 2, IsNumber );

	args.GetReturnValue().Set( Number::New( isolate,
		OCInit(
			( const char * )*String::Utf8Value( args[ 0 ] ),
			( uint16_t )args[ 1 ]->ToUint32()->Value(),
			( OCMode )args[ 2 ]->ToNumber()->Value() ) ) );
}

void bind_OCStop( const FunctionCallbackInfo<Value>& args ) {
	Isolate *isolate = Isolate::GetCurrent();

	args.GetReturnValue().Set( Number::New( isolate, OCStop() ) );
}

inline Local<Value> get_js_callback( Isolate *isolate, int uuid ) {
	return module_exports->
		Get( String::NewFromUtf8( isolate, "_callbacks" ) )->ToObject()->
			Get( String::NewFromUtf8( isolate, "callbacks" ) )->ToObject()->
				Get( uuid );
}

void dispose_of_callback_info( const v8::WeakCallbackData<v8::Value, _callback_info>& data ) {
	callback_info_free( ( callback_info * )data.GetParameter() );
}

// Marshaller for OCEntityHandler callback
// defaultEntityHandler is placed in a closure each time someone calls OCCreateResource. Closures
// differ from one another only by the value of uuid, which is a key into the hash of JS callbacks.
// When the C API executes one of the closures, we construct a call to the JS callback identified
// by its UUID, and pass the return value from the callback back to the C API.
void defaultEntityHandler(
		ffi_cif* cif,
		OCEntityHandlerResult *returnValueLocation,
		void**arguments,
		int uuid ) {
	Isolate *isolate = Isolate::GetCurrent();
	Local<Value> jsCallback = get_js_callback( isolate, uuid );
	Local<Value> jsCallbackArguments[ 2 ] = {
		Number::New( isolate, ( double )*( OCEntityHandlerFlag * )( arguments[ 0 ] ) ),
		Buffer::Use( isolate, ( char * )*( OCEntityHandlerRequest ** )( arguments[ 1 ] ),
			sizeof( OCEntityHandlerRequest ) )
	};

	// Make sure the JS callback is present
	if ( !jsCallback->IsFunction() ) {
		isolate->ThrowException( Exception::TypeError(
			String::Concat(
				String::Concat(
					String::NewFromUtf8( isolate, "JS Callback with UUID " ),
					String::NewFromUtf8( isolate,
						*String::Utf8Value( Number::New( isolate, ( double )uuid ) ) ) ),
				String::NewFromUtf8( isolate, " not found" ) ) ) );
		return;
	}

	// Call the JS callback
	Local<Value> returnValue = Local<Function>::Cast( jsCallback )->Call(
		isolate->GetCurrentContext()->Global(),
		2, jsCallbackArguments );

	VALIDATE_CALLBACK_RETURN_VALUE_TYPE( isolate, returnValue, IsNumber );

	*returnValueLocation = ( OCEntityHandlerResult )( returnValue->ToNumber()->Value() );
}

void bind__partial_OCCreateResource( const FunctionCallbackInfo<Value>& args ) {
	Isolate *isolate = Isolate::GetCurrent();
	int uuid;
	OCResourceHandle handle = 0;
	OCStackResult result;
	Handle<Array> returnArray;
	callback_info *info;

	VALIDATE_ARGUMENT_COUNT( isolate, args, 5 );
	VALIDATE_ARGUMENT_TYPE( isolate, args, 0, IsString );
	VALIDATE_ARGUMENT_TYPE( isolate, args, 1, IsString );
	VALIDATE_ARGUMENT_TYPE( isolate, args, 2, IsString );
	VALIDATE_ARGUMENT_TYPE( isolate, args, 3, IsUint32 ); // uuid used as key into callbacks array
	VALIDATE_ARGUMENT_TYPE( isolate, args, 4, IsUint32 );

	uuid = args[ 3 ]->ToUint32()->Value();

	// Create a new callback
	info = callback_info_new(

		// Location of JS callback
		uuid,

		// Function signature - return value
		&ffi_type_uint32,

		// Function signature - location of function
		( Marshaller )defaultEntityHandler,

		// Function signature - number of arguments
		2,

		// Function signature - arguments
		&ffi_type_uint32, &ffi_type_pointer );

	if ( !info ) {
		(isolate)->ThrowException( Exception::TypeError(
			String::NewFromUtf8( (isolate),
				"OCCreateResource: Unable to allocate C callback" ) ) );
		return;
	}

	result = OCCreateResource(
		&handle,
		( const char * )*String::Utf8Value( args[ 0 ] ),
		( const char * )*String::Utf8Value( args[ 1 ] ),
		( const char * )*String::Utf8Value( args[ 2 ] ),
		( OCEntityHandler )( info->resultingFunction ),
		( uint8_t )args[ 4 ]->ToUint32()->Value() );

	// We return an array containing the result code and the handle. It is made weakly
	// persistent so as to allow us to dispose of the callback_info structure when it's no
	// longer in use.
	returnArray = Array::New( isolate, 3 );
	returnArray->Set( 0, Number::New( isolate, ( double )result ) );
	returnArray->Set( 1,
		Buffer::New( isolate, ( const char * )&handle, sizeof( OCResourceHandle ) ) );
	returnArray->Set( 2, Number::New( isolate, ( double )uuid ) );

	Persistent<Value> jsReturnValue( isolate, returnArray );

	jsReturnValue.SetWeak( info, dispose_of_callback_info );

	args.GetReturnValue().Set( jsReturnValue );
}

void bind__partial_OCDeleteResource( const FunctionCallbackInfo<Value>& args ) {
	Isolate *isolate = Isolate::GetCurrent();

	VALIDATE_ARGUMENT_COUNT( isolate, args, 1 );
	VALIDATE_ARGUMENT_TYPE( isolate, args, 0, IsArray );

	args.GetReturnValue().Set(
		Number::New( isolate, ( double )OCDeleteResource(
			( OCResourceHandle )Buffer::Data(
				Handle<Array>::Cast( args[ 0 ] )->Get( 1 )->ToObject() ) ) ) );
}

void InitFunctions( Handle<Object> exports ) {
	module_exports = exports;

	NODE_SET_METHOD( exports, "OCInit", bind_OCInit );
	NODE_SET_METHOD( exports, "OCStop", bind_OCStop );
	NODE_SET_METHOD( exports, "_partial_OCCreateResource", bind__partial_OCCreateResource );
	NODE_SET_METHOD( exports, "_partial_OCDeleteResource", bind__partial_OCDeleteResource );
}
<commit_msg>Functions: Do not define variable if there's gonna be an exception<commit_after>#include <node.h>
#include <node_buffer.h>
#include <v8.h>

extern "C" {
#include <ocstack.h>
#include <ffi.h>
#include "callback-info.h"
}

#define THROW_TYPECHECK_EXCEPTION( isolate, typecheck, message ) \
		(isolate)->ThrowException( Exception::TypeError( \
			String::NewFromUtf8( (isolate), \
				message " must satisfy " #typecheck "()" ) ) )

#define VALIDATE_CALLBACK_RETURN_VALUE_TYPE( isolate, value, typecheck ) \
	if ( !value->typecheck() ) { \
		THROW_TYPECHECK_EXCEPTION( isolate, typecheck, "Callback return value type" ); \
	}

#define VALIDATE_ARGUMENT_COUNT( isolate, args, length ) \
	if ( (args).Length() < (length) ) { \
		(isolate)->ThrowException( Exception::TypeError( \
			String::NewFromUtf8( (isolate), "Need " #length " arguments" ) ) ); \
		return; \
	}

#define VALIDATE_ARGUMENT_TYPE( isolate, args, index, typecheck  ) \
	if ( !(args)[ (index) ]->typecheck() ) { \
		THROW_TYPECHECK_EXCEPTION( isolate, typecheck, "Argument " #index " " ); \
		return; \
	}

using namespace v8;
using namespace node;

Handle<Object> module_exports;

void bind_OCInit( const FunctionCallbackInfo<Value>& args ) {
	Isolate *isolate = Isolate::GetCurrent();

	VALIDATE_ARGUMENT_COUNT( isolate, args, 3 );
	VALIDATE_ARGUMENT_TYPE( isolate, args, 0, IsString );
	VALIDATE_ARGUMENT_TYPE( isolate, args, 1, IsUint32 );
	VALIDATE_ARGUMENT_TYPE( isolate, args, 2, IsNumber );

	args.GetReturnValue().Set( Number::New( isolate,
		OCInit(
			( const char * )*String::Utf8Value( args[ 0 ] ),
			( uint16_t )args[ 1 ]->ToUint32()->Value(),
			( OCMode )args[ 2 ]->ToNumber()->Value() ) ) );
}

void bind_OCStop( const FunctionCallbackInfo<Value>& args ) {
	Isolate *isolate = Isolate::GetCurrent();

	args.GetReturnValue().Set( Number::New( isolate, OCStop() ) );
}

inline Local<Value> get_js_callback( Isolate *isolate, int uuid ) {
	return module_exports->
		Get( String::NewFromUtf8( isolate, "_callbacks" ) )->ToObject()->
			Get( String::NewFromUtf8( isolate, "callbacks" ) )->ToObject()->
				Get( uuid );
}

void dispose_of_callback_info( const v8::WeakCallbackData<v8::Value, _callback_info>& data ) {
	callback_info_free( ( callback_info * )data.GetParameter() );
}

// Marshaller for OCEntityHandler callback
// defaultEntityHandler is placed in a closure each time someone calls OCCreateResource. Closures
// differ from one another only by the value of uuid, which is a key into the hash of JS callbacks.
// When the C API executes one of the closures, we construct a call to the JS callback identified
// by its UUID, and pass the return value from the callback back to the C API.
void defaultEntityHandler(
		ffi_cif* cif,
		OCEntityHandlerResult *returnValueLocation,
		void**arguments,
		int uuid ) {
	Isolate *isolate = Isolate::GetCurrent();
	Local<Value> jsCallback = get_js_callback( isolate, uuid );

	// Make sure the JS callback is present
	if ( !jsCallback->IsFunction() ) {
		isolate->ThrowException( Exception::TypeError(
			String::Concat(
				String::Concat(
					String::NewFromUtf8( isolate, "JS Callback with UUID " ),
					String::NewFromUtf8( isolate,
						*String::Utf8Value( Number::New( isolate, ( double )uuid ) ) ) ),
				String::NewFromUtf8( isolate, " not found" ) ) ) );
		return;
	}

	// Call the JS callback
	Local<Value> jsCallbackArguments[ 2 ] = {
		Number::New( isolate, ( double )*( OCEntityHandlerFlag * )( arguments[ 0 ] ) ),
		Buffer::Use( isolate, ( char * )*( OCEntityHandlerRequest ** )( arguments[ 1 ] ),
			sizeof( OCEntityHandlerRequest ) )
	};
	Local<Value> returnValue = Local<Function>::Cast( jsCallback )->Call(
		isolate->GetCurrentContext()->Global(),
		2, jsCallbackArguments );

	VALIDATE_CALLBACK_RETURN_VALUE_TYPE( isolate, returnValue, IsNumber );

	*returnValueLocation = ( OCEntityHandlerResult )( returnValue->ToNumber()->Value() );
}

void bind__partial_OCCreateResource( const FunctionCallbackInfo<Value>& args ) {
	Isolate *isolate = Isolate::GetCurrent();
	int uuid;
	OCResourceHandle handle = 0;
	OCStackResult result;
	Handle<Array> returnArray;
	callback_info *info;

	VALIDATE_ARGUMENT_COUNT( isolate, args, 5 );
	VALIDATE_ARGUMENT_TYPE( isolate, args, 0, IsString );
	VALIDATE_ARGUMENT_TYPE( isolate, args, 1, IsString );
	VALIDATE_ARGUMENT_TYPE( isolate, args, 2, IsString );
	VALIDATE_ARGUMENT_TYPE( isolate, args, 3, IsUint32 ); // uuid used as key into callbacks array
	VALIDATE_ARGUMENT_TYPE( isolate, args, 4, IsUint32 );

	uuid = args[ 3 ]->ToUint32()->Value();

	// Create a new callback
	info = callback_info_new(

		// Location of JS callback
		uuid,

		// Function signature - return value
		&ffi_type_uint32,

		// Function signature - location of function
		( Marshaller )defaultEntityHandler,

		// Function signature - number of arguments
		2,

		// Function signature - arguments
		&ffi_type_uint32, &ffi_type_pointer );

	if ( !info ) {
		(isolate)->ThrowException( Exception::TypeError(
			String::NewFromUtf8( (isolate),
				"OCCreateResource: Unable to allocate C callback" ) ) );
		return;
	}

	result = OCCreateResource(
		&handle,
		( const char * )*String::Utf8Value( args[ 0 ] ),
		( const char * )*String::Utf8Value( args[ 1 ] ),
		( const char * )*String::Utf8Value( args[ 2 ] ),
		( OCEntityHandler )( info->resultingFunction ),
		( uint8_t )args[ 4 ]->ToUint32()->Value() );

	// We return an array containing the result code and the handle. It is made weakly
	// persistent so as to allow us to dispose of the callback_info structure when it's no
	// longer in use.
	returnArray = Array::New( isolate, 3 );
	returnArray->Set( 0, Number::New( isolate, ( double )result ) );
	returnArray->Set( 1,
		Buffer::New( isolate, ( const char * )&handle, sizeof( OCResourceHandle ) ) );
	returnArray->Set( 2, Number::New( isolate, ( double )uuid ) );

	Persistent<Value> jsReturnValue( isolate, returnArray );

	jsReturnValue.SetWeak( info, dispose_of_callback_info );

	args.GetReturnValue().Set( jsReturnValue );
}

void bind__partial_OCDeleteResource( const FunctionCallbackInfo<Value>& args ) {
	Isolate *isolate = Isolate::GetCurrent();

	VALIDATE_ARGUMENT_COUNT( isolate, args, 1 );
	VALIDATE_ARGUMENT_TYPE( isolate, args, 0, IsArray );

	args.GetReturnValue().Set(
		Number::New( isolate, ( double )OCDeleteResource(
			( OCResourceHandle )Buffer::Data(
				Handle<Array>::Cast( args[ 0 ] )->Get( 1 )->ToObject() ) ) ) );
}

void InitFunctions( Handle<Object> exports ) {
	module_exports = exports;

	NODE_SET_METHOD( exports, "OCInit", bind_OCInit );
	NODE_SET_METHOD( exports, "OCStop", bind_OCStop );
	NODE_SET_METHOD( exports, "_partial_OCCreateResource", bind__partial_OCCreateResource );
	NODE_SET_METHOD( exports, "_partial_OCDeleteResource", bind__partial_OCDeleteResource );
}
<|endoftext|>


<commit_before>
template<typename T>
class ClName {
  T* ptr1;
  double* ptr2;
public:
  ClName()
  : ptr1(new T[100])
  {
    ptr2 = new double(3.3);
  }

  virtual ~ClName()
  {
    delete[] ptr1;
    delete ptr2;
  }

};

int main(void) {
  int* pT = new int(53);
  delete pT;

  pT = reinterpret_cast<int*>(::operator new[](200));

  ClName<short> cl1;
  { ClName<int> cl2; }

  ::operator delete[](pT);

  return 0;
}

<commit_msg>made the complex example more complex<commit_after>
template<typename T>
class ClName {
  T* ptr1;
  double* ptr2;
public:
  ClName()
  : ptr1(new T[100])
  {
    ptr2 = new double(3.3);
  }

  virtual ~ClName()
  {
    delete[] ptr1;
    delete ptr2;
  }

};

template<>
class ClName<char> {
public:
  char* cc;

  ClName()
  : cc(new char[1337]){}

  ~ClName()
  {
    delete[] cc;
  }
};

int main(void) {
  int* pT = new int(53);
  delete pT;

  pT = reinterpret_cast<int*>(::operator new[](200));

  ClName<short> cl1;
  { ClName<int> cl2; }

  ClName<char> cl_spec;

  ::operator delete[](pT);

  return 0;
}

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2011 Stephen Williams (steve@icarus.com)
 *
 *    This source code is free software; you can redistribute it
 *    and/or modify it in source code form under the terms of the GNU
 *    General Public License as published by the Free Software
 *    Foundation; either version 2 of the License, or (at your option)
 *    any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with this program; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 */

# include  "vtype.h"
# include  "parse_types.h"
# include  <map>
# include  <typeinfo>

using namespace std;

VType::~VType()
{
}

void VType::show(ostream&out) const
{
      out << typeid(*this).name();
}

VTypePrimitive::VTypePrimitive(VTypePrimitive::type_t tt)
: type_(tt)
{
}

VTypePrimitive::~VTypePrimitive()
{
}

void VTypePrimitive::show(ostream&out) const
{
      switch (type_) {
	  case BOOLEAN:
	    out << "BOOLEAN";
	    break;
	  case BIT:
	    out << "BIT";
	    break;
	  case INTEGER:
	    out << "INTEGER";
	    break;
	  case STDLOGIC:
	    out << "std_logic";
	    break;
      }
}

VTypeArray::VTypeArray(const VType*element, const vector<VTypeArray::range_t>&r, bool sv)
: etype_(element), ranges_(r), signed_flag_(sv)
{
}

/*
 * Create a VTypeArray range set from a list of parsed ranges.
 * FIXME: We are copying pointers from the prange_t object into the
 * range_t. This means that we cannot delete the prange_t object
 * unless we invent a way to remove the pointers from that object. So
 * this is a memory leak. Something to fix.
 */
VTypeArray::VTypeArray(const VType*element, std::list<prange_t*>*r, bool sv)
: etype_(element), ranges_(r->size()), signed_flag_(sv)
{
      for (size_t idx = 0 ; idx < ranges_.size() ; idx += 1) {
	    prange_t*curp = r->front();
	    r->pop_front();
	    Expression*msb = curp->msb();
	    Expression*lsb = curp->lsb();
	    ranges_[idx] = range_t(msb, lsb);
      }
}

VTypeArray::~VTypeArray()
{
}

size_t VTypeArray::dimensions() const
{
      return ranges_.size();
}

const VType* VTypeArray::element_type() const
{
      return etype_;
}

void VTypeArray::show(ostream&out) const
{
      out << "array ";
      for (vector<range_t>::const_iterator cur = ranges_.begin()
		 ; cur != ranges_.end() ; ++cur) {
	    out << "(" << cur->msb() << " downto " << cur->lsb() << ")";
      }
      out << " of ";
      if (signed_flag_)
	    out << "signed ";
      if (etype_)
	    etype_->show(out);
      else
	    out << "<nil>";
}

VTypeRange::VTypeRange(const VType*base, int64_t max_val, int64_t min_val)
: base_(base)
{
      max_ = max_val;
      min_ = min_val;
}

VTypeRange::~VTypeRange()
{
}

VTypeEnum::VTypeEnum(const std::list<perm_string>*names)
: names_(names->size())
{
      size_t idx = 0;

      for (list<perm_string>::const_iterator cur = names->begin()
		 ; cur != names->end() ; ++cur, ++idx) {
	    names_[idx] = *cur;
      }
}

VTypeEnum::~VTypeEnum()
{
}

void VTypeEnum::show(ostream&out) const
{
      out << "(";
      if (names_.size() >= 1)
	    out << names_[0];
      for (size_t idx = 1 ; idx < names_.size() ; idx += 1)
	    out << ", " << names_[idx];
      out << ")";
}

VTypeDef::VTypeDef(perm_string nam, const VType*typ)
: name_(nam), type_(typ)
{
}

VTypeDef::~VTypeDef()
{
}
<commit_msg>Fix dump display of array ranges.<commit_after>/*
 * Copyright (c) 2011 Stephen Williams (steve@icarus.com)
 *
 *    This source code is free software; you can redistribute it
 *    and/or modify it in source code form under the terms of the GNU
 *    General Public License as published by the Free Software
 *    Foundation; either version 2 of the License, or (at your option)
 *    any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with this program; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 */

# include  "vtype.h"
# include  "parse_types.h"
# include  <map>
# include  <typeinfo>

using namespace std;

VType::~VType()
{
}

void VType::show(ostream&out) const
{
      out << typeid(*this).name();
}

VTypePrimitive::VTypePrimitive(VTypePrimitive::type_t tt)
: type_(tt)
{
}

VTypePrimitive::~VTypePrimitive()
{
}

void VTypePrimitive::show(ostream&out) const
{
      switch (type_) {
	  case BOOLEAN:
	    out << "BOOLEAN";
	    break;
	  case BIT:
	    out << "BIT";
	    break;
	  case INTEGER:
	    out << "INTEGER";
	    break;
	  case STDLOGIC:
	    out << "std_logic";
	    break;
      }
}

VTypeArray::VTypeArray(const VType*element, const vector<VTypeArray::range_t>&r, bool sv)
: etype_(element), ranges_(r), signed_flag_(sv)
{
}

/*
 * Create a VTypeArray range set from a list of parsed ranges.
 * FIXME: We are copying pointers from the prange_t object into the
 * range_t. This means that we cannot delete the prange_t object
 * unless we invent a way to remove the pointers from that object. So
 * this is a memory leak. Something to fix.
 */
VTypeArray::VTypeArray(const VType*element, std::list<prange_t*>*r, bool sv)
: etype_(element), ranges_(r->size()), signed_flag_(sv)
{
      for (size_t idx = 0 ; idx < ranges_.size() ; idx += 1) {
	    prange_t*curp = r->front();
	    r->pop_front();
	    Expression*msb = curp->msb();
	    Expression*lsb = curp->lsb();
	    ranges_[idx] = range_t(msb, lsb);
      }
}

VTypeArray::~VTypeArray()
{
}

size_t VTypeArray::dimensions() const
{
      return ranges_.size();
}

const VType* VTypeArray::element_type() const
{
      return etype_;
}

void VTypeArray::show(ostream&out) const
{
      out << "array ";
      for (vector<range_t>::const_iterator cur = ranges_.begin()
		 ; cur != ranges_.end() ; ++cur) {
	    out << "(";
	    if (cur->msb())
		  cur->msb()->write_to_stream(out);
	    else
		  out << "<>";
	    out << " downto ";
	    if (cur->lsb())
		  cur->lsb()->write_to_stream(out);
	    else
		  out << "<>";
	    out << ")";
      }
      out << " of ";
      if (signed_flag_)
	    out << "signed ";
      if (etype_)
	    etype_->show(out);
      else
	    out << "<nil>";
}

VTypeRange::VTypeRange(const VType*base, int64_t max_val, int64_t min_val)
: base_(base)
{
      max_ = max_val;
      min_ = min_val;
}

VTypeRange::~VTypeRange()
{
}

VTypeEnum::VTypeEnum(const std::list<perm_string>*names)
: names_(names->size())
{
      size_t idx = 0;

      for (list<perm_string>::const_iterator cur = names->begin()
		 ; cur != names->end() ; ++cur, ++idx) {
	    names_[idx] = *cur;
      }
}

VTypeEnum::~VTypeEnum()
{
}

void VTypeEnum::show(ostream&out) const
{
      out << "(";
      if (names_.size() >= 1)
	    out << names_[0];
      for (size_t idx = 1 ; idx < names_.size() ; idx += 1)
	    out << ", " << names_[idx];
      out << ")";
}

VTypeDef::VTypeDef(perm_string nam, const VType*typ)
: name_(nam), type_(typ)
{
}

VTypeDef::~VTypeDef()
{
}
<|endoftext|>