<commit_before>// Copyright (c) 2013-2018 Mathieu Taillefumier, Anton Kozhevnikov, Thomas Schulthess
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that
// the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
//    following disclaimer.
// 2. 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.
//
// 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS 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.

/** \file hubbard.hpp
 *
 *  \brief Contains declaration and partial implementation of sirius::Hubbard class.
 */

#ifndef __HUBBARD_HPP__
#define __HUBBARD_HPP__

#include <cstdio>
#include <cstdlib>
#include "simulation_context.hpp"
#include "K_point/k_point.hpp"
#include "wave_functions.hpp"
#include "Hamiltonian/non_local_operator.hpp"
#include "Beta_projectors/beta_projectors.hpp"
#include "Beta_projectors/beta_projectors_gradient.hpp"
#include "Beta_projectors/beta_projectors_strain_deriv.hpp"
#include "radial_integrals.hpp"
#include "mixer.hpp"

namespace sirius {

/// Apply Hubbard correction in the colinear case
class Hubbard
{
  private:
    Simulation_context& ctx_;

    Unit_cell& unit_cell_;

    int lmax_{-1};

    int number_of_hubbard_orbitals_{0};

    mdarray<double_complex, 5> occupancy_number_;

    double hubbard_energy_{0.0};
    double hubbard_energy_u_{0.0};
    double hubbard_energy_dc_contribution_{0.0};
    double hubbard_energy_noflip_{0.0};
    double hubbard_energy_flip_{0.0};

    mdarray<double_complex, 5> hubbard_potential_;

    /// Type of hubbard correction to be considered.
    /** True if we consider a simple hubbard correction. Not valid if spin orbit coupling is included */
    bool approximation_{false};

    /// Orthogonalize and/or normalize the projectors.
    bool orthogonalize_hubbard_orbitals_{false};

    /// True if localized orbitals have to be normalized.
    bool normalize_orbitals_only_{false};

    /// hubbard correction with next nearest neighbors
    bool hubbard_U_plus_V_{false};

    /// hubbard projection method. By default we use the wave functions
    /// provided by the pseudo potentials.
    int projection_method_{0};

    /// Hubbard with multi channels (not implemented yet)
    bool multi_channels_{false};

    /// file containing the hubbard wave functions
    std::string wave_function_file_;

    void calculate_initial_occupation_numbers();

    void compute_occupancies(K_point&                    kp,
                             dmatrix<double_complex>&    phi_s_psi,
                             dmatrix<double_complex>&    dphi_s_psi,
                             Wave_functions&             dphi,
                             mdarray<double_complex, 5>& dn_,
                             matrix<double_complex>&     dm,
                             const int                   index);

    inline void symmetrize_occupancy_matrix_noncolinear_case();
    inline void symmetrize_occupancy_matrix();
    inline void print_occupancies();

    inline void calculate_wavefunction_with_U_offset()
    {
        offset.clear();
        offset.resize(ctx_.unit_cell().num_atoms(), -1);

        int counter = 0;

        // we loop over atoms to check which atom has hubbard orbitals
        // and then compute the number of hubbard orbitals associated to
        // it.
        for (auto ia = 0; ia < unit_cell_.num_atoms(); ia++) {
            auto& atom = unit_cell_.atom(ia);
            if (atom.type().hubbard_correction()) {
                offset[ia] = counter;
                if (ctx_.num_mag_dims() == 3) {
                    for (auto&& orb : atom.type().hubbard_orbital()) {
                        if (atom.type().spin_orbit_coupling()) {
                            counter += (2 * orb.l() + 1);
                        } else {
                            counter += 2 * (2 * orb.l() + 1);
                        }
                    }
                } else {
                    for (auto&& orb : atom.type().hubbard_orbital()) {
                        counter += (2 * orb.l() + 1);
                    }
                }
            }
        }

        this->number_of_hubbard_orbitals_ = counter;
    }

    /// Compute the strain gradient of the hubbard wave functions.
    /// Unfortunately it is dependent of the pp.

    void compute_gradient_strain_wavefunctions(K_point&                  kp,
                                               Wave_functions&           dphi,
                                               const mdarray<double, 2>& rlm_g,
                                               const mdarray<double, 3>& rlm_dg,
                                               const int                 mu,
                                               const int                 nu);

    /// apply the S operator in the us pp case. Otherwise it makes a simple copy
    void apply_S_operator(K_point&                    kp,
                          Q_operator<double_complex>& q_op,
                          Wave_functions&             phi,
                          Wave_functions&             ophi,
                          const int                   idx0,
                          const int                   num_phi);

    /// orthogonize (normalize) the hubbard wave functions
    void orthogonalize_atomic_orbitals(K_point& kp, Wave_functions& sphi);

  public:
    std::vector<int> offset;

    void set_hubbard_U_plus_V()
    {
        hubbard_U_plus_V_ = true;
    }

    void set_hubbard_simple_correction()
    {
        approximation_ = true;
    }

    inline int lmax() const
    {
        return lmax_;
    }

    void set_orthogonalize_hubbard_orbitals(const bool test)
    {
        orthogonalize_hubbard_orbitals_ = test;
    }

    void set_normalize_hubbard_orbitals(const bool test)
    {
        this->normalize_orbitals_only_ = test;
    }

    double_complex U(int m1, int m2, int m3, int m4) const
    {
        return hubbard_potential_(m1, m2, m3, m4, 0);
    }

    double_complex& U(int m1, int m2, int m3, int m4)
    {
        return hubbard_potential_(m1, m2, m3, m4, 0);
    }

    double_complex U(int m1, int m2, int m3, int m4, int channel) const
    {
        return hubbard_potential_(m1, m2, m3, m4, channel);
    }

    double_complex& U(int m1, int m2, int m3, int m4, int channel)
    {
        return hubbard_potential_(m1, m2, m3, m4, channel);
    }

    bool orthogonalize_hubbard_orbitals() const
    {
        return orthogonalize_hubbard_orbitals_;
    }

    bool normalize_hubbard_orbitals() const
    {
        return normalize_orbitals_only_;
    }

    /// Apply the hubbard potential on wave functions
    void apply_hubbard_potential(K_point&        kp,
                                 const int       ispn,
                                 const int       idx,
                                 const int       n,
                                 Wave_functions& phi,
                                 Wave_functions& ophi);

    /// Generate the atomic orbitals.
    void generate_atomic_orbitals(K_point& kp, Q_operator<double_complex>& q_op);
    void generate_atomic_orbitals(K_point& kp, Q_operator<double>& q_op);

    void hubbard_compute_occupation_numbers(K_point_set& kset_);

    void compute_occupancies_derivatives(K_point&                    kp,
                                         Q_operator<double_complex>& q_op,
                                         mdarray<double_complex, 6>& dn);

    /// Compute derivatives of the occupancy matrix w.r.t.atomic displacement.
    /** \param [in]  kp   K-point.
     *  \param [in]  q_op Overlap operator.
     *  \param [out] dn   Derivative of the occupation number compared to displacement of each atom.
     */
    void compute_occupancies_stress_derivatives(K_point&                    kp,
                                                Q_operator<double_complex>& q_op,
                                                mdarray<double_complex, 5>& dn);

    void calculate_hubbard_potential_and_energy_colinear_case();
    void calculate_hubbard_potential_and_energy_non_colinear_case();
    void calculate_hubbard_potential_and_energy()
    {
        this->hubbard_energy_                 = 0.0;
        this->hubbard_energy_u_               = 0.0;
        this->hubbard_energy_dc_contribution_ = 0.0;
        this->hubbard_energy_noflip_          = 0.0;
        this->hubbard_energy_flip_            = 0.0;
        // the hubbard potential has the same structure than the occupation
        // numbers
        this->hubbard_potential_.zero();

        if (ctx_.num_mag_dims() != 3) {
            calculate_hubbard_potential_and_energy_colinear_case();
        } else {
            calculate_hubbard_potential_and_energy_non_colinear_case();
        }
    }

    inline double hubbard_energy() const
    {
        return this->hubbard_energy_;
    }

    inline int number_of_hubbard_orbitals() const
    {
        return number_of_hubbard_orbitals_;
    }

    Hubbard(Simulation_context& ctx__)
        : ctx_(ctx__)
        , unit_cell_(ctx__.unit_cell())
    {
        if (!ctx_.hubbard_correction()) {
            return;
        }
        orthogonalize_hubbard_orbitals_ = ctx_.Hubbard().orthogonalize_hubbard_orbitals_;
        normalize_orbitals_only_        = ctx_.Hubbard().normalize_hubbard_orbitals_;
        projection_method_              = ctx_.Hubbard().projection_method_;

        // if the projectors are defined externaly then we need the file
        // that contains them. All the other methods do not depend on
        // that parameter
        if (this->projection_method_ == 1) {
            this->wave_function_file_ = ctx_.Hubbard().wave_function_file_;
        }

        for (int ia = 0; ia < ctx_.unit_cell().num_atoms(); ia++) {
            auto& atom_type = ctx_.unit_cell().atom(ia).type();
            if (ctx__.unit_cell().atom(ia).type().hubbard_correction()) {
                for (int channel = 0; channel < atom_type.number_of_hubbard_channels(); channel++) {
                    this->lmax_ = std::max(this->lmax_, atom_type.hubbard_orbital(channel).l());
                }
            }
        }

        /// if spin orbit coupling or non colinear magnetisms are
        /// activated, then we consider the full spherical hubbard
        /// correction
        if ((ctx_.so_correction()) || (ctx_.num_mag_dims() == 3)) {
            approximation_ = false;
        }

        // prepare things for the multi channel case. The last index
        // indicates which channel we consider. By default we only have
        // one channel per atomic type
        occupancy_number_  = mdarray<double_complex, 5>(2 * lmax_ + 1, 2 * lmax_ + 1, 4, ctx_.unit_cell().num_atoms(), 1);
        hubbard_potential_ = mdarray<double_complex, 5>(2 * lmax_ + 1, 2 * lmax_ + 1, 4, ctx_.unit_cell().num_atoms(), 1);

        calculate_wavefunction_with_U_offset();
        calculate_initial_occupation_numbers();
        calculate_hubbard_potential_and_energy();
    }

