<commit_before>//
// Created by Dennis Goldfarb on 9/28/16.
//

#include <iostream>
#include <fstream>
#include <random>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>

#include <OpenMS/CHEMISTRY/AASequence.h>
#include <OpenMS/CHEMISTRY/ResidueDB.h>
#include <OpenMS/CHEMISTRY/ElementDB.h>

static const OpenMS::ResidueDB* residueDB = OpenMS::ResidueDB::getInstance();
static const OpenMS::ElementDB* elementDB = OpenMS::ElementDB::getInstance();

static std::string AMINO_ACIDS = "ADEFGHIKLNPQRSTVWY";
static std::string AMINO_ACIDS_SULFUR = "CM";
static std::string AMINO_ACIDS_SELENIUM = "U";

std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis_AA(0, AMINO_ACIDS.length()-1);
std::uniform_int_distribution<> dis_S(0, AMINO_ACIDS_SULFUR.length()-1);

int max_depth;

OpenMS::AASequence create_random_peptide_sequence(int peptide_length, int num_sulfurs, int num_c_sulfurs, int num_selenium, int num_c_selenium) {
    OpenMS::AASequence random_peptide;

    // for insertion of sulfur containing amino acids in fragment
    for (int i = 0; i < num_sulfurs; ++i) {
        random_peptide += residueDB->getResidue(AMINO_ACIDS_SULFUR[dis_S(gen)]);
    }

    // for insertion of selenocysteines in fragment
    for (int i = 0; i < num_selenium; ++i) {
        random_peptide += residueDB->getResidue(AMINO_ACIDS_SELENIUM[0]);
    }

    // random amino acid insertion (non Sulfur and Selenium amino acids)
    for (int aa_index = 0; aa_index < peptide_length; ++aa_index) {
        random_peptide += residueDB->getResidue(AMINO_ACIDS[dis_AA(gen)]);
    }

    // for insertion of sulfur containing amino acids in fragment
    for (int i = 0; i < num_c_sulfurs; ++i) {
        random_peptide += residueDB->getResidue(AMINO_ACIDS_SULFUR[dis_S(gen)]);
    }

    // for insertion of selenocysteines in fragment
    for (int i = 0; i < num_c_selenium; ++i) {
        random_peptide += residueDB->getResidue(AMINO_ACIDS_SELENIUM[0]);
    }

    return random_peptide;
}

void create_fragments(OpenMS::AASequence &p, std::ofstream** outfiles, int num_sulfurs, int num_c_sulfurs, int num_selenium, int num_c_selenium) {
    int num_fragments = p.size()-1;

    int tot_left_SSe = std::max(num_sulfurs + num_selenium,1);
    int tot_right_SSe = std::max(num_c_sulfurs + num_c_selenium,1);

    OpenMS::EmpiricalFormula precursor_ef = p.getFormula();

    for (int index = tot_left_SSe; index < num_fragments-tot_right_SSe; ++index)
    {
        OpenMS::EmpiricalFormula b_ion = p.getPrefix(index).getFormula(OpenMS::Residue::ResidueType::BIon);
        OpenMS::EmpiricalFormula y_ion = p.getPrefix(index).getFormula(OpenMS::Residue::ResidueType::YIon);

        for (int precursor_isotope = 0; precursor_isotope < max_depth; ++precursor_isotope)
        {
            std::vector<OpenMS::UInt> isolated_isotopes;
            isolated_isotopes.push_back(precursor_isotope);

            OpenMS::IsotopeDistribution b_id = b_ion.getConditionalFragmentIsotopeDist(precursor_ef, isolated_isotopes);
            OpenMS::IsotopeDistribution y_id = y_ion.getConditionalFragmentIsotopeDist(precursor_ef, isolated_isotopes);

            for (int fragment_isotope = 0; fragment_isotope <= precursor_isotope && fragment_isotope < b_id.size(); ++fragment_isotope)
            {
                outfiles[precursor_isotope][fragment_isotope] << b_id.getContainer()[fragment_isotope].second
                                                              << "\t" << b_ion.getMonoWeight()
                                                              << "\t" << p.getMonoWeight() << std::endl;
                outfiles[precursor_isotope][fragment_isotope] << y_id.getContainer()[fragment_isotope].second
                                                              << "\t" << y_ion.getMonoWeight()
                                                              << "\t" << p.getMonoWeight() << std::endl;
            }
        }
    }
}

void sample_fragment_isotopic_distributions(std::string base_path, float max_mass, int num_samples, int num_sulfurs, int num_c_sulfurs, int num_selenium, int num_c_selenium) {

    // create all output files and write header to each
    std::ofstream** outfiles = new std::ofstream*[max_depth];
    for (int precursor_isotope = 1; precursor_isotope < max_depth; ++precursor_isotope) {
        outfiles[precursor_isotope] = new std::ofstream[max_depth];
        for (int fragment_isotope = 0; fragment_isotope <= precursor_isotope; ++fragment_isotope) {
            std::string filename = "Precursor" + std::to_string(precursor_isotope) + "_" +
                                   "Fragment" + std::to_string(fragment_isotope) + ".tab";
            outfiles[precursor_isotope][fragment_isotope].open(base_path + filename);

            outfiles[precursor_isotope][fragment_isotope] << "probability" << "\tfrag.mass" << "\tprecursor.mass" << std::endl; //"\tfrag.a.mass" << "\tprecursor.a.mass" << std::endl;
        }
    }

    int max_length = max_mass/100;

    for (int peptide_length = 0; peptide_length <= max_length; ++peptide_length) {

        for (int sample = 0; sample < num_samples; ++sample) {

            OpenMS::AASequence random_sequence = create_random_peptide_sequence(peptide_length, num_sulfurs, num_c_sulfurs,
                                                                         num_selenium, num_c_selenium);

            if (random_sequence.size() > 0 && random_sequence.getMonoWeight() <= max_mass) {
                create_fragments(random_sequence, outfiles, num_sulfurs, num_c_sulfurs, num_selenium, num_c_selenium);
            }
        }

    }

    // close all output files
    for (int precursor_isotope = 1; precursor_isotope < max_depth; ++precursor_isotope) {
        for (int fragment_isotope = 0; fragment_isotope <= precursor_isotope; ++fragment_isotope) {
            outfiles[precursor_isotope][fragment_isotope].close();
        }
        delete[] outfiles[precursor_isotope];
    }
    delete[] outfiles;
}

void usage()
{
    std::cout << "PeptideFragmentSampler out_path max_mass num_samples S CS Se CSe max_isotope" << std::endl;
    std::cout << "out_path: The path to the directory that will store the training data, e.g. ~/data/" << std::endl;
    std::cout << "max_mass: maximum mass allowed for sampled peptides, e.g. 8500" << std::endl;
    std::cout << "num_samples: number of random peptides to generate for each peptide length, e.g 100" << std::endl;
    std::cout << "S: number of sulfurs that should be in the fragment ion, e.g. 0" << std::endl;
    std::cout << "CS: number of sulfurs that should be in the complementary fragment ion, e.g. 0" << std::endl;
    std::cout << "Se: number of seleniums that should be in the fragment ion, e.g. 0" << std::endl;
    std::cout << "CSe: number of seleniums that should be in the complementary fragment ion, e.g. 0" << std::endl;
    std::cout << "max_isotope: The maximum isotope to generate training data for, e.g. 5" << std::endl;
}

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

    if (argc != 8)
    {
        usage();
    }

    // Increase the maximum number of open files for this process. Was necessary for me.
    struct rlimit rlp;
    rlp.rlim_cur = 600;
    setrlimit(RLIMIT_NOFILE, &rlp);

    max_depth = atoi(argv[8])+1;
    sample_fragment_isotopic_distributions(argv[1], atof(argv[2]), atoi(argv[3]), atoi(argv[4]), atoi(argv[5]), atoi(argv[6]), atoi(argv[7]));

    return 0;
}<commit_msg>had the number of command line arguments wrong<commit_after>//
// Created by Dennis Goldfarb on 9/28/16.
//

#include <iostream>
#include <fstream>
#include <random>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>

#include <OpenMS/CHEMISTRY/AASequence.h>
#include <OpenMS/CHEMISTRY/ResidueDB.h>
#include <OpenMS/CHEMISTRY/ElementDB.h>

static const OpenMS::ResidueDB* residueDB = OpenMS::ResidueDB::getInstance();
static const OpenMS::ElementDB* elementDB = OpenMS::ElementDB::getInstance();

static std::string AMINO_ACIDS = "ADEFGHIKLNPQRSTVWY";
static std::string AMINO_ACIDS_SULFUR = "CM";
static std::string AMINO_ACIDS_SELENIUM = "U";

std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis_AA(0, AMINO_ACIDS.length()-1);
std::uniform_int_distribution<> dis_S(0, AMINO_ACIDS_SULFUR.length()-1);

int max_depth;

OpenMS::AASequence create_random_peptide_sequence(int peptide_length, int num_sulfurs, int num_c_sulfurs, int num_selenium, int num_c_selenium) {
    OpenMS::AASequence random_peptide;

    // for insertion of sulfur containing amino acids in fragment
    for (int i = 0; i < num_sulfurs; ++i) {
        random_peptide += residueDB->getResidue(AMINO_ACIDS_SULFUR[dis_S(gen)]);
    }

    // for insertion of selenocysteines in fragment
    for (int i = 0; i < num_selenium; ++i) {
        random_peptide += residueDB->getResidue(AMINO_ACIDS_SELENIUM[0]);
    }

    // random amino acid insertion (non Sulfur and Selenium amino acids)
    for (int aa_index = 0; aa_index < peptide_length; ++aa_index) {
        random_peptide += residueDB->getResidue(AMINO_ACIDS[dis_AA(gen)]);
    }

    // for insertion of sulfur containing amino acids in fragment
    for (int i = 0; i < num_c_sulfurs; ++i) {
        random_peptide += residueDB->getResidue(AMINO_ACIDS_SULFUR[dis_S(gen)]);
    }

    // for insertion of selenocysteines in fragment
    for (int i = 0; i < num_c_selenium; ++i) {
        random_peptide += residueDB->getResidue(AMINO_ACIDS_SELENIUM[0]);
    }

    return random_peptide;
}

void create_fragments(OpenMS::AASequence &p, std::ofstream** outfiles, int num_sulfurs, int num_c_sulfurs, int num_selenium, int num_c_selenium) {
    int num_fragments = p.size()-1;

    int tot_left_SSe = std::max(num_sulfurs + num_selenium,1);
    int tot_right_SSe = std::max(num_c_sulfurs + num_c_selenium,1);

    OpenMS::EmpiricalFormula precursor_ef = p.getFormula();

    for (int index = tot_left_SSe; index < num_fragments-tot_right_SSe; ++index)
    {
        OpenMS::EmpiricalFormula b_ion = p.getPrefix(index).getFormula(OpenMS::Residue::ResidueType::BIon);
        OpenMS::EmpiricalFormula y_ion = p.getPrefix(index).getFormula(OpenMS::Residue::ResidueType::YIon);

        for (int precursor_isotope = 0; precursor_isotope < max_depth; ++precursor_isotope)
        {
            std::vector<OpenMS::UInt> isolated_isotopes;
            isolated_isotopes.push_back(precursor_isotope);

            OpenMS::IsotopeDistribution b_id = b_ion.getConditionalFragmentIsotopeDist(precursor_ef, isolated_isotopes);
            OpenMS::IsotopeDistribution y_id = y_ion.getConditionalFragmentIsotopeDist(precursor_ef, isolated_isotopes);

            for (int fragment_isotope = 0; fragment_isotope <= precursor_isotope && fragment_isotope < b_id.size(); ++fragment_isotope)
            {
                outfiles[precursor_isotope][fragment_isotope] << b_id.getContainer()[fragment_isotope].second
                                                              << "\t" << b_ion.getMonoWeight()
                                                              << "\t" << p.getMonoWeight() << std::endl;
                outfiles[precursor_isotope][fragment_isotope] << y_id.getContainer()[fragment_isotope].second
                                                              << "\t" << y_ion.getMonoWeight()
                                                              << "\t" << p.getMonoWeight() << std::endl;
            }
        }
    }
}

