<commit_before>/*
 *            Copyright 2009-2017 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/gwbse.h>

#include <boost/format.hpp>
#include <boost/filesystem.hpp>
#include <boost/numeric/ublas/operation.hpp>
#include <votca/xtp/aomatrix.h>
#include <votca/xtp/threecenters.h>
// #include <votca/xtp/logger.h>
#include <votca/xtp/qmpackagefactory.h>
#include <boost/math/constants/constants.hpp>
#include <boost/numeric/ublas/symmetric.hpp>
#include <votca/xtp/aoshell.h>

using boost::format;
using namespace boost::filesystem;

namespace votca {
    namespace xtp {
        namespace ub = boost::numeric::ublas;

        void GWBSE::PPM_construct_parameters(const ub::matrix<double>& _overlap_cholesky_inverse) {

            // multiply with L-1^t from the right

            ub::matrix<double> _temp = ub::prod(_epsilon[0], ub::trans(_overlap_cholesky_inverse));
            // multiply with L-1 from the left

            _temp = ub::prod(_overlap_cholesky_inverse, _temp);

            // get eigenvalues and eigenvectors of this matrix
            ub::vector<double> _eigenvalues;
            ub::matrix<double> _eigenvectors;

            linalg_eigenvalues(_temp, _eigenvalues, _eigenvectors);
            _eigenvectors=ub::trans(_eigenvectors);
            // multiply eigenvectors with overlap_cholesky_inverse and store as eigenvalues of epsilon
            _ppm_phi = ub::prod(_eigenvectors, _overlap_cholesky_inverse);

            // store PPM weights from eigenvalues
            _ppm_weight.resize(_eigenvalues.size());
            for (unsigned _i = 0; _i < _eigenvalues.size(); _i++) {
                _ppm_weight(_i) = 1.0 - 1.0 / _eigenvalues(_i);
            }

            // determine PPM frequencies
            _ppm_freq.resize(_eigenvalues.size());
            // a) phi^t * epsilon(1) * phi

            _temp = ub::prod(_ppm_phi, _epsilon[1]);

            _eigenvectors = ub::prod(_temp, ub::trans(_ppm_phi));
            // b) invert

            linalg_invert(_eigenvectors, _temp);
            // c) PPM parameters -> diagonal elements

            #pragma omp parallel for
            for (unsigned _i = 0; _i < _eigenvalues.size(); _i++) {

                if (_screening_freq(1, 0) == 0.0) {
                    if (_ppm_weight(_i) < 1.e-5) {
                        _ppm_weight(_i) = 0.0;
                        _ppm_freq(_i) = 0.5;//Hartree
                        continue;
                    } else {
                        double _nom = _temp(_i, _i) - 1.0;
                        double _frac = -1.0 * _nom / (_nom + _ppm_weight(_i)) * _screening_freq(1, 1) * _screening_freq(1, 1);
                        _ppm_freq(_i) = sqrt(std::abs(_frac));
                    }

                } else {
                    // only purely imaginary frequency assumed
                    cerr << " mixed frequency! real part: " << _screening_freq(1, 0) << " imaginary part: " << _screening_freq(1, 1) << flush;
                    exit(1);
                }

            }

            // epsilon can be deleted
            _epsilon[0].resize(0, 0);
            _epsilon[1].resize(0, 0);

            return;
        }

        //imaginary
        ub::matrix<double> GWBSE::RPA_imaginary(const TCMatrix& _Mmn_RPA,const double screening_freq) {
            const int _size = _Mmn_RPA.get_beta(); // size of gwbasis
            const int index_n = _Mmn_RPA.get_nmin();
            const int index_m = _Mmn_RPA.get_mmin();
            const double screenf2=screening_freq * screening_freq;

            std::vector<ub::matrix<double> > result_thread;
            unsigned nthreads = 1;
            #ifdef _OPENMP
               nthreads = omp_get_max_threads();
            #endif
            const ub::vector<double>& qp_energies=   _qp_energies;

            for(unsigned i=0;i<nthreads;++i){
                result_thread.push_back(ub::zero_matrix<double>(_size));
            }

            #pragma omp parallel for
            for(unsigned thread=0;thread<nthreads;++thread){
            for (int _m_level = thread; _m_level < _Mmn_RPA.get_mtot(); _m_level+=nthreads) {
                const double _qp_energy_m=qp_energies(_m_level + index_m);
#if (GWBSE_DOUBLE)
                const ub::matrix<double>& Mmn_RPA = _Mmn_RPA[ _m_level ];
#else
                const ub::matrix<double> Mmn_RPA = _Mmn_RPA[ _m_level ];
#endif
                // a temporary matrix, that will get filled in empty levels loop
                ub::matrix<double> _temp = ub::matrix<double>(_Mmn_RPA.get_ntot(), _size);

                // loop over empty levels
                for (int _n_level = 0; _n_level < _Mmn_RPA.get_ntot(); _n_level++) {

                    const double _deltaE = qp_energies(_n_level + index_n) -_qp_energy_m ; // get indices and units right!!!

                    // this only works, if we have either purely real or purely imaginary frequencies

                    // purely imaginary
                    const double _energy_factor = 4.0 * _deltaE / (_deltaE * _deltaE + screenf2);//hartree
                    for (int _i_gw = 0; _i_gw < _size; _i_gw++) {
                        _temp(_n_level, _i_gw) = _energy_factor * Mmn_RPA(_i_gw, _n_level);
                    } // matrix size

                } // empty levels

                // now multiply and add to epsilon
                result_thread[thread] += ub::prod(Mmn_RPA, _temp);
            } // occupied levels
            }
            ub::matrix<double> result=ub::zero_matrix<double>(_size);
               for(unsigned thread=0;thread<nthreads;++thread){
                   result+=result_thread[thread];
               }
            return result;
        }
        //real

        ub::matrix<double> GWBSE::RPA_real(const TCMatrix& _Mmn_RPA, const double screening_freq) {
            const int _size = _Mmn_RPA.get_beta(); // size of gwbasis
            const int index_n = _Mmn_RPA.get_nmin();
            const int index_m = _Mmn_RPA.get_mmin();
            const ub::vector<double>& qp_energies=   _qp_energies;

            std::vector<ub::matrix<double> > result_thread;
            unsigned nthreads = 1;
            #ifdef _OPENMP
               nthreads = omp_get_max_threads();
            #endif

            for(unsigned i=0;i<nthreads;++i){
                result_thread.push_back(ub::zero_matrix<double>(_size));
            }

            #pragma omp parallel for
            for(unsigned thread=0;thread<nthreads;++thread){
            for (int _m_level = thread; _m_level < _Mmn_RPA.get_mtot(); _m_level+=nthreads) {
                const double _qp_energy_m=qp_energies(_m_level + index_m);

#if (GWBSE_DOUBLE)
                const ub::matrix<double>& Mmn_RPA = _Mmn_RPA[ _m_level ];
#else
                const ub::matrix<double> Mmn_RPA = _Mmn_RPA[ _m_level ];
#endif

                // a temporary matrix, that will get filled in empty levels loop
                ub::matrix<double> _temp = ub::matrix<double>(_Mmn_RPA.get_ntot(), _size);

                // loop over empty levels
                for (int _n_level = 0; _n_level < _Mmn_RPA.get_ntot(); _n_level++) {

                    const double _deltaE = qp_energies(_n_level + index_n) - _qp_energy_m; // get indices and units right!!!

                    // this only works, if we have either purely real or purely imaginary frequencies

                    // purely real
                    const double _energy_factor =2.0*  (1.0 / (_deltaE - screening_freq) + 1.0 / (_deltaE + screening_freq));//hartree

                    for (int _i_gw = 0; _i_gw < _size; _i_gw++) {
                        _temp(_n_level, _i_gw) = _energy_factor * Mmn_RPA(_i_gw, _n_level);
                    } // matrix size

                } // empty levels

                // now multiply and add to epsilon

                result_thread[thread] += ub::prod(Mmn_RPA, _temp);

            } // occupied levels
            }
               ub::matrix<double> result=ub::zero_matrix<double>(_size);
               for(unsigned thread=0;thread<nthreads;++thread){
                   result+=result_thread[thread];
               }

            return result;
        }

    void GWBSE::RPA_calculate_epsilon(const TCMatrix& _Mmn_RPA){

        // loop over frequencies
        for ( unsigned _i_freq = 0 ; _i_freq < _screening_freq.size1() ; _i_freq++ ){

             if ( _screening_freq( _i_freq, 0) == 0.0 ) {
                 _epsilon[ _i_freq ]+=RPA_imaginary(_Mmn_RPA, _screening_freq( _i_freq, 1));
             }

             else if ( _screening_freq( _i_freq, 1) == 0.0  ) {
                  // purely real
                 _epsilon[ _i_freq ]+= RPA_real(_Mmn_RPA, _screening_freq( _i_freq, 0));
                    }
             else {
                    // mixed -> FAIL
                    cerr << " mixed frequency! real part: " << _screening_freq( _i_freq, 0 ) << " imaginary part: "  << _screening_freq( _i_freq, 1 ) << flush;
                    exit(1);
                    }

        } // loop over frequencies

        return;
    }

    void GWBSE::RPA_prepare_threecenters(TCMatrix& _Mmn_RPA,const TCMatrix& _Mmn_full){

        ub::range full=ub::range(0, _Mmn_full.get_beta());
        ub::range RPA_cut=ub::range(_Mmn_RPA.get_nmin() - _Mmn_full.get_nmin(), _Mmn_RPA.get_nmax() - _Mmn_full.get_nmin() + 1);
            // loop over m-levels in _Mmn_RPA
            #pragma omp parallel for
            for (int _m_level = 0; _m_level < _Mmn_RPA.size(); _m_level++) {

                // copy to _Mmn_RPA
                _Mmn_RPA[ _m_level ] = ub::project(_Mmn_full[ _m_level ], full, RPA_cut);

            }// loop m-levels
     return;
    }

}};
<commit_msg>rewrote RPA to old stuff again<commit_after>/*
 *            Copyright 2009-2017 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/gwbse.h>

#include <boost/format.hpp>
#include <boost/filesystem.hpp>
#include <boost/numeric/ublas/operation.hpp>
#include <votca/xtp/aomatrix.h>
#include <votca/xtp/threecenters.h>
// #include <votca/xtp/logger.h>
#include <votca/xtp/qmpackagefactory.h>
#include <boost/math/constants/constants.hpp>
#include <boost/numeric/ublas/symmetric.hpp>
#include <votca/xtp/aoshell.h>

using boost::format;
using namespace boost::filesystem;

namespace votca {
    namespace xtp {
        namespace ub = boost::numeric::ublas;

        void GWBSE::PPM_construct_parameters(const ub::matrix<double>& _overlap_cholesky_inverse) {

            // multiply with L-1^t from the right

            ub::matrix<double> _temp = ub::prod(_epsilon[0], ub::trans(_overlap_cholesky_inverse));
            // multiply with L-1 from the left

            _temp = ub::prod(_overlap_cholesky_inverse, _temp);

            // get eigenvalues and eigenvectors of this matrix
            ub::vector<double> _eigenvalues;
            ub::matrix<double> _eigenvectors;

            linalg_eigenvalues(_temp, _eigenvalues, _eigenvectors);
            _eigenvectors=ub::trans(_eigenvectors);
            // multiply eigenvectors with overlap_cholesky_inverse and store as eigenvalues of epsilon
            _ppm_phi = ub::prod(_eigenvectors, _overlap_cholesky_inverse);

            // store PPM weights from eigenvalues
            _ppm_weight.resize(_eigenvalues.size());
            for (unsigned _i = 0; _i < _eigenvalues.size(); _i++) {
                _ppm_weight(_i) = 1.0 - 1.0 / _eigenvalues(_i);
            }

            // determine PPM frequencies
            _ppm_freq.resize(_eigenvalues.size());
            // a) phi^t * epsilon(1) * phi

            _temp = ub::prod(_ppm_phi, _epsilon[1]);

            _eigenvectors = ub::prod(_temp, ub::trans(_ppm_phi));
            // b) invert

            linalg_invert(_eigenvectors, _temp);
            // c) PPM parameters -> diagonal elements

            #pragma omp parallel for
            for (unsigned _i = 0; _i < _eigenvalues.size(); _i++) {

                if (_screening_freq(1, 0) == 0.0) {
                    if (_ppm_weight(_i) < 1.e-5) {
                        _ppm_weight(_i) = 0.0;
                        _ppm_freq(_i) = 0.5;//Hartree
                        continue;
                    } else {
                        double _nom = _temp(_i, _i) - 1.0;
                        double _frac = -1.0 * _nom / (_nom + _ppm_weight(_i)) * _screening_freq(1, 1) * _screening_freq(1, 1);
                        _ppm_freq(_i) = sqrt(std::abs(_frac));
                    }

                } else {
                    // only purely imaginary frequency assumed
                    cerr << " mixed frequency! real part: " << _screening_freq(1, 0) << " imaginary part: " << _screening_freq(1, 1) << flush;
                    exit(1);
                }

            }

            // epsilon can be deleted
            _epsilon[0].resize(0, 0);
            _epsilon[1].resize(0, 0);

            return;
        }

        //imaginary
        ub::matrix<double> GWBSE::RPA_imaginary(const TCMatrix& _Mmn_RPA,const double screening_freq) {
            const int _size = _Mmn_RPA.get_beta(); // size of gwbasis
            const int index_n = _Mmn_RPA.get_nmin();
            const int index_m = _Mmn_RPA.get_mmin();
            const double screenf2=screening_freq * screening_freq;
            ub::matrix<double> result=ub::zero_matrix<double>(_size);

            const ub::vector<double>& qp_energies=   _qp_energies;

            #pragma omp parallel for
            for (int _m_level = 0; _m_level < _Mmn_RPA.get_mtot(); _m_level++) {
                const double _qp_energy_m=qp_energies(_m_level + index_m);
#if (GWBSE_DOUBLE)
                const ub::matrix<double>& Mmn_RPA = _Mmn_RPA[ _m_level ];
#else
                const ub::matrix<double> Mmn_RPA = _Mmn_RPA[ _m_level ];
#endif
                // a temporary matrix, that will get filled in empty levels loop
                ub::matrix<double> _temp = ub::matrix<double>(_Mmn_RPA.get_ntot(), _size);

                // loop over empty levels
                for (int _n_level = 0; _n_level < _Mmn_RPA.get_ntot(); _n_level++) {

                    const double _deltaE = qp_energies(_n_level + index_n) -_qp_energy_m ; // get indices and units right!!!

                    // this only works, if we have either purely real or purely imaginary frequencies

                    // purely imaginary
                    const double _energy_factor = 4.0 * _deltaE / (_deltaE * _deltaE + screenf2);//hartree
                    for (int _i_gw = 0; _i_gw < _size; _i_gw++) {
                        _temp(_n_level, _i_gw) = _energy_factor * Mmn_RPA(_i_gw, _n_level);
                    } // matrix size

                } // empty levels
                _temp=ub::prod(Mmn_RPA, _temp);
                // now multiply and add to epsilon
                #pragma omp critical
                {
                result+=_temp;
                }
            } // occupied levels

            return result;
        }
        //real

        ub::matrix<double> GWBSE::RPA_real(const TCMatrix& _Mmn_RPA, const double screening_freq) {
            const int _size = _Mmn_RPA.get_beta(); // size of gwbasis
            const int index_n = _Mmn_RPA.get_nmin();
            const int index_m = _Mmn_RPA.get_mmin();
            const ub::vector<double>& qp_energies=   _qp_energies;
            ub::matrix<double> result=ub::zero_matrix<double>(_size);

            #pragma omp parallel for
            for (int _m_level = 0; _m_level < _Mmn_RPA.get_mtot(); _m_level++) {
                const double _qp_energy_m=qp_energies(_m_level + index_m);

#if (GWBSE_DOUBLE)
                const ub::matrix<double>& Mmn_RPA = _Mmn_RPA[ _m_level ];
#else
                const ub::matrix<double> Mmn_RPA = _Mmn_RPA[ _m_level ];
#endif

                // a temporary matrix, that will get filled in empty levels loop
                ub::matrix<double> _temp = ub::matrix<double>(_Mmn_RPA.get_ntot(), _size);

                // loop over empty levels
                for (int _n_level = 0; _n_level < _Mmn_RPA.get_ntot(); _n_level++) {

                    const double _deltaE = qp_energies(_n_level + index_n) - _qp_energy_m; // get indices and units right!!!

                    // this only works, if we have either purely real or purely imaginary frequencies

                    // purely real
                    const double _energy_factor =2.0*  (1.0 / (_deltaE - screening_freq) + 1.0 / (_deltaE + screening_freq));//hartree

                    for (int _i_gw = 0; _i_gw < _size; _i_gw++) {
                        _temp(_n_level, _i_gw) = _energy_factor * Mmn_RPA(_i_gw, _n_level);
                    } // matrix size

                } // empty levels

                // now multiply and add to epsilon
               _temp=ub::prod(Mmn_RPA, _temp);
                #pragma omp critical
                {
                result+=_temp;
                }
            } // occupied levels

            return result;
        }

    void GWBSE::RPA_calculate_epsilon(const TCMatrix& _Mmn_RPA){

        // loop over frequencies
        for ( unsigned _i_freq = 0 ; _i_freq < _screening_freq.size1() ; _i_freq++ ){

             if ( _screening_freq( _i_freq, 0) == 0.0 ) {
                 _epsilon[ _i_freq ]+=RPA_imaginary(_Mmn_RPA, _screening_freq( _i_freq, 1));
             }

             else if ( _screening_freq( _i_freq, 1) == 0.0  ) {
                  // purely real
                 _epsilon[ _i_freq ]+= RPA_real(_Mmn_RPA, _screening_freq( _i_freq, 0));
                    }
             else {
                    // mixed -> FAIL
                    cerr << " mixed frequency! real part: " << _screening_freq( _i_freq, 0 ) << " imaginary part: "  << _screening_freq( _i_freq, 1 ) << flush;
                    exit(1);
                    }

        } // loop over frequencies

        return;
    }

    void GWBSE::RPA_prepare_threecenters(TCMatrix& _Mmn_RPA,const TCMatrix& _Mmn_full){

        ub::range full=ub::range(0, _Mmn_full.get_beta());
        ub::range RPA_cut=ub::range(_Mmn_RPA.get_nmin() - _Mmn_full.get_nmin(), _Mmn_RPA.get_nmax() - _Mmn_full.get_nmin() + 1);
            // loop over m-levels in _Mmn_RPA
            #pragma omp parallel for
            for (int _m_level = 0; _m_level < _Mmn_RPA.size(); _m_level++) {

                // copy to _Mmn_RPA
                _Mmn_RPA[ _m_level ] = ub::project(_Mmn_full[ _m_level ], full, RPA_cut);

            }// loop m-levels
     return;
    }

}};
<|endoftext|>


<commit_before>#include <map>
#include <cmath>
#include <algorithm>
#include <fstream>
#include <sstream>
#include <ctime>
#include <memory>
#include "ChatBot.h"

struct userinfo
{
    unsigned smiles;
    int lastReply;
    long long context;

    userinfo(): smiles(0), lastReply(0), context(0) {}

    explicit userinfo(const wstring &s): userinfo()
    {
        wstring t;
        unsigned i = 0;
        for(;s[i]!=L';'&&i<s.length();i++)
            t.push_back(s[i]);
        if(i == s.length())
            return;
        smiles = stoi(t);
        t.clear();
        i++;
        for(;s[i]!=L';'&&i<s.length();i++)
            t.push_back(s[i]);
        if(i == s.length())
            return;
        lastReply = stoi(t);
        t.clear();
        i++;
        for(;i<s.length();i++)
            t.push_back(s[i]);
        context = stoll(t);
    }

    wstring dump() const
    {
        return to_wstring(smiles) + L';' + to_wstring(lastReply) + L';' + to_wstring(context);
    }
};

struct replyinfo
{
    vector<wstring> replies;
    wstring limiter;
    long long context;

    replyinfo(): replies(), limiter(), context(0) {}
    replyinfo(vector<wstring> &r, wstring &l, long long c): replies(r), limiter(l), context(c) {}
};

unsigned MAX_SMILES;
int myName;

vector<wstring> request;
vector<shared_ptr<replyinfo> > reply;
vector<pair<vector<long long>, long long> > tf;
vector<pair<long long, long long> > fixedstem;
vector<pair<long long, long long> > replaced;
vector<pair<long long, bool> > blacklist;
vector<long long> plain_blacklist;
vector<double> tfnorm;
map<long long, int> df;
map<int, userinfo> users;
set<long long> names;
map<long long, wstring> context_map;

inline double tfidf(long long &word)
{
    return df.count(word) ? log((double)tf.size() / df[word]) : 0.;
}

inline double sqr(double x)
{
    return x * x;
}

double norm(vector<long long> &arr)
{
    double ans = 0;
    for(auto&& i: arr)
    {
        ans += sqr(tfidf(i));
    }
    return sqrt(ans);
}

wstring RandReply(vector<wstring> &v)
{
    return v.size() == 1 ? v[0] : v[rand() % v.size()];
}

int randint(int a, int b)
{
    return rand() % (b - a + 1) + a;
}

void SwapFirst(vector<wstring> &v, bool canStay)
{
    if(v.size() > 1)
    {
        swap(v[0], v[randint(1 - canStay, v.size()-1)]);
    }
}

template<class T>
vector<long long> PlainWords(const vector<pair<long long, T> > &words_pos)
{
    vector<long long> words;
    for(auto &i : words_pos)
        words.push_back(i.first);
    return words;
}

void Highlight(wstring &line, const vector<pair<long long, pair<int, int> > > &words_pos, const vector<long long> &common)
{
    set<int> bpos;
    for(auto i : common)
    {
        for(auto& j : words_pos)
        {
            if(i == j.first)
            {
                bpos.insert(j.second.first);
                bpos.insert(-(j.second.first + j.second.second)-1);
            }
        }
    }
    int tadd = 0;
    for(int i=0;i<(int)line.size();i++)
    {
        if(bpos.count(-i-1))
        {
            line.insert(i+tadd, L"}`");
            tadd += 2;
        }
        if(bpos.count(i))
        {
            line.insert(i+tadd, L"`{");
            tadd += 2;
        }
    }
}

long long phnamec = phash(L"firstnamec");

bool HasLetters(const wstring &line)
{
    for(auto i : line)
    {
        if(towupper(i) != towlower(i) || i == '?')
            return true;
    }
    return false;
}

//-1: comment
//-2: flat
wstring Say(wstring &line, int id, bool conf)
{
    vector<wstring> limiters;
    line += L' ';
    if(id > 0)
    {
        wistringstream is;
        is.str(line);
        wstring t;
        is >> t;
        while(t.length() && t[0] != L'|')
        {
            if(t[0] == L'@')
            {
                limiters.push_back(t.substr(1));
            }
            is >> t;
        }
        getline(is, line);
    }
    long long context = users[id].context;
    if(line[1] == L'$' && id == -2)
    {
        wstring ctx;
        int i;
        for(i=2;line[i]!=L' ';i++)
        {
            ctx += line[i];
        }
        line = line.substr(i);
        context = phash(ctx);
    }
    auto words_pos = splitWords(line, fixedstem, replaced, names);
    vector<long long> words = PlainWords(words_pos);
    if(conf)
    {
        replace(words.begin(), words.end(), phname, phnamec);
    }
    sort(words.begin(), words.end());
    words.resize(unique(words.begin(), words.end()) - words.begin());
    for(auto &i : blacklist)
    {
        if(i.second && id != -1)
            continue;
        if(find(words.begin(), words.end(), i.first) != words.end())
        {
            Highlight(line, words_pos, (id==-1) ? PlainWords(blacklist) : plain_blacklist);
            wcerr << "red|" << line << L"- blacklisted\n";
            return L"$blacklisted";
        }
    }
    double mx = 0;
    int imx = 0;
    vector<long long> common;
    for(int i=0;i<(int)tf.size();i++)
    {
        if(tf[i].second != 0 && context != tf[i].second)
        {
            continue;
        }
        common.clear();
        set_intersection(words.begin(), words.end(), tf[i].first.begin(), tf[i].first.end(), back_inserter(common));
        double ans = 0;
        for(auto&& word: common)
        {
            ans += sqr(tfidf(word));
        }
        ans /= tfnorm[i];
        if(ans > mx + 0.00000001 || (tf[i].second && ans > mx - 0.00000001))
        {
            mx = ans;
            imx = i;
        }
    }

    if(mx == 0)
    {
        if(conf && !HasLetters(line))
        {
            wcerr << "red|" << line << "- no match\n";
            users[id].smiles++;
            return L"";
        }
        if(id >= 0 && users[id].smiles >= MAX_SMILES)
        {
            wcerr << "red|" << line << "- too many smiles\n";
            return L"";
        }
        if(id >= 0)
        {
            wcerr << "yellow|" << line << L"- no match\n";
            users[id].smiles++;
        }
        return L"$noans";
    }

    common.clear();
    set_intersection(words.begin(), words.end(), tf[imx].first.begin(), tf[imx].first.end(), back_inserter(common));
    Highlight(line, words_pos, common);
    wstring req = request[imx];
    Highlight(req, splitWords(req, fixedstem, replaced, names), common);

    if(id >= 0)
    {
        users[id].context = reply[imx]->context;
        if(users[id].lastReply == imx + 1)
        {
            users[id].lastReply = -(imx + 1);
        }
        else if(users[id].lastReply == -(imx + 1))
        {
            wcerr << "red|" << line << L"== " << req << (tf[imx].second ? L" (context, " : L" (") << mx / norm(words) << L")" << " - repeated\n";
            return L"";
        }
        else
        {
            users[id].lastReply = imx + 1;
        }
        users[id].smiles = 0;
    }
    if(id >= 0)
    {
        for(auto &limiter : limiters)
        {
            if(limiter == reply[imx]->limiter)
            {
                wcerr << "red|" << line << L"== " << req << (tf[imx].second ? L" (context, " : L" (") << mx / norm(words) << L")" << " - limited\n";
                return L"";
            }
        }
        wcerr << "green|" << line << L"== " << req << (tf[imx].second ? L" (context, " : L" (") << mx / norm(words) << L")";
        if(reply[imx]->replies.size() > 1)
        {
            wcerr << L", " << reply[imx]->replies.size() << L" replies";
        }
        wcerr << L"\n";
    }
    if(id == -2)
    {
        for(int i=0;i<(int)reply[imx]->replies.size();i++)
        {
            req += '|';
            req += reply[imx]->replies[i];
        }
        req += '|';
        req += to_wstring(mx / norm(words));
        req += '|';
        req += context_map[reply[imx]->context];
        req += '|';
        req += reply[imx]->limiter;
        return req;
    }
    wstring ans = (reply[imx]->limiter.length() ? L"@" + reply[imx]->limiter : L"") + L"|" + reply[imx]->replies[0];
    SwapFirst(reply[imx]->replies, 0);
    return ans;
}

shared_ptr<replyinfo> splitReply(const wstring &t)
{
    vector<wstring> ans;
    wstring s;
    wstring ctx;
    wstring lim;
    int i = 0;
    if(t[0] == L'@')
    {
        for(i=1;i<(int)t.size();i++)
        {
            if(t[i] == L' ')
            {
                i++;
                break;
            }
            lim += t[i];
        }
    }
    if(t[i] == L'$')
    {
        i++;
        for(;i<(int)t.size();i++)
        {
            if(t[i] == L' ')
            {
                i++;
                break;
            }
            ctx += t[i];
        }
    }
    for(;i<(int)t.size();i++)
    {
        if(t[i] == L'|')
        {
            if(s.length())
                ans.push_back(s);
            s.clear();
        }
        else
        {
            s.push_back(t[i]);
        }
    }
    if(s.length())
        ans.push_back(s);
    context_map[phash(ctx)] = ctx;
    return make_shared<replyinfo>(ans, lim, phash(ctx));
}

void AddReply(const wstring &req, const wstring &rep)
{
    auto v = splitReply(rep);
    auto u = *splitReply(req);
    SwapFirst(v->replies, 1);
    for(wstring& i : u.replies)
    {
        reply.push_back(v);
        request.push_back(i);
        auto words_pos = splitWords(i, fixedstem, replaced, names);
        vector<long long> words = PlainWords(words_pos);
        sort(words.begin(), words.end());
        words.resize(unique(words.begin(), words.end()) - words.begin());
        for(auto& j: words)
        {
            df[j]++;
        }
        tf.push_back({words, u.context});
    }
}

wchar_t buf1[12000], buf2[12000];
const string file = "data/bot.txt";
const string filebl = "data/blacklist.txt";
const string filestem = "data/fixedstem.txt";
const string filenames = "data/names.txt";

void Load()
{
    locale loc("");
    reply.clear();
    request.clear();
    tf.clear();
    tfnorm.clear();
    df.clear();
    blacklist.clear();
    plain_blacklist.clear();
    fixedstem.clear();
    names.clear();
    context_map.clear();
    context_map[0] = L"";
    srand(time(0));
    wifstream fin(file);
    wifstream fstem(filestem);
    fstem.imbue(loc);
    while(fstem >> buf1)
    {
        fstem >> buf2;
        if(buf1[0] == '$')
        {
            replaced.push_back(make_pair(stem(buf1 + 1), stem(buf2)));
        }
        else
        {
            wstring s = buf1;
            for(auto &i : s)
                i = towupper(i);
            fixedstem.push_back(make_pair(phash(s), phash(buf2)));
        }
    }
    fstem.close();
    fin.imbue(loc);
    while(fin.getline(buf1, 10000))
    {
        fin.getline(buf2, 10000);
        AddReply(buf1, buf2);  //this should be done BEFORE filling names
    }
    df[phnamec] = 10000;
    for(auto&& i : tf)
    {
        tfnorm.push_back(norm(i.first));
    }
    fin.close();
    wifstream fbl(filebl);
    fbl.imbue(loc);
    while(fbl.getline(buf1, 10000))
    {
        if(buf1[0] == '$')
            blacklist.push_back({stem(buf1 + 1), 1});
        else
        {
            blacklist.push_back({stem(buf1), 0});
            plain_blacklist.push_back(stem(buf1));
        }
    }
    fbl.close();
    wifstream fnm(filenames);
    fnm.imbue(loc);
    long long phmyname = phash(L"а");
    for(int l=0;fnm.getline(buf1, 10000);l++)
    {
        int j = 0;
        for(int i=0;buf1[i];i++)
        {
            if(buf1[i] <= L' ')
            {
                buf2[j] = 0;
                if(l == myName)
                    replaced.push_back(make_pair(stem(buf2), phmyname));
                else
                    names.insert(phash(buf2));
                j = 0;
            }
            else
            {
                buf2[j++] = towupper(buf1[i]);
            }
        }
        buf2[j] = 0;
        if(l == myName)
            fixedstem.push_back(make_pair(phash(buf2), phmyname));
        else
            names.insert(phash(buf2));
    }
    fnm.close();
    for(auto &i : users)
    {
        i.second.lastReply = 0;
    }
}

void LoadData(const wstring &data)
{
    users.clear();
    wistringstream is;
    is.str(data);
    int id;
    wstring s;
    while(is >> id)
    {
        is >> s;
        users[id] = userinfo(s);
    }
}

wstring Dump()
{
    wstring res;
    for(auto &i : users)
    {
        res += to_wstring(i.first) + L' ' + i.second.dump() + L' ';
    }
    return res;
}

<commit_msg>Highlight blacklisted names correctly<commit_after>#include <map>
#include <cmath>
#include <algorithm>
#include <fstream>
#include <sstream>
#include <ctime>
#include <memory>
#include "ChatBot.h"

struct userinfo
{
    unsigned smiles;
    int lastReply;
    long long context;

    userinfo(): smiles(0), lastReply(0), context(0) {}

    explicit userinfo(const wstring &s): userinfo()
    {
        wstring t;
        unsigned i = 0;
        for(;s[i]!=L';'&&i<s.length();i++)
            t.push_back(s[i]);
        if(i == s.length())
            return;
        smiles = stoi(t);
        t.clear();
        i++;
        for(;s[i]!=L';'&&i<s.length();i++)
            t.push_back(s[i]);
        if(i == s.length())
            return;
        lastReply = stoi(t);
        t.clear();
        i++;
        for(;i<s.length();i++)
            t.push_back(s[i]);
        context = stoll(t);
    }

    wstring dump() const
    {
        return to_wstring(smiles) + L';' + to_wstring(lastReply) + L';' + to_wstring(context);
    }
};

struct replyinfo
{
    vector<wstring> replies;
    wstring limiter;
    long long context;

    replyinfo(): replies(), limiter(), context(0) {}
    replyinfo(vector<wstring> &r, wstring &l, long long c): replies(r), limiter(l), context(c) {}
};

unsigned MAX_SMILES;
int myName;

vector<wstring> request;
vector<shared_ptr<replyinfo> > reply;
vector<pair<vector<long long>, long long> > tf;
vector<pair<long long, long long> > fixedstem;
vector<pair<long long, long long> > replaced;
vector<pair<long long, bool> > blacklist;
vector<long long> plain_blacklist;
vector<double> tfnorm;
map<long long, int> df;
map<int, userinfo> users;
set<long long> names;
map<long long, wstring> context_map;

inline double tfidf(long long &word)
{
    return df.count(word) ? log((double)tf.size() / df[word]) : 0.;
}

inline double sqr(double x)
{
    return x * x;
}

double norm(vector<long long> &arr)
{
    double ans = 0;
    for(auto&& i: arr)
    {
        ans += sqr(tfidf(i));
    }
    return sqrt(ans);
}

wstring RandReply(vector<wstring> &v)
{
    return v.size() == 1 ? v[0] : v[rand() % v.size()];
}

int randint(int a, int b)
{
    return rand() % (b - a + 1) + a;
}

void SwapFirst(vector<wstring> &v, bool canStay)
{
    if(v.size() > 1)
    {
        swap(v[0], v[randint(1 - canStay, v.size()-1)]);
    }
}

template<class T>
vector<long long> PlainWords(const vector<pair<long long, T> > &words_pos)
{
    vector<long long> words;
    for(auto &i : words_pos)
        words.push_back(i.first);
    return words;
}

void Highlight(wstring &line, const vector<pair<long long, pair<int, int> > > &words_pos, const vector<long long> &common)
{
    set<int> bpos;
    for(auto i : common)
    {
        for(auto& j : words_pos)
        {
            if(i == j.first)
            {
                bpos.insert(j.second.first);
                bpos.insert(-(j.second.first + j.second.second)-1);
            }
        }
    }
    int tadd = 0;
    for(int i=0;i<(int)line.size();i++)
    {
        if(bpos.count(-i-1))
        {
            line.insert(i+tadd, L"}`");
            tadd += 2;
        }
        if(bpos.count(i))
        {
            line.insert(i+tadd, L"`{");
            tadd += 2;
        }
    }
}

long long phnamec = phash(L"firstnamec");

bool HasLetters(const wstring &line)
{
    for(auto i : line)
    {
        if(towupper(i) != towlower(i) || i == '?')
            return true;
    }
    return false;
}

//-1: comment
//-2: flat
wstring Say(wstring &line, int id, bool conf)
{
    vector<wstring> limiters;
    line += L' ';
    if(id > 0)
    {
        wistringstream is;
        is.str(line);
        wstring t;
        is >> t;
        while(t.length() && t[0] != L'|')
        {
            if(t[0] == L'@')
            {
                limiters.push_back(t.substr(1));
            }
            is >> t;
        }
        getline(is, line);
    }
    long long context = users[id].context;
    if(line[1] == L'$' && id == -2)
    {
        wstring ctx;
        int i;
        for(i=2;line[i]!=L' ';i++)
        {
            ctx += line[i];
        }
        line = line.substr(i);
        context = phash(ctx);
    }
    auto words_pos = splitWords(line, fixedstem, replaced, names);
    if(conf)
    {
        for(auto &i : words_pos)
        {
            if(i.first == phname)
                i.first = phnamec;
        }
    }
    vector<long long> words = PlainWords(words_pos);
    sort(words.begin(), words.end());
    words.resize(unique(words.begin(), words.end()) - words.begin());
    for(auto &i : blacklist)
    {
        if(i.second && id != -1)
            continue;
        if(find(words.begin(), words.end(), i.first) != words.end())
        {
            Highlight(line, words_pos, (id==-1) ? PlainWords(blacklist) : plain_blacklist);
            wcerr << "red|" << line << L"- blacklisted\n";
            return L"$blacklisted";
        }
    }
    double mx = 0;
    int imx = 0;
    vector<long long> common;
    for(int i=0;i<(int)tf.size();i++)
    {
        if(tf[i].second != 0 && context != tf[i].second)
        {
            continue;
        }
        common.clear();
        set_intersection(words.begin(), words.end(), tf[i].first.begin(), tf[i].first.end(), back_inserter(common));
        double ans = 0;
        for(auto&& word: common)
        {
            ans += sqr(tfidf(word));
        }
        ans /= tfnorm[i];
        if(ans > mx + 0.00000001 || (tf[i].second && ans > mx - 0.00000001))
        {
            mx = ans;
            imx = i;
        }
    }

    if(mx == 0)
    {
        if(conf && !HasLetters(line))
        {
            wcerr << "red|" << line << "- no match\n";
            users[id].smiles++;
            return L"";
        }
        if(id >= 0 && users[id].smiles >= MAX_SMILES)
        {
            wcerr << "red|" << line << "- too many smiles\n";
            return L"";
        }
        if(id >= 0)
        {
            wcerr << "yellow|" << line << L"- no match\n";
            users[id].smiles++;
        }
        return L"$noans";
    }

    common.clear();
    set_intersection(words.begin(), words.end(), tf[imx].first.begin(), tf[imx].first.end(), back_inserter(common));
    Highlight(line, words_pos, common);
    wstring req = request[imx];
    Highlight(req, splitWords(req, fixedstem, replaced, names), common);

    if(id >= 0)
    {
        users[id].context = reply[imx]->context;
        if(users[id].lastReply == imx + 1)
        {
            users[id].lastReply = -(imx + 1);
        }
        else if(users[id].lastReply == -(imx + 1))
        {
            wcerr << "red|" << line << L"== " << req << (tf[imx].second ? L" (context, " : L" (") << mx / norm(words) << L")" << " - repeated\n";
            return L"";
        }
        else
        {
            users[id].lastReply = imx + 1;
        }
        users[id].smiles = 0;
    }
    if(id >= 0)
    {
        for(auto &limiter : limiters)
        {
            if(limiter == reply[imx]->limiter)
            {
                wcerr << "red|" << line << L"== " << req << (tf[imx].second ? L" (context, " : L" (") << mx / norm(words) << L")" << " - limited\n";
                return L"";
            }
        }
        wcerr << "green|" << line << L"== " << req << (tf[imx].second ? L" (context, " : L" (") << mx / norm(words) << L")";
        if(reply[imx]->replies.size() > 1)
        {
            wcerr << L", " << reply[imx]->replies.size() << L" replies";
        }
        wcerr << L"\n";
    }
    if(id == -2)
    {
        for(int i=0;i<(int)reply[imx]->replies.size();i++)
        {
            req += '|';
            req += reply[imx]->replies[i];
        }
        req += '|';
        req += to_wstring(mx / norm(words));
        req += '|';
        req += context_map[reply[imx]->context];
        req += '|';
        req += reply[imx]->limiter;
        return req;
    }
    wstring ans = (reply[imx]->limiter.length() ? L"@" + reply[imx]->limiter : L"") + L"|" + reply[imx]->replies[0];
    SwapFirst(reply[imx]->replies, 0);
    return ans;
}

shared_ptr<replyinfo> splitReply(const wstring &t)
{
    vector<wstring> ans;
    wstring s;
    wstring ctx;
    wstring lim;
    int i = 0;
    if(t[0] == L'@')
    {
        for(i=1;i<(int)t.size();i++)
        {
            if(t[i] == L' ')
            {
                i++;
                break;
            }
            lim += t[i];
        }
    }
    if(t[i] == L'$')
    {
        i++;
        for(;i<(int)t.size();i++)
        {
            if(t[i] == L' ')
            {
                i++;
                break;
            }
            ctx += t[i];
        }
    }
    for(;i<(int)t.size();i++)
    {
        if(t[i] == L'|')
        {
            if(s.length())
                ans.push_back(s);
            s.clear();
        }
        else
        {
            s.push_back(t[i]);
        }
    }
    if(s.length())
        ans.push_back(s);
    context_map[phash(ctx)] = ctx;
    return make_shared<replyinfo>(ans, lim, phash(ctx));
}

void AddReply(const wstring &req, const wstring &rep)
{
    auto v = splitReply(rep);
    auto u = *splitReply(req);
    SwapFirst(v->replies, 1);
    for(wstring& i : u.replies)
    {
        reply.push_back(v);
        request.push_back(i);
        auto words_pos = splitWords(i, fixedstem, replaced, names);
        vector<long long> words = PlainWords(words_pos);
        sort(words.begin(), words.end());
        words.resize(unique(words.begin(), words.end()) - words.begin());
        for(auto& j: words)
        {
            df[j]++;
        }
        tf.push_back({words, u.context});
    }
}

wchar_t buf1[12000], buf2[12000];
const string file = "data/bot.txt";
const string filebl = "data/blacklist.txt";
const string filestem = "data/fixedstem.txt";
const string filenames = "data/names.txt";

void Load()
{
    locale loc("");
    reply.clear();
    request.clear();
    tf.clear();
    tfnorm.clear();
    df.clear();
    blacklist.clear();
    plain_blacklist.clear();
    fixedstem.clear();
    names.clear();
    context_map.clear();
    context_map[0] = L"";
    srand(time(0));
    wifstream fin(file);
    wifstream fstem(filestem);
    fstem.imbue(loc);
    while(fstem >> buf1)
    {
        fstem >> buf2;
        if(buf1[0] == '$')
        {
            replaced.push_back(make_pair(stem(buf1 + 1), stem(buf2)));
        }
        else
        {
            wstring s = buf1;
            for(auto &i : s)
                i = towupper(i);
            fixedstem.push_back(make_pair(phash(s), phash(buf2)));
        }
    }
    fstem.close();
    fin.imbue(loc);
    while(fin.getline(buf1, 10000))
    {
        fin.getline(buf2, 10000);
        AddReply(buf1, buf2);  //this should be done BEFORE filling names
    }
    df[phnamec] = 10000;
    for(auto&& i : tf)
    {
        tfnorm.push_back(norm(i.first));
    }
    fin.close();
    wifstream fbl(filebl);
    fbl.imbue(loc);
    while(fbl.getline(buf1, 10000))
    {
        if(buf1[0] == '$')
            blacklist.push_back({stem(buf1 + 1), 1});
        else
        {
            blacklist.push_back({stem(buf1), 0});
            plain_blacklist.push_back(stem(buf1));
        }
    }
    fbl.close();
    wifstream fnm(filenames);
    fnm.imbue(loc);
    long long phmyname = phash(L"а");
    for(int l=0;fnm.getline(buf1, 10000);l++)
    {
        int j = 0;
        for(int i=0;buf1[i];i++)
        {
            if(buf1[i] <= L' ')
            {
                buf2[j] = 0;
                if(l == myName)
                    replaced.push_back(make_pair(stem(buf2), phmyname));
                else
                    names.insert(phash(buf2));
                j = 0;
            }
            else
            {
                buf2[j++] = towupper(buf1[i]);
            }
        }
        buf2[j] = 0;
        if(l == myName)
            fixedstem.push_back(make_pair(phash(buf2), phmyname));
        else
            names.insert(phash(buf2));
    }
    fnm.close();
    for(auto &i : users)
    {
        i.second.lastReply = 0;
    }
}

void LoadData(const wstring &data)
{
    users.clear();
    wistringstream is;
    is.str(data);
    int id;
    wstring s;
    while(is >> id)
    {
        is >> s;
        users[id] = userinfo(s);
    }
}

wstring Dump()
{
    wstring res;
    for(auto &i : users)
    {
        res += to_wstring(i.first) + L' ' + i.second.dump() + L' ';
    }
    return res;
}

<|endoftext|>


<commit_before>//===- NameMap.cpp - PDB Name Map -------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "llvm/DebugInfo/PDB/Raw/NameMap.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/DebugInfo/CodeView/StreamReader.h"
#include "llvm/DebugInfo/PDB/Raw/RawError.h"

using namespace llvm;
using namespace llvm::pdb;

NameMap::NameMap() {}

Error NameMap::load(codeview::StreamReader &Stream) {

  // This is some sort of weird string-set/hash table encoded in the stream.
  // It starts with the number of bytes in the table.
  uint32_t NumberOfBytes;
  if (auto EC = Stream.readInteger(NumberOfBytes))
    return joinErrors(std::move(EC),
                      make_error<RawError>(raw_error_code::corrupt_file,
                                           "Expected name map length"));
  if (Stream.bytesRemaining() < NumberOfBytes)
    return make_error<RawError>(raw_error_code::corrupt_file,
                                "Invalid name map length");

  // Following that field is the starting offset of strings in the name table.
  uint32_t StringsOffset = Stream.getOffset();
  Stream.setOffset(StringsOffset + NumberOfBytes);

  // This appears to be equivalent to the total number of strings *actually*
  // in the name table.
  uint32_t HashSize;
  if (auto EC = Stream.readInteger(HashSize))
    return joinErrors(std::move(EC),
                      make_error<RawError>(raw_error_code::corrupt_file,
                                           "Expected name map hash size"));

  // This appears to be an upper bound on the number of strings in the name
  // table.
  uint32_t MaxNumberOfStrings;
  if (auto EC = Stream.readInteger(MaxNumberOfStrings))
    return joinErrors(std::move(EC),
                      make_error<RawError>(raw_error_code::corrupt_file,
                                           "Expected name map max strings"));

  const uint32_t MaxNumberOfWords = UINT32_MAX / sizeof(uint32_t);

  // This appears to be a hash table which uses bitfields to determine whether
  // or not a bucket is 'present'.
  uint32_t NumPresentWords;
  if (auto EC = Stream.readInteger(NumPresentWords))
    return joinErrors(std::move(EC),
                      make_error<RawError>(raw_error_code::corrupt_file,
                                           "Expected name map num words"));

  if (NumPresentWords > MaxNumberOfWords)
    return make_error<RawError>(raw_error_code::corrupt_file,
                                "Number of present words is too large");

  // Store all the 'present' bits in a vector for later processing.
  SmallVector<uint32_t, 1> PresentWords;
  for (uint32_t I = 0; I != NumPresentWords; ++I) {
    uint32_t Word;
    if (auto EC = Stream.readInteger(Word))
      return joinErrors(std::move(EC),
                        make_error<RawError>(raw_error_code::corrupt_file,
                                             "Expected name map word"));

    PresentWords.push_back(Word);
  }

  // This appears to be a hash table which uses bitfields to determine whether
  // or not a bucket is 'deleted'.
  uint32_t NumDeletedWords;
  if (auto EC = Stream.readInteger(NumDeletedWords))
    return joinErrors(
        std::move(EC),
        make_error<RawError>(raw_error_code::corrupt_file,
                             "Expected name map num deleted words"));

  if (NumDeletedWords > MaxNumberOfWords)
    return make_error<RawError>(raw_error_code::corrupt_file,
                                "Number of deleted words is too large");

  // Store all the 'deleted' bits in a vector for later processing.
  SmallVector<uint32_t, 1> DeletedWords;
  for (uint32_t I = 0; I != NumDeletedWords; ++I) {
    uint32_t Word;
    if (auto EC = Stream.readInteger(Word))
      return joinErrors(std::move(EC),
                        make_error<RawError>(raw_error_code::corrupt_file,
                                             "Expected name map deleted word"));

    DeletedWords.push_back(Word);
  }

  BitVector Present(MaxNumberOfStrings, false);
  if (!PresentWords.empty())
    Present.setBitsInMask(PresentWords.data(), PresentWords.size());
  BitVector Deleted(MaxNumberOfStrings, false);
  if (!DeletedWords.empty())
    Deleted.setBitsInMask(DeletedWords.data(), DeletedWords.size());

  for (uint32_t I = 0; I < MaxNumberOfStrings; ++I) {
    if (!Present.test(I))
      continue;

    // For all present entries, dump out their mapping.

    // This appears to be an offset relative to the start of the strings.
    // It tells us where the null-terminated string begins.
    uint32_t NameOffset;
    if (auto EC = Stream.readInteger(NameOffset))
      return joinErrors(std::move(EC),
                        make_error<RawError>(raw_error_code::corrupt_file,
                                             "Expected name map name offset"));

    // This appears to be a stream number into the stream directory.
    uint32_t NameIndex;
    if (auto EC = Stream.readInteger(NameIndex))
      return joinErrors(std::move(EC),
                        make_error<RawError>(raw_error_code::corrupt_file,
                                             "Expected name map name index"));

    // Compute the offset of the start of the string relative to the stream.
    uint32_t StringOffset = StringsOffset + NameOffset;
    uint32_t OldOffset = Stream.getOffset();
    // Pump out our c-string from the stream.
    StringRef Str;
    Stream.setOffset(StringOffset);
    if (auto EC = Stream.readZeroString(Str))
      return joinErrors(std::move(EC),
                        make_error<RawError>(raw_error_code::corrupt_file,
                                             "Expected name map name"));

    Stream.setOffset(OldOffset);
    // Add this to a string-map from name to stream number.
    Mapping.insert({Str, NameIndex});
  }

  return Error::success();
}

iterator_range<StringMapConstIterator<uint32_t>> NameMap::entries() const {
  return llvm::make_range<StringMapConstIterator<uint32_t>>(Mapping.begin(),
                                                            Mapping.end());
}

bool NameMap::tryGetValue(StringRef Name, uint32_t &Value) const {
  auto Iter = Mapping.find(Name);
  if (Iter == Mapping.end())
    return false;
  Value = Iter->second;
  return true;
}
<commit_msg>Tighten some of the name map checks further<commit_after>//===- NameMap.cpp - PDB Name Map -------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "llvm/DebugInfo/PDB/Raw/NameMap.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/DebugInfo/CodeView/StreamReader.h"
#include "llvm/DebugInfo/PDB/Raw/RawError.h"

using namespace llvm;
using namespace llvm::pdb;

NameMap::NameMap() {}

Error NameMap::load(codeview::StreamReader &Stream) {

  // This is some sort of weird string-set/hash table encoded in the stream.
  // It starts with the number of bytes in the table.
  uint32_t NumberOfBytes;
  if (auto EC = Stream.readInteger(NumberOfBytes))
    return joinErrors(std::move(EC),
                      make_error<RawError>(raw_error_code::corrupt_file,
                                           "Expected name map length"));
  if (Stream.bytesRemaining() < NumberOfBytes)
    return make_error<RawError>(raw_error_code::corrupt_file,
                                "Invalid name map length");

  // Following that field is the starting offset of strings in the name table.
  uint32_t StringsOffset = Stream.getOffset();
  Stream.setOffset(StringsOffset + NumberOfBytes);

  // This appears to be equivalent to the total number of strings *actually*
  // in the name table.
  uint32_t HashSize;
  if (auto EC = Stream.readInteger(HashSize))
    return joinErrors(std::move(EC),
                      make_error<RawError>(raw_error_code::corrupt_file,
                                           "Expected name map hash size"));

  // This appears to be an upper bound on the number of strings in the name
  // table.
  uint32_t MaxNumberOfStrings;
  if (auto EC = Stream.readInteger(MaxNumberOfStrings))
    return joinErrors(std::move(EC),
                      make_error<RawError>(raw_error_code::corrupt_file,
                                           "Expected name map max strings"));

  if (MaxNumberOfStrings > (UINT32_MAX / sizeof(uint32_t)))
    return make_error<RawError>(raw_error_code::corrupt_file,
                                "Implausible number of strings");

  const uint32_t MaxNumberOfWords = UINT32_MAX / (sizeof(uint32_t) * 8);

  // This appears to be a hash table which uses bitfields to determine whether
  // or not a bucket is 'present'.
  uint32_t NumPresentWords;
  if (auto EC = Stream.readInteger(NumPresentWords))
    return joinErrors(std::move(EC),
                      make_error<RawError>(raw_error_code::corrupt_file,
                                           "Expected name map num words"));

  if (NumPresentWords > MaxNumberOfWords)
    return make_error<RawError>(raw_error_code::corrupt_file,
                                "Number of present words is too large");

  // Store all the 'present' bits in a vector for later processing.
  SmallVector<uint32_t, 1> PresentWords;
  for (uint32_t I = 0; I != NumPresentWords; ++I) {
    uint32_t Word;
    if (auto EC = Stream.readInteger(Word))
      return joinErrors(std::move(EC),
                        make_error<RawError>(raw_error_code::corrupt_file,
                                             "Expected name map word"));

    PresentWords.push_back(Word);
  }

  // This appears to be a hash table which uses bitfields to determine whether
  // or not a bucket is 'deleted'.
  uint32_t NumDeletedWords;
  if (auto EC = Stream.readInteger(NumDeletedWords))
    return joinErrors(
        std::move(EC),
        make_error<RawError>(raw_error_code::corrupt_file,
                             "Expected name map num deleted words"));

  if (NumDeletedWords > MaxNumberOfWords)
    return make_error<RawError>(raw_error_code::corrupt_file,
                                "Number of deleted words is too large");

  // Store all the 'deleted' bits in a vector for later processing.
  SmallVector<uint32_t, 1> DeletedWords;
  for (uint32_t I = 0; I != NumDeletedWords; ++I) {
    uint32_t Word;
    if (auto EC = Stream.readInteger(Word))
      return joinErrors(std::move(EC),
                        make_error<RawError>(raw_error_code::corrupt_file,
                                             "Expected name map deleted word"));

    DeletedWords.push_back(Word);
  }

  BitVector Present(MaxNumberOfStrings, false);
  if (!PresentWords.empty())
    Present.setBitsInMask(PresentWords.data(), PresentWords.size());
  BitVector Deleted(MaxNumberOfStrings, false);
  if (!DeletedWords.empty())
    Deleted.setBitsInMask(DeletedWords.data(), DeletedWords.size());

  for (uint32_t I = 0; I < MaxNumberOfStrings; ++I) {
    if (!Present.test(I))
      continue;

    // For all present entries, dump out their mapping.

    // This appears to be an offset relative to the start of the strings.
    // It tells us where the null-terminated string begins.
    uint32_t NameOffset;
    if (auto EC = Stream.readInteger(NameOffset))
      return joinErrors(std::move(EC),
                        make_error<RawError>(raw_error_code::corrupt_file,
                                             "Expected name map name offset"));

    // This appears to be a stream number into the stream directory.
    uint32_t NameIndex;
    if (auto EC = Stream.readInteger(NameIndex))
      return joinErrors(std::move(EC),
                        make_error<RawError>(raw_error_code::corrupt_file,
                                             "Expected name map name index"));

    // Compute the offset of the start of the string relative to the stream.
    uint32_t StringOffset = StringsOffset + NameOffset;
    uint32_t OldOffset = Stream.getOffset();
    // Pump out our c-string from the stream.
    StringRef Str;
    Stream.setOffset(StringOffset);
    if (auto EC = Stream.readZeroString(Str))
      return joinErrors(std::move(EC),
                        make_error<RawError>(raw_error_code::corrupt_file,
                                             "Expected name map name"));

    Stream.setOffset(OldOffset);
    // Add this to a string-map from name to stream number.
    Mapping.insert({Str, NameIndex});
  }

  return Error::success();
}

iterator_range<StringMapConstIterator<uint32_t>> NameMap::entries() const {
  return llvm::make_range<StringMapConstIterator<uint32_t>>(Mapping.begin(),
                                                            Mapping.end());
}

bool NameMap::tryGetValue(StringRef Name, uint32_t &Value) const {
  auto Iter = Mapping.find(Name);
  if (Iter == Mapping.end())
    return false;
  Value = Iter->second;
  return true;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2012, 2015, 2017 ARM Limited
 * All rights reserved
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER 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.
 */