    mdarray<double_complex, 5>& occupation_matrix()
    {
        return occupancy_number_;
    }

    mdarray<double_complex, 5>& potential_matrix()
    {
        return hubbard_potential_;
    }

    void access_hubbard_potential(char const*     what,
                                  double_complex* occ,
                                  int const*      ld);

    void access_hubbard_occupancies(char const*     what,
                                    double_complex* occ,
                                    int const*      ld);
};

#include "hubbard_generate_atomic_orbitals.hpp"
#include "hubbard_potential_energy.hpp"
#include "apply_hubbard_potential.hpp"
#include "hubbard_occupancy.hpp"
#include "hubbard_occupancies_derivatives.hpp"

} // namespace sirius

#endif // __HUBBARD_HPP__
<commit_msg>simplify non_local_operator<commit_after>// Copyright (c) 2013-2018 Mathieu Taillefumier, Anton Kozhevnikov, Thomas Schulthess
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that
// the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
//    following disclaimer.
// 2. 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.
//
// 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS 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.

/** \file hubbard.hpp
 *
 *  \brief Contains declaration and partial implementation of sirius::Hubbard class.
 */

#ifndef __HUBBARD_HPP__
#define __HUBBARD_HPP__

#include <cstdio>
#include <cstdlib>
#include "simulation_context.hpp"
#include "K_point/k_point.hpp"
#include "wave_functions.hpp"
#include "Hamiltonian/non_local_operator.hpp"
#include "Beta_projectors/beta_projectors.hpp"
#include "Beta_projectors/beta_projectors_gradient.hpp"
#include "Beta_projectors/beta_projectors_strain_deriv.hpp"
#include "radial_integrals.hpp"
#include "mixer.hpp"

namespace sirius {

/// Apply Hubbard correction in the colinear case
class Hubbard
{
  private:
    Simulation_context& ctx_;

    Unit_cell& unit_cell_;

    int lmax_{-1};

    int number_of_hubbard_orbitals_{0};

    mdarray<double_complex, 5> occupancy_number_;

    double hubbard_energy_{0.0};
    double hubbard_energy_u_{0.0};
    double hubbard_energy_dc_contribution_{0.0};
    double hubbard_energy_noflip_{0.0};
    double hubbard_energy_flip_{0.0};

    mdarray<double_complex, 5> hubbard_potential_;

    /// Type of hubbard correction to be considered.
    /** True if we consider a simple hubbard correction. Not valid if spin orbit coupling is included */
    bool approximation_{false};

    /// Orthogonalize and/or normalize the projectors.
    bool orthogonalize_hubbard_orbitals_{false};

    /// True if localized orbitals have to be normalized.
    bool normalize_orbitals_only_{false};

    /// hubbard correction with next nearest neighbors
    bool hubbard_U_plus_V_{false};

    /// hubbard projection method. By default we use the wave functions
    /// provided by the pseudo potentials.
    int projection_method_{0};

    /// Hubbard with multi channels (not implemented yet)
    bool multi_channels_{false};

    /// file containing the hubbard wave functions
    std::string wave_function_file_;

    void calculate_initial_occupation_numbers();

    void compute_occupancies(K_point&                    kp,
                             dmatrix<double_complex>&    phi_s_psi,
                             dmatrix<double_complex>&    dphi_s_psi,
                             Wave_functions&             dphi,
                             mdarray<double_complex, 5>& dn_,
                             matrix<double_complex>&     dm,
                             const int                   index);

    inline void symmetrize_occupancy_matrix_noncolinear_case();
    inline void symmetrize_occupancy_matrix();
    inline void print_occupancies();

    inline void calculate_wavefunction_with_U_offset()
    {
        offset.clear();
        offset.resize(ctx_.unit_cell().num_atoms(), -1);

        int counter = 0;

        // we loop over atoms to check which atom has hubbard orbitals
        // and then compute the number of hubbard orbitals associated to
        // it.
        for (auto ia = 0; ia < unit_cell_.num_atoms(); ia++) {
            auto& atom = unit_cell_.atom(ia);
            if (atom.type().hubbard_correction()) {
                offset[ia] = counter;
                if (ctx_.num_mag_dims() == 3) {
                    for (auto&& orb : atom.type().hubbard_orbital()) {
                        if (atom.type().spin_orbit_coupling()) {
                            counter += (2 * orb.l() + 1);
                        } else {
                            counter += 2 * (2 * orb.l() + 1);
                        }
                    }
                } else {
                    for (auto&& orb : atom.type().hubbard_orbital()) {
                        counter += (2 * orb.l() + 1);
                    }
                }
            }
        }

        this->number_of_hubbard_orbitals_ = counter;
    }

    /// Compute the strain gradient of the hubbard wave functions.
    /// Unfortunately it is dependent of the pp.

    void compute_gradient_strain_wavefunctions(K_point&                  kp,
                                               Wave_functions&           dphi,
                                               const mdarray<double, 2>& rlm_g,
                                               const mdarray<double, 3>& rlm_dg,
                                               const int                 mu,
                                               const int                 nu);

    /// apply the S operator in the us pp case. Otherwise it makes a simple copy
    void apply_S_operator(K_point&        kp,
                          Q_operator&     q_op,
                          Wave_functions& phi,
                          Wave_functions& ophi,
                          const int       idx0,
                          const int       num_phi);

    /// orthogonize (normalize) the hubbard wave functions
    void orthogonalize_atomic_orbitals(K_point& kp, Wave_functions& sphi);

  public:
    std::vector<int> offset;

    void set_hubbard_U_plus_V()
    {
        hubbard_U_plus_V_ = true;
    }

    void set_hubbard_simple_correction()
    {
        approximation_ = true;
    }

    inline int lmax() const
    {
        return lmax_;
    }

    void set_orthogonalize_hubbard_orbitals(const bool test)
    {
        orthogonalize_hubbard_orbitals_ = test;
    }

    void set_normalize_hubbard_orbitals(const bool test)
    {
        this->normalize_orbitals_only_ = test;
    }

    double_complex U(int m1, int m2, int m3, int m4) const
    {
        return hubbard_potential_(m1, m2, m3, m4, 0);
    }

    double_complex& U(int m1, int m2, int m3, int m4)
    {
        return hubbard_potential_(m1, m2, m3, m4, 0);
    }

    double_complex U(int m1, int m2, int m3, int m4, int channel) const
    {
        return hubbard_potential_(m1, m2, m3, m4, channel);
    }

    double_complex& U(int m1, int m2, int m3, int m4, int channel)
    {
        return hubbard_potential_(m1, m2, m3, m4, channel);
    }

    bool orthogonalize_hubbard_orbitals() const
    {
        return orthogonalize_hubbard_orbitals_;
    }

    bool normalize_hubbard_orbitals() const
    {
        return normalize_orbitals_only_;
    }

    /// Apply the hubbard potential on wave functions
    void apply_hubbard_potential(K_point&        kp,
                                 const int       ispn,
                                 const int       idx,
                                 const int       n,
                                 Wave_functions& phi,
                                 Wave_functions& ophi);

    /// Generate the atomic orbitals.
    void generate_atomic_orbitals(K_point& kp, Q_operator& q_op);

    void hubbard_compute_occupation_numbers(K_point_set& kset_);

    void compute_occupancies_derivatives(K_point&                    kp,
                                         Q_operator& q_op,
                                         mdarray<double_complex, 6>& dn);

    /// Compute derivatives of the occupancy matrix w.r.t.atomic displacement.
    /** \param [in]  kp   K-point.
     *  \param [in]  q_op Overlap operator.
     *  \param [out] dn   Derivative of the occupation number compared to displacement of each atom.
     */
    void compute_occupancies_stress_derivatives(K_point&                    kp,
                                                Q_operator& q_op,
                                                mdarray<double_complex, 5>& dn);

    void calculate_hubbard_potential_and_energy_colinear_case();
    void calculate_hubbard_potential_and_energy_non_colinear_case();
    void calculate_hubbard_potential_and_energy()
    {
        this->hubbard_energy_                 = 0.0;
        this->hubbard_energy_u_               = 0.0;
        this->hubbard_energy_dc_contribution_ = 0.0;
        this->hubbard_energy_noflip_          = 0.0;
        this->hubbard_energy_flip_            = 0.0;
        // the hubbard potential has the same structure than the occupation
        // numbers
        this->hubbard_potential_.zero();

        if (ctx_.num_mag_dims() != 3) {
            calculate_hubbard_potential_and_energy_colinear_case();
        } else {
            calculate_hubbard_potential_and_energy_non_colinear_case();
        }
    }

    inline double hubbard_energy() const
    {
        return this->hubbard_energy_;
    }

    inline int number_of_hubbard_orbitals() const
    {
        return number_of_hubbard_orbitals_;
    }