void sample_fragment_isotopic_distributions(std::string base_path, float max_mass, int num_samples, int num_sulfurs, int num_c_sulfurs, int num_selenium, int num_c_selenium) {

    // create all output files and write header to each
    std::ofstream** outfiles = new std::ofstream*[max_depth];
    for (int precursor_isotope = 1; precursor_isotope < max_depth; ++precursor_isotope) {
        outfiles[precursor_isotope] = new std::ofstream[max_depth];
        for (int fragment_isotope = 0; fragment_isotope <= precursor_isotope; ++fragment_isotope) {
            std::string filename = "Precursor" + std::to_string(precursor_isotope) + "_" +
                                   "Fragment" + std::to_string(fragment_isotope) + ".tab";
            outfiles[precursor_isotope][fragment_isotope].open(base_path + filename);

            outfiles[precursor_isotope][fragment_isotope] << "probability" << "\tfrag.mass" << "\tprecursor.mass" << std::endl; //"\tfrag.a.mass" << "\tprecursor.a.mass" << std::endl;
        }
    }

    int max_length = max_mass/100;

    for (int peptide_length = 0; peptide_length <= max_length; ++peptide_length) {

        for (int sample = 0; sample < num_samples; ++sample) {

            OpenMS::AASequence random_sequence = create_random_peptide_sequence(peptide_length, num_sulfurs, num_c_sulfurs,
                                                                         num_selenium, num_c_selenium);

            if (random_sequence.size() > 0 && random_sequence.getMonoWeight() <= max_mass) {
                create_fragments(random_sequence, outfiles, num_sulfurs, num_c_sulfurs, num_selenium, num_c_selenium);
            }
        }

    }

    // close all output files
    for (int precursor_isotope = 1; precursor_isotope < max_depth; ++precursor_isotope) {
        for (int fragment_isotope = 0; fragment_isotope <= precursor_isotope; ++fragment_isotope) {
            outfiles[precursor_isotope][fragment_isotope].close();
        }
        delete[] outfiles[precursor_isotope];
    }
    delete[] outfiles;
}

void usage()
{
    std::cout << "PeptideFragmentSampler out_path max_mass num_samples S CS Se CSe max_isotope" << std::endl;
    std::cout << "out_path: The path to the directory that will store the training data, e.g. ~/data/" << std::endl;
    std::cout << "max_mass: maximum mass allowed for sampled peptides, e.g. 8500" << std::endl;
    std::cout << "num_samples: number of random peptides to generate for each peptide length, e.g 100" << std::endl;
    std::cout << "S: number of sulfurs that should be in the fragment ion, e.g. 0" << std::endl;
    std::cout << "CS: number of sulfurs that should be in the complementary fragment ion, e.g. 0" << std::endl;
    std::cout << "Se: number of seleniums that should be in the fragment ion, e.g. 0" << std::endl;
    std::cout << "CSe: number of seleniums that should be in the complementary fragment ion, e.g. 0" << std::endl;
    std::cout << "max_isotope: The maximum isotope to generate training data for, e.g. 5" << std::endl;
}

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

    if (argc != 9)
    {
        usage();
    }

    // Increase the maximum number of open files for this process. Was necessary for me.
    struct rlimit rlp;
    rlp.rlim_cur = 600;
    setrlimit(RLIMIT_NOFILE, &rlp);

    max_depth = atoi(argv[8])+1;
    sample_fragment_isotopic_distributions(argv[1], atof(argv[2]), atoi(argv[3]), atoi(argv[4]), atoi(argv[5]), atoi(argv[6]), atoi(argv[7]));

    return 0;
}<|endoftext|>


<commit_before>/***
Created by: Veer Shubhranshu Shrivastav
Mail: veer@veershubhranshu.com
Copyright: Veer S. Shrivastav

SQLHelper version1.0

SQLHelper - SelectDBExample.cpp

In this file, I am trying to show you how to use Multiple connection
with the database. this is one of the best way to use this library
for creating multiple connection. Somehow, there may be some memory error
which is yet to be sorted. You can use this library for your use to create multiple
connections.

**Note:
     If you look closely at the structure
     of program you will find that I have
     declared the two databases but have
     not opened it without use. When you
     open a database, the previous connection
     is lost. Good part in this is you don't
     need to explicitely close the connection.
     It is handled automatically.

**Suggestion:
     Try to use this library with only one database.
     If you need to access another database, try to use
     synonyms in that case.

     Do not switch database unnecessarily. It is a
     good habbit to fetch data just from one table.
     Else it can result in massive outputs.

This program works in following manner:

1. Connection to databases are declared BUT NOT CONNECTED.

2. Under try-catch block the connection is opened for first database.

3. Value is fetched and used.

4. Again when the other SQLHelper Object makes a connection, the previous
   connection is closed and the connection is re-written over the
   previous connection pointer.

5. Again the Data is fetched from the newly connected database.

**Explanation:
     SQLHelper can make multiple connection, however it holds one
     connection at a time. That is, when you will write a normal
     program, before connecting to the database, you have to disconnect
     from the current database being used.

     Here you don't need to bother about closing the connection.
     It is handled automatically. Just create the new connection and
     it will close the previous connection.

     You can think it another way also, you can hold only one connection
     at a time, when using Oracle Database - sqlplus. To make another
     connection you have to open a new SSH connection to the server over
     new window.

****/
#include<iostream>
#include<vector>
using namespace std;
#include "../../SQLHelper/SQLHelper.h"
#include "../../SQLHelperException/SQLHelperException.h"

int main()
{
     SQLHelper DB("scott@unixdb","tiger");
     SQLHelper DB2("veer@unixdb","Veer");
     vector< vector<string> > rowData;
     try
     {
          DB.openDB();
          if(DB.checkDBStatus())
          {
               cout<<"connected"<<endl;
          }
          rowData=DB.selectDB("select * from veer_date");
          if(rowData.size()>0)
          {
               for(int i=0;i<rowData.size();i++)
               {
                    for(int j=0;j<rowData.at(i).size();j++)
                    {
                         cout<<rowData.at(i).at(j)<<"\t";
                    }
                    cout<<endl;
               }
          }
          else
          {
               cout<<"No rows fetched"<<endl;
          }

          DB2.openDB();
          rowData = DB2.selectDB("select to_char(sysdate) from dual");
          if(rowData.size()>0)
          {
               for(int i=0;i<rowData.size();i++)
               {
                    for(int j=0;j<rowData.at(i).size();j++)
                    {
                         cout<<rowData.at(i).at(j);
                    }
                    cout<<endl;
               }
          }
          else
          {
               cout<<"No rows fetched"<<endl;
          }
          DB.openDB();
          rowData=DB.selectDB("select * from veer_date");
          if(rowData.size()>0)
          {
               for(int i=0;i<rowData.size();i++)
               {
                    for(int j=0;j<rowData.at(i).size();j++)
                    {
                         cout<<rowData.at(i).at(j)<<"\t";
                    }
                    cout<<endl;
               }
          }
          else
          {
               cout<<"No rows fetched"<<endl;
          }

     }
     catch(SQLHelperException sqlExp)
     {
          cout<<sqlExp.getExceptionString()<<endl;
     }
	return 0;
}

<commit_msg>Update MultipleConnection.cpp<commit_after>/***
Created by: Veer Shubhranshu Shrivastav
Mail: veer@veershubhranshu.com
Copyright: Veer S. Shrivastav

SQLHelper version1.0

SQLHelper - MultipleConnection.cpp

In this file, I am trying to show you how to use Multiple connection
with the database. this is one of the best way to use this library
for creating multiple connection. Somehow, there may be some memory error
which is yet to be sorted. You can use this library for your use to create multiple
connections.

**Note:
     If you look closely at the structure
     of program you will find that I have
     declared the two databases but have
     not opened it without use. When you
     open a database, the previous connection
     is lost. Good part in this is you don't
     need to explicitely close the connection.
     It is handled automatically.

**Suggestion:
     Try to use this library with only one database.
     If you need to access another database, try to use
     synonyms in that case.

     Do not switch database unnecessarily. It is a
     good habbit to fetch data just from one table.
     Else it can result in massive outputs.

This program works in following manner:

1. Connection to databases are declared BUT NOT CONNECTED.

2. Under try-catch block the connection is opened for first database.

3. Value is fetched and used.

4. Again when the other SQLHelper Object makes a connection, the previous
   connection is closed and the connection is re-written over the
   previous connection pointer.

5. Again the Data is fetched from the newly connected database.

**Explanation:
     SQLHelper can make multiple connection, however it holds one
     connection at a time. That is, when you will write a normal
     program, before connecting to the database, you have to disconnect
     from the current database being used.

     Here you don't need to bother about closing the connection.
     It is handled automatically. Just create the new connection and
     it will close the previous connection.

     You can think it another way also, you can hold only one connection
     at a time, when using Oracle Database - sqlplus. To make another
     connection you have to open a new SSH connection to the server over
     new window.

****/
#include<iostream>
#include<vector>
using namespace std;
#include "../../SQLHelper/SQLHelper.h"
#include "../../SQLHelperException/SQLHelperException.h"

int main()
{
     SQLHelper DB("scott@unixdb","tiger");
     SQLHelper DB2("veer@unixdb","Veer");
     vector< vector<string> > rowData;
     try
     {
          DB.openDB();
          if(DB.checkDBStatus())
          {
               cout<<"connected"<<endl;
          }
          rowData=DB.selectDB("select * from veer_date");
          if(rowData.size()>0)
          {
               for(int i=0;i<rowData.size();i++)
               {
                    for(int j=0;j<rowData.at(i).size();j++)
                    {
                         cout<<rowData.at(i).at(j)<<"\t";
                    }
                    cout<<endl;
               }
          }
          else
          {
               cout<<"No rows fetched"<<endl;
          }

          DB2.openDB();
          rowData = DB2.selectDB("select to_char(sysdate) from dual");
          if(rowData.size()>0)
          {
               for(int i=0;i<rowData.size();i++)
               {
                    for(int j=0;j<rowData.at(i).size();j++)
                    {
                         cout<<rowData.at(i).at(j);
                    }
                    cout<<endl;
               }
          }
          else
          {
               cout<<"No rows fetched"<<endl;
          }
          DB.openDB();
          rowData=DB.selectDB("select * from veer_date");
          if(rowData.size()>0)
          {
               for(int i=0;i<rowData.size();i++)
               {
                    for(int j=0;j<rowData.at(i).size();j++)
                    {
                         cout<<rowData.at(i).at(j)<<"\t";
                    }
                    cout<<endl;
               }
          }
          else
          {
               cout<<"No rows fetched"<<endl;
          }

     }
     catch(SQLHelperException sqlExp)
     {
          cout<<sqlExp.getExceptionString()<<endl;
     }
	return 0;
}

<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/p9_mss_draminit_training_adv.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2017,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
///
/// @file p9_mss_draminit_training_adv.C
/// @brief Perform read_centering again but with a custom pattern for better eye
///
// *HWP HWP Owner: Jacob Harvey <jlharvey@us.ibm.com>
// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 3
// *HWP Consumed by: FSP:HB

#include <fapi2.H>
#include <mss.H>
#include <vector>

#include <p9_mss_draminit_training_adv.H>
#include <lib/utils/count_dimm.H>
#include <lib/shared/mss_const.H>
#include <lib/phy/dp16.H>
#include <lib/phy/seq.H>
#include <lib/phy/ddr_phy.H>
#include <lib/phy/mss_training.H>

using fapi2::TARGET_TYPE_MCBIST;
using fapi2::TARGET_TYPE_MCA;