#include "sim/drain.hh"

#include <algorithm>

#include "base/logging.hh"
#include "base/trace.hh"
#include "debug/Drain.hh"
#include "sim/sim_exit.hh"
#include "sim/sim_object.hh"

DrainManager DrainManager::_instance;

DrainManager::DrainManager()
    : _count(0),
      _state(DrainState::Running)
{
}

DrainManager::~DrainManager()
{
}

bool
DrainManager::tryDrain()
{
    panic_if(_state == DrainState::Drained,
             "Trying to drain a drained system\n");

    panic_if(_count != 0,
             "Drain counter must be zero at the start of a drain cycle\n");

    DPRINTF(Drain, "Trying to drain %u objects.\n", drainableCount());
    _state = DrainState::Draining;
    for (auto *obj : _allDrainable) {
        DrainState status = obj->dmDrain();
        if (Debug::Drain && status != DrainState::Drained) {
            SimObject *temp = dynamic_cast<SimObject*>(obj);
            if (temp)
                DPRINTF(Drain, "Failed to drain %s\n", temp->name());
        }
        _count += status == DrainState::Drained ? 0 : 1;
    }

    if (_count == 0) {
        DPRINTF(Drain, "Drain done.\n");
        _state = DrainState::Drained;
        return true;
    } else {
        DPRINTF(Drain, "Need another drain cycle. %u/%u objects not ready.\n",
                _count, drainableCount());
        return false;
    }
}