    Hubbard(Simulation_context& ctx__)
        : ctx_(ctx__)
        , unit_cell_(ctx__.unit_cell())
    {
        if (!ctx_.hubbard_correction()) {
            return;
        }
        orthogonalize_hubbard_orbitals_ = ctx_.Hubbard().orthogonalize_hubbard_orbitals_;
        normalize_orbitals_only_        = ctx_.Hubbard().normalize_hubbard_orbitals_;
        projection_method_              = ctx_.Hubbard().projection_method_;

        // if the projectors are defined externaly then we need the file
        // that contains them. All the other methods do not depend on
        // that parameter
        if (this->projection_method_ == 1) {
            this->wave_function_file_ = ctx_.Hubbard().wave_function_file_;
        }

        for (int ia = 0; ia < ctx_.unit_cell().num_atoms(); ia++) {
            auto& atom_type = ctx_.unit_cell().atom(ia).type();
            if (ctx__.unit_cell().atom(ia).type().hubbard_correction()) {
                for (int channel = 0; channel < atom_type.number_of_hubbard_channels(); channel++) {
                    this->lmax_ = std::max(this->lmax_, atom_type.hubbard_orbital(channel).l());
                }
            }
        }

        /// if spin orbit coupling or non colinear magnetisms are
        /// activated, then we consider the full spherical hubbard
        /// correction
        if ((ctx_.so_correction()) || (ctx_.num_mag_dims() == 3)) {
            approximation_ = false;
        }

        // prepare things for the multi channel case. The last index
        // indicates which channel we consider. By default we only have
        // one channel per atomic type
        occupancy_number_  = mdarray<double_complex, 5>(2 * lmax_ + 1, 2 * lmax_ + 1, 4, ctx_.unit_cell().num_atoms(), 1);
        hubbard_potential_ = mdarray<double_complex, 5>(2 * lmax_ + 1, 2 * lmax_ + 1, 4, ctx_.unit_cell().num_atoms(), 1);

        calculate_wavefunction_with_U_offset();
        calculate_initial_occupation_numbers();
        calculate_hubbard_potential_and_energy();
    }

    mdarray<double_complex, 5>& occupation_matrix()
    {
        return occupancy_number_;
    }

    mdarray<double_complex, 5>& potential_matrix()
    {
        return hubbard_potential_;
    }

    void access_hubbard_potential(char const*     what,
                                  double_complex* occ,
                                  int const*      ld);

    void access_hubbard_occupancies(char const*     what,
                                    double_complex* occ,
                                    int const*      ld);
};

#include "hubbard_generate_atomic_orbitals.hpp"
#include "hubbard_potential_energy.hpp"
#include "apply_hubbard_potential.hpp"
#include "hubbard_occupancy.hpp"
#include "hubbard_occupancies_derivatives.hpp"

} // namespace sirius

#endif // __HUBBARD_HPP__
<|endoftext|>


<commit_before>#ifndef VEXCL_EXCLUSIVE_HPP
#define VEXCLEXCLUSIVE_HPP

/*
The MIT License

Copyright (c) 2012 Denis Demidov <ddemidov@ksu.ru>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

/**
 * \file   exclusive.hpp
 * \author Denis Demidov <ddemidov@ksu.ru>
 * \brief  Device filter allowing exclusive access
 *
 * \note This file should be included manually since it depends on
 * boost::interprocess library.
 */

#ifndef __CL_ENABLE_EXCEPTIONS
#  define __CL_ENABLE_EXCEPTIONS
#endif

#include <vector>
#include <string>
#include <fstream>
#include <memory>
#include <boost/interprocess/sync/file_lock.hpp>
#include <CL/cl.hpp>

namespace vex {

/// Device filters.
namespace Filter {

    /// Allows exclusive access to given number of devices across several processes.
    /**
     * \note This filter should be the last in filter expression.
     */
    class Exclusive {
	private:
	    static std::map<cl_device_id, std::string> get_uids() {
		std::map<cl_device_id, std::string> uids;

		std::vector<cl::Platform> platform;
		cl::Platform::get(&platform);

		for(size_t p_id = 0; p_id < platform.size(); p_id++) {
		    std::vector<cl::Device> device;

		    platform[p_id].getDevices(CL_DEVICE_TYPE_ALL, &device);

		    for(size_t d_id = 0; d_id < device.size(); d_id++) {
			std::ostringstream id;
#ifdef WIN32
			id << getenv("TMPDIR") << "\\vexcl_device_";
#else
			id << "/var/lock/vexcl/device_";
#endif
			id << p_id << "_" << d_id << ".lock";

			uids[device[d_id]()] = id.str();
		    }
		}

		return uids;
	    }

	    struct locker {
		locker(std::string fname) : file(fname)
		{
		    if (!file.is_open() || file.fail()) {
			std::cout
			    << "WARNING: failed to open file \"" << fname << "\"\n"
			    << "  Check that target directory is exists and is writable.\n"
			    << "  Exclusive mode is off.\n"
			    << std::endl;
		    } else {
			flock.reset(new boost::interprocess::file_lock(fname.c_str()));
		    }
		}

		bool try_lock() {
		    if (flock)
			return flock->try_lock();
		    else
			return true;
		}

		std::ofstream file;
		std::unique_ptr<boost::interprocess::file_lock> flock;
	    };

	    mutable int count;
	public:
	    Exclusive(int count) : count(count) {}

	    bool operator()(const cl::Device &d) const {
		static std::map<cl_device_id, std::string> dev_uids = get_uids();
		static std::vector<std::unique_ptr<locker>> locks;

		if (count > 0) {
		    try {
			std::unique_ptr<locker> lck(new locker(dev_uids[d()]));
			if (lck->try_lock()) {
			    locks.push_back(std::move(lck));
			    count--;
			    return true;
			}
		    } catch (const std::exception &e) {
			std::cout << e.what() << std::endl;
		    }
		}

		return false;
	    }

    };
}

}

#endif
<commit_msg>doc update<commit_after>#ifndef VEXCL_EXCLUSIVE_HPP
#define VEXCLEXCLUSIVE_HPP

/*
The MIT License

Copyright (c) 2012 Denis Demidov <ddemidov@ksu.ru>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

/**
 * \file   exclusive.hpp
 * \author Denis Demidov <ddemidov@ksu.ru>
 * \brief  Device filter allowing exclusive access
 *
 * \note This file should be included manually since it depends on
 * boost::interprocess library.
 */

#ifndef __CL_ENABLE_EXCEPTIONS
#  define __CL_ENABLE_EXCEPTIONS
#endif

#include <vector>
#include <string>
#include <fstream>
#include <memory>
#include <boost/interprocess/sync/file_lock.hpp>
#include <CL/cl.hpp>

namespace vex {

/// Device filters.
namespace Filter {

    /// Allows exclusive access to given number of devices across several processes.
    /**
     * \note This filter should be the last in filter expression.
     * \note Depends on boost::interprocess library.
     */
    class Exclusive {
	private:
	    static std::map<cl_device_id, std::string> get_uids() {
		std::map<cl_device_id, std::string> uids;

		std::vector<cl::Platform> platform;
		cl::Platform::get(&platform);

		for(size_t p_id = 0; p_id < platform.size(); p_id++) {
		    std::vector<cl::Device> device;

		    platform[p_id].getDevices(CL_DEVICE_TYPE_ALL, &device);

		    for(size_t d_id = 0; d_id < device.size(); d_id++) {
			std::ostringstream id;
#ifdef WIN32
			id << getenv("TMPDIR") << "\\vexcl_device_";
#else
			id << "/var/lock/vexcl/device_";
#endif
			id << p_id << "_" << d_id << ".lock";

			uids[device[d_id]()] = id.str();
		    }
		}

		return uids;
	    }

	    struct locker {
		locker(std::string fname) : file(fname)
		{
		    if (!file.is_open() || file.fail()) {
			std::cout
			    << "WARNING: failed to open file \"" << fname << "\"\n"
			    << "  Check that target directory is exists and is writable.\n"
			    << "  Exclusive mode is off.\n"
			    << std::endl;
		    } else {
			flock.reset(new boost::interprocess::file_lock(fname.c_str()));
		    }
		}

		bool try_lock() {
		    if (flock)
			return flock->try_lock();
		    else
			return true;
		}

		std::ofstream file;
		std::unique_ptr<boost::interprocess::file_lock> flock;
	    };

	    mutable int count;
	public:
	    Exclusive(int count) : count(count) {}

	    bool operator()(const cl::Device &d) const {
		static std::map<cl_device_id, std::string> dev_uids = get_uids();
		static std::vector<std::unique_ptr<locker>> locks;

		if (count > 0) {
		    try {
			std::unique_ptr<locker> lck(new locker(dev_uids[d()]));
			if (lck->try_lock()) {
			    locks.push_back(std::move(lck));
			    count--;
			    return true;
			}
		    } catch (const std::exception &e) {
			std::cout << e.what() << std::endl;
		    }
		}

		return false;
	    }

    };
}

}

#endif
<|endoftext|>


<commit_before>//Copyright (c) 2018 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.

#ifdef _OPENMP
    #include <omp.h> // omp_get_num_threads
#endif // _OPENMP
#include <string>
#include "Application.h"
#include "FffProcessor.h"
#include "communication/ArcusCommunication.h" //To connect via Arcus to the front-end.
#include "communication/CommandLine.h" //To use the command line to slice stuff.
#include "progress/Progress.h"
#include "utils/logoutput.h"
#include "utils/string.h" //For stringcasecompare.