extern "C"
{
///
/// @brief Perform training_adv on the dimms (perform read centering with custom pattern)
/// @param[in] i_target, the McBIST of the ports of the dram you're training
/// @param[in] i_abort_on_error, optional CAL_ABORT_ON_ERROR override. Used in sim, debug
/// @return FAPI2_RC_SUCCESS iff ok
/// @note turn off rd cntr periodic cal if training_adv is run. Add OFF value for CUSTOM_PATTERN?
///

    fapi2::ReturnCode p9_mss_draminit_training_adv( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target,
            const uint8_t i_abort_on_error)
    {
        uint8_t l_cal_abort_on_error = i_abort_on_error;
        uint8_t l_sim = 0;
        FAPI_TRY( mss::is_simulation (l_sim) );

        FAPI_INF("Start draminit training advance %s", mss::c_str(i_target));

        // If there are no DIMMs installed, we don't need to bother. In fact, we can't as we didn't setup
        // attributes for the PHY, etc.
        if (mss::count_dimm(i_target) == 0 || l_sim)
        {
            FAPI_INF("... skipping draminit_training_adv %s... %s Dimms. %s SIM.",
                     mss::c_str(i_target),
                     mss::count_dimm(i_target) == 0 ? "Has no" : "Has",
                     l_sim ? "Is" : "Is not");
            return fapi2::FAPI2_RC_SUCCESS;
        }

        if (i_abort_on_error == CAL_ADV_ABORT_SENTINAL)
        {
            FAPI_TRY( mss::cal_abort_on_error(l_cal_abort_on_error) );
        }

        // If Custom Read Centering or Custom Write Centering was performed,
        // an Initial Pattern Write of 5555 hex, the reset value of the registers described in,
        // must be performed before any periodic calibration routines are performed.
        // Clean out any previous calibration results, set bad-bits and configure the ranks.
        for( const auto& p : mss::find_targets<TARGET_TYPE_MCA>(i_target))
        {
            fapi2::buffer<uint32_t> l_cal_steps_enabled;
            std::vector<std::shared_ptr<mss::training::step>> l_steps;
            FAPI_TRY( mss::cal_step_enable(p, l_cal_steps_enabled), "Error in p9_mss_draminit_training %s", mss::c_str(i_target) );

            if (!l_cal_steps_enabled.getBit<mss::TRAINING_ADV>())
            {
                FAPI_INF("ATTR_MSS_CAL_STEPS_ENABLED says to skip draminit training advance, so skipping %s",
                         mss::c_str(i_target));
                continue;
            }

            // If we see the bit to for training_adv, let's set up our cal config.
            // As per the PHY spec, only INITIAL_PAT_WRITE and the CUSTOM_RD_PATTERN bits should be set
            // TRAINING_ADV == CUSTOM_RD_PATTERN
            l_cal_steps_enabled = 0;
            l_cal_steps_enabled.setBit<mss::INITIAL_PAT_WR>().setBit<mss::TRAINING_ADV>();

            // Gets the training steps to calibrate
            l_steps = mss::training::steps_factory(l_cal_steps_enabled, l_sim);

            // Keep track of the last error seen by a rank pair
            fapi2::ReturnCode l_rank_pair_error(fapi2::FAPI2_RC_SUCCESS);

            // Clear all of the errors before we start
            FAPI_TRY(mss::clear_initial_cal_errors(p), "%s error resetting errors prior to init cal", mss::c_str(p));

            // Returned from set_rank_pairs, it tells us how many rank pairs
            // we configured on this port.
            std::vector<uint64_t> l_pairs;

            // Let's set the pattern to run
            FAPI_TRY( mss::configure_custom_pattern(p) );

            // Set staggered mode
            FAPI_TRY( mss::rc::change_staggered_pattern(p) );

            // Set custom read centering mode
            FAPI_TRY( mss::dp16::setup_custom_read_centering_mode(p), "Error in p9_mss_draminit_training %s",
                      mss::c_str(i_target) );

            // Get our rank pairs.
            FAPI_TRY( mss::rank::get_rank_pairs(p, l_pairs), "Error in p9_mss_draminit_training" );

            // For each rank pair we need to calibrate, pop a ccs instruction in an array and execute it.
            // NOTE: IF YOU CALIBRATE MORE THAN ONE RANK PAIR PER CCS PROGRAM, MAKE SURE TO CHANGE
            // THE PROCESSING OF THE ERRORS. (it's hard to figure out which DIMM failed, too) BRS.
            for (const auto& rp : l_pairs)
            {
                bool l_cal_fail = false;

                // Save off registers in case adv training fails
                mss::dp16::rd_ctr_settings<TARGET_TYPE_MCA> l_original_settings(p, rp);
                FAPI_TRY( l_original_settings.save() );

                std::vector<fapi2::ReturnCode> l_fails_on_rp;

                // Loop through all of the steps (should just be initial pattern write and custom read centering)
                for(const auto l_step : l_steps)
                {
                    FAPI_TRY( l_step->execute(p, rp, l_cal_abort_on_error) );
                }

                FAPI_TRY( mss::find_and_log_cal_errors(p, rp, l_cal_abort_on_error, l_cal_fail, l_fails_on_rp) );

                // If we got a fail, let's ignore the previous fails and run backup pattern
                if (l_fails_on_rp.size() != 0)
                {
                    l_cal_fail = false;
                    l_fails_on_rp.clear();

                    // Clear the disable bits from last run.
                    // This function restores bad_bits to how the attribute has them
                    // (which was updated at the end of regular training)
                    // So we won't run on known bad bits, but will rerun on the iffy bits from last custom_pattern run
                    FAPI_TRY( mss::dp16::reset_bad_bits( p ) );
                    FAPI_INF("%s rp%x running back up pattern for draminit_training_adv", mss::c_str(p), rp);

                    // Clear the cal errors so we can retry
                    FAPI_TRY(mss::clear_initial_cal_errors(p), "%s error resetting errors prior to init cal", mss::c_str(p));

                    fapi2::buffer<uint32_t> l_backup;
                    FAPI_TRY( mss::custom_training_adv_backup_patterns( p, l_backup) );

                    // Put the backup into the registers
                    FAPI_TRY( mss::seq::setup_rd_wr_data( p, l_backup) );

                    // Rerun the training for this rp
                    // Loop through all of the steps (should just be initial pattern write and custom read centering)
                    for(const auto l_step : l_steps)
                    {
                        FAPI_TRY( l_step->execute(p, rp, l_cal_abort_on_error) );
                    }

                    FAPI_TRY( mss::find_and_log_cal_errors(p, rp, l_cal_abort_on_error, l_cal_fail, l_fails_on_rp) );

                    // If we got fails from the backup pattern, restore the pre-adv training settings for this rank pair
                    if (l_fails_on_rp.size() != 0)
                    {
                        l_fails_on_rp.clear();
                        FAPI_INF("%s rp%d draminit_training_adv failed. Restoring original settings", mss::c_str(p), rp);

                        // Restore pre-training_adv settings
                        FAPI_TRY( l_original_settings.restore() );
                    }
                }
            }// rank pairs

            // Resetting current_err.
            // The error has either already been "logged" or we have exited and returned the error up the call stack.
            fapi2::current_err = fapi2::FAPI2_RC_SUCCESS;
        }

        return fapi2::FAPI2_RC_SUCCESS;
    fapi_try_exit:
        return fapi2::current_err;
    }
}
<commit_msg>Updates training advanced and adds custom WR CTR<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/p9_mss_draminit_training_adv.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2017,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
///
/// @file p9_mss_draminit_training_adv.C
/// @brief Perform read_centering again but with a custom pattern for better eye
///
// *HWP HWP Owner: Jacob Harvey <jlharvey@us.ibm.com>
// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 3
// *HWP Consumed by: FSP:HB

#include <fapi2.H>
#include <mss.H>
#include <vector>

#include <p9_mss_draminit_training_adv.H>
#include <lib/utils/count_dimm.H>
#include <lib/shared/mss_const.H>
#include <lib/phy/dp16.H>
#include <lib/phy/seq.H>
#include <lib/phy/ddr_phy.H>
#include <lib/phy/mss_training.H>

using fapi2::TARGET_TYPE_MCBIST;
using fapi2::TARGET_TYPE_MCA;

extern "C"
{
///
/// @brief Perform training_adv on the dimms (perform read centering with custom pattern)
/// @param[in] i_target, the McBIST of the ports of the dram you're training
/// @param[in] i_abort_on_error, optional CAL_ABORT_ON_ERROR override. Used in sim, debug
/// @return FAPI2_RC_SUCCESS iff ok
/// @note turn off rd cntr periodic cal if training_adv is run. Add OFF value for CUSTOM_PATTERN?
///

    fapi2::ReturnCode p9_mss_draminit_training_adv( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target,
            const uint8_t i_abort_on_error)
    {
        uint8_t l_cal_abort_on_error = i_abort_on_error;
        uint8_t l_sim = 0;
        FAPI_TRY( mss::is_simulation (l_sim) );

        FAPI_INF("Start draminit training advance %s", mss::c_str(i_target));

        // If there are no DIMMs installed, we don't need to bother. In fact, we can't as we didn't setup
        // attributes for the PHY, etc.
        if (mss::count_dimm(i_target) == 0 || l_sim)
        {
            FAPI_INF("... skipping draminit_training_adv %s... %s Dimms. %s SIM.",
                     mss::c_str(i_target),
                     mss::count_dimm(i_target) == 0 ? "Has no" : "Has",
                     l_sim ? "Is" : "Is not");
            return fapi2::FAPI2_RC_SUCCESS;
        }

        if (i_abort_on_error == CAL_ADV_ABORT_SENTINAL)
        {
            FAPI_TRY( mss::cal_abort_on_error(l_cal_abort_on_error) );
        }

        // If Custom Read Centering or Custom Write Centering was performed,
        // an Initial Pattern Write of 5555 hex, the reset value of the registers described in,
        // must be performed before any periodic calibration routines are performed.
        // Clean out any previous calibration results, set bad-bits and configure the ranks.
        for( const auto& p : mss::find_targets<TARGET_TYPE_MCA>(i_target))
        {
            fapi2::buffer<uint32_t> l_cal_steps_enabled;
            std::vector<std::shared_ptr<mss::training::step>> l_steps;
            FAPI_TRY( mss::cal_step_enable(p, l_cal_steps_enabled), "Error in p9_mss_draminit_training %s", mss::c_str(i_target) );

            if (!((l_cal_steps_enabled.getBit<mss::TRAINING_ADV_RD>()) || (l_cal_steps_enabled.getBit<mss::TRAINING_ADV_WR>())))
            {
                FAPI_INF("ATTR_MSS_CAL_STEPS_ENABLED says to skip draminit training advance, so skipping %s",
                         mss::c_str(i_target));
                continue;
            }

            // Clear all non training advanced bits
            l_cal_steps_enabled.clearBit<0, mss::TRAINING_ADV_RD>();

            // Gets the training steps to calibrate
            l_steps = mss::training::steps_factory(l_cal_steps_enabled, l_sim);

            // Keep track of the last error seen by a rank pair
            fapi2::ReturnCode l_rank_pair_error(fapi2::FAPI2_RC_SUCCESS);

            // Returned from set_rank_pairs, it tells us how many rank pairs
            // we configured on this port.
            std::vector<uint64_t> l_pairs;

            // Get our rank pairs.
            FAPI_TRY( mss::rank::get_rank_pairs(p, l_pairs), "Error in p9_mss_draminit_training" );

            // For each rank pair we need to calibrate, pop a ccs instruction in an array and execute it.
            // NOTE: IF YOU CALIBRATE MORE THAN ONE RANK PAIR PER CCS PROGRAM, MAKE SURE TO CHANGE
            // THE PROCESSING OF THE ERRORS. (it's hard to figure out which DIMM failed, too) BRS.
            for (const auto& rp : l_pairs)
            {
                // Loop through all of the steps (should just be initial pattern write and custom read centering)
                for(const auto l_step : l_steps)
                {
                    FAPI_TRY( l_step->execute(p, rp, l_cal_abort_on_error) );
                }
            }// rank pairs

            // Resetting current_err.
            // The error has either already been "logged" or we have exited and returned the error up the call stack.
            fapi2::current_err = fapi2::FAPI2_RC_SUCCESS;
        }

        return fapi2::FAPI2_RC_SUCCESS;
    fapi_try_exit:
        return fapi2::current_err;
    }
}
<|endoftext|>