void
DrainManager::resume()
{
    panic_if(_state == DrainState::Running,
             "Trying to resume a system that is already running\n");

    warn_if(_state == DrainState::Draining,
            "Resuming a system that isn't fully drained, this is untested and "
            "likely to break\n");

    panic_if(_state == DrainState::Resuming,
             "Resuming a system that is already trying to resume. This should "
             "never happen.\n");

    panic_if(_count != 0,
             "Resume called in the middle of a drain cycle. %u objects "
             "left to drain.\n", _count);

    // At this point in time the DrainManager and all objects will be
    // in the the Drained state. New objects (i.e., objects created
    // while resuming) will inherit the Resuming state from the
    // DrainManager, which means we have to resume objects until all
    // objects are in the Running state.
    _state = DrainState::Resuming;

    do {
        DPRINTF(Drain, "Resuming %u objects.\n", drainableCount());
        for (auto *obj : _allDrainable) {
            if (obj->drainState() != DrainState::Running) {
                assert(obj->drainState() == DrainState::Drained ||
                       obj->drainState() == DrainState::Resuming);
                obj->dmDrainResume();
            }
        }
    } while (!allInState(DrainState::Running));

    _state = DrainState::Running;
}

void
DrainManager::preCheckpointRestore()
{
    panic_if(_state != DrainState::Running,
             "preCheckpointRestore() called on a system that isn't in the "
             "Running state.\n");

    DPRINTF(Drain, "Applying pre-restore fixes to %u objects.\n",
            drainableCount());
    _state = DrainState::Drained;
    for (auto *obj : _allDrainable)
        obj->_drainState = DrainState::Drained;
}