namespace cura
{

Application::Application()
: communication(nullptr)
, current_slice(0)
{
}

Application::~Application()
{
    delete communication;
}

Application& Application::getInstance()
{
    static Application instance; //Constructs using the default constructor.
    return instance;
}

#ifdef ARCUS
void Application::connect()
{
    std::string ip = "127.0.0.1";
    int port = 49674;

    //Parse port number from IP address.
    std::string ip_port(argv[2]);
    std::size_t found_pos = ip_port.find(':');
    if (found_pos != std::string::npos)
    {
        ip = ip_port.substr(0, found_pos);
        port = std::stoi(ip_port.substr(found_pos + 1).data());
    }

#ifdef _OPENMP
    int n_threads;
#endif // _OPENMP

    for(size_t argn = 3; argn < argc; argn++)
    {
        char* str = argv[argn];
        if (str[0] == '-')
        {
            for(str++; *str; str++)
            {
                switch(*str)
                {
                case 'v':
                    increaseVerboseLevel();
                    break;
#ifdef _OPENMP
                case 'm':
                    str++;
                    n_threads = std::strtol(str, &str, 10);
                    str--;
                    n_threads = std::max(1, n_threads);
                    omp_set_num_threads(n_threads);
                    break;
#endif // _OPENMP
                default:
                    logError("Unknown option: %c\n", *str);
                    printCall();
                    printHelp();
                    break;
                }
            }
        }
    }

    ArcusCommunication* arcus_communication = new ArcusCommunication();
    arcus_communication->connect(ip, port);
    communication = arcus_communication;
}
#endif //ARCUS

void Application::printCall() const
{
    cura::logError("Command called:\n");
    for (size_t argument_index = 0; argument_index < argc; argument_index++)
    {
        cura::logError("%s ", argv[argument_index]);
    }
    cura::logError("\n");
}

void Application::printHelp() const
{
    logAlways("\n");
    logAlways("usage:\n");
    logAlways("CuraEngine help\n");
    logAlways("\tShow this help message\n");
    logAlways("\n");
#ifdef ARCUS
    logAlways("CuraEngine connect <host>[:<port>] [-j <settings.def.json>]\n");
    logAlways("  --connect <host>[:<port>]\n\tConnect to <host> via a command socket, \n\tinstead of passing information via the command line\n");
    logAlways("  -v\n\tIncrease the verbose level (show log messages).\n");
#ifdef _OPENMP
    logAlways("  -m<thread_count>\n\tSet the desired number of threads. Supports only a single digit.\n");
#endif // _OPENMP
    logAlways("\n");
#endif //ARCUS
    logAlways("CuraEngine slice [-v] [-p] [-j <settings.json>] [-s <settingkey>=<value>] [-g] [-e<extruder_nr>] [-o <output.gcode>] [-l <model.stl>] [--next]\n");
    logAlways("  -v\n\tIncrease the verbose level (show log messages).\n");
#ifdef _OPENMP
    logAlways("  -m<thread_count>\n\tSet the desired number of threads.\n");
#endif // _OPENMP
    logAlways("  -p\n\tLog progress information.\n");
    logAlways("  -j\n\tLoad settings.def.json file to register all settings and their defaults.\n");
    logAlways("  -s <setting>=<value>\n\tSet a setting to a value for the last supplied object, \n\textruder train, or general settings.\n");
    logAlways("  -l <model_file>\n\tLoad an STL model. \n");
    logAlways("  -g\n\tSwitch setting focus to the current mesh group only.\n\tUsed for one-at-a-time printing.\n");
    logAlways("  -e<extruder_nr>\n\tSwitch setting focus to the extruder train with the given number.\n");
    logAlways("  --next\n\tGenerate gcode for the previously supplied mesh group and append that to \n\tthe gcode of further models for one-at-a-time printing.\n");
    logAlways("  -o <output_file>\n\tSpecify a file to which to write the generated gcode.\n");
    logAlways("\n");
    logAlways("The settings are appended to the last supplied object:\n");
    logAlways("CuraEngine slice [general settings] \n\t-g [current group settings] \n\t-e0 [extruder train 0 settings] \n\t-l obj_inheriting_from_last_extruder_train.stl [object settings] \n\t--next [next group settings]\n\t... etc.\n");
    logAlways("\n");
    logAlways("In order to load machine definitions from custom locations, you need to create the environment variable CURA_ENGINE_SEARCH_PATH, which should contain all search paths delimited by a (semi-)colon.\n");
    logAlways("\n");
}

void Application::printLicense() const
{
    logAlways("\n");
    logAlways("Cura_SteamEngine version %s\n", VERSION);
    logAlways("Copyright (C) 2018 Ultimaker\n");
    logAlways("\n");
    logAlways("This program is free software: you can redistribute it and/or modify\n");
    logAlways("it under the terms of the GNU Affero General Public License as published by\n");
    logAlways("the Free Software Foundation, either version 3 of the License, or\n");
    logAlways("(at your option) any later version.\n");
    logAlways("\n");
    logAlways("This program is distributed in the hope that it will be useful,\n");
    logAlways("but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
    logAlways("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n");
    logAlways("GNU Affero General Public License for more details.\n");
    logAlways("\n");
    logAlways("You should have received a copy of the GNU Affero General Public License\n");
    logAlways("along with this program.  If not, see <http://www.gnu.org/licenses/>.\n");
}

void Application::slice()
{
    std::vector<std::string> arguments;
    for (size_t argument_index = 0; argument_index < argc; argument_index++)
    {
        arguments.emplace_back(argv[argument_index]);
    }

    communication = new CommandLine(arguments);
}

void Application::run(const size_t argc, char** argv)
{
    this->argc = argc;
    this->argv = argv;

    printLicense();
    Progress::init();

    if (argc < 2)
    {
        printHelp();
        exit(1);
    }

#pragma omp parallel
    {
#pragma omp master
        {
#ifdef _OPENMP
            log("OpenMP multithreading enabled, likely number of threads to be used: %u\n", omp_get_num_threads());
#else
            log("OpenMP multithreading disabled\n");
#endif
        }
    }

#ifdef ARCUS
    if (stringcasecompare(argv[1], "connect") == 0)
    {
        connect();
    }
    else
#endif //ARCUS
    if (stringcasecompare(argv[1], "slice") == 0)
    {
        slice();
    }
    else if (stringcasecompare(argv[1], "help") == 0)
    {
        printHelp();
    }
    else
    {
        logError("Unknown command: %s\n", argv[1]);
        printCall();
        printHelp();
        exit(1);
    }

    if (!communication)
    {
        //No communication channel is open any more, so either:
        //- communication failed to connect, or
        //- the engine was called with an unknown command or a command that doesn't connect (like "help").
        //In either case, we don't want to slice.
        exit(0);
    }
    while (communication->hasSlice())
    {
        communication->sliceNext();
    }
}

} //Cura namespace.<commit_msg>Change the year, because we don't live in the past<commit_after>//Copyright (c) 2018 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.

#ifdef _OPENMP
    #include <omp.h> // omp_get_num_threads
#endif // _OPENMP
#include <string>
#include "Application.h"
#include "FffProcessor.h"
#include "communication/ArcusCommunication.h" //To connect via Arcus to the front-end.
#include "communication/CommandLine.h" //To use the command line to slice stuff.
#include "progress/Progress.h"
#include "utils/logoutput.h"
#include "utils/string.h" //For stringcasecompare.

namespace cura
{

Application::Application()
: communication(nullptr)
, current_slice(0)
{
}

Application::~Application()
{
    delete communication;
}

Application& Application::getInstance()
{
    static Application instance; //Constructs using the default constructor.
    return instance;
}

#ifdef ARCUS
void Application::connect()
{
    std::string ip = "127.0.0.1";
    int port = 49674;

    //Parse port number from IP address.
    std::string ip_port(argv[2]);
    std::size_t found_pos = ip_port.find(':');
    if (found_pos != std::string::npos)
    {
        ip = ip_port.substr(0, found_pos);
        port = std::stoi(ip_port.substr(found_pos + 1).data());
    }

#ifdef _OPENMP
    int n_threads;
#endif // _OPENMP

    for(size_t argn = 3; argn < argc; argn++)
    {
        char* str = argv[argn];
        if (str[0] == '-')
        {
            for(str++; *str; str++)
            {
                switch(*str)
                {
                case 'v':
                    increaseVerboseLevel();
                    break;
#ifdef _OPENMP
                case 'm':
                    str++;
                    n_threads = std::strtol(str, &str, 10);
                    str--;
                    n_threads = std::max(1, n_threads);
                    omp_set_num_threads(n_threads);
                    break;
#endif // _OPENMP
                default:
                    logError("Unknown option: %c\n", *str);
                    printCall();
                    printHelp();
                    break;
                }
            }
        }
    }

    ArcusCommunication* arcus_communication = new ArcusCommunication();
    arcus_communication->connect(ip, port);
    communication = arcus_communication;
}
#endif //ARCUS

void Application::printCall() const
{
    cura::logError("Command called:\n");
    for (size_t argument_index = 0; argument_index < argc; argument_index++)
    {
        cura::logError("%s ", argv[argument_index]);
    }
    cura::logError("\n");
}

void Application::printHelp() const
{
    logAlways("\n");
    logAlways("usage:\n");
    logAlways("CuraEngine help\n");
    logAlways("\tShow this help message\n");
    logAlways("\n");
#ifdef ARCUS
    logAlways("CuraEngine connect <host>[:<port>] [-j <settings.def.json>]\n");
    logAlways("  --connect <host>[:<port>]\n\tConnect to <host> via a command socket, \n\tinstead of passing information via the command line\n");
    logAlways("  -v\n\tIncrease the verbose level (show log messages).\n");
#ifdef _OPENMP
    logAlways("  -m<thread_count>\n\tSet the desired number of threads. Supports only a single digit.\n");
#endif // _OPENMP
    logAlways("\n");
#endif //ARCUS
    logAlways("CuraEngine slice [-v] [-p] [-j <settings.json>] [-s <settingkey>=<value>] [-g] [-e<extruder_nr>] [-o <output.gcode>] [-l <model.stl>] [--next]\n");
    logAlways("  -v\n\tIncrease the verbose level (show log messages).\n");
#ifdef _OPENMP
    logAlways("  -m<thread_count>\n\tSet the desired number of threads.\n");
#endif // _OPENMP
    logAlways("  -p\n\tLog progress information.\n");
    logAlways("  -j\n\tLoad settings.def.json file to register all settings and their defaults.\n");
    logAlways("  -s <setting>=<value>\n\tSet a setting to a value for the last supplied object, \n\textruder train, or general settings.\n");
    logAlways("  -l <model_file>\n\tLoad an STL model. \n");
    logAlways("  -g\n\tSwitch setting focus to the current mesh group only.\n\tUsed for one-at-a-time printing.\n");
    logAlways("  -e<extruder_nr>\n\tSwitch setting focus to the extruder train with the given number.\n");
    logAlways("  --next\n\tGenerate gcode for the previously supplied mesh group and append that to \n\tthe gcode of further models for one-at-a-time printing.\n");
    logAlways("  -o <output_file>\n\tSpecify a file to which to write the generated gcode.\n");
    logAlways("\n");
    logAlways("The settings are appended to the last supplied object:\n");
    logAlways("CuraEngine slice [general settings] \n\t-g [current group settings] \n\t-e0 [extruder train 0 settings] \n\t-l obj_inheriting_from_last_extruder_train.stl [object settings] \n\t--next [next group settings]\n\t... etc.\n");
    logAlways("\n");
    logAlways("In order to load machine definitions from custom locations, you need to create the environment variable CURA_ENGINE_SEARCH_PATH, which should contain all search paths delimited by a (semi-)colon.\n");
    logAlways("\n");
}

void Application::printLicense() const
{
    logAlways("\n");
    logAlways("Cura_SteamEngine version %s\n", VERSION);
    logAlways("Copyright (C) 2019 Ultimaker\n");
    logAlways("\n");
    logAlways("This program is free software: you can redistribute it and/or modify\n");
    logAlways("it under the terms of the GNU Affero General Public License as published by\n");
    logAlways("the Free Software Foundation, either version 3 of the License, or\n");
    logAlways("(at your option) any later version.\n");
    logAlways("\n");
    logAlways("This program is distributed in the hope that it will be useful,\n");
    logAlways("but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
    logAlways("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n");
    logAlways("GNU Affero General Public License for more details.\n");
    logAlways("\n");
    logAlways("You should have received a copy of the GNU Affero General Public License\n");
    logAlways("along with this program.  If not, see <http://www.gnu.org/licenses/>.\n");
}

void Application::slice()
{
    std::vector<std::string> arguments;
    for (size_t argument_index = 0; argument_index < argc; argument_index++)
    {
        arguments.emplace_back(argv[argument_index]);
    }

    communication = new CommandLine(arguments);
}

void Application::run(const size_t argc, char** argv)
{
    this->argc = argc;
    this->argv = argv;

    printLicense();
    Progress::init();

    if (argc < 2)
    {
        printHelp();
        exit(1);
    }

#pragma omp parallel
    {
#pragma omp master
        {
#ifdef _OPENMP
            log("OpenMP multithreading enabled, likely number of threads to be used: %u\n", omp_get_num_threads());
#else
            log("OpenMP multithreading disabled\n");
#endif
        }
    }

#ifdef ARCUS
    if (stringcasecompare(argv[1], "connect") == 0)
    {
        connect();
    }
    else
#endif //ARCUS
    if (stringcasecompare(argv[1], "slice") == 0)
    {
        slice();
    }
    else if (stringcasecompare(argv[1], "help") == 0)
    {
        printHelp();
    }
    else
    {
        logError("Unknown command: %s\n", argv[1]);
        printCall();
        printHelp();
        exit(1);
    }

    if (!communication)
    {
        //No communication channel is open any more, so either:
        //- communication failed to connect, or
        //- the engine was called with an unknown command or a command that doesn't connect (like "help").
        //In either case, we don't want to slice.
        exit(0);
    }
    while (communication->hasSlice())
    {
        communication->sliceNext();
    }
}

} //Cura namespace.<|endoftext|>


<commit_before>#include"../header/CThreadPool.h"
#include<memory>	//make_unique
#include<mutex>
#include<utility>	//move
#include<vector>
#include"../../lib/header/algorithm/algorithm.h"
using namespace std;

namespace nThread
{
	CThreadPool::CThreadPool(const size_t count)
		:mut_{new mutex()},size_{count},thr_{new CThreadPoolItem<void>[count]()}
	{
		nAlgorithm::for_each(thr_,thr_+count,[&](const auto p){
			p->setCommun(make_unique<CThreadPoolCommun>(p,join_anyList_,waitingQue_,id_++));
			waitingQue_.emplace(id_.get(),p);
		});
	}