<commit_before>/*
 * This software is distributed under BSD 3-clause license (see LICENSE file).
 *
 * Authors: Saurabh Mahindre, Soumyajit De, Thoralf Klein, Heiko Strathmann,
 *          Viktor Gal
 */

#include <algorithm>
#include <gtest/gtest.h>
#include <numeric>
#include <shogun/features/DenseFeatures.h>
#include <shogun/mathematics/RandomNamespace.h>
#include <shogun/mathematics/UniformIntDistribution.h>
#include <shogun/mathematics/NormalDistribution.h>
#include <shogun/lib/View.h>

#include <random>

namespace shogun
{

class DenseFeaturesMock : public DenseFeatures<float64_t>
{
public:
	DenseFeaturesMock(const SGMatrix<float64_t>& data) : DenseFeatures<float64_t>(data)
	{
	}

	void copy_feature_matrix_public(const SGMatrix<float64_t>& target, index_t column_offset)
	{
		copy_feature_matrix(target, column_offset);
	}
};

}

using namespace shogun;

TEST(DenseFeaturesTest,create_merged_copy)
{
	/* create two matrices, feature objects for them, call create_merged_copy,
	 * and check if it worked */
	int32_t seed = 10;
	index_t n_1=3;
	index_t n_2=4;
	index_t dim=2;

	SGMatrix<float64_t> data_1(dim,n_1);
	for (index_t i=0; i<dim*n_1; ++i)
		data_1.matrix[i]=i;

	//data_1.display_matrix("data_1");
	std::mt19937_64 prng(seed);
	NormalDistribution<float64_t> normal_dist;
	SGMatrix<float64_t> data_2(dim,n_2);
	for (index_t i=0; i<dim*n_2; ++i)
		data_2.matrix[i]=normal_dist(prng);

	//data_2.display_matrix("data_2");

	auto features_1=std::make_shared<DenseFeatures<float64_t>>(data_1);
	auto features_2=std::make_shared<DenseFeatures<float64_t>>(data_2);

	auto concatenation=features_1->create_merged_copy(features_2);

	SGMatrix<float64_t> concat_data=
			concatenation->as<DenseFeatures<float64_t>>()->get_feature_matrix();
	//concat_data.display_matrix("concat_data");

	/* check for equality with data_1 */
	for (index_t i=0; i<dim*n_1; ++i)
		EXPECT_EQ(data_1.matrix[i], concat_data.matrix[i]);

	/* check for equality with data_2 */
	for (index_t i=0; i<dim*n_2; ++i)
		EXPECT_NEAR(data_2.matrix[i], concat_data.matrix[n_1*dim+i], 1E-15);

}

TEST(DenseFeaturesTest, create_merged_copy_with_subsets)
{
	const index_t n_1=10;
	const index_t n_2=15;
	const index_t dim=2;
	std::mt19937_64 prng(57);

	SGMatrix<float64_t> data_1(dim, n_1);
	std::iota(data_1.matrix, data_1.matrix + data_1.size(), 1);

	SGMatrix<float64_t> data_2(dim, n_2);
	std::iota(data_2.matrix, data_2.matrix + data_2.size(), data_2.size());

	auto features_1=std::make_shared<DenseFeatures<float64_t> >(data_1);
	auto features_2=std::make_shared<DenseFeatures<float64_t> >(data_2);

	SGVector<index_t> subset_1(n_1/2);
	random::fill_array(subset_1, 0, n_1-1, prng);
	features_1->add_subset(subset_1);
	auto active_data_1=features_1->get_feature_matrix();

	SGVector<index_t> subset_2(n_2/3);
	random::fill_array(subset_2, 0, n_2-1, prng);
	features_2->add_subset(subset_2);
	auto active_data_2=features_2->get_feature_matrix();

	SGMatrix<float64_t> expected_merged_mat(dim, active_data_1.num_cols+active_data_2.num_cols);
	std::copy(active_data_1.matrix, active_data_1.matrix+active_data_1.size(),
			expected_merged_mat.matrix);
	std::copy(active_data_2.matrix, active_data_2.matrix+active_data_2.size(),
			expected_merged_mat.matrix+active_data_1.size());

	auto merged=features_1->create_merged_copy(features_2)->as<DenseFeatures<float64_t>>();
	SGMatrix<float64_t> merged_mat = merged->get_feature_matrix();

	ASSERT_EQ(expected_merged_mat.num_rows, merged_mat.num_rows);
	ASSERT_EQ(expected_merged_mat.num_cols, merged_mat.num_cols);
	for (index_t j=0; j<expected_merged_mat.num_cols; ++j)
	{
		for (index_t i=0; i<expected_merged_mat.num_rows; ++i)
			EXPECT_NEAR(expected_merged_mat(i, j), merged_mat(i, j), 1E-15);
	}

}

TEST(DenseFeaturesTest, copy_dimension_subset)
{
	int32_t seed = 12;
	index_t dim=5;
	index_t n=10;

	SGMatrix<float64_t> data(dim, n);
	for (index_t i=0; i<dim*n; ++i)
		data.matrix[i]=i;

	auto features=std::make_shared<DenseFeatures<float64_t>>(data);

	SGVector<index_t> dims(dim/2);
	std::mt19937_64 prng(seed);
	UniformIntDistribution<int32_t> uniform_int_dist;
	for (index_t i=0; i<dims.vlen; ++i)
		dims[i]=uniform_int_dist(prng, {0, dim-1});

	auto f_reduced=
		features->copy_dimension_subset(dims)->as<DenseFeatures<float64_t>>();

	SGMatrix<float64_t> data_reduced=f_reduced->get_feature_matrix();

	for (index_t i=0; i<data_reduced.num_rows; ++i)
	{
		for (index_t j=0; j<data_reduced.num_cols; ++j)
			EXPECT_NEAR(data(dims[i], j), data_reduced(i, j), 1E-16);
	}

}

TEST(DenseFeaturesTest, copy_dimension_subset_with_subsets)
{
	int32_t seed = 12;
	index_t dim=5;
	index_t n=10;

	SGMatrix<float64_t> data(dim, n);
	for (index_t i=0; i<dim*n; ++i)
		data.matrix[i]=i;

	auto features=std::make_shared<DenseFeatures<float64_t>>(data);

	std::mt19937_64 prng(seed);
	UniformIntDistribution<int32_t> uniform_int_dist;
	SGVector<index_t> inds(n/2);
	for (index_t i=0; i<inds.vlen; ++i)
		inds[i]=uniform_int_dist(prng, {0, n-1});

	features->add_subset(inds);

	SGVector<index_t> dims(dim/2);
	for (index_t i=0; i<dims.vlen; ++i)
		dims[i]=uniform_int_dist(prng, {0, dim-1});

	auto f_reduced=
		features->copy_dimension_subset(dims)->as<DenseFeatures<float64_t>>();

	SGMatrix<float64_t> data_reduced=f_reduced->get_feature_matrix();
	for (index_t i=0; i<data_reduced.num_rows; ++i)
	{
		for (index_t j=0; j<data_reduced.num_cols; ++j)
			EXPECT_NEAR(data(dims[i], inds[j]), data_reduced(i, j), 1E-16);
	}

}

TEST(DenseFeaturesTest, shallow_copy_subset_data)
{
	index_t dim=5;
	index_t n=10;
	std::mt19937_64 prng(57);

	SGMatrix<float64_t> data(dim, n);
	std::iota(data.data(), data.data()+data.size(), 1);
	SGVector<index_t> inds(n/2);
	random::fill_array(inds, 0, n-1, prng);

	auto features=std::make_shared<DenseFeatures<float64_t>>(data);
	features->add_subset(inds);
	auto features_copy = features->shallow_subset_copy();

	SGMatrix<float64_t> orig_matrix=features->get_feature_matrix();
	SGMatrix<float64_t> copy_matrix=features_copy->as<DenseFeatures<float64_t>>()->get_feature_matrix();

	for (index_t i=0; i<dim; ++i)
	{
		for (index_t j=0; j<inds.size(); ++j)
			EXPECT_NEAR(orig_matrix(i,j), copy_matrix(i,j), 1E-15);
	}

}

TEST(DenseFeaturesTest, copy_feature_matrix)
{
	index_t dim=5;
	index_t n=10;
	std::mt19937_64 prng(57);

	SGMatrix<float64_t> data(dim, n);
	std::iota(data.data(), data.data()+data.size(), 1);
	SGVector<index_t> inds(n/2);
	random::fill_array(inds, 0, n-1, prng);

	auto features=std::make_shared<DenseFeaturesMock>(data);
	features->add_subset(inds);

	index_t offset=3;
	SGMatrix<float64_t> copy(dim, inds.vlen+offset);
	auto data_ptr=copy.matrix;
	std::fill(copy.data(), copy.data()+copy.size(), 0);
	features->copy_feature_matrix_public(copy, offset);

	ASSERT_EQ(copy.num_rows, dim);
	ASSERT_EQ(copy.num_cols, inds.vlen+offset);
	ASSERT_EQ(copy.matrix, data_ptr);

	for (index_t j=0; j<offset; ++j)
	{
		for (index_t i=0; i<dim; ++i)
			EXPECT_NEAR(copy(i, j), 0, 1E-15);
	}

	for (index_t j=0; j<inds.vlen; ++j)
	{
		for (index_t i=0; i<dim; ++i)
			EXPECT_NEAR(copy(i, j+offset), data(i, inds[j]), 1E-15);
	}
}

TEST(DenseFeaturesTest, view)
{
	auto num_feats = 2;
	auto num_vectors = 4;
	SGMatrix<float64_t> data(num_feats, num_vectors);

	for (auto i : range(num_feats * num_vectors))
	{
		data[i] = i;
	}
	auto feats_original = std::make_shared<DenseFeatures<float64_t>>(data);

	SGVector<index_t> subset1{0, 2, 3};
	auto feats_subset1 = view(feats_original, subset1);
	ASSERT_EQ(feats_subset1->get_num_features(), num_feats);
	ASSERT_EQ(feats_subset1->get_num_vectors(), subset1.vlen);
	auto feature_matrix_subset1 = feats_subset1->get_feature_matrix();

	// check feature_matrix(i, j) == feature_matrix_original(i, subset(j))
	for (auto j : range(subset1.vlen))
	{
		for (auto i : range(num_feats))
			EXPECT_EQ(feature_matrix_subset1(i, j), data(i, subset1[j]));
	}

	SGVector<index_t> subset2{
	    0, 2}; // subset2 is column 0 & 3 of original features
	auto feats_subset2 = view(feats_subset1, subset2);
	ASSERT_EQ(feats_subset2->get_num_features(), num_feats);
	ASSERT_EQ(feats_subset2->get_num_vectors(), subset2.vlen);
	auto feature_matrix_subset2 = feats_subset2->get_feature_matrix();

	for (auto j : range(subset2.size()))
	{
		for (auto i : range(num_feats))
			EXPECT_EQ(
			    feature_matrix_subset2(i, j), data(i, subset1[subset2[j]]));
	}
}
<commit_msg>dense features iterator tests<commit_after>/*
 * This software is distributed under BSD 3-clause license (see LICENSE file).
 *
 * Authors: Saurabh Mahindre, Soumyajit De, Thoralf Klein, Heiko Strathmann,
 *          Viktor Gal
 */

#include <algorithm>
#include <gtest/gtest.h>
#include <numeric>
#include <shogun/features/DenseFeatures.h>
#include <shogun/mathematics/RandomNamespace.h>
#include <shogun/mathematics/UniformIntDistribution.h>
#include <shogun/mathematics/NormalDistribution.h>
#include <shogun/lib/View.h>

#include <random>

namespace shogun
{

class DenseFeaturesMock : public DenseFeatures<float64_t>
{
public:
	DenseFeaturesMock(const SGMatrix<float64_t>& data) : DenseFeatures<float64_t>(data)
	{
	}

	void copy_feature_matrix_public(const SGMatrix<float64_t>& target, index_t column_offset)
	{
		copy_feature_matrix(target, column_offset);
	}
};

}

using namespace shogun;