void
DrainManager::signalDrainDone()
{
    assert(_count > 0);
    if (--_count == 0) {
        DPRINTF(Drain, "All %u objects drained..\n", drainableCount());
        exitSimLoop("Finished drain", 0);
    }
}

void
DrainManager::registerDrainable(Drainable *obj)
{
    std::lock_guard<std::mutex> lock(globalLock);
    assert(std::find(_allDrainable.begin(), _allDrainable.end(), obj) ==
           _allDrainable.end());
    _allDrainable.push_back(obj);
}

void
DrainManager::unregisterDrainable(Drainable *obj)
{
    std::lock_guard<std::mutex> lock(globalLock);
    auto o = std::find(_allDrainable.begin(), _allDrainable.end(), obj);
    assert(o != _allDrainable.end());
    _allDrainable.erase(o);
}

bool
DrainManager::allInState(DrainState state) const
{
    for (const auto *obj : _allDrainable) {
        if (obj->drainState() != state)
            return false;
    }

    return true;
}

size_t
DrainManager::drainableCount() const
{
    std::lock_guard<std::mutex> lock(globalLock);
    return _allDrainable.size();
}

Drainable::Drainable()
    : _drainManager(DrainManager::instance()),
      _drainState(_drainManager.state())
{
    _drainManager.registerDrainable(this);
}