	void CThreadPool::join_all()
	{
		nAlgorithm::for_each<size_t>(0,count(),[&](const auto i){
			if(joinable(i))
				join(i);
		});
	}

	size_t CThreadPool::join_any()
	{
		auto temp{join_anyList_.wait_and_pop()};
		const auto id{temp.first};
		temp.second->join();
		return id;
	}

	void CThreadPool::wait_until_all_available() const
	{
		lock_guard<mutex> lock{*mut_};
		vector<typename CThreadPoolCommun::pair> vec;
		vec.reserve(count());
		for(size_t i{0};i!=count();++i)
			vec.emplace_back(waitingQue_.wait_and_pop());
		for(auto &val:vec)
			waitingQue_.emplace(move(val));
	}

	CThreadPool::~CThreadPool()
	{
		delete []thr_;	//CThreadPoolItem is RAII, you don't have to call join_all()
		delete mut_;
	}
}<commit_msg>capture this<commit_after>#include"../header/CThreadPool.h"
#include<memory>	//make_unique
#include<mutex>
#include<utility>	//move
#include<vector>
#include"../../lib/header/algorithm/algorithm.h"
using namespace std;

namespace nThread
{
	CThreadPool::CThreadPool(const size_t count)
		:mut_{new mutex()},size_{count},thr_{new CThreadPoolItem<void>[count]()}
	{
		nAlgorithm::for_each(thr_,thr_+count,[&](const auto p){
			p->setCommun(make_unique<CThreadPoolCommun>(p,join_anyList_,waitingQue_,id_++));
			waitingQue_.emplace(id_.get(),p);
		});
	}

	void CThreadPool::join_all()
	{
		nAlgorithm::for_each<size_t>(0,count(),[this](const auto i){
			if(this->joinable(i))
				this->join(i);
		});
	}

	size_t CThreadPool::join_any()
	{
		auto temp{join_anyList_.wait_and_pop()};
		const auto id{temp.first};
		temp.second->join();
		return id;
	}

	void CThreadPool::wait_until_all_available() const
	{
		lock_guard<mutex> lock{*mut_};
		vector<typename CThreadPoolCommun::pair> vec;
		vec.reserve(count());
		for(size_t i{0};i!=count();++i)
			vec.emplace_back(waitingQue_.wait_and_pop());
		for(auto &val:vec)
			waitingQue_.emplace(move(val));
	}