TEST(DenseFeaturesTest,create_merged_copy)
{
	/* create two matrices, feature objects for them, call create_merged_copy,
	 * and check if it worked */
	int32_t seed = 10;
	index_t n_1=3;
	index_t n_2=4;
	index_t dim=2;

	SGMatrix<float64_t> data_1(dim,n_1);
	for (index_t i=0; i<dim*n_1; ++i)
		data_1.matrix[i]=i;

	//data_1.display_matrix("data_1");
	std::mt19937_64 prng(seed);
	NormalDistribution<float64_t> normal_dist;
	SGMatrix<float64_t> data_2(dim,n_2);
	for (index_t i=0; i<dim*n_2; ++i)
		data_2.matrix[i]=normal_dist(prng);

	//data_2.display_matrix("data_2");

	auto features_1=std::make_shared<DenseFeatures<float64_t>>(data_1);
	auto features_2=std::make_shared<DenseFeatures<float64_t>>(data_2);

	auto concatenation=features_1->create_merged_copy(features_2);

	SGMatrix<float64_t> concat_data=
			concatenation->as<DenseFeatures<float64_t>>()->get_feature_matrix();
	//concat_data.display_matrix("concat_data");

	/* check for equality with data_1 */
	for (index_t i=0; i<dim*n_1; ++i)
		EXPECT_EQ(data_1.matrix[i], concat_data.matrix[i]);

	/* check for equality with data_2 */
	for (index_t i=0; i<dim*n_2; ++i)
		EXPECT_NEAR(data_2.matrix[i], concat_data.matrix[n_1*dim+i], 1E-15);

}

TEST(DenseFeaturesTest, create_merged_copy_with_subsets)
{
	const index_t n_1=10;
	const index_t n_2=15;
	const index_t dim=2;
	std::mt19937_64 prng(57);

	SGMatrix<float64_t> data_1(dim, n_1);
	std::iota(data_1.matrix, data_1.matrix + data_1.size(), 1);

	SGMatrix<float64_t> data_2(dim, n_2);
	std::iota(data_2.matrix, data_2.matrix + data_2.size(), data_2.size());

	auto features_1=std::make_shared<DenseFeatures<float64_t> >(data_1);
	auto features_2=std::make_shared<DenseFeatures<float64_t> >(data_2);

	SGVector<index_t> subset_1(n_1/2);
	random::fill_array(subset_1, 0, n_1-1, prng);
	features_1->add_subset(subset_1);
	auto active_data_1=features_1->get_feature_matrix();

	SGVector<index_t> subset_2(n_2/3);
	random::fill_array(subset_2, 0, n_2-1, prng);
	features_2->add_subset(subset_2);
	auto active_data_2=features_2->get_feature_matrix();

	SGMatrix<float64_t> expected_merged_mat(dim, active_data_1.num_cols+active_data_2.num_cols);
	std::copy(active_data_1.matrix, active_data_1.matrix+active_data_1.size(),
			expected_merged_mat.matrix);
	std::copy(active_data_2.matrix, active_data_2.matrix+active_data_2.size(),
			expected_merged_mat.matrix+active_data_1.size());

	auto merged=features_1->create_merged_copy(features_2)->as<DenseFeatures<float64_t>>();
	SGMatrix<float64_t> merged_mat = merged->get_feature_matrix();

	ASSERT_EQ(expected_merged_mat.num_rows, merged_mat.num_rows);
	ASSERT_EQ(expected_merged_mat.num_cols, merged_mat.num_cols);
	for (index_t j=0; j<expected_merged_mat.num_cols; ++j)
	{
		for (index_t i=0; i<expected_merged_mat.num_rows; ++i)
			EXPECT_NEAR(expected_merged_mat(i, j), merged_mat(i, j), 1E-15);
	}

}

TEST(DenseFeaturesTest, copy_dimension_subset)
{
	int32_t seed = 12;
	index_t dim=5;
	index_t n=10;

	SGMatrix<float64_t> data(dim, n);
	for (index_t i=0; i<dim*n; ++i)
		data.matrix[i]=i;

	auto features=std::make_shared<DenseFeatures<float64_t>>(data);

	SGVector<index_t> dims(dim/2);
	std::mt19937_64 prng(seed);
	UniformIntDistribution<int32_t> uniform_int_dist;
	for (index_t i=0; i<dims.vlen; ++i)
		dims[i]=uniform_int_dist(prng, {0, dim-1});

	auto f_reduced=
		features->copy_dimension_subset(dims)->as<DenseFeatures<float64_t>>();

	SGMatrix<float64_t> data_reduced=f_reduced->get_feature_matrix();

	for (index_t i=0; i<data_reduced.num_rows; ++i)
	{
		for (index_t j=0; j<data_reduced.num_cols; ++j)
			EXPECT_NEAR(data(dims[i], j), data_reduced(i, j), 1E-16);
	}

}

TEST(DenseFeaturesTest, copy_dimension_subset_with_subsets)
{
	int32_t seed = 12;
	index_t dim=5;
	index_t n=10;

	SGMatrix<float64_t> data(dim, n);
	for (index_t i=0; i<dim*n; ++i)
		data.matrix[i]=i;

	auto features=std::make_shared<DenseFeatures<float64_t>>(data);

	std::mt19937_64 prng(seed);
	UniformIntDistribution<int32_t> uniform_int_dist;
	SGVector<index_t> inds(n/2);
	for (index_t i=0; i<inds.vlen; ++i)
		inds[i]=uniform_int_dist(prng, {0, n-1});

	features->add_subset(inds);

	SGVector<index_t> dims(dim/2);
	for (index_t i=0; i<dims.vlen; ++i)
		dims[i]=uniform_int_dist(prng, {0, dim-1});

	auto f_reduced=
		features->copy_dimension_subset(dims)->as<DenseFeatures<float64_t>>();

	SGMatrix<float64_t> data_reduced=f_reduced->get_feature_matrix();
	for (index_t i=0; i<data_reduced.num_rows; ++i)
	{
		for (index_t j=0; j<data_reduced.num_cols; ++j)
			EXPECT_NEAR(data(dims[i], inds[j]), data_reduced(i, j), 1E-16);
	}

}

TEST(DenseFeaturesTest, shallow_copy_subset_data)
{
	index_t dim=5;
	index_t n=10;
	std::mt19937_64 prng(57);

	SGMatrix<float64_t> data(dim, n);
	std::iota(data.data(), data.data()+data.size(), 1);
	SGVector<index_t> inds(n/2);
	random::fill_array(inds, 0, n-1, prng);

	auto features=std::make_shared<DenseFeatures<float64_t>>(data);
	features->add_subset(inds);
	auto features_copy = features->shallow_subset_copy();

	SGMatrix<float64_t> orig_matrix=features->get_feature_matrix();
	SGMatrix<float64_t> copy_matrix=features_copy->as<DenseFeatures<float64_t>>()->get_feature_matrix();

	for (index_t i=0; i<dim; ++i)
	{
		for (index_t j=0; j<inds.size(); ++j)
			EXPECT_NEAR(orig_matrix(i,j), copy_matrix(i,j), 1E-15);
	}

}

TEST(DenseFeaturesTest, copy_feature_matrix)
{
	index_t dim=5;
	index_t n=10;
	std::mt19937_64 prng(57);

	SGMatrix<float64_t> data(dim, n);
	std::iota(data.data(), data.data()+data.size(), 1);
	SGVector<index_t> inds(n/2);
	random::fill_array(inds, 0, n-1, prng);

	auto features=std::make_shared<DenseFeaturesMock>(data);
	features->add_subset(inds);

	index_t offset=3;
	SGMatrix<float64_t> copy(dim, inds.vlen+offset);
	auto data_ptr=copy.matrix;
	std::fill(copy.data(), copy.data()+copy.size(), 0);
	features->copy_feature_matrix_public(copy, offset);

	ASSERT_EQ(copy.num_rows, dim);
	ASSERT_EQ(copy.num_cols, inds.vlen+offset);
	ASSERT_EQ(copy.matrix, data_ptr);

	for (index_t j=0; j<offset; ++j)
	{
		for (index_t i=0; i<dim; ++i)
			EXPECT_NEAR(copy(i, j), 0, 1E-15);
	}

	for (index_t j=0; j<inds.vlen; ++j)
	{
		for (index_t i=0; i<dim; ++i)
			EXPECT_NEAR(copy(i, j+offset), data(i, inds[j]), 1E-15);
	}
}

TEST(DenseFeaturesTest, view)
{
	auto num_feats = 2;
	auto num_vectors = 4;
	SGMatrix<float64_t> data(num_feats, num_vectors);

	for (auto i : range(num_feats * num_vectors))
	{
		data[i] = i;
	}
	auto feats_original = std::make_shared<DenseFeatures<float64_t>>(data);

	SGVector<index_t> subset1{0, 2, 3};
	auto feats_subset1 = view(feats_original, subset1);
	ASSERT_EQ(feats_subset1->get_num_features(), num_feats);
	ASSERT_EQ(feats_subset1->get_num_vectors(), subset1.vlen);
	auto feature_matrix_subset1 = feats_subset1->get_feature_matrix();

	// check feature_matrix(i, j) == feature_matrix_original(i, subset(j))
	for (auto j : range(subset1.vlen))
	{
		for (auto i : range(num_feats))
			EXPECT_EQ(feature_matrix_subset1(i, j), data(i, subset1[j]));
	}

	SGVector<index_t> subset2{
	    0, 2}; // subset2 is column 0 & 3 of original features
	auto feats_subset2 = view(feats_subset1, subset2);
	ASSERT_EQ(feats_subset2->get_num_features(), num_feats);
	ASSERT_EQ(feats_subset2->get_num_vectors(), subset2.vlen);
	auto feature_matrix_subset2 = feats_subset2->get_feature_matrix();

	for (auto j : range(subset2.size()))
	{
		for (auto i : range(num_feats))
			EXPECT_EQ(
			    feature_matrix_subset2(i, j), data(i, subset1[subset2[j]]));
	}
}

TEST(DenseFeaturesTest, iterator)
{
    SGVector<float64_t> vals(20);
    vals.range_fill();
    auto mat = SGMatrix(vals, 5, 4);
    auto subset = SGVector{1,0,2,4,1,3,1,1,2};
    auto ordered_subset = SGVector{0,1,1,1,1,2,2,3,4};
    auto feat = some<CDenseFeatures<float64_t>>(mat);
    int counter = 0;
    feat->add_subset(subset);
    for (auto iter: *feat)
    {
        int i = 0;
        for (const auto& val: iter)
        {
            EXPECT_EQ(val, mat[ordered_subset[counter]*5+i]);
            i++;
        }
        counter++;
    }
}

TEST(DenseFeaturesTest, const_iterator)
{
    SGVector<float64_t> vals(20);
    vals.range_fill();
    auto mat = SGMatrix(vals, 5, 4);
    const auto feat = some<CDenseFeatures<float64_t>>(mat);
    int counter = 0;
    for (const auto& iter: *feat)
    {
        for (int i = 0; i<5;++i)
            EXPECT_EQ(iter[i], mat[counter*5+i]);
        counter++;
    }
}<|endoftext|>


<commit_before>/*

Copyright (c) 2007-2012, Un Shyam & Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author 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.

*/

#ifndef TORRENT_DISABLE_ENCRYPTION

#ifndef TORRENT_PE_CRYPTO_HPP_INCLUDED
#define TORRENT_PE_CRYPTO_HPP_INCLUDED

#include "libtorrent/config.hpp"

#ifdef TORRENT_USE_GCRYPT
#include <gcrypt.h>
#elif defined TORRENT_USE_OPENSSL
#include <openssl/rc4.h>
#include <openssl/evp.h>
#include <openssl/aes.h>
#else
// RC4 state from libtomcrypt
struct rc4 {
	int x, y;
	unsigned char buf[256];
};

void TORRENT_EXTRA_EXPORT rc4_init(const unsigned char* in, unsigned long len, rc4 *state);
unsigned long TORRENT_EXTRA_EXPORT rc4_encrypt(unsigned char *out, unsigned long outlen, rc4 *state);
#endif

#include "libtorrent/peer_id.hpp" // For sha1_hash
#include "libtorrent/assert.hpp"