Drainable::~Drainable()
{
    _drainManager.unregisterDrainable(this);
}

DrainState
Drainable::dmDrain()
{
    _drainState = DrainState::Draining;
    _drainState = drain();
    assert(_drainState == DrainState::Draining ||
           _drainState == DrainState::Drained);

    return _drainState;
}

void
Drainable::dmDrainResume()
{
    panic_if(_drainState != DrainState::Drained &&
             _drainState != DrainState::Resuming,
             "Trying to resume an object that hasn't been drained\n");

    _drainState = DrainState::Running;
    drainResume();
}
<commit_msg>sim: Remove SimObject dependency from Drainable<commit_after>/*
 * Copyright (c) 2012, 2015, 2017 ARM Limited
 * All rights reserved
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER 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.
 */

#include "sim/drain.hh"

#include <algorithm>

#include "base/logging.hh"
#include "base/named.hh"
#include "base/trace.hh"
#include "debug/Drain.hh"
#include "sim/sim_exit.hh"

DrainManager DrainManager::_instance;

DrainManager::DrainManager()
    : _count(0),
      _state(DrainState::Running)
{
}

DrainManager::~DrainManager()
{
}

bool
DrainManager::tryDrain()
{
    panic_if(_state == DrainState::Drained,
             "Trying to drain a drained system\n");

    panic_if(_count != 0,
             "Drain counter must be zero at the start of a drain cycle\n");

    DPRINTF(Drain, "Trying to drain %u objects.\n", drainableCount());
    _state = DrainState::Draining;
    for (auto *obj : _allDrainable) {
        DrainState status = obj->dmDrain();
        if (Debug::Drain && status != DrainState::Drained) {
            Named *temp = dynamic_cast<Named*>(obj);
            if (temp)
                DPRINTF(Drain, "Failed to drain %s\n", temp->name());
        }
        _count += status == DrainState::Drained ? 0 : 1;
    }

    if (_count == 0) {
        DPRINTF(Drain, "Drain done.\n");
        _state = DrainState::Drained;
        return true;
    } else {
        DPRINTF(Drain, "Need another drain cycle. %u/%u objects not ready.\n",
                _count, drainableCount());
        return false;
    }
}