	CThreadPool::~CThreadPool()
	{
		delete []thr_;	//CThreadPoolItem is RAII, you don't have to call join_all()
		delete mut_;
	}
}<|endoftext|>


<commit_before>#if defined(_MSC_VER)
#define _CRTDBG_MAP_ALLOC
#define _CRT_SECURE_NO_WARNINGS
#include <crtdbg.h>
#else
#include <fenv.h>
#endif

#include "CoolPropLib.h"
#include "CoolProp.h"
#include "HumidAirProp.h"
#include "DataStructures.h"
#include "Exceptions.h"
#include "float.h"

#include <string.h>

// In Microsoft Excel, they seem to check the FPU exception bits and error out because of it.
// By calling the _clearfp(), we can reset these bits, and not get the error
// See also http://stackoverflow.com/questions/11685441/floating-point-error-when-calling-dll-function-from-vba/27336496#27336496
// See also http://stackoverflow.com/questions/16849009/in-linux-do-there-exist-functions-similar-to-clearfp-and-statusfp for linux and OSX
void reset_fpu()
{
    #if defined(_MSC_VER)
        _clearfp(); // For MSVC, clear the floating point error flags
    #elif defined(FE_ALL_EXCEPT)
        feclearexcept(FE_ALL_EXCEPT);
    #endif
}
double convert_from_kSI_to_SI(long iInput, double value)
{
    if (get_debug_level() > 8){
        std::cout << format("%s:%d: convert_from_kSI_to_SI(i=%d,value=%g)\n",__FILE__,__LINE__,iInput,value).c_str();
    }

    switch (iInput)
    {
    case CoolProp::iP:
    case CoolProp::iCpmass:
    case CoolProp::iCp0mass:
    case CoolProp::iSmass:
    case CoolProp::iGmass:
    case CoolProp::iCvmass:
    case CoolProp::iHmass:
    case CoolProp::iUmass:
    case CoolProp::iconductivity:
        return value*1000.0;
    case CoolProp::iDmass:
    case CoolProp::ispeed_sound:
    case CoolProp::iQ:
    case CoolProp::iviscosity:
    case CoolProp::iT:
    case CoolProp::iPrandtl:
    case CoolProp::isurface_tension:
        return value;
    default:
        throw CoolProp::ValueError(format("index [%d] is invalid in convert_from_kSI_to_SI",iInput).c_str());
        break;
    }
    return _HUGE;
}

double convert_from_SI_to_kSI(long iInput, double value)
{
    if (get_debug_level() > 8){
        std::cout << format("%s:%d: convert_from_SI_to_kSI(%d,%g)\n",__FILE__,__LINE__,iInput,value).c_str();
    }

    switch (iInput)
    {
    case CoolProp::iP:
    case CoolProp::iCpmass:
    case CoolProp::iCp0mass:
    case CoolProp::iSmass:
    case CoolProp::iGmass:
    case CoolProp::iCvmass:
    case CoolProp::iHmass:
    case CoolProp::iUmass:
    case CoolProp::iconductivity:
        return value/1000.0;
    case CoolProp::iDmass:
    case CoolProp::iQ:
    case CoolProp::ispeed_sound:
    case CoolProp::iviscosity:
    case CoolProp::iT:
    case CoolProp::isurface_tension:
        return value;
    default:
        throw CoolProp::ValueError(format("index [%d] is invalid in convert_from_SI_to_kSI", iInput).c_str());
        break;
    }
    return _HUGE;
}

EXPORT_CODE long CONVENTION redirect_stdout(const char* file){
    freopen(file, "a+", stdout);
    reset_fpu();
    return 0;
}
EXPORT_CODE int CONVENTION set_reference_stateS(const char *Ref, const char *reference_state)
{
    std::string _Ref = Ref, _reference_state = reference_state;
    try{
        CoolProp::set_reference_stateS(_Ref, _reference_state);
        reset_fpu();
        return true;
    }
    catch(std::exception &){
        reset_fpu();
        return false;
    }
}
EXPORT_CODE int CONVENTION set_reference_stateD(const char *Ref, double T, double rho, double h0, double s0)
{
    try{
        CoolProp::set_reference_stateD(std::string(Ref), T, rho, h0, s0);
        reset_fpu();
        return true;
    }
    catch(std::exception &){
        reset_fpu();
        return false;
    }
}

// All the function interfaces that point to the single-input Props function
EXPORT_CODE double CONVENTION Props1(const char *FluidName, const char *Output){
    double val = PropsS(Output, "", 0, "", 0, FluidName);
    reset_fpu();
    return val;
}
EXPORT_CODE double CONVENTION PropsS(const char *Output, const char* Name1, double Prop1, const char* Name2, double Prop2, const char * Ref){
    double val = Props(Output,Name1[0],Prop1,Name2[0],Prop2,Ref);
    reset_fpu();
    return val;
}
EXPORT_CODE double CONVENTION Props(const char *Output, const char Name1, double Prop1, const char Name2, double Prop2, const char * Ref)
{
    try
    {
        // Get parameter indices
        std::string sName1 = std::string(1, Name1), sName2 = std::string(1, Name2);
        long iOutput = get_param_index(Output);
        long iName1 = CoolProp::get_parameter_index(sName1);
        long iName2 = CoolProp::get_parameter_index(sName2);

        // Convert inputs to SI
        Prop1 = convert_from_kSI_to_SI(iName1, Prop1);
        Prop2 = convert_from_kSI_to_SI(iName2, Prop2);

        // Call the SI function
        double val = PropsSI(Output, sName1.c_str(), Prop1, sName2.c_str(), Prop2, Ref);

        reset_fpu();

        // Convert back to unit system
        return convert_from_SI_to_kSI(iOutput, val);
    }
    catch(std::exception &e){CoolProp::set_error_string(e.what()); return _HUGE;}
    catch(...){CoolProp::set_error_string("Undefined error"); return _HUGE;}
}
EXPORT_CODE double CONVENTION saturation_ancillary(const char *fluid_name, const char *output, int Q, const char *input, double value)
{
    try
    {
        std::string _output = output, _input = input;
        double val = CoolProp::saturation_ancillary(fluid_name, _output, Q, _input, value);
        reset_fpu();
        return val;
    }
    catch(std::exception &e){CoolProp::set_error_string(e.what()); return _HUGE;}
    catch(...){CoolProp::set_error_string("Undefined error"); return _HUGE;}
}
EXPORT_CODE double CONVENTION Props1SI(const char *FluidName, const char *Output)
{
    std::string _Output = Output, _FluidName = FluidName;
    double val = CoolProp::Props1SI(_FluidName, _Output);
    reset_fpu();
    return val;
}
EXPORT_CODE double CONVENTION PropsSI(const char *Output, const char *Name1, double Prop1, const char *Name2, double Prop2, const char * FluidName)
{
    std::string _Output = Output, _Name1 = Name1, _Name2 = Name2, _FluidName = FluidName;
    double val = CoolProp::PropsSI(_Output, _Name1, Prop1, _Name2, Prop2, _FluidName);
    reset_fpu();
    return val;
}
EXPORT_CODE long CONVENTION PhaseSI(const char *Name1, double Prop1, const char *Name2, double Prop2, const char * FluidName, char *phase, int n)
{
    std::string _Name1 = Name1, _Name2 = Name2, _FluidName = FluidName;
    std::string s = CoolProp::PhaseSI(_Name1, Prop1, _Name2, Prop2, _FluidName);
    if (s.size() < static_cast<unsigned int>(n)){
        strcpy(phase, s.c_str());
        reset_fpu();
        return 1;
    }
    else{
        reset_fpu();
        return 0;
    }
}
/*
 * EXPORT_CODE double CONVENTION PropsSIZ(const char *Output, const char *Name1, double Prop1, const char *Name2, double Prop2, const char * FluidName, const double *z, int n)
{
    std::string _Output = Output, _Name1 = Name1, _Name2 = Name2, _FluidName = FluidName;
    double val = CoolProp::PropsSI(_Output, _Name1, Prop1, _Name2, Prop2, _FluidName, std::vector<double>(z, z+n));
    reset_fpu();
    return val;
}
 * */
EXPORT_CODE void CONVENTION propssi_(const char *Output, const char *Name1, double *Prop1, const char *Name2, double *Prop2, const char * FluidName, double *output)
{
    std::string _Output = Output, _Name1 = Name1, _Name2 = Name2, _FluidName = FluidName;
    *output = CoolProp::PropsSI(_Output, _Name1, *Prop1, _Name2, *Prop2, _FluidName);
    reset_fpu();
}

EXPORT_CODE double CONVENTION K2F(double T){
    return T * 9 / 5 - 459.67;
}
EXPORT_CODE double CONVENTION F2K(double T_F){
    return (T_F + 459.67) * 5 / 9;
}
EXPORT_CODE int CONVENTION get_debug_level(){
    return CoolProp::get_debug_level();
}
EXPORT_CODE void CONVENTION set_debug_level(int level){
    CoolProp::set_debug_level(level);
}
EXPORT_CODE long CONVENTION get_param_index(const char * param){
    try{
        return CoolProp::get_parameter_index(param);
    }
    catch(std::exception &){
        return -1;
    }
}
EXPORT_CODE long CONVENTION get_global_param_string(const char *param, char * Output, int n)
{
    std::string s;
    try{
        s = CoolProp::get_global_param_string(param);
    }
    catch(std::exception &){
        return 0;
    }
    if (s.size() < static_cast<unsigned int>(n)){
        strcpy(Output, s.c_str());
        return 1;
    }
    else{
        return 0;
    }
}
EXPORT_CODE long CONVENTION get_parameter_information_string(const char *param, char * Output, int n)
{
    int key;
    try{
        key = CoolProp::get_parameter_index(param);
    }
    catch(std::exception &){
        return 0;
    }
    if (key >= 0){
        std::string s = CoolProp::get_parameter_information(key, Output);
        if (s.size() < static_cast<unsigned int>(n)){
            strcpy(Output, s.c_str());
            return 1;
        }
        else{
            return 0;
        }
    }
    else{
        strcpy(Output, format("parameter is invalid: %s", param).c_str());
        return 0;
    }
}
EXPORT_CODE long CONVENTION get_fluid_param_string(const char *fluid, const char *param, char * Output, int n)
{
    std::string s;
    try{
        s = CoolProp::get_fluid_param_string(std::string(fluid), std::string(param));
    }
    catch(std::exception &){
        return 0;
    }
    if (s.size() < static_cast<unsigned int>(n)){
        strcpy(Output, s.c_str());
        return 1;
    }
    else{
        return 0;
    }
}
EXPORT_CODE double CONVENTION HAPropsSI(const char *Output, const char *Name1, double Prop1, const char *Name2, double Prop2, const char * Name3, double Prop3)
{
    std::string _Output = Output, _Name1 = Name1, _Name2 = Name2, _Name3 = Name3;
    double val = HumidAir::HAPropsSI(Output, _Name1, Prop1, _Name2, Prop2, _Name3, Prop3);
    reset_fpu();
    return val;
}
EXPORT_CODE void CONVENTION hapropssi_(const char *Output, const char *Name1, double *Prop1, const char *Name2, double *Prop2, const char * Name3, double * Prop3, double *output)
{
    std::string _Output = Output, _Name1 = Name1, _Name2 = Name2, _Name3 = Name3;
    *output = HumidAir::HAPropsSI(_Output, _Name1, *Prop1, _Name2, *Prop2, _Name3, *Prop3);
    reset_fpu();
}
EXPORT_CODE double CONVENTION HAProps(const char *Output, const char *Name1, double Prop1, const char *Name2, double Prop2, const char * Name3, double Prop3)
{
    std::string _Output = Output, _Name1 = Name1, _Name2 = Name2, _Name3 = Name3;
    double val = HumidAir::HAProps(Output, _Name1, Prop1, _Name2, Prop2, _Name3, Prop3);
    reset_fpu();
    return val;
}
EXPORT_CODE void CONVENTION haprops_(const char *Output, const char *Name1, double *Prop1, const char *Name2, double *Prop2, const char * Name3, double * Prop3, double *output)
{
    *output = HAProps(Output, Name1, *Prop1, Name2, *Prop2, Name3, *Prop3);
    reset_fpu();
}
<commit_msg>Fix potential buffer overflow; fixed #472<commit_after>#if defined(_MSC_VER)
#define _CRTDBG_MAP_ALLOC
#define _CRT_SECURE_NO_WARNINGS
#include <crtdbg.h>
#else
#include <fenv.h>
#endif

#include "CoolPropLib.h"
#include "CoolProp.h"
#include "HumidAirProp.h"
#include "DataStructures.h"
#include "Exceptions.h"
#include "float.h"

#include <string.h>

bool str2buf(const std::string& str, char * buf, int n)
{
  if (str.size() < static_cast<unsigned int>(n)) {
    strcpy(buf, str.c_str());
    return true;
  }
  return false;
}

// In Microsoft Excel, they seem to check the FPU exception bits and error out because of it.
// By calling the _clearfp(), we can reset these bits, and not get the error
// See also http://stackoverflow.com/questions/11685441/floating-point-error-when-calling-dll-function-from-vba/27336496#27336496
// See also http://stackoverflow.com/questions/16849009/in-linux-do-there-exist-functions-similar-to-clearfp-and-statusfp for linux and OSX
void reset_fpu()
{
    #if defined(_MSC_VER)
        _clearfp(); // For MSVC, clear the floating point error flags
    #elif defined(FE_ALL_EXCEPT)
        feclearexcept(FE_ALL_EXCEPT);
    #endif
}
double convert_from_kSI_to_SI(long iInput, double value)
{
    if (get_debug_level() > 8){
        std::cout << format("%s:%d: convert_from_kSI_to_SI(i=%d,value=%g)\n",__FILE__,__LINE__,iInput,value).c_str();
    }

    switch (iInput)
    {
    case CoolProp::iP:
    case CoolProp::iCpmass:
    case CoolProp::iCp0mass:
    case CoolProp::iSmass:
    case CoolProp::iGmass:
    case CoolProp::iCvmass:
    case CoolProp::iHmass:
    case CoolProp::iUmass:
    case CoolProp::iconductivity:
        return value*1000.0;
    case CoolProp::iDmass:
    case CoolProp::ispeed_sound:
    case CoolProp::iQ:
    case CoolProp::iviscosity:
    case CoolProp::iT:
    case CoolProp::iPrandtl:
    case CoolProp::isurface_tension:
        return value;
    default:
        throw CoolProp::ValueError(format("index [%d] is invalid in convert_from_kSI_to_SI",iInput).c_str());
        break;
    }
    return _HUGE;
}

double convert_from_SI_to_kSI(long iInput, double value)
{
    if (get_debug_level() > 8){
        std::cout << format("%s:%d: convert_from_SI_to_kSI(%d,%g)\n",__FILE__,__LINE__,iInput,value).c_str();
    }

    switch (iInput)
    {
    case CoolProp::iP:
    case CoolProp::iCpmass:
    case CoolProp::iCp0mass:
    case CoolProp::iSmass:
    case CoolProp::iGmass:
    case CoolProp::iCvmass:
    case CoolProp::iHmass:
    case CoolProp::iUmass:
    case CoolProp::iconductivity:
        return value/1000.0;
    case CoolProp::iDmass:
    case CoolProp::iQ:
    case CoolProp::ispeed_sound:
    case CoolProp::iviscosity:
    case CoolProp::iT:
    case CoolProp::isurface_tension:
        return value;
    default:
        throw CoolProp::ValueError(format("index [%d] is invalid in convert_from_SI_to_kSI", iInput).c_str());
        break;
    }
    return _HUGE;
}

EXPORT_CODE long CONVENTION redirect_stdout(const char* file){
    freopen(file, "a+", stdout);
    reset_fpu();
    return 0;
}
EXPORT_CODE int CONVENTION set_reference_stateS(const char *Ref, const char *reference_state)
{
    std::string _Ref = Ref, _reference_state = reference_state;
    try{
        CoolProp::set_reference_stateS(_Ref, _reference_state);
        reset_fpu();
        return true;
    }
    catch(std::exception &){
        reset_fpu();
        return false;
    }
}
EXPORT_CODE int CONVENTION set_reference_stateD(const char *Ref, double T, double rho, double h0, double s0)
{
    try{
        CoolProp::set_reference_stateD(std::string(Ref), T, rho, h0, s0);
        reset_fpu();
        return true;
    }
    catch(std::exception &){
        reset_fpu();
        return false;
    }
}

// All the function interfaces that point to the single-input Props function
EXPORT_CODE double CONVENTION Props1(const char *FluidName, const char *Output){
    double val = PropsS(Output, "", 0, "", 0, FluidName);
    reset_fpu();
    return val;
}
EXPORT_CODE double CONVENTION PropsS(const char *Output, const char* Name1, double Prop1, const char* Name2, double Prop2, const char * Ref){
    double val = Props(Output,Name1[0],Prop1,Name2[0],Prop2,Ref);
    reset_fpu();
    return val;
}
EXPORT_CODE double CONVENTION Props(const char *Output, const char Name1, double Prop1, const char Name2, double Prop2, const char * Ref)
{
    try
    {
        // Get parameter indices
        std::string sName1 = std::string(1, Name1), sName2 = std::string(1, Name2);
        long iOutput = get_param_index(Output);
        long iName1 = CoolProp::get_parameter_index(sName1);
        long iName2 = CoolProp::get_parameter_index(sName2);

        // Convert inputs to SI
        Prop1 = convert_from_kSI_to_SI(iName1, Prop1);
        Prop2 = convert_from_kSI_to_SI(iName2, Prop2);

        // Call the SI function
        double val = PropsSI(Output, sName1.c_str(), Prop1, sName2.c_str(), Prop2, Ref);

        reset_fpu();

        // Convert back to unit system
        return convert_from_SI_to_kSI(iOutput, val);
    }
    catch(std::exception &e){CoolProp::set_error_string(e.what()); return _HUGE;}
    catch(...){CoolProp::set_error_string("Undefined error"); return _HUGE;}
}
EXPORT_CODE double CONVENTION saturation_ancillary(const char *fluid_name, const char *output, int Q, const char *input, double value)
{
    try
    {
        std::string _output = output, _input = input;
        double val = CoolProp::saturation_ancillary(fluid_name, _output, Q, _input, value);
        reset_fpu();
        return val;
    }
    catch(std::exception &e){CoolProp::set_error_string(e.what()); return _HUGE;}
    catch(...){CoolProp::set_error_string("Undefined error"); return _HUGE;}
}
EXPORT_CODE double CONVENTION Props1SI(const char *FluidName, const char *Output)
{
    std::string _Output = Output, _FluidName = FluidName;
    double val = CoolProp::Props1SI(_FluidName, _Output);
    reset_fpu();
    return val;
}
EXPORT_CODE double CONVENTION PropsSI(const char *Output, const char *Name1, double Prop1, const char *Name2, double Prop2, const char * FluidName)
{
    std::string _Output = Output, _Name1 = Name1, _Name2 = Name2, _FluidName = FluidName;
    double val = CoolProp::PropsSI(_Output, _Name1, Prop1, _Name2, Prop2, _FluidName);
    reset_fpu();
    return val;
}
EXPORT_CODE long CONVENTION PhaseSI(const char *Name1, double Prop1, const char *Name2, double Prop2, const char * FluidName, char *phase, int n)
{
    std::string _Name1 = Name1, _Name2 = Name2, _FluidName = FluidName;
    std::string s = CoolProp::PhaseSI(_Name1, Prop1, _Name2, Prop2, _FluidName);
    if (s.size() < static_cast<unsigned int>(n)){
        strcpy(phase, s.c_str());
        reset_fpu();
        return 1;
    }
    else{
        reset_fpu();
        return 0;
    }
}
/*
 * EXPORT_CODE double CONVENTION PropsSIZ(const char *Output, const char *Name1, double Prop1, const char *Name2, double Prop2, const char * FluidName, const double *z, int n)
{
    std::string _Output = Output, _Name1 = Name1, _Name2 = Name2, _FluidName = FluidName;
    double val = CoolProp::PropsSI(_Output, _Name1, Prop1, _Name2, Prop2, _FluidName, std::vector<double>(z, z+n));
    reset_fpu();
    return val;
}
 * */
EXPORT_CODE void CONVENTION propssi_(const char *Output, const char *Name1, double *Prop1, const char *Name2, double *Prop2, const char * FluidName, double *output)
{
    std::string _Output = Output, _Name1 = Name1, _Name2 = Name2, _FluidName = FluidName;
    *output = CoolProp::PropsSI(_Output, _Name1, *Prop1, _Name2, *Prop2, _FluidName);
    reset_fpu();
}

EXPORT_CODE double CONVENTION K2F(double T){
    return T * 9 / 5 - 459.67;
}
EXPORT_CODE double CONVENTION F2K(double T_F){
    return (T_F + 459.67) * 5 / 9;
}
EXPORT_CODE int CONVENTION get_debug_level(){
    return CoolProp::get_debug_level();
}
EXPORT_CODE void CONVENTION set_debug_level(int level){
    CoolProp::set_debug_level(level);
}
EXPORT_CODE long CONVENTION get_param_index(const char * param){
    try{
        return CoolProp::get_parameter_index(param);
    }
    catch(std::exception &){
        return -1;
    }
}
EXPORT_CODE long CONVENTION get_global_param_string(const char *param, char * Output, int n)
{
    std::string s;
    try{
        s = CoolProp::get_global_param_string(param);
    }
    catch(std::exception &){
        return 0;
    }
    if (s.size() < static_cast<unsigned int>(n)){
        strcpy(Output, s.c_str());
        return 1;
    }
    else{
        return 0;
    }
}
EXPORT_CODE long CONVENTION get_parameter_information_string(const char *param, char * Output, int n)
{
    int key;
    try{
        key = CoolProp::get_parameter_index(param);
    }
    catch(std::exception &){
        return 0;
    }
    if (key >= 0){
        std::string s = CoolProp::get_parameter_information(key, Output);
        return str2buf(s, Output, n) ? 1 : 0;
    }
    else{
        str2buf(format("parameter is invalid: %s", param), Output, n);
        return 0;
    }
}
EXPORT_CODE long CONVENTION get_fluid_param_string(const char *fluid, const char *param, char * Output, int n)
{
    std::string s;
    try{
        s = CoolProp::get_fluid_param_string(std::string(fluid), std::string(param));
    }
    catch(std::exception &){
        return 0;
    }
    if (s.size() < static_cast<unsigned int>(n)){
        strcpy(Output, s.c_str());
        return 1;
    }
    else{
        return 0;
    }
}
EXPORT_CODE double CONVENTION HAPropsSI(const char *Output, const char *Name1, double Prop1, const char *Name2, double Prop2, const char * Name3, double Prop3)
{
    std::string _Output = Output, _Name1 = Name1, _Name2 = Name2, _Name3 = Name3;
    double val = HumidAir::HAPropsSI(Output, _Name1, Prop1, _Name2, Prop2, _Name3, Prop3);
    reset_fpu();
    return val;
}
EXPORT_CODE void CONVENTION hapropssi_(const char *Output, const char *Name1, double *Prop1, const char *Name2, double *Prop2, const char * Name3, double * Prop3, double *output)
{
    std::string _Output = Output, _Name1 = Name1, _Name2 = Name2, _Name3 = Name3;
    *output = HumidAir::HAPropsSI(_Output, _Name1, *Prop1, _Name2, *Prop2, _Name3, *Prop3);
    reset_fpu();
}
EXPORT_CODE double CONVENTION HAProps(const char *Output, const char *Name1, double Prop1, const char *Name2, double Prop2, const char * Name3, double Prop3)
{
    std::string _Output = Output, _Name1 = Name1, _Name2 = Name2, _Name3 = Name3;
    double val = HumidAir::HAProps(Output, _Name1, Prop1, _Name2, Prop2, _Name3, Prop3);
    reset_fpu();
    return val;
}
EXPORT_CODE void CONVENTION haprops_(const char *Output, const char *Name1, double *Prop1, const char *Name2, double *Prop2, const char * Name3, double * Prop3, double *output)
{
    *output = HAProps(Output, Name1, *Prop1, Name2, *Prop2, Name3, *Prop3);
    reset_fpu();
}
<|endoftext|>


<commit_before>/*
 * Copyright 2012-2013 Falltergeist Developers.
 *
 * This file is part of Falltergeist.
 *
 * Falltergeist is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Falltergeist 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 Falltergeist.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <string.h>
#include "../src/DatFileItem.h"
#include "../src/DatFile.h"
#include <algorithm>
#include <zlib.h>

namespace libfalltergeist
{

DatFileItem::DatFileItem(DatFile * datFile): _datFile(datFile)
{
    _data = 0;
    _filename = 0;
    _dataOffset = 0;
    _unpackedSize = 0;
    _packedSize = 0;
    _isCompressed = false;
    _initialized = false;
    _position = 0;
}

DatFileItem::~DatFileItem()
{
    delete [] _data;
    delete [] _filename;
}

/**
 * Sets filename with path
 * @brief DatFileItem::setFilename
 * @param filename
 */
void DatFileItem::setFilename(char * filename)
{
    if (_filename != 0) delete [] _filename;

    // convert to lowercase and replace slashes
    std::string fname(filename);
    std::replace(fname.begin(),fname.end(),'\\','/');
    std::transform(fname.begin(),fname.end(),fname.begin(), ::tolower);

    _filename = new char[strlen(fname.c_str()) + 1]();
    strcpy(_filename, fname.c_str());
}

/**
 * Returns filename with path
 * @brief DatFileItem::getFilename
 */
char * DatFileItem::getFilename()
{
    return _filename;
}

unsigned int DatFileItem::getDataOffset()
{
    return _dataOffset;
}

void DatFileItem::setDataOffset(unsigned int offset)
{
    _dataOffset = offset;
}

unsigned int DatFileItem::getUnpackedSize()
{
    return _unpackedSize;
}

void DatFileItem::setUnpackedSize(unsigned int size)
{
    _unpackedSize = size;
}

unsigned int DatFileItem::getPackedSize()
{
    return _packedSize;
}

void DatFileItem::setPackedSize(unsigned int size)
{
    _packedSize = size;
}

void DatFileItem::setIsCompressed(bool compressed)
{
    _isCompressed = compressed;
}

bool DatFileItem::isCompressed()
{
    return _isCompressed;
}

unsigned int DatFileItem::readUint32()
{
    _init();
    unsigned int pos = getPosition();
    unsigned int value = (_data[pos] << 24) | (_data[pos+ 1] << 16) | (_data[pos + 2] << 8) | _data[pos + 3];
    setPosition(pos + 4);
    return value;
}

int DatFileItem::readInt32()
{
    return (int) readUint32();
}

unsigned short DatFileItem::readUint16()
{
    _init();
    unsigned int pos = getPosition();
    unsigned short value = (_data[pos] << 8) | _data[pos+ 1];
    setPosition(pos + 2);
    return value;
}

short DatFileItem::readInt16()
{
    return (short) readUint16();
}

unsigned char DatFileItem::readUint8()
{
    _init();
    unsigned int pos = getPosition();
    unsigned char value = _data[pos];
    setPosition(pos + 1);
    return value;
}

char DatFileItem::readInt8()
{
    return (char) readUint8();
}

unsigned int DatFileItem::size()
{
    return getUnpackedSize();
}

void DatFileItem::setPosition(unsigned int position)
{
    _position = position;
}

unsigned int DatFileItem::getPosition()
{
    return _position;
}

void DatFileItem::_init()
{
    if (_initialized) return;

    _data = new char[getUnpackedSize()]();

    if (isCompressed())
    {
        char * packedData = new char[getPackedSize()]();
        _datFile->readBytes(packedData, getPackedSize());

        // unpacking
        z_stream zStream;
        zStream.total_in  = zStream.avail_in  = getPackedSize();
        zStream.avail_in = getPackedSize();
        zStream.next_in  = (unsigned char *) packedData;
        zStream.total_out = zStream.avail_out = getUnpackedSize();
        zStream.next_out = (unsigned char *) _data;
        zStream.zalloc = Z_NULL;
        zStream.zfree = Z_NULL;
        zStream.opaque = Z_NULL;
        inflateInit( &zStream );            // zlib function
        inflate( &zStream, Z_FINISH );      // zlib function
        inflateEnd( &zStream );             // zlib function

        delete [] packedData;
    }
    else
    {
        // just copying from dat file
        _datFile->setPosition(getDataOffset());
        _datFile->readBytes(_data, getUnpackedSize());
    }
    _initialized = true;
}

void DatFileItem::skipBytes(unsigned int numberOfBytes)
{
    setPosition(getPosition() + numberOfBytes);
}

void DatFileItem::readBytes(char * destination, unsigned int numberOfBytes)
{
    memcpy(destination, _data + getPosition(), numberOfBytes);
    setPosition(getPosition() + numberOfBytes);
}

}
<commit_msg>readBytes error fixed<commit_after>/*
 * Copyright 2012-2013 Falltergeist Developers.
 *
 * This file is part of Falltergeist.
 *
 * Falltergeist is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Falltergeist 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 Falltergeist.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <string.h>
#include "../src/DatFileItem.h"
#include "../src/DatFile.h"
#include <algorithm>
#include <zlib.h>
#include <iostream>

namespace libfalltergeist
{

DatFileItem::DatFileItem(DatFile * datFile): _datFile(datFile)
{
    _data = 0;
    _filename = 0;
    _dataOffset = 0;
    _unpackedSize = 0;
    _packedSize = 0;
    _isCompressed = false;
    _initialized = false;
    _position = 0;
}

DatFileItem::~DatFileItem()
{
    delete [] _data;
    delete [] _filename;
}

/**
 * Sets filename with path
 * @brief DatFileItem::setFilename
 * @param filename
 */
void DatFileItem::setFilename(char * filename)
{
    if (_filename != 0) delete [] _filename;

    // convert to lowercase and replace slashes
    std::string fname(filename);
    std::replace(fname.begin(),fname.end(),'\\','/');
    std::transform(fname.begin(),fname.end(),fname.begin(), ::tolower);

    _filename = new char[strlen(fname.c_str()) + 1]();
    strcpy(_filename, fname.c_str());
}

/**
 * Returns filename with path
 * @brief DatFileItem::getFilename
 */
char * DatFileItem::getFilename()
{
    return _filename;
}

unsigned int DatFileItem::getDataOffset()
{
    return _dataOffset;
}

void DatFileItem::setDataOffset(unsigned int offset)
{
    _dataOffset = offset;
}

unsigned int DatFileItem::getUnpackedSize()
{
    return _unpackedSize;
}

void DatFileItem::setUnpackedSize(unsigned int size)
{
    _unpackedSize = size;
}

unsigned int DatFileItem::getPackedSize()
{
    return _packedSize;
}

void DatFileItem::setPackedSize(unsigned int size)
{
    _packedSize = size;
}

void DatFileItem::setIsCompressed(bool compressed)
{
    _isCompressed = compressed;
}

bool DatFileItem::isCompressed()
{
    return _isCompressed;
}

unsigned int DatFileItem::readUint32()
{
    _init();
    unsigned int pos = getPosition();
    unsigned int value = (_data[pos] << 24) | (_data[pos+ 1] << 16) | (_data[pos + 2] << 8) | _data[pos + 3];
    setPosition(pos + 4);
    return value;
}

int DatFileItem::readInt32()
{
    return (int) readUint32();
}

unsigned short DatFileItem::readUint16()
{
    _init();
    unsigned int pos = getPosition();
    unsigned short value = (_data[pos] << 8) | _data[pos+ 1];
    setPosition(pos + 2);
    return value;
}

short DatFileItem::readInt16()
{
    return (short) readUint16();
}

unsigned char DatFileItem::readUint8()
{
    _init();
    unsigned int pos = getPosition();
    unsigned char value = _data[pos];
    setPosition(pos + 1);
    return value;
}

char DatFileItem::readInt8()
{
    return (char) readUint8();
}

unsigned int DatFileItem::size()
{
    return getUnpackedSize();
}

void DatFileItem::setPosition(unsigned int position)
{
    _position = position;
}

unsigned int DatFileItem::getPosition()
{
    return _position;
}

void DatFileItem::_init()
{
    if (_initialized) return;

    _data = new char[getUnpackedSize()]();
    _datFile->setPosition(getDataOffset());

    if (isCompressed())
    {
        char * packedData = new char[getPackedSize()]();
        _datFile->readBytes(packedData, getPackedSize());

        // unpacking
        z_stream zStream;
        zStream.total_in  = zStream.avail_in  = getPackedSize();
        zStream.avail_in = getPackedSize();
        zStream.next_in  = (unsigned char *) packedData;
        zStream.total_out = zStream.avail_out = getUnpackedSize();
        zStream.next_out = (unsigned char *) _data;
        zStream.zalloc = Z_NULL;
        zStream.zfree = Z_NULL;
        zStream.opaque = Z_NULL;
        inflateInit( &zStream );            // zlib function
        inflate( &zStream, Z_FINISH );      // zlib function
        inflateEnd( &zStream );             // zlib function

        delete [] packedData;
    }
    else
    {
        // just copying from dat file
        _datFile->readBytes(_data, getUnpackedSize());
    }
    _initialized = true;
}

void DatFileItem::skipBytes(unsigned int numberOfBytes)
{
    setPosition(getPosition() + numberOfBytes);
}

void DatFileItem::readBytes(char * destination, unsigned int numberOfBytes)
{
    _init();
    memcpy(destination, _data + getPosition(), numberOfBytes);
    setPosition(getPosition() + numberOfBytes);
}

}
<|endoftext|>