namespace libtorrent
{
	class TORRENT_EXTRA_EXPORT dh_key_exchange
	{
	public:
		dh_key_exchange();
		bool good() const { return true; }

		// Get local public key, always 96 bytes
		char const* get_local_key() const;

		// read remote_pubkey, generate and store shared secret in
		// m_dh_shared_secret.
		int compute_secret(const char* remote_pubkey);

		char const* get_secret() const { return m_dh_shared_secret; }

		sha1_hash const& get_hash_xor_mask() const { return m_xor_mask; }

	private:

		int get_local_key_size() const
		{ return sizeof(m_dh_local_key); }

		char m_dh_local_key[96];
		char m_dh_local_secret[96];
		char m_dh_shared_secret[96];
		sha1_hash m_xor_mask;
	};

	struct encryption_handler
	{
		virtual void set_incoming_key(unsigned char const* key, int len) = 0;
		virtual void set_outgoing_key(unsigned char const* key, int len) = 0;
		virtual void encrypt(char* pos, int len) = 0;
		virtual void decrypt(char* pos, int len) = 0;
		virtual ~encryption_handler() {}
	};

	struct rc4_handler : encryption_handler
	{
	public:
		// Input longkeys must be 20 bytes
		rc4_handler()
			: m_encrypt(false)
			, m_decrypt(false)
		{
#ifdef TORRENT_USE_GCRYPT
			gcry_cipher_open(&m_rc4_incoming, GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM, 0);
			gcry_cipher_open(&m_rc4_outgoing, GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM, 0);
#endif
		};

		void set_incoming_key(unsigned char const* key, int len)
		{
			m_decrypt = true;
#ifdef TORRENT_USE_GCRYPT
			gcry_cipher_close(m_rc4_incoming);
			gcry_cipher_open(&m_rc4_incoming, GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM, 0);
			gcry_cipher_setkey(m_rc4_incoming, key, len);
#elif defined TORRENT_USE_OPENSSL
			RC4_set_key(&m_remote_key, len, key);
#else
			rc4_init(key, len, &m_rc4_incoming);
#endif
			// Discard first 1024 bytes
			char buf[1024];
			decrypt(buf, 1024);
		}

		void set_outgoing_key(unsigned char const* key, int len)
		{
			m_encrypt = true;
#ifdef TORRENT_USE_GCRYPT
			gcry_cipher_close(m_rc4_outgoing);
			gcry_cipher_open(&m_rc4_outgoing, GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM, 0);
			gcry_cipher_setkey(m_rc4_outgoing, key, len);
#elif defined TORRENT_USE_OPENSSL
			RC4_set_key(&m_local_key, len, key);
#else
			rc4_init(key, len, &m_rc4_outgoing);
#endif
			// Discard first 1024 bytes
			char buf[1024];
			encrypt(buf, 1024);
		}

		~rc4_handler()
		{
#ifdef TORRENT_USE_GCRYPT
			gcry_cipher_close(m_rc4_incoming);
			gcry_cipher_close(m_rc4_outgoing);
#endif
		};

		void encrypt(char* pos, int len)
		{
			if (!m_encrypt) return;

			TORRENT_ASSERT(len >= 0);
			TORRENT_ASSERT(pos);

#ifdef TORRENT_USE_GCRYPT
			gcry_cipher_encrypt(m_rc4_outgoing, pos, len, 0, 0);
#elif defined TORRENT_USE_OPENSSL
			RC4(&m_local_key, len, (const unsigned char*)pos, (unsigned char*)pos);
#else
			rc4_encrypt((unsigned char*)pos, len, &m_rc4_outgoing);
#endif
		}

		void decrypt(char* pos, int len)
		{
			if (!m_decrypt) return;

			TORRENT_ASSERT(len >= 0);
			TORRENT_ASSERT(pos);

#ifdef TORRENT_USE_GCRYPT
			gcry_cipher_decrypt(m_rc4_incoming, pos, len, 0, 0);
#elif defined TORRENT_USE_OPENSSL
			RC4(&m_remote_key, len, (const unsigned char*)pos, (unsigned char*)pos);
#else
			rc4_encrypt((unsigned char*)pos, len, &m_rc4_incoming);
#endif
		}

	private:
#ifdef TORRENT_USE_GCRYPT
		gcry_cipher_hd_t m_rc4_incoming;
		gcry_cipher_hd_t m_rc4_outgoing;
#elif defined TORRENT_USE_OPENSSL
		RC4_KEY m_local_key; // Key to encrypt outgoing data
		RC4_KEY m_remote_key; // Key to decrypt incoming data
#else
		rc4 m_rc4_incoming;
		rc4 m_rc4_outgoing;
#endif
		// determines whether or not encryption and decryption is enabled
		bool m_encrypt;
		bool m_decrypt;
	};

#ifdef TORRENT_USE_OPENSSL
	struct aes256_handler : encryption_handler
	{
		aes256_handler() : m_enc_pos(0), m_dec_pos(0)
		{
			EVP_CIPHER_CTX_init(&m_enc);
			EVP_CIPHER_CTX_init(&m_dec);
		}

		~aes256_handler()
		{
			EVP_CIPHER_CTX_cleanup(&m_enc);
			EVP_CIPHER_CTX_cleanup(&m_dec);
		}

		void set_incoming_key(unsigned char const* in_key, int len)
		{
			const int nrounds = 5;
			boost::uint8_t salt[8] = { 0xf1, 0x03, 0x46, 0xe2, 0xb1, 0xa8, 0x29, 0x63 };
			boost::uint8_t key[32];
			boost::uint8_t iv[32];

			EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(), salt, in_key, len, nrounds, key, iv);
			TORRENT_ASSERT(len == 32);
			EVP_EncryptInit_ex(&m_enc, EVP_aes_256_cbc(), NULL, key, iv);
			// since we're using the AES as a stream cipher, both the encrypt and
			// decrypt context will in fact only _encrypt_ stuff, so initializing
			// this as encrypt is not a typo
			EVP_EncryptInit_ex(&m_dec, EVP_aes_256_cbc(), NULL, key, iv);
			m_enc_pos = 0;
			m_dec_pos = 0;
			std::memcpy(m_enc_state, iv, sizeof(m_enc_state));
			std::memcpy(m_dec_state, iv, sizeof(m_enc_state));
		}
		void set_outgoing_key(unsigned char const* key, int len) { /* no-op */ }
		void encrypt(char* pos, int len)
		{
			while (len > 0)
			{
				while (m_enc_pos < AES_BLOCK_SIZE && len > 0)
				{
					*pos ^= m_enc_state[m_enc_pos];
					++m_enc_pos;
					++pos;
					--len;
				}

				if (m_enc_pos == AES_BLOCK_SIZE)
				{
					next_block(&m_enc, m_enc_state);
					m_enc_pos = 0;
				}
			}
		}

		void decrypt(char* pos, int len)
		{
			while (len > 0)
			{
				while (m_dec_pos < AES_BLOCK_SIZE && len > 0)
				{
					*pos ^= m_dec_state[m_dec_pos];
					++m_dec_pos;
					++pos;
					--len;
				}

				if (m_dec_pos == AES_BLOCK_SIZE)
				{
					next_block(&m_dec, m_dec_state);
					m_dec_pos = 0;
				}
			}
		}

	private:

		// we're turning the AES block-cipher into a stream cipher. This
		// function will produce the next block in the sequence of
		// block-sized buffers. We're using "Output feedback" (OFB) mode.
		void next_block(EVP_CIPHER_CTX* ctx, boost::uint8_t* pad)
		{
			int outlen = AES_BLOCK_SIZE;
			EVP_EncryptUpdate(ctx, pad, &outlen, pad, AES_BLOCK_SIZE);
			TORRENT_ASSERT(outlen == AES_BLOCK_SIZE);
		}

		EVP_CIPHER_CTX m_enc;
		EVP_CIPHER_CTX m_dec;

		boost::uint8_t m_enc_state[AES_BLOCK_SIZE];
		boost::uint8_t m_dec_state[AES_BLOCK_SIZE];
		int m_enc_pos;
		int m_dec_pos;

	};
#endif // TORRENT_USE_OPENSSL

} // namespace libtorrent

#endif // TORRENT_PE_CRYPTO_HPP_INCLUDED
#endif // TORRENT_DISABLE_ENCRYPTION

<commit_msg>Fix build with LibreSSL<commit_after>/*

Copyright (c) 2007-2012, Un Shyam & Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author 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.

*/

#ifndef TORRENT_DISABLE_ENCRYPTION

#ifndef TORRENT_PE_CRYPTO_HPP_INCLUDED
#define TORRENT_PE_CRYPTO_HPP_INCLUDED

#include "libtorrent/config.hpp"

#ifdef TORRENT_USE_GCRYPT
#include <gcrypt.h>
#elif defined TORRENT_USE_OPENSSL
#include <openssl/rc4.h>
#include <openssl/evp.h>
#include <openssl/aes.h>
#include <openssl/rand.h>
#else
// RC4 state from libtomcrypt
struct rc4 {
	int x, y;
	unsigned char buf[256];
};

void TORRENT_EXTRA_EXPORT rc4_init(const unsigned char* in, unsigned long len, rc4 *state);
unsigned long TORRENT_EXTRA_EXPORT rc4_encrypt(unsigned char *out, unsigned long outlen, rc4 *state);
#endif

#include "libtorrent/peer_id.hpp" // For sha1_hash
#include "libtorrent/assert.hpp"

namespace libtorrent
{
	class TORRENT_EXTRA_EXPORT dh_key_exchange
	{
	public:
		dh_key_exchange();
		bool good() const { return true; }

		// Get local public key, always 96 bytes
		char const* get_local_key() const;

		// read remote_pubkey, generate and store shared secret in
		// m_dh_shared_secret.
		int compute_secret(const char* remote_pubkey);

		char const* get_secret() const { return m_dh_shared_secret; }

		sha1_hash const& get_hash_xor_mask() const { return m_xor_mask; }

	private:

		int get_local_key_size() const
		{ return sizeof(m_dh_local_key); }

		char m_dh_local_key[96];
		char m_dh_local_secret[96];
		char m_dh_shared_secret[96];
		sha1_hash m_xor_mask;
	};

	struct encryption_handler
	{
		virtual void set_incoming_key(unsigned char const* key, int len) = 0;
		virtual void set_outgoing_key(unsigned char const* key, int len) = 0;
		virtual void encrypt(char* pos, int len) = 0;
		virtual void decrypt(char* pos, int len) = 0;
		virtual ~encryption_handler() {}
	};

	struct rc4_handler : encryption_handler
	{
	public:
		// Input longkeys must be 20 bytes
		rc4_handler()
			: m_encrypt(false)
			, m_decrypt(false)
		{
#ifdef TORRENT_USE_GCRYPT
			gcry_cipher_open(&m_rc4_incoming, GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM, 0);
			gcry_cipher_open(&m_rc4_outgoing, GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM, 0);
#endif
		};

		void set_incoming_key(unsigned char const* key, int len)
		{
			m_decrypt = true;
#ifdef TORRENT_USE_GCRYPT
			gcry_cipher_close(m_rc4_incoming);
			gcry_cipher_open(&m_rc4_incoming, GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM, 0);
			gcry_cipher_setkey(m_rc4_incoming, key, len);
#elif defined TORRENT_USE_OPENSSL
			RC4_set_key(&m_remote_key, len, key);
#else
			rc4_init(key, len, &m_rc4_incoming);
#endif
			// Discard first 1024 bytes
			char buf[1024];
			decrypt(buf, 1024);
		}

		void set_outgoing_key(unsigned char const* key, int len)
		{
			m_encrypt = true;
#ifdef TORRENT_USE_GCRYPT
			gcry_cipher_close(m_rc4_outgoing);
			gcry_cipher_open(&m_rc4_outgoing, GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM, 0);
			gcry_cipher_setkey(m_rc4_outgoing, key, len);
#elif defined TORRENT_USE_OPENSSL
			RC4_set_key(&m_local_key, len, key);
#else
			rc4_init(key, len, &m_rc4_outgoing);
#endif
			// Discard first 1024 bytes
			char buf[1024];
			encrypt(buf, 1024);
		}