void
DrainManager::resume()
{
    panic_if(_state == DrainState::Running,
             "Trying to resume a system that is already running\n");

    warn_if(_state == DrainState::Draining,
            "Resuming a system that isn't fully drained, this is untested and "
            "likely to break\n");

    panic_if(_state == DrainState::Resuming,
             "Resuming a system that is already trying to resume. This should "
             "never happen.\n");

    panic_if(_count != 0,
             "Resume called in the middle of a drain cycle. %u objects "
             "left to drain.\n", _count);

    // At this point in time the DrainManager and all objects will be
    // in the the Drained state. New objects (i.e., objects created
    // while resuming) will inherit the Resuming state from the
    // DrainManager, which means we have to resume objects until all
    // objects are in the Running state.
    _state = DrainState::Resuming;

    do {
        DPRINTF(Drain, "Resuming %u objects.\n", drainableCount());
        for (auto *obj : _allDrainable) {
            if (obj->drainState() != DrainState::Running) {
                assert(obj->drainState() == DrainState::Drained ||
                       obj->drainState() == DrainState::Resuming);
                obj->dmDrainResume();
            }
        }
    } while (!allInState(DrainState::Running));

    _state = DrainState::Running;
}

void
DrainManager::preCheckpointRestore()
{
    panic_if(_state != DrainState::Running,
             "preCheckpointRestore() called on a system that isn't in the "
             "Running state.\n");

    DPRINTF(Drain, "Applying pre-restore fixes to %u objects.\n",
            drainableCount());
    _state = DrainState::Drained;
    for (auto *obj : _allDrainable)
        obj->_drainState = DrainState::Drained;
}