		~rc4_handler()
		{
#ifdef TORRENT_USE_GCRYPT
			gcry_cipher_close(m_rc4_incoming);
			gcry_cipher_close(m_rc4_outgoing);
#endif
		};

		void encrypt(char* pos, int len)
		{
			if (!m_encrypt) return;

			TORRENT_ASSERT(len >= 0);
			TORRENT_ASSERT(pos);

#ifdef TORRENT_USE_GCRYPT
			gcry_cipher_encrypt(m_rc4_outgoing, pos, len, 0, 0);
#elif defined TORRENT_USE_OPENSSL
			RC4(&m_local_key, len, (const unsigned char*)pos, (unsigned char*)pos);
#else
			rc4_encrypt((unsigned char*)pos, len, &m_rc4_outgoing);
#endif
		}

		void decrypt(char* pos, int len)
		{
			if (!m_decrypt) return;

			TORRENT_ASSERT(len >= 0);
			TORRENT_ASSERT(pos);

#ifdef TORRENT_USE_GCRYPT
			gcry_cipher_decrypt(m_rc4_incoming, pos, len, 0, 0);
#elif defined TORRENT_USE_OPENSSL
			RC4(&m_remote_key, len, (const unsigned char*)pos, (unsigned char*)pos);
#else
			rc4_encrypt((unsigned char*)pos, len, &m_rc4_incoming);
#endif
		}

	private:
#ifdef TORRENT_USE_GCRYPT
		gcry_cipher_hd_t m_rc4_incoming;
		gcry_cipher_hd_t m_rc4_outgoing;
#elif defined TORRENT_USE_OPENSSL
		RC4_KEY m_local_key; // Key to encrypt outgoing data
		RC4_KEY m_remote_key; // Key to decrypt incoming data
#else
		rc4 m_rc4_incoming;
		rc4 m_rc4_outgoing;
#endif
		// determines whether or not encryption and decryption is enabled
		bool m_encrypt;
		bool m_decrypt;
	};

#ifdef TORRENT_USE_OPENSSL
	struct aes256_handler : encryption_handler
	{
		aes256_handler() : m_enc_pos(0), m_dec_pos(0)
		{
			EVP_CIPHER_CTX_init(&m_enc);
			EVP_CIPHER_CTX_init(&m_dec);
		}

		~aes256_handler()
		{
			EVP_CIPHER_CTX_cleanup(&m_enc);
			EVP_CIPHER_CTX_cleanup(&m_dec);
		}

		void set_incoming_key(unsigned char const* in_key, int len)
		{
			const int nrounds = 5;
			boost::uint8_t salt[8] = { 0xf1, 0x03, 0x46, 0xe2, 0xb1, 0xa8, 0x29, 0x63 };
			boost::uint8_t key[32];
			boost::uint8_t iv[32];

			EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(), salt, in_key, len, nrounds, key, iv);
			TORRENT_ASSERT(len == 32);
			EVP_EncryptInit_ex(&m_enc, EVP_aes_256_cbc(), NULL, key, iv);
			// since we're using the AES as a stream cipher, both the encrypt and
			// decrypt context will in fact only _encrypt_ stuff, so initializing
			// this as encrypt is not a typo
			EVP_EncryptInit_ex(&m_dec, EVP_aes_256_cbc(), NULL, key, iv);
			m_enc_pos = 0;
			m_dec_pos = 0;
			std::memcpy(m_enc_state, iv, sizeof(m_enc_state));
			std::memcpy(m_dec_state, iv, sizeof(m_enc_state));
		}
		void set_outgoing_key(unsigned char const* key, int len) { /* no-op */ }
		void encrypt(char* pos, int len)
		{
			while (len > 0)
			{
				while (m_enc_pos < AES_BLOCK_SIZE && len > 0)
				{
					*pos ^= m_enc_state[m_enc_pos];
					++m_enc_pos;
					++pos;
					--len;
				}

				if (m_enc_pos == AES_BLOCK_SIZE)
				{
					next_block(&m_enc, m_enc_state);
					m_enc_pos = 0;
				}
			}
		}

		void decrypt(char* pos, int len)
		{
			while (len > 0)
			{
				while (m_dec_pos < AES_BLOCK_SIZE && len > 0)
				{
					*pos ^= m_dec_state[m_dec_pos];
					++m_dec_pos;
					++pos;
					--len;
				}

				if (m_dec_pos == AES_BLOCK_SIZE)
				{
					next_block(&m_dec, m_dec_state);
					m_dec_pos = 0;
				}
			}
		}

	private:

		// we're turning the AES block-cipher into a stream cipher. This
		// function will produce the next block in the sequence of
		// block-sized buffers. We're using "Output feedback" (OFB) mode.
		void next_block(EVP_CIPHER_CTX* ctx, boost::uint8_t* pad)
		{
			int outlen = AES_BLOCK_SIZE;
			EVP_EncryptUpdate(ctx, pad, &outlen, pad, AES_BLOCK_SIZE);
			TORRENT_ASSERT(outlen == AES_BLOCK_SIZE);
		}

		EVP_CIPHER_CTX m_enc;
		EVP_CIPHER_CTX m_dec;

		boost::uint8_t m_enc_state[AES_BLOCK_SIZE];
		boost::uint8_t m_dec_state[AES_BLOCK_SIZE];
		int m_enc_pos;
		int m_dec_pos;

	};
#endif // TORRENT_USE_OPENSSL

} // namespace libtorrent

#endif // TORRENT_PE_CRYPTO_HPP_INCLUDED
#endif // TORRENT_DISABLE_ENCRYPTION

<|endoftext|>


<commit_before>#include "ut_volumebarlogic.h"
#include <volumebarlogic.h>

void
Ut_VolumeBarLogic::init ()
{
}

void
Ut_VolumeBarLogic::cleanup ()
{
}

void
Ut_VolumeBarLogic::initTestCase ()
{
    m_Api = new VolumeBarLogic;
    m_Api->stepsUpdated (30, 100);
}

void
Ut_VolumeBarLogic::cleanupTestCase ()
{
    delete m_Api;
}

// Check if setting / getting works correctly
void
Ut_VolumeBarLogic::testVolumeSetGet ()
{
    quint32 val = 5;

    m_Api->setVolume (val);

    QVERIFY (m_Api->getVolume () == val)  ;
}

void
Ut_VolumeBarLogic::testVolumeChangeByPa ()
{
    quint32 currentstep = 10;
    quint32 stepcount   = 20;

    // A D-bus message calls this slot [inside the logic],
    // now we call this outside :
    m_Api->stepsUpdated (currentstep, stepcount);

    // Check the current ...
    QVERIFY (m_Api->getVolume () == currentstep);
    // .. and the maximal values
    QVERIFY (m_Api->getMaxVolume () == stepcount);
}

void
Ut_VolumeBarLogic::testSignaling ()
{
    quint32 currentstep = 0;
    quint32 stepcount   = 13;

    // Whe PulseAudio sends the D-Bus signal about stepcount/currentstep
    // changes logic should emit itself volumeChanged signal
    QSignalSpy spy (m_Api, SIGNAL (volumeChanged (quint32, quint32)));

    // Do what PulseAudio do [of course Pa doing this indirectly...]
    m_Api->stepsUpdated (currentstep, stepcount);

    QTest::qWait (500); // wait for a little time

    QList<QVariant> arguments = spy.takeFirst ();
    // Verify the signal parameters
    QVERIFY (arguments.at (0).toUInt () == currentstep);
    QVERIFY (arguments.at (1).toUInt () == stepcount);
}

QTEST_MAIN(Ut_VolumeBarLogic)
<commit_msg>Update ut_volumebarlogic<commit_after>#include "ut_volumebarlogic.h"
#include <volumebarlogic.h>

void
Ut_VolumeBarLogic::init ()
{
}

void
Ut_VolumeBarLogic::cleanup ()
{
}

void
Ut_VolumeBarLogic::initTestCase ()
{
    m_Api = new VolumeBarLogic;
    m_Api->stepsUpdated (30, 100);
}

void
Ut_VolumeBarLogic::cleanupTestCase ()
{
    delete m_Api;
}

// Check if setting / getting works correctly
void
Ut_VolumeBarLogic::testVolumeSetGet ()
{
    quint32 val = 5;

    m_Api->setVolume (val);

    QVERIFY (m_Api->getVolume () == val)  ;
}

void
Ut_VolumeBarLogic::testVolumeChangeByPa ()
{
    quint32 currentstep = 10;
    quint32 stepcount   = 20;

    // A D-bus message calls this slot [inside the logic],
    // now we call this outside :
    m_Api->stepsUpdated (currentstep, stepcount);

    // Check the current ...
    QVERIFY (m_Api->getVolume () == currentstep);
    // .. and the maximal values
    QVERIFY (m_Api->getMaxVolume () == stepcount);
}

void
Ut_VolumeBarLogic::testSignaling ()
{
    quint32 currentstep = 0;
    quint32 stepcount   = 13;

    // Whe PulseAudio sends the D-Bus signal about stepcount/currentstep
    // changes logic should emit itself volumeChanged signal
    QSignalSpy spy (m_Api, SIGNAL (volumeChanged (quint32, quint32, bool)));

    // Do what PulseAudio do [of course Pa doing this indirectly...]
    m_Api->stepsUpdated (currentstep, stepcount);

    QTest::qWait (500); // wait for a little time

    QList<QVariant> arguments = spy.takeFirst ();
    // Verify the signal parameters
    QVERIFY (arguments.at (0).toUInt () == currentstep);
    QVERIFY (arguments.at (1).toUInt () == stepcount);
}

QTEST_MAIN(Ut_VolumeBarLogic)
<|endoftext|>


<commit_before>/*ckwg +5
 * Copyright 2011 by Kitware, Inc. All Rights Reserved. Please refer to
 * KITWARE_LICENSE.TXT for licensing information, or contact General Counsel,
 * Kitware, Inc., 28 Corporate Drive, Clifton Park, NY 12065.
 */

#include <test_common.h>

#include <vistk/pipeline_util/export_dot.h>
#include <vistk/pipeline_util/export_dot_exception.h>
#include <vistk/pipeline_util/pipe_bakery.h>

#include <vistk/pipeline/modules.h>

#include <boost/filesystem/path.hpp>

#include <exception>
#include <iostream>
#include <sstream>
#include <string>

static std::string const pipe_ext = ".pipe";

static void run_test(std::string const& test_name, boost::filesystem::path const& pipe_file);

int
main(int argc, char* argv[])
{
  if (argc != 3)
  {
    std::cerr << "Error: Expected two arguments" << std::endl;

    return 1;
  }

  std::string const test_name = argv[1];
  boost::filesystem::path const pipe_dir = argv[2];

  boost::filesystem::path const pipe_file = pipe_dir / (test_name + pipe_ext);

  try
  {
    run_test(test_name, pipe_file);
  }
  catch (std::exception& e)
  {
    std::cerr << "Error: Unexpected exception: " << e.what() << std::endl;

    return 1;
  }

  return 0;
}

static void test_pipeline_null(boost::filesystem::path const& pipe_file);
static void test_simple_pipeline(boost::filesystem::path const& pipe_file);

void
run_test(std::string const& test_name, boost::filesystem::path const& pipe_file)
{
  if (test_name == "pipeline_null")
  {
    test_pipeline_null(pipe_file);
  }
  else if (test_name == "simple_pipeline")
  {
    test_simple_pipeline(pipe_file);
  }
  else
  {
    std::cerr << "Error: Unknown test: " << test_name << std::endl;
  }
}

void test_pipeline_null(boost::filesystem::path const& /*pipe_file*/)
{
  vistk::pipeline_t pipeline;

  std::ostringstream sstr;

  EXPECT_EXCEPTION(vistk::null_pipeline_export_dot_exception,
                   vistk::export_dot(sstr, pipeline, "(unnamed)"),
                   "exporting a NULL pipeline to dot");
}