void
DrainManager::signalDrainDone()
{
    assert(_count > 0);
    if (--_count == 0) {
        DPRINTF(Drain, "All %u objects drained..\n", drainableCount());
        exitSimLoop("Finished drain", 0);
    }
}

void
DrainManager::registerDrainable(Drainable *obj)
{
    std::lock_guard<std::mutex> lock(globalLock);
    assert(std::find(_allDrainable.begin(), _allDrainable.end(), obj) ==
           _allDrainable.end());
    _allDrainable.push_back(obj);
}

void
DrainManager::unregisterDrainable(Drainable *obj)
{
    std::lock_guard<std::mutex> lock(globalLock);
    auto o = std::find(_allDrainable.begin(), _allDrainable.end(), obj);
    assert(o != _allDrainable.end());
    _allDrainable.erase(o);
}

bool
DrainManager::allInState(DrainState state) const
{
    for (const auto *obj : _allDrainable) {
        if (obj->drainState() != state)
            return false;
    }

    return true;
}

size_t
DrainManager::drainableCount() const
{
    std::lock_guard<std::mutex> lock(globalLock);
    return _allDrainable.size();
}

Drainable::Drainable()
    : _drainManager(DrainManager::instance()),
      _drainState(_drainManager.state())
{
    _drainManager.registerDrainable(this);
}

Drainable::~Drainable()
{
    _drainManager.unregisterDrainable(this);
}

DrainState
Drainable::dmDrain()
{
    _drainState = DrainState::Draining;
    _drainState = drain();
    assert(_drainState == DrainState::Draining ||
           _drainState == DrainState::Drained);

    return _drainState;
}

void
Drainable::dmDrainResume()
{
    panic_if(_drainState != DrainState::Drained &&
             _drainState != DrainState::Resuming,
             "Trying to resume an object that hasn't been drained\n");

    _drainState = DrainState::Running;
    drainResume();
}
<|endoftext|>


<commit_before>// RUN: %empty-directory(%t)

// RUN: %target-swift-frontend %S/swift-functions-errors.swift -typecheck -module-name Functions -clang-header-expose-decls=has-expose-attr -emit-clang-header-path %t/functions.h

// RUN: %target-interop-build-clangxx -std=c++17 -x objective-c++ -c %s -I %t -o %t/swift-functions-errors-execution.o
// RUN: %target-interop-build-swift %S/swift-functions-errors.swift -o %t/swift-functions-errors-execution -Xlinker %t/swift-functions-errors-execution.o -module-name Functions -Xfrontend -entry-point-function-name -Xfrontend swiftMain

// RUN: %target-codesign %t/swift-functions-errors-execution
// RUN: %target-run %t/swift-functions-errors-execution | %FileCheck %s

// REQUIRES: executable_test

#include <cassert>
#include <cstdio>
#include "functions.h"

int main() {
  static_assert(!noexcept(Functions::emptyThrowFunction()), "noexcept function");
  static_assert(!noexcept(Functions::throwFunction()), "noexcept function");
  static_assert(!noexcept(Functions::throwFunctionWithReturn()), "noexcept function");

  try {
    Functions::emptyThrowFunction();
  } catch (swift::Error& e) {
    printf("Exception\n");
  }
  try {
    Functions::throwFunction();
  } catch (swift::Error& e) {
      auto errorVal = e.as<Functions::NaiveErrors>();
      if (errorVal) {
        assert(errorVal == Functions::NaiveErrors::throwError);
        errorVal->getMessage();
      }
  }
  try {
    Functions::throwFunctionWithReturn();
  } catch (swift::Error& e) {
     printf("Exception\n");
  }
  try {
    Functions::testDestroyedError();
  } catch(const swift::Error &e) { }

  return 0;
}

// CHECK: passEmptyThrowFunction
// CHECK-NEXT: passThrowFunction
// CHECK-NEXT: throwError
// CHECK-NEXT: passThrowFunctionWithReturn
// CHECK-NEXT: Exception
// CHECK-NEXT: Test destroyed<commit_msg>Fixing test to check the new realist implementation of dynamic cast<commit_after>// RUN: %empty-directory(%t)

// RUN: %target-swift-frontend %S/swift-functions-errors.swift -typecheck -module-name Functions -clang-header-expose-decls=has-expose-attr -emit-clang-header-path %t/functions.h

// RUN: %target-interop-build-clangxx -std=c++17 -x objective-c++ -c %s -I %t -o %t/swift-functions-errors-execution.o
// RUN: %target-interop-build-swift %S/swift-functions-errors.swift -o %t/swift-functions-errors-execution -Xlinker %t/swift-functions-errors-execution.o -module-name Functions -Xfrontend -entry-point-function-name -Xfrontend swiftMain

// RUN: %target-codesign %t/swift-functions-errors-execution
// RUN: %target-run %t/swift-functions-errors-execution | %FileCheck %s

// REQUIRES: executable_test

#include <cassert>
#include <cstdio>
#include "functions.h"

int main() {
  static_assert(!noexcept(Functions::emptyThrowFunction()), "noexcept function");
  static_assert(!noexcept(Functions::throwFunction()), "noexcept function");
  static_assert(!noexcept(Functions::throwFunctionWithReturn()), "noexcept function");

  try {
    Functions::emptyThrowFunction();
  } catch (swift::Error& e) {
    printf("Exception\n");
  }
  try {
    Functions::throwFunction();
  } catch (swift::Error& e) {
      auto errorVal = e.as<Functions::NaiveErrors>();
      assert(errorVal == Functions::NaiveErrors::throwError);
      errorVal.getMessage();
  }
  try {
    Functions::throwFunctionWithReturn();
  } catch (swift::Error& e) {
     printf("Exception\n");
  }
  try {
    Functions::testDestroyedError();
  } catch(const swift::Error &e) { }

  return 0;
}

// CHECK: passEmptyThrowFunction
// CHECK-NEXT: passThrowFunction
// CHECK-NEXT: throwError
// CHECK-NEXT: passThrowFunctionWithReturn
// CHECK-NEXT: Exception
// CHECK-NEXT: Test destroyed
<|endoftext|>


<commit_before><commit_msg>Add the initial template of the solution to question 3.8<commit_after><|endoftext|>