void
test_simple_pipeline(boost::filesystem::path const& pipe_file)
{
  vistk::load_known_modules();

  vistk::pipeline_t const pipeline = vistk::bake_pipe_from_file(pipe_file);

  std::ostringstream sstr;

  vistk::export_dot(sstr, pipeline, "(unnamed)");
}
<commit_msg>Fix some style<commit_after>/*ckwg +5
 * Copyright 2011 by Kitware, Inc. All Rights Reserved. Please refer to
 * KITWARE_LICENSE.TXT for licensing information, or contact General Counsel,
 * Kitware, Inc., 28 Corporate Drive, Clifton Park, NY 12065.
 */

#include <test_common.h>

#include <vistk/pipeline_util/export_dot.h>
#include <vistk/pipeline_util/export_dot_exception.h>
#include <vistk/pipeline_util/pipe_bakery.h>

#include <vistk/pipeline/modules.h>

#include <boost/filesystem/path.hpp>

#include <exception>
#include <iostream>
#include <sstream>
#include <string>

static std::string const pipe_ext = ".pipe";

static void run_test(std::string const& test_name, boost::filesystem::path const& pipe_file);

int
main(int argc, char* argv[])
{
  if (argc != 3)
  {
    std::cerr << "Error: Expected two arguments" << std::endl;

    return 1;
  }

  std::string const test_name = argv[1];
  boost::filesystem::path const pipe_dir = argv[2];

  boost::filesystem::path const pipe_file = pipe_dir / (test_name + pipe_ext);

  try
  {
    run_test(test_name, pipe_file);
  }
  catch (std::exception& e)
  {
    std::cerr << "Error: Unexpected exception: " << e.what() << std::endl;

    return 1;
  }

  return 0;
}

static void test_pipeline_null(boost::filesystem::path const& pipe_file);
static void test_simple_pipeline(boost::filesystem::path const& pipe_file);

void
run_test(std::string const& test_name, boost::filesystem::path const& pipe_file)
{
  if (test_name == "pipeline_null")
  {
    test_pipeline_null(pipe_file);
  }
  else if (test_name == "simple_pipeline")
  {
    test_simple_pipeline(pipe_file);
  }
  else
  {
    std::cerr << "Error: Unknown test: " << test_name << std::endl;
  }
}

void
test_pipeline_null(boost::filesystem::path const& /*pipe_file*/)
{
  vistk::pipeline_t pipeline;

  std::ostringstream sstr;

  EXPECT_EXCEPTION(vistk::null_pipeline_export_dot_exception,
                   vistk::export_dot(sstr, pipeline, "(unnamed)"),
                   "exporting a NULL pipeline to dot");
}

void
test_simple_pipeline(boost::filesystem::path const& pipe_file)
{
  vistk::load_known_modules();

  vistk::pipeline_t const pipeline = vistk::bake_pipe_from_file(pipe_file);

  std::ostringstream sstr;

  vistk::export_dot(sstr, pipeline, "(unnamed)");
}
<|endoftext|>


<commit_before>#include "PlatformAbstractions.h"
#include <nan.h>
#include <stdlib.h>
#include <uv.h>
#include "CallbackData.h"

namespace ClrLoader {

using namespace v8;

typedef void (STDMETHODCALLTYPE *PUnmanagedCallback)(const intptr_t, const char*);

typedef void (STDMETHODCALLTYPE *PManagedEntryPoint)(const intptr_t, const char*, const char*, const void (*PUnmanagedCallback));

// Declare a variable pointing to our managed method.
PManagedEntryPoint pManagedEntryPoint;

void ClrCallback(const intptr_t returnPtr, const char* value){
    auto callbackData = (CallbackData*)returnPtr;
    callbackData->setResult(value);
    uv_async_send(callbackData->getLoopData());
}

void FinalizeUvCallback(uv_async_t* handle){
    Nan::HandleScope handleScope;
    auto data = (CallbackData*)handle->data;
    const unsigned argc = 1;
    Local<Value> argv[argc] = {  Nan::New<String>(data->getResult()).ToLocalChecked() };
    Local<Function> origFunc = Nan::New(*data->getCallback());
    Nan::Callback cb(origFunc);
    cb.Call(argc, argv);
    delete data;
}

void ClrExecute(const Nan::FunctionCallbackInfo<Value>& args) {
  if (args.Length() < 3) {
    Nan::ThrowTypeError("Wrong number of arguments");
    return;
  }

  if (!args[0]->IsString()
          || !args[1]->IsString()
          || !args[2]->IsFunction()) {
    Nan::ThrowError("Wrong arguments");
    return;
  }

  String::Utf8Value utfStringConfig(args[0].As<String>());
  auto stdCStringConfig = std::string(*utfStringConfig);

  String::Utf8Value utfStringData(args[1].As<String>());
  auto stdCStringData = std::string(*utfStringData);

  // Perform the operation
  auto cb = args[2].As<Function>();
  auto nanCb = new CallbackData(new Nan::Persistent<Function>(cb));
  auto initResult = uv_async_init(uv_default_loop(), nanCb->getLoopData(), FinalizeUvCallback);
  if (!SUCCEEDED(initResult)){
      Nan::ThrowError(uv_strerror(initResult));
      return;
  }

  pManagedEntryPoint((intptr_t)nanCb, stdCStringConfig.c_str(), stdCStringData.c_str(), ClrCallback);
}

void Init(Local<Object> exports) {
  auto libPath = std::getenv("CLR_LIB_PATH");
  if (libPath == NULL){
    Nan::ThrowError("CLR_LIB_PATH not set");
    return;
  }

  auto appBasePath = std::getenv("CLR_APPBASE_PATH");
  if (appBasePath == NULL){
      Nan::ThrowError("CLR_APPBASE_PATH not set");
      return;
  }

  auto trustedPlatformAssemblies = std::getenv("CLR_TRUSTED_PLATFORM_ASSEMBLIES");
  if (trustedPlatformAssemblies == NULL){
    Nan::ThrowError("CLR_TRUSTED_PLATFORM_ASSEMBLIES not set");
    return;
  }

  auto appPaths = std::getenv("CLR_APP_PATHS");
  if (appPaths == NULL){
    Nan::ThrowError("CLR_APP_PATHS not set");
    return;
  }

  void* pCLRRuntimeHost = nullptr;
  clr_domain_id domainId;
  auto initClrResult = InitializeCoreClr(libPath,
		  appBasePath,
		  trustedPlatformAssemblies,
		  appPaths,
		  pCLRRuntimeHost,
		  (void*)&pManagedEntryPoint,
		  &domainId);
  switch(initClrResult){
    case Success:
      break;
    case CantLoadLibrary:
      Nan::ThrowError("Can't load coreclr.dll");
      return;
    case CantFindRuntimeHostFactory:
      Nan::ThrowError("Can't get CLR Runtime Host factory");
      return;
    case CantStartClrHost:
      Nan::ThrowError("Error starting CLR host");
      return;
    case CantSetStartupFlags:
      Nan::ThrowError("Error while setting CLR Runtime startup flags");
      return;
    case CantAuthenticateHost:
      Nan::ThrowError("Error while authenticating CLR host");
      return;
    case CantCreateClrHost:
      Nan::ThrowError("Error while initializing CLR Runtime host");
      return;
    case CantCreateAppDomain:
      Nan::ThrowError("Failed to create default AppDomain");
      return;
    case CantFindClrDelegate:
      Nan::ThrowError("Failed to find managed entry point");
      return;
    default:
      Nan::ThrowError("Unknown error");
      return;
  }

  Nan::SetMethod(exports, "ClrExecute", ClrExecute);
}

NODE_MODULE(addon, Init)
}
<commit_msg>Cross platform fixes<commit_after>#include "PlatformAbstractions.h"
#include <nan.h>
#include <stdlib.h>
#include <uv.h>
#include "CallbackData.h"

namespace ClrLoader {

using namespace v8;

typedef void (PUnmanagedCallback)(const intptr_t, const char*);

typedef void (PManagedEntryPoint)(const intptr_t, const char*, const char*, const void (*PUnmanagedCallback));

// Declare a variable pointing to our managed method.
PManagedEntryPoint* pManagedEntryPoint;

void ClrCallback(const intptr_t returnPtr, const char* value){
    auto callbackData = (CallbackData*)returnPtr;
    callbackData->setResult(value);
    uv_async_send(callbackData->getLoopData());
}

void FinalizeUvCallback(uv_async_t* handle){
    Nan::HandleScope handleScope;
    auto data = (CallbackData*)handle->data;
    const unsigned argc = 1;
    Local<Value> argv[argc] = {  Nan::New<String>(data->getResult()).ToLocalChecked() };
    Local<Function> origFunc = Nan::New(*data->getCallback());
    Nan::Callback cb(origFunc);
    cb.Call(argc, argv);
    delete data;
}

void ClrExecute(const Nan::FunctionCallbackInfo<Value>& args) {
  if (args.Length() < 3) {
    Nan::ThrowTypeError("Wrong number of arguments");
    return;
  }

  if (!args[0]->IsString()
          || !args[1]->IsString()
          || !args[2]->IsFunction()) {
    Nan::ThrowError("Wrong arguments");
    return;
  }

  String::Utf8Value utfStringConfig(args[0].As<String>());
  auto stdCStringConfig = std::string(*utfStringConfig);

  String::Utf8Value utfStringData(args[1].As<String>());
  auto stdCStringData = std::string(*utfStringData);

  // Perform the operation
  auto cb = args[2].As<Function>();
  auto nanCb = new CallbackData(new Nan::Persistent<Function>(cb));
  auto initResult = uv_async_init(uv_default_loop(), nanCb->getLoopData(), FinalizeUvCallback);
  if (!SUCCEEDED(initResult)){
      Nan::ThrowError(uv_strerror(initResult));
      return;
  }

  pManagedEntryPoint((intptr_t)nanCb, stdCStringConfig.c_str(), stdCStringData.c_str(), ClrCallback);
}

void Init(Local<Object> exports) {
  auto libPath = std::getenv("CLR_LIB_PATH");
  if (libPath == NULL){
    Nan::ThrowError("CLR_LIB_PATH not set");
    return;
  }

  auto appBasePath = std::getenv("CLR_APPBASE_PATH");
  if (appBasePath == NULL){
      Nan::ThrowError("CLR_APPBASE_PATH not set");
      return;
  }

  auto trustedPlatformAssemblies = std::getenv("CLR_TRUSTED_PLATFORM_ASSEMBLIES");
  if (trustedPlatformAssemblies == NULL){
    Nan::ThrowError("CLR_TRUSTED_PLATFORM_ASSEMBLIES not set");
    return;
  }

  auto appPaths = std::getenv("CLR_APP_PATHS");
  if (appPaths == NULL){
    Nan::ThrowError("CLR_APP_PATHS not set");
    return;
  }

  void* pCLRRuntimeHost = nullptr;
  clr_domain_id domainId;
  auto initClrResult = InitializeCoreClr(libPath,
		  appBasePath,
		  trustedPlatformAssemblies,
		  appPaths,
		  pCLRRuntimeHost,
		  (void*)&pManagedEntryPoint,
		  &domainId);
  switch(initClrResult){
    case Success:
      break;
    case CantLoadLibrary:
      Nan::ThrowError("Can't load coreclr.dll");
      return;
    case CantFindRuntimeHostFactory:
      Nan::ThrowError("Can't get CLR Runtime Host factory");
      return;
    case CantStartClrHost:
      Nan::ThrowError("Error starting CLR host");
      return;
    case CantSetStartupFlags:
      Nan::ThrowError("Error while setting CLR Runtime startup flags");
      return;
    case CantAuthenticateHost:
      Nan::ThrowError("Error while authenticating CLR host");
      return;
    case CantCreateClrHost:
      Nan::ThrowError("Error while initializing CLR Runtime host");
      return;
    case CantCreateAppDomain:
      Nan::ThrowError("Failed to create default AppDomain");
      return;
    case CantFindClrDelegate:
      Nan::ThrowError("Failed to find managed entry point");
      return;
    default:
      Nan::ThrowError("Unknown error");
      return;
  }

  Nan::SetMethod(exports, "ClrExecute", ClrExecute);
}

NODE_MODULE(addon, Init)
}
<|endoftext|>