<commit_before>/*!
*	@file	libpsalm.cpp
*	@brief	Exports a function for filling holes in meshes. Used by GigaMesh.
*	@author	Bastian Rieck <bastian.rieck@iwr.uni-heidelberg.de>
*/

#include <sstream>
#include <string>
#include <vector>

#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <boost/uuid/uuid_generators.hpp>

#include "libpsalm.h"
#include "mesh.h"

#include "SubdivisionAlgorithms/Liepa.h"
#include "TriangulationAlgorithms/MinimumWeightTriangulation.h"

/*!
*	Generates a filename by creating a UUID and attaching the extension
*	onto it. This function is used for debugging purposes in order to save
*	auxiliary results of the triangulation.
*
*	@param	extension File extension
*	@return UUID.extension as a filename
*/

std::string generate_filename(std::string extension = "ply")
{
	boost::uuids::uuid uuid = boost::uuids::random_generator()();

	std::stringstream converter;
	converter << uuid << "." << extension;

	return(converter.str());
}

/*!
*	Given a polygonal line described as a list of vertices, this function
*	triangulates the hole and subdivides it. Afterwards, the new data is
*	stored in some arrays given as parameters of the caller.
*
*	@param num_vertices	Number of vertices in polygonal line
*	@param vertex_IDs	List of vertex IDs, used to identify them. If
*				this parameter is NULL, the mesh class will
*				assign sequential vertex IDs, starting with 0.
*	@param coordinates	Array of vertex coordinates (size: 3*num_vertices)
*	@param normals		Array of vertex normals (size: 3*num_vertices)
*	@param desired_density	Desired density value (approximate) for the
*				filled hole
*
*	@param num_new_vertices	Number of new vertices created by the algorithm
*	@param new_coordinates	Array of vertex coordinates created by the
*				algorithm (size: 3*num_new_vertices)
*	@param num_new_faces	Number of new faces created by the algorithm
*	@param new_vertex_IDs	List of vertex IDs for the new faces (size:
*				3*num_new_faces). Negative IDs signify that the
*				vertex is _not_ new.
*
*	The nomenclature here might be confusing: new_vertex_IDs contains 3
*	vertex IDs that describe a new face created by the algorithm.
*
*	@returns true if the hole could be filled, otherwise false
*/

bool fill_hole(	int num_vertices, long* vertex_IDs, double* coordinates, double* normals, double desired_density,
		int* num_new_vertices, double** new_coordinates, int* num_new_faces, long** new_vertex_IDs)
{
	bool result = true;
	if(	num_vertices == 0		||
		coordinates == NULL		||
		num_new_vertices == NULL	||
		new_coordinates == NULL		||
		num_new_faces == NULL		||
		new_vertex_IDs == NULL)
		return(false);

	psalm::mesh M;

	psalm::Liepa liepa_algorithm;
	psalm::MinimumWeightTriangulation triangulation_algorithm;

	M.load_raw_data(num_vertices, vertex_IDs, coordinates, normals);

	result = triangulation_algorithm.apply_to(M);						// step 1: triangulate the hole

	double density = M.get_density();
	if(density <= desired_density)
		liepa_algorithm.set_alpha(libpsalm::estimate_density(	density,		// step 2: estimate density based on input parameters
												// and the triangulation from step 1
									desired_density));
	else
		liepa_algorithm.set_alpha(1.0);

	result = (result && liepa_algorithm.apply_to(M));					// step 3: apply Liepa's subdivision scheme; density
												// parameter has been set in step 2

	if(result)
	{
		M.save_raw_data(num_new_vertices,
				new_coordinates,
				num_new_faces,
				new_vertex_IDs);

		/*
		   XXX

		   system("touch cat.ply");
		   M.save("test.ply");
		   M.save(generate_filename());
		   system("../catply.pl test.ply cat.ply > cat_.ply");
		   system("mv cat_.ply cat.ply");
		*/
	}

	// signal an error for the calling function
	else
	{
		*num_new_vertices	= 0;
		*num_new_faces		= 0;
	}

	return(result);
}

/*!
*	Given a mesh input density and the desired density of the triangulated
*	hole, calculates an estimate for the density parameter of Liepa's
*	subdivision scheme.
*
*	@param input_density	Average density of the input data
*	@param desired_density	Desired density of triangulated hole
*
*	@returns Estimated value for the alpha parameter of Liepa's subdivision
*	scheme.
*
*	@warning The estimation is only useful for density values < 2000. A
*	density much larger than this would require separate treatment.
*/

namespace libpsalm
{

double estimate_density(double input_density, double desired_density)
{
	// Fitted parameter values with asymptotic standard error of < 3%,
	// which is sufficient for most mesh data.

	double a0 =  7.63324e-07;
	double a1 = -0.00710062;
	double b0 = -4.70052e-07;
	double b1 =  0.00573126 ;
	double c0 =  2.29083;

	/*
	double a0 =  6.08864e-07;
	double a1 = -0.00167679;
	double b0 = -1.61397e-06;
	double b1 =  0.00500891;
	double c0 =  1.77846;
	*/

	double x = input_density; // abbreviations so that the function is written more easily
	double y = desired_density;

	return(a0*x*x+a1*x+b0*y*y+b1*y+c0);
}

} // end of namespace "libpsalm"
<commit_msg>libpsalm: Removed old density parameter values<commit_after>/*!
*	@file	libpsalm.cpp
*	@brief	Exports a function for filling holes in meshes. Used by GigaMesh.
*	@author	Bastian Rieck <bastian.rieck@iwr.uni-heidelberg.de>
*/

#include <sstream>
#include <string>
#include <vector>

#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <boost/uuid/uuid_generators.hpp>

#include "libpsalm.h"
#include "mesh.h"

#include "SubdivisionAlgorithms/Liepa.h"
#include "TriangulationAlgorithms/MinimumWeightTriangulation.h"

/*!
*	Generates a filename by creating a UUID and attaching the extension
*	onto it. This function is used for debugging purposes in order to save
*	auxiliary results of the triangulation.
*
*	@param	extension File extension
*	@return UUID.extension as a filename
*/

std::string generate_filename(std::string extension = "ply")
{
	boost::uuids::uuid uuid = boost::uuids::random_generator()();

	std::stringstream converter;
	converter << uuid << "." << extension;

	return(converter.str());
}

/*!
*	Given a polygonal line described as a list of vertices, this function
*	triangulates the hole and subdivides it. Afterwards, the new data is
*	stored in some arrays given as parameters of the caller.
*
*	@param num_vertices	Number of vertices in polygonal line
*	@param vertex_IDs	List of vertex IDs, used to identify them. If
*				this parameter is NULL, the mesh class will
*				assign sequential vertex IDs, starting with 0.
*	@param coordinates	Array of vertex coordinates (size: 3*num_vertices)
*	@param normals		Array of vertex normals (size: 3*num_vertices)
*	@param desired_density	Desired density value (approximate) for the
*				filled hole
*
*	@param num_new_vertices	Number of new vertices created by the algorithm
*	@param new_coordinates	Array of vertex coordinates created by the
*				algorithm (size: 3*num_new_vertices)
*	@param num_new_faces	Number of new faces created by the algorithm
*	@param new_vertex_IDs	List of vertex IDs for the new faces (size:
*				3*num_new_faces). Negative IDs signify that the
*				vertex is _not_ new.
*
*	The nomenclature here might be confusing: new_vertex_IDs contains 3
*	vertex IDs that describe a new face created by the algorithm.
*
*	@returns true if the hole could be filled, otherwise false
*/

bool fill_hole(	int num_vertices, long* vertex_IDs, double* coordinates, double* normals, double desired_density,
		int* num_new_vertices, double** new_coordinates, int* num_new_faces, long** new_vertex_IDs)
{
	bool result = true;
	if(	num_vertices == 0		||
		coordinates == NULL		||
		num_new_vertices == NULL	||
		new_coordinates == NULL		||
		num_new_faces == NULL		||
		new_vertex_IDs == NULL)
		return(false);

	psalm::mesh M;

	psalm::Liepa liepa_algorithm;
	psalm::MinimumWeightTriangulation triangulation_algorithm;

	M.load_raw_data(num_vertices, vertex_IDs, coordinates, normals);

	result = triangulation_algorithm.apply_to(M);						// step 1: triangulate the hole

	double density = M.get_density();
	if(density <= desired_density)
		liepa_algorithm.set_alpha(libpsalm::estimate_density(	density,		// step 2: estimate density based on input parameters
												// and the triangulation from step 1
									desired_density));
	else
		liepa_algorithm.set_alpha(1.0);

	result = (result && liepa_algorithm.apply_to(M));					// step 3: apply Liepa's subdivision scheme; density
												// parameter has been set in step 2

	if(result)
	{
		M.save_raw_data(num_new_vertices,
				new_coordinates,
				num_new_faces,
				new_vertex_IDs);

		/*
		   XXX

		   system("touch cat.ply");
		   M.save("test.ply");
		   M.save(generate_filename());
		   system("../catply.pl test.ply cat.ply > cat_.ply");
		   system("mv cat_.ply cat.ply");
		*/
	}

	// signal an error for the calling function
	else
	{
		*num_new_vertices	= 0;
		*num_new_faces		= 0;
	}

	return(result);
}

/*!
*	Given a mesh input density and the desired density of the triangulated
*	hole, calculates an estimate for the density parameter of Liepa's
*	subdivision scheme.
*
*	@param input_density	Average density of the input data
*	@param desired_density	Desired density of triangulated hole
*
*	@returns Estimated value for the alpha parameter of Liepa's subdivision
*	scheme.
*
*	@warning The estimation is only useful for density values < 2000. A
*	density much larger than this would require separate treatment.
*/

namespace libpsalm
{

double estimate_density(double input_density, double desired_density)
{
	// Fitted parameter values with asymptotic standard error of < 3%,
	// which is sufficient for most mesh data.

	double a0 =  7.63324e-07;
	double a1 = -0.00710062;
	double b0 = -4.70052e-07;
	double b1 =  0.00573126 ;
	double c0 =  2.29083;

	double x = input_density; // abbreviations so that the function is written more easily
	double y = desired_density;

	return(a0*x*x+a1*x+b0*y*y+b1*y+c0);
}

} // end of namespace "libpsalm"
<|endoftext|>