<commit_before>#ifndef __FAST5_HPP
#define __FAST5_HPP

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

#include "hdf5_tools.hpp"

namespace fast5
{

//
// This struct represents the expected signal measured
// given the kmer sequence that is in the pore when the
// the observations are made. A pore model consists
// of 1024 of these entries (one per 5-mer) and global
// shift/scaling parameters.
//
struct Model_Entry
{
    char kmer[6];
    long long variant;
    double level_mean;
    double level_stdv;
    double sd_mean;
    double sd_stdv;
    double weight;
}; // struct Model_Entry

//
// This struct represents the global transformations
// that must be applied to each Model_Entry
//
struct Model_Parameters
{
    double drift;
    double scale;
    double scale_sd;
    double shift;
    double var;
    double var_sd;
}; // struct Model_Parameters

//
// This struct represents an observed event.
// The members of the struct are the same as
// the fields encoded in the FAST5 file.
//
struct Event_Entry
{
    double mean;
    double start;
    double stdv;
    double length;
    char model_state[6];
    double model_level;
    long long move;
    double p_model_state;
    char mp_state[6];
    double p_mp_state;
    double p_A;
    double p_C;
    double p_G;
    double p_T;
}; // struct Event_Entry

//
// This struct represents a template-to-complement
// match that is emitted by ONT's 2D basecaller
//
struct Event_Alignment_Entry
{
    long long template_index;
    long long complement_index;
    char kmer[6];
}; // struct Event_Alignment_Entry

class File
    : private hdf5_tools::File_Reader
{
private:
    typedef hdf5_tools::File_Reader Base;
public:
    using Base::Base;

    using Base::is_open;
    using Base::file_name;
    using Base::open;
    using Base::close;

    std::string file_version() const
    {
        double v;
        assert(Base::exists("/file_version"));
        Base::read< double >("/file_version", v);
        // convert it to string
        std::ostringstream os;
        os << v;
        return os.str();
    }

    std::string basecall_version() const
    {
        std::string res;
        assert(Base::exists("/Analyses/Basecall_2D_000/version"));
        Base::read< std::string >("/Analyses/Basecall_2D_000/version", res);
        return res;
    }

    std::string eventdetection_version() const
    {
        std::string res;
        assert(Base::exists("/Analyses/EventDetection_000/version"));
        Base::read< std::string >("/Analyses/EventDetection_000/version", res);
        return res;
    }

    std::string get_log() const
    {
        std::string res;
        assert(Base::exists("/Analyses/Basecall_2D_000/Log"));
        Base::read< std::string >("/Analyses/Basecall_2D_000/Log", res);
        return res;
    }

    double get_sampling_rate() const
    {
        assert(have_sampling_rate());

        auto lg = get_log();
        auto idx = lg.find("Sampling rate is");

        std::string line;
        std::stringstream ss1(lg.substr(idx));
        std::getline(ss1,line,'\n');

        std::stringstream ss2(line);

        std::string token;
        std::getline(ss2,token,' ');    //Sampling
        std::getline(ss2,token,' ');    //rate
        std::getline(ss2,token,' ');    //is
        std::getline(ss2,token,' ');    //Hz value

        return std::atof(token.c_str());
    }

    bool have_sampling_rate() const
    {
        auto lg = get_log();
        auto idx = lg.find("Sampling rate is");
        return idx != std::string::npos;
    }

    std::string get_model_file(size_t i) const
    {
        std::string res;
        assert(Base::exists(model_file_path(i)));
        Base::read< std::string >(model_file_path(i), res);
        return res;
    }

    std::string sequences_version() const
    {
        std::vector< std::string > tmp;
        assert(Base::exists("/Sequences/Meta/version"));
        Base::read< std::string >("/Sequences/Meta/version", tmp);
        std::string res;
        for (const auto& s: tmp)
        {
            res += s;
        }
        return res;
    }

    bool have_basecalled_2D() const
    {
        return Base::exists("/Analyses/Basecall_2D_000/BaseCalled_2D/Fastq");
    }

    std::string basecalled_2D() const
    {
        std::string res;
        Base::read< std::string >("/Analyses/Basecall_2D_000/BaseCalled_2D/Fastq", res);

        // Split the FASTQ record on newlines
        size_t nl1 = res.find_first_of('\n');
        size_t nl2 = res.find_first_of('\n', nl1 + 1);

        if(nl1 == std::string::npos || nl2 == std::string::npos)
            return "";
        else
            return res.substr(nl1 + 1, nl2 - nl1 - 1);
    }

    std::vector< Event_Alignment_Entry > get_event_alignments() const
    {
        std::vector< Event_Alignment_Entry > res;
        hdf5_tools::Compound_Map m;
        m.add_member("template", &Event_Alignment_Entry::template_index);
        m.add_member("complement", &Event_Alignment_Entry::complement_index);
        m.add_member("kmer", &Event_Alignment_Entry::kmer);
        Base::read< Event_Alignment_Entry >("/Analyses/Basecall_2D_000/BaseCalled_2D/Alignment", res, &m);
        return res;
    }

    bool have_model(size_t i) const
    {
        return Base::exists(model_path(i));
    }
    bool have_events(size_t i) const
    {
        return Base::exists(events_path(i));
    }

    std::vector< Model_Entry > get_model(size_t i) const
    {
        std::vector< Model_Entry > res;
        hdf5_tools::Compound_Map m;
        m.add_member("kmer", &Model_Entry::kmer);
        m.add_member("level_mean", &Model_Entry::level_mean);
        m.add_member("level_stdv", &Model_Entry::level_stdv);
        Base::read< Model_Entry >(model_path(i), res, &m);
        return res;
    }

    Model_Parameters get_model_parameters(size_t i) const
    {
        Model_Parameters res;
        std::string path = model_path(i);
        Base::read< double >(path + "/drift", res.drift);
        Base::read< double >(path + "/scale", res.scale);
        Base::read< double >(path + "/scale_sd", res.scale_sd);
        Base::read< double >(path + "/shift", res.shift);
        Base::read< double >(path + "/var", res.var);
        Base::read< double >(path + "/var_sd", res.var_sd);
        return res;
    }

    std::vector< Event_Entry > get_events(size_t i) const
    {
        std::vector< Event_Entry > res;
        hdf5_tools::Compound_Map m;
        m.add_member("mean", &Event_Entry::mean);
        m.add_member("start", &Event_Entry::start);
        m.add_member("stdv", &Event_Entry::stdv);
        m.add_member("length", &Event_Entry::length);
        Base::read< Event_Entry >(events_path(i), res, &m);
        return res;
    }

private:
    static const std::string& model_path(size_t i)
    {
        static std::vector< std::string > _model_path =
            { "/Analyses/Basecall_2D_000/BaseCalled_template/Model",
              "/Analyses/Basecall_2D_000/BaseCalled_complement/Model" };
        return _model_path.at(i);
    }

    static const std::string& events_path(size_t i)
    {
        static std::vector< std::string > _events_path =
            { "/Analyses/Basecall_2D_000/BaseCalled_template/Events",
              "/Analyses/Basecall_2D_000/BaseCalled_complement/Events" };
        return _events_path.at(i);
    }

    static const std::string& model_file_path(size_t i)
    {
        static std::vector< std::string > _model_file_path =
            { "/Analyses/Basecall_2D_000/Summary/basecall_1d_template/model_file",
              "/Analyses/Basecall_2D_000/Summary/basecall_1d_complement/model_file" };
        return _model_file_path.at(i);
    }

}; // class File

} // namespace fast5

#endif
<commit_msg>added sd_mean and sd_stdv to get_model(size_t i) in fast5.hpp<commit_after>#ifndef __FAST5_HPP
#define __FAST5_HPP

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

#include "hdf5_tools.hpp"

namespace fast5
{

//
// This struct represents the expected signal measured
// given the kmer sequence that is in the pore when the
// the observations are made. A pore model consists
// of 1024 of these entries (one per 5-mer) and global
// shift/scaling parameters.
//
struct Model_Entry
{
    char kmer[6];
    long long variant;
    double level_mean;
    double level_stdv;
    double sd_mean;
    double sd_stdv;
    double weight;
}; // struct Model_Entry

//
// This struct represents the global transformations
// that must be applied to each Model_Entry
//
struct Model_Parameters
{
    double drift;
    double scale;
    double scale_sd;
    double shift;
    double var;
    double var_sd;
}; // struct Model_Parameters

//
// This struct represents an observed event.
// The members of the struct are the same as
// the fields encoded in the FAST5 file.
//
struct Event_Entry
{
    double mean;
    double start;
    double stdv;
    double length;
    char model_state[6];
    double model_level;
    long long move;
    double p_model_state;
    char mp_state[6];
    double p_mp_state;
    double p_A;
    double p_C;
    double p_G;
    double p_T;
}; // struct Event_Entry

//
// This struct represents a template-to-complement
// match that is emitted by ONT's 2D basecaller
//
struct Event_Alignment_Entry
{
    long long template_index;
    long long complement_index;
    char kmer[6];
}; // struct Event_Alignment_Entry

class File
    : private hdf5_tools::File_Reader
{
private:
    typedef hdf5_tools::File_Reader Base;
public:
    using Base::Base;

    using Base::is_open;
    using Base::file_name;
    using Base::open;
    using Base::close;

    std::string file_version() const
    {
        double v;
        assert(Base::exists("/file_version"));
        Base::read< double >("/file_version", v);
        // convert it to string
        std::ostringstream os;
        os << v;
        return os.str();
    }

    std::string basecall_version() const
    {
        std::string res;
        assert(Base::exists("/Analyses/Basecall_2D_000/version"));
        Base::read< std::string >("/Analyses/Basecall_2D_000/version", res);
        return res;
    }

    std::string eventdetection_version() const
    {
        std::string res;
        assert(Base::exists("/Analyses/EventDetection_000/version"));
        Base::read< std::string >("/Analyses/EventDetection_000/version", res);
        return res;
    }

    std::string get_log() const
    {
        std::string res;
        assert(Base::exists("/Analyses/Basecall_2D_000/Log"));
        Base::read< std::string >("/Analyses/Basecall_2D_000/Log", res);
        return res;
    }

    double get_sampling_rate() const
    {
        assert(have_sampling_rate());

        auto lg = get_log();
        auto idx = lg.find("Sampling rate is");

        std::string line;
        std::stringstream ss1(lg.substr(idx));
        std::getline(ss1,line,'\n');

        std::stringstream ss2(line);

        std::string token;
        std::getline(ss2,token,' ');    //Sampling
        std::getline(ss2,token,' ');    //rate
        std::getline(ss2,token,' ');    //is
        std::getline(ss2,token,' ');    //Hz value

        return std::atof(token.c_str());
    }

    bool have_sampling_rate() const
    {
        auto lg = get_log();
        auto idx = lg.find("Sampling rate is");
        return idx != std::string::npos;
    }

    std::string get_model_file(size_t i) const
    {
        std::string res;
        assert(Base::exists(model_file_path(i)));
        Base::read< std::string >(model_file_path(i), res);
        return res;
    }

    std::string sequences_version() const
    {
        std::vector< std::string > tmp;
        assert(Base::exists("/Sequences/Meta/version"));
        Base::read< std::string >("/Sequences/Meta/version", tmp);
        std::string res;
        for (const auto& s: tmp)
        {
            res += s;
        }
        return res;
    }

    bool have_basecalled_2D() const
    {
        return Base::exists("/Analyses/Basecall_2D_000/BaseCalled_2D/Fastq");
    }

    std::string basecalled_2D() const
    {
        std::string res;
        Base::read< std::string >("/Analyses/Basecall_2D_000/BaseCalled_2D/Fastq", res);

        // Split the FASTQ record on newlines
        size_t nl1 = res.find_first_of('\n');
        size_t nl2 = res.find_first_of('\n', nl1 + 1);

        if(nl1 == std::string::npos || nl2 == std::string::npos)
            return "";
        else
            return res.substr(nl1 + 1, nl2 - nl1 - 1);
    }

    std::vector< Event_Alignment_Entry > get_event_alignments() const
    {
        std::vector< Event_Alignment_Entry > res;
        hdf5_tools::Compound_Map m;
        m.add_member("template", &Event_Alignment_Entry::template_index);
        m.add_member("complement", &Event_Alignment_Entry::complement_index);
        m.add_member("kmer", &Event_Alignment_Entry::kmer);
        Base::read< Event_Alignment_Entry >("/Analyses/Basecall_2D_000/BaseCalled_2D/Alignment", res, &m);
        return res;
    }

    bool have_model(size_t i) const
    {
        return Base::exists(model_path(i));
    }
    bool have_events(size_t i) const
    {
        return Base::exists(events_path(i));
    }

    std::vector< Model_Entry > get_model(size_t i) const
    {
        std::vector< Model_Entry > res;
        hdf5_tools::Compound_Map m;
        m.add_member("kmer", &Model_Entry::kmer);
        m.add_member("level_mean", &Model_Entry::level_mean);
        m.add_member("level_stdv", &Model_Entry::level_stdv);
        m.add_member("sd_mean", &Model_Entry::sd_mean);
        m.add_member("sd_stdv", &Model_Entry::sd_stdv);
        Base::read< Model_Entry >(model_path(i), res, &m);
        return res;
    }

    Model_Parameters get_model_parameters(size_t i) const
    {
        Model_Parameters res;
        std::string path = model_path(i);
        Base::read< double >(path + "/drift", res.drift);
        Base::read< double >(path + "/scale", res.scale);
        Base::read< double >(path + "/scale_sd", res.scale_sd);
        Base::read< double >(path + "/shift", res.shift);
        Base::read< double >(path + "/var", res.var);
        Base::read< double >(path + "/var_sd", res.var_sd);
        return res;
    }

    std::vector< Event_Entry > get_events(size_t i) const
    {
        std::vector< Event_Entry > res;
        hdf5_tools::Compound_Map m;
        m.add_member("mean", &Event_Entry::mean);
        m.add_member("start", &Event_Entry::start);
        m.add_member("stdv", &Event_Entry::stdv);
        m.add_member("length", &Event_Entry::length);
        Base::read< Event_Entry >(events_path(i), res, &m);
        return res;
    }

private:
    static const std::string& model_path(size_t i)
    {
        static std::vector< std::string > _model_path =
            { "/Analyses/Basecall_2D_000/BaseCalled_template/Model",
              "/Analyses/Basecall_2D_000/BaseCalled_complement/Model" };
        return _model_path.at(i);
    }

    static const std::string& events_path(size_t i)
    {
        static std::vector< std::string > _events_path =
            { "/Analyses/Basecall_2D_000/BaseCalled_template/Events",
              "/Analyses/Basecall_2D_000/BaseCalled_complement/Events" };
        return _events_path.at(i);
    }

    static const std::string& model_file_path(size_t i)
    {
        static std::vector< std::string > _model_file_path =
            { "/Analyses/Basecall_2D_000/Summary/basecall_1d_template/model_file",
              "/Analyses/Basecall_2D_000/Summary/basecall_1d_complement/model_file" };
        return _model_file_path.at(i);
    }

}; // class File

} // namespace fast5

#endif
<|endoftext|>


<commit_before>/**
 * Self-Organizing Maps on a cluster
 *  Copyright (C) 2013 Peter Wittek
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include <cmath>
#include <cstdlib>
#ifdef CLI
#include <iostream>
#include <iomanip>
#include <sstream>
#else
#include <stdexcept>
#endif  // CLI
#ifdef HAVE_R
#include <R.h>
#endif  // HAVE_R
#include "somoclu.h"

using namespace std;

void my_abort(string err) {
#ifdef CLI
#ifdef HAVE_MPI
    int rank = 0;
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    if (rank == 0) {
        cerr << "Error: " << err << endl;
    }
    MPI_Abort(MPI_COMM_WORLD, 1);
#else
    cerr << "Error: " << err << endl;
    exit(1);
#endif  // HAVE_MPI
#else
    throw std::runtime_error(err);
#endif  // CLI
}

void train(float *data, int data_length, unsigned int nEpoch,
           unsigned int nSomX, unsigned int nSomY,
           unsigned int nDimensions, unsigned int nVectors,
           unsigned int radius0, unsigned int radiusN, string radiusCooling,
           float scale0, float scaleN, string scaleCooling,
           unsigned int kernelType, string mapType,
           string gridType, bool compact_support, bool gaussian,
           float *codebook, int codebook_size,
           int *globalBmus, int globalBmus_size,
           float *uMatrix, int uMatrix_size) {
    train(0, data, NULL, codebook, globalBmus, uMatrix, nSomX, nSomY,
          nDimensions, nVectors, nVectors,
          nEpoch, radius0, radiusN, radiusCooling,
          scale0, scaleN, scaleCooling,
          kernelType, mapType,
          gridType, compact_support, gaussian
#ifdef CLI
          , "", 0);
#else
         );
#endif
    calculateUMatrix(uMatrix, codebook, nSomX, nSomY, nDimensions, mapType,
                     gridType);
}

void train(int itask, float *data, svm_node **sparseData,
           float *codebook, int *globalBmus, float *uMatrix,
           unsigned int nSomX, unsigned int nSomY,
           unsigned int nDimensions, unsigned int nVectors,
           unsigned int nVectorsPerRank, unsigned int nEpoch,
           unsigned int radius0, unsigned int radiusN, string radiusCooling,
           float scale0, float scaleN, string scaleCooling,
           unsigned int kernelType, string mapType,
           string gridType, bool compact_support, bool gaussian
#ifdef CLI
           , string outPrefix, unsigned int snapshots)
#else
          )
#endif
{
    int nProcs = 1;
#ifdef HAVE_MPI
    MPI_Comm_size(MPI_COMM_WORLD, &nProcs);
#endif
#ifdef CUDA
    if (kernelType == DENSE_GPU) {
        setDevice(itask, nProcs);
        initializeGpu(data, nVectorsPerRank, nDimensions, nSomX, nSomY);
    }
#endif
    // (Re-)Initialize codebook with random values only if requested through
    // the passed codebook -- meaning that the user did not have an initial
    // codebook

    if (codebook[0] == 1000 && codebook[1] == 2000) {
        initializeCodebook(0, codebook, nSomX, nSomY, nDimensions);
    }
    ///
    /// Parameters for SOM
    ///
    if (radius0 == 0) {
        unsigned int minDim = min(nSomX, nSomY);
        radius0 = minDim / 2.0f;              /// init radius for updating neighbors
    }
    if (radiusN == 0) {
        radiusN = 1;
    }
    if (scale0 == 0) {
        scale0 = 0.1;
    }

    ///
    /// Training
    ///
    unsigned int currentEpoch = 0;             /// 0...nEpoch-1
    while ( currentEpoch < nEpoch ) {

#ifdef HAVE_MPI
        double epoch_time = MPI_Wtime();
#endif

        trainOneEpoch(itask, data, sparseData, codebook, globalBmus,
                      nEpoch, currentEpoch,
                      nSomX, nSomY, nDimensions, nVectors, nVectorsPerRank,
                      radius0, radiusN, radiusCooling,
                      scale0, scaleN, scaleCooling, kernelType, mapType,
                      gridType, compact_support, gaussian);
#ifdef CLI
        if (snapshots > 0 && itask == 0) {
            calculateUMatrix(uMatrix, codebook, nSomX, nSomY, nDimensions,
                             mapType, gridType);
            stringstream sstm;
            sstm << outPrefix << "." << currentEpoch + 1;
            saveUMatrix(sstm.str() + string(".umx"), uMatrix, nSomX, nSomY);
            if (snapshots == 2) {
                saveBmus(sstm.str() + string(".bm"), globalBmus, nSomX, nSomY, nVectors);
                saveCodebook(sstm.str() + string(".wts"), codebook, nSomX, nSomY, nDimensions);
            }
        }
#endif
        ++currentEpoch;

#ifdef CLI
#ifdef HAVE_MPI
        if (itask == 0) {
            epoch_time = MPI_Wtime() - epoch_time;
            cerr << "Epoch Time: " << epoch_time << endl;
            if ( (currentEpoch != nEpoch) && (currentEpoch % (nEpoch / 100 + 1) != 0) ) {}
            else {
                float ratio  =  currentEpoch / (float)nEpoch;
                int   c      =  ratio * 50 + 1;
                cout << std::setw(7) << (int)(ratio * 100) << "% [";
                for (int x = 0; x < c; x++) cout << "=";
                for (int x = c; x < 50; x++) cout << " ";
                cout << "]\n" << flush;
            }
        }
#endif
#endif
    }
#ifdef CUDA
    if (kernelType == DENSE_GPU) {
        freeGpu();
    }
#endif
}

float linearCooling(float start, float end, float nEpoch, float epoch) {
    float diff = (start - end) / (nEpoch - 1);
    return start - (epoch * diff);
}

float exponentialCooling(float start, float end, float nEpoch, float epoch) {
    float diff = 0;
    if (end == 0.0) {
        diff = -log(0.1) / nEpoch;
    }
    else {
        diff = -log(end / start) / nEpoch;
    }
    return start * exp(-epoch * diff);
}

/** Initialize SOM codebook with random values
 * @param seed - random seed
 * @param codebook - the codebook to fill in
 * @param nSomX - dimensions of SOM map in the currentEpoch direction
 * @param nSomY - dimensions of SOM map in the y direction
 * @param nDimensions - dimensions of a data instance
 */

void initializeCodebook(unsigned int seed, float *codebook, unsigned int nSomX,
                        unsigned int nSomY, unsigned int nDimensions) {
    ///
    /// Fill initial random weights
    ///
#ifdef HAVE_R
    GetRNGstate();
#else
    srand(seed);
#endif
    for (unsigned int som_y = 0; som_y < nSomY; som_y++) {
        for (unsigned int som_x = 0; som_x < nSomX; som_x++) {
            for (unsigned int d = 0; d < nDimensions; d++) {
#ifdef HAVE_R
                int w = 0xFFF & (int) (RAND_MAX * unif_rand());
#else
                int w = 0xFFF & rand();
#endif
                w -= 0x800;
                codebook[som_y * nSomX * nDimensions + som_x * nDimensions + d] = (float)w / 4096.0f;
            }
        }
    }
#ifdef HAVE_R
    PutRNGstate();
#endif
}

void trainOneEpoch(int itask, float *data, svm_node **sparseData,
                   float *codebook, int *globalBmus,
                   unsigned int nEpoch, unsigned int currentEpoch,
                   unsigned int nSomX, unsigned int nSomY,
                   unsigned int nDimensions, unsigned int nVectors,
                   unsigned int nVectorsPerRank,
                   unsigned int radius0, unsigned int radiusN,
                   string radiusCooling,
                   float scale0, float scaleN,
                   string scaleCooling,
                   unsigned int kernelType, string mapType,
                   string gridType, bool compact_support, bool gaussian) {

    float N = (float)nEpoch;
    float *numerator;
    float *denominator;
    float scale = scale0;
    float radius = radius0;
    if (itask == 0) {
        numerator = new float[nSomY * nSomX * nDimensions];
        denominator = new float[nSomY * nSomX];
        for (unsigned int som_y = 0; som_y < nSomY; som_y++) {
            for (unsigned int som_x = 0; som_x < nSomX; som_x++) {
                denominator[som_y * nSomX + som_x] = 0.0;
                for (unsigned int d = 0; d < nDimensions; d++) {
                    numerator[som_y * nSomX * nDimensions + som_x * nDimensions + d] = 0.0;
                }
            }
        }

        if (radiusCooling == "linear") {
            radius = linearCooling(float(radius0), radiusN, N, currentEpoch);
        }
        else {
            radius = exponentialCooling(radius0, radiusN, N, currentEpoch);
        }
        if (scaleCooling == "linear") {
            scale = linearCooling(scale0, scaleN, N, currentEpoch);
        }
        else {
            scale = exponentialCooling(scale0, scaleN, N, currentEpoch);
        }
//        cout << "Epoch: " << currentEpoch << " Radius: " << radius << endl;
    }
#ifdef HAVE_MPI
    MPI_Bcast(&radius, 1, MPI_FLOAT, 0, MPI_COMM_WORLD);
    MPI_Bcast(&scale, 1, MPI_FLOAT, 0, MPI_COMM_WORLD);
    MPI_Bcast(codebook, nSomY * nSomX * nDimensions, MPI_FLOAT,
              0, MPI_COMM_WORLD);
#endif

    /// 1. Each task fills localNumerator and localDenominator
    /// 2. MPI_reduce sums up each tasks localNumerator and localDenominator to the root's
    ///    numerator and denominator.
    switch (kernelType) {
    default:
    case DENSE_CPU:
        trainOneEpochDenseCPU(itask, data, numerator, denominator,
                              codebook, nSomX, nSomY, nDimensions,
                              nVectors, nVectorsPerRank, radius, scale,
                              mapType, gridType, compact_support, gaussian, globalBmus);
        break;
    case DENSE_GPU:
#ifdef CUDA
        trainOneEpochDenseGPU(itask, data, numerator, denominator,
                              codebook, nSomX, nSomY, nDimensions,
                              nVectors, nVectorsPerRank, radius, scale,
                              mapType, gridType, compact_support, gaussian, globalBmus);
        break;
#else
        my_abort("Compiled without CUDA!");
#endif
    case SPARSE_CPU:
        trainOneEpochSparseCPU(itask, sparseData, numerator, denominator,
                               codebook, nSomX, nSomY, nDimensions,
                               nVectors, nVectorsPerRank, radius, scale,
                               mapType, gridType, compact_support, gaussian, globalBmus);
        break;
    }

    /// 3. Update codebook using numerator and denominator
#ifdef HAVE_MPI
    MPI_Barrier(MPI_COMM_WORLD);
#endif
    if (itask == 0) {
        #pragma omp parallel for
#ifdef _WIN32
        for (int som_y = 0; som_y < nSomY; som_y++) {
#else
        for (unsigned int som_y = 0; som_y < nSomY; som_y++) {
#endif
            for (unsigned int som_x = 0; som_x < nSomX; som_x++) {
                float denom = denominator[som_y * nSomX + som_x];
                for (unsigned int d = 0; d < nDimensions; d++) {
                    float newWeight = numerator[som_y * nSomX * nDimensions
                                                + som_x * nDimensions + d] / denom;
                    if (newWeight > 0.0) {
                        codebook[som_y * nSomX * nDimensions + som_x * nDimensions + d] = newWeight;
                    }
                }
            }
        }
    }
    if (itask == 0) {
        delete [] numerator;
        delete [] denominator;
    }
}
<commit_msg>add CUDA sanity check for R<commit_after>/**
 * Self-Organizing Maps on a cluster
 *  Copyright (C) 2013 Peter Wittek
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include <cmath>
#include <cstdlib>
#ifdef CLI
#include <iostream>
#include <iomanip>
#include <sstream>
#else
#include <stdexcept>
#endif  // CLI
#ifdef HAVE_R
#include <R.h>
#endif  // HAVE_R
#include "somoclu.h"

using namespace std;

void my_abort(string err) {
#ifdef CLI
#ifdef HAVE_MPI
    int rank = 0;
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    if (rank == 0) {
        cerr << "Error: " << err << endl;
    }
    MPI_Abort(MPI_COMM_WORLD, 1);
#else
    cerr << "Error: " << err << endl;
    exit(1);
#endif  // HAVE_MPI
#else
    throw std::runtime_error(err);
#endif  // CLI
}

void train(float *data, int data_length, unsigned int nEpoch,
           unsigned int nSomX, unsigned int nSomY,
           unsigned int nDimensions, unsigned int nVectors,
           unsigned int radius0, unsigned int radiusN, string radiusCooling,
           float scale0, float scaleN, string scaleCooling,
           unsigned int kernelType, string mapType,
           string gridType, bool compact_support, bool gaussian,
           float *codebook, int codebook_size,
           int *globalBmus, int globalBmus_size,
           float *uMatrix, int uMatrix_size) {
#ifdef HAVE_R
#ifndef CUDA
	if(kernelType == DENSE_GPU){
		Rprintf("Error: CUDA kernel not compiled \n");
		return;
	}
#endif // CUDA
#endif // HAVE_R
    train(0, data, NULL, codebook, globalBmus, uMatrix, nSomX, nSomY,
          nDimensions, nVectors, nVectors,
          nEpoch, radius0, radiusN, radiusCooling,
          scale0, scaleN, scaleCooling,
          kernelType, mapType,
          gridType, compact_support, gaussian
#ifdef CLI
          , "", 0);
#else
         );
#endif
    calculateUMatrix(uMatrix, codebook, nSomX, nSomY, nDimensions, mapType,
                     gridType);
}

void train(int itask, float *data, svm_node **sparseData,
           float *codebook, int *globalBmus, float *uMatrix,
           unsigned int nSomX, unsigned int nSomY,
           unsigned int nDimensions, unsigned int nVectors,
           unsigned int nVectorsPerRank, unsigned int nEpoch,
           unsigned int radius0, unsigned int radiusN, string radiusCooling,
           float scale0, float scaleN, string scaleCooling,
           unsigned int kernelType, string mapType,
           string gridType, bool compact_support, bool gaussian
#ifdef CLI
           , string outPrefix, unsigned int snapshots)
#else
          )
#endif
{
    int nProcs = 1;
#ifdef HAVE_MPI
    MPI_Comm_size(MPI_COMM_WORLD, &nProcs);
#endif
#ifdef CUDA
    if (kernelType == DENSE_GPU) {
        setDevice(itask, nProcs);
        initializeGpu(data, nVectorsPerRank, nDimensions, nSomX, nSomY);
    }
#endif
    // (Re-)Initialize codebook with random values only if requested through
    // the passed codebook -- meaning that the user did not have an initial
    // codebook

    if (codebook[0] == 1000 && codebook[1] == 2000) {
        initializeCodebook(0, codebook, nSomX, nSomY, nDimensions);
    }
    ///
    /// Parameters for SOM
    ///
    if (radius0 == 0) {
        unsigned int minDim = min(nSomX, nSomY);
        radius0 = minDim / 2.0f;              /// init radius for updating neighbors
    }
    if (radiusN == 0) {
        radiusN = 1;
    }
    if (scale0 == 0) {
        scale0 = 0.1;
    }

    ///
    /// Training
    ///
    unsigned int currentEpoch = 0;             /// 0...nEpoch-1
    while ( currentEpoch < nEpoch ) {

#ifdef HAVE_MPI
        double epoch_time = MPI_Wtime();
#endif

        trainOneEpoch(itask, data, sparseData, codebook, globalBmus,
                      nEpoch, currentEpoch,
                      nSomX, nSomY, nDimensions, nVectors, nVectorsPerRank,
                      radius0, radiusN, radiusCooling,
                      scale0, scaleN, scaleCooling, kernelType, mapType,
                      gridType, compact_support, gaussian);
#ifdef CLI
        if (snapshots > 0 && itask == 0) {
            calculateUMatrix(uMatrix, codebook, nSomX, nSomY, nDimensions,
                             mapType, gridType);
            stringstream sstm;
            sstm << outPrefix << "." << currentEpoch + 1;
            saveUMatrix(sstm.str() + string(".umx"), uMatrix, nSomX, nSomY);
            if (snapshots == 2) {
                saveBmus(sstm.str() + string(".bm"), globalBmus, nSomX, nSomY, nVectors);
                saveCodebook(sstm.str() + string(".wts"), codebook, nSomX, nSomY, nDimensions);
            }
        }
#endif
        ++currentEpoch;

#ifdef CLI
#ifdef HAVE_MPI
        if (itask == 0) {
            epoch_time = MPI_Wtime() - epoch_time;
            cerr << "Epoch Time: " << epoch_time << endl;
            if ( (currentEpoch != nEpoch) && (currentEpoch % (nEpoch / 100 + 1) != 0) ) {}
            else {
                float ratio  =  currentEpoch / (float)nEpoch;
                int   c      =  ratio * 50 + 1;
                cout << std::setw(7) << (int)(ratio * 100) << "% [";
                for (int x = 0; x < c; x++) cout << "=";
                for (int x = c; x < 50; x++) cout << " ";
                cout << "]\n" << flush;
            }
        }
#endif
#endif
    }
#ifdef CUDA
    if (kernelType == DENSE_GPU) {
        freeGpu();
    }
#endif
}

float linearCooling(float start, float end, float nEpoch, float epoch) {
    float diff = (start - end) / (nEpoch - 1);
    return start - (epoch * diff);
}

float exponentialCooling(float start, float end, float nEpoch, float epoch) {
    float diff = 0;
    if (end == 0.0) {
        diff = -log(0.1) / nEpoch;
    }
    else {
        diff = -log(end / start) / nEpoch;
    }
    return start * exp(-epoch * diff);
}

/** Initialize SOM codebook with random values
 * @param seed - random seed
 * @param codebook - the codebook to fill in
 * @param nSomX - dimensions of SOM map in the currentEpoch direction
 * @param nSomY - dimensions of SOM map in the y direction
 * @param nDimensions - dimensions of a data instance
 */

void initializeCodebook(unsigned int seed, float *codebook, unsigned int nSomX,
                        unsigned int nSomY, unsigned int nDimensions) {
    ///
    /// Fill initial random weights
    ///
#ifdef HAVE_R
    GetRNGstate();
#else
    srand(seed);
#endif
    for (unsigned int som_y = 0; som_y < nSomY; som_y++) {
        for (unsigned int som_x = 0; som_x < nSomX; som_x++) {
            for (unsigned int d = 0; d < nDimensions; d++) {
#ifdef HAVE_R
                int w = 0xFFF & (int) (RAND_MAX * unif_rand());
#else
                int w = 0xFFF & rand();
#endif
                w -= 0x800;
                codebook[som_y * nSomX * nDimensions + som_x * nDimensions + d] = (float)w / 4096.0f;
            }
        }
    }
#ifdef HAVE_R
    PutRNGstate();
#endif
}

void trainOneEpoch(int itask, float *data, svm_node **sparseData,
                   float *codebook, int *globalBmus,
                   unsigned int nEpoch, unsigned int currentEpoch,
                   unsigned int nSomX, unsigned int nSomY,
                   unsigned int nDimensions, unsigned int nVectors,
                   unsigned int nVectorsPerRank,
                   unsigned int radius0, unsigned int radiusN,
                   string radiusCooling,
                   float scale0, float scaleN,
                   string scaleCooling,
                   unsigned int kernelType, string mapType,
                   string gridType, bool compact_support, bool gaussian) {

    float N = (float)nEpoch;
    float *numerator;
    float *denominator;
    float scale = scale0;
    float radius = radius0;
    if (itask == 0) {
        numerator = new float[nSomY * nSomX * nDimensions];
        denominator = new float[nSomY * nSomX];
        for (unsigned int som_y = 0; som_y < nSomY; som_y++) {
            for (unsigned int som_x = 0; som_x < nSomX; som_x++) {
                denominator[som_y * nSomX + som_x] = 0.0;
                for (unsigned int d = 0; d < nDimensions; d++) {
                    numerator[som_y * nSomX * nDimensions + som_x * nDimensions + d] = 0.0;
                }
            }
        }

        if (radiusCooling == "linear") {
            radius = linearCooling(float(radius0), radiusN, N, currentEpoch);
        }
        else {
            radius = exponentialCooling(radius0, radiusN, N, currentEpoch);
        }
        if (scaleCooling == "linear") {
            scale = linearCooling(scale0, scaleN, N, currentEpoch);
        }
        else {
            scale = exponentialCooling(scale0, scaleN, N, currentEpoch);
        }
//        cout << "Epoch: " << currentEpoch << " Radius: " << radius << endl;
    }
#ifdef HAVE_MPI
    MPI_Bcast(&radius, 1, MPI_FLOAT, 0, MPI_COMM_WORLD);
    MPI_Bcast(&scale, 1, MPI_FLOAT, 0, MPI_COMM_WORLD);
    MPI_Bcast(codebook, nSomY * nSomX * nDimensions, MPI_FLOAT,
              0, MPI_COMM_WORLD);
#endif

    /// 1. Each task fills localNumerator and localDenominator
    /// 2. MPI_reduce sums up each tasks localNumerator and localDenominator to the root's
    ///    numerator and denominator.
    switch (kernelType) {
    default:
    case DENSE_CPU:
        trainOneEpochDenseCPU(itask, data, numerator, denominator,
                              codebook, nSomX, nSomY, nDimensions,
                              nVectors, nVectorsPerRank, radius, scale,
                              mapType, gridType, compact_support, gaussian, globalBmus);
        break;
    case DENSE_GPU:
#ifdef CUDA
        trainOneEpochDenseGPU(itask, data, numerator, denominator,
                              codebook, nSomX, nSomY, nDimensions,
                              nVectors, nVectorsPerRank, radius, scale,
                              mapType, gridType, compact_support, gaussian, globalBmus);
#else
        my_abort("Compiled without CUDA!");
#endif
        break;
    case SPARSE_CPU:
        trainOneEpochSparseCPU(itask, sparseData, numerator, denominator,
                               codebook, nSomX, nSomY, nDimensions,
                               nVectors, nVectorsPerRank, radius, scale,
                               mapType, gridType, compact_support, gaussian, globalBmus);
        break;
    }

    /// 3. Update codebook using numerator and denominator
#ifdef HAVE_MPI
    MPI_Barrier(MPI_COMM_WORLD);
#endif
    if (itask == 0) {
        #pragma omp parallel for
#ifdef _WIN32
        for (int som_y = 0; som_y < nSomY; som_y++) {
#else
        for (unsigned int som_y = 0; som_y < nSomY; som_y++) {
#endif
            for (unsigned int som_x = 0; som_x < nSomX; som_x++) {
                float denom = denominator[som_y * nSomX + som_x];
                for (unsigned int d = 0; d < nDimensions; d++) {
                    float newWeight = numerator[som_y * nSomX * nDimensions
                                                + som_x * nDimensions + d] / denom;
                    if (newWeight > 0.0) {
                        codebook[som_y * nSomX * nDimensions + som_x * nDimensions + d] = newWeight;
                    }
                }
            }
        }
    }
    if (itask == 0) {
        delete [] numerator;
        delete [] denominator;
    }
}
<|endoftext|>


<commit_before>#define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h>

#include <iostream>
#include <string>
#include <thread>
#include <cmath>

#include "glcxt.hpp"
#include "myshaders.hpp"

namespace mbwk {

static auto
createWindow(int width, int height, std::string title) -> GLFWwindow*
{
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
    glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);

    return glfwCreateWindow(width, height, title.c_str(), nullptr, nullptr);
}

static auto
keyCallbackFunc(GLFWwindow *window, int key, int scancode, int action, int mods) -> void
{
    switch (key) {
        case GLFW_KEY_Q:
        case GLFW_KEY_ESCAPE:
            glfwSetWindowShouldClose(window, GL_TRUE);
            break;
    }
}

GlContext::GlContext()
{
    glfwInit();
}

GlContext::~GlContext()
{
    glfwTerminate();
}

auto static
loadShaders() -> GLuint
{
    GLuint shaderProgram = glCreateProgram();

    GLuint vertShader = glCreateShader(GL_VERTEX_SHADER);
    auto vsrc = vertsrc();
    glShaderSource(vertShader, 1, &vsrc, NULL);
    glCompileShader(vertShader);

    GLuint fragShader = glCreateShader(GL_FRAGMENT_SHADER);
    auto fsrc = fragsrc();
    glShaderSource(fragShader, 1, &fsrc, NULL);
    glCompileShader(fragShader);

    glAttachShader(shaderProgram, vertShader);
    glAttachShader(shaderProgram, fragShader);

    glBindFragDataLocation(shaderProgram, 0, "outColor");

    glLinkProgram(shaderProgram);
    glUseProgram(shaderProgram);

    return shaderProgram;
}

GLfloat vertices[] = {
    -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
     0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
     0.0f,  0.5f, 0.0f, 0.0f, 1.0f,
     0.5f,  0.5f, 0.0f, 0.0f, 0.0f,
    -0.5f,  0.5f, 1.0f, 1.0f, 0.0f
};

GLuint tri_elements[] = {
    0, 1, 2
};

GLuint sqr_elements[] = {
    0, 1, 3,
    1, 3, 4
};

static GLsizei elec = 3;

auto static
selectElements()
{
    switch (elec) {
        case 6:
            glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(sqr_elements), sqr_elements, GL_STATIC_DRAW);
            break;
        case 3:
        default:
            glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(tri_elements), tri_elements, GL_STATIC_DRAW);
            break;
    }

}

auto static
mainWindow() -> void
{
    auto mainWindow = createWindow(800, 600, "main window");
    glfwMakeContextCurrent(mainWindow);
    glewExperimental = GL_TRUE;
    glewInit();

    glfwSetKeyCallback(mainWindow, keyCallbackFunc);

    GLuint vbo, vao, ebo, tex;

    glGenBuffers(1, &vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

    glGenBuffers(1, &ebo);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
    selectElements();

    glGenTextures(1, &tex);
    glBindTexture(GL_TEXTURE_2D, tex);

    GLuint shaderProgram = loadShaders();

    GLint posAttrib = glGetAttribLocation(shaderProgram, "position");
    glEnableVertexAttribArray(posAttrib);
    glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), 0);

    GLint colAttrib = glGetAttribLocation(shaderProgram, "color");
    glEnableVertexAttribArray(colAttrib);
    glVertexAttribPointer(colAttrib, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (void*)(2 * sizeof(GLfloat)));

    GLfloat unialpha = glGetUniformLocation(shaderProgram, "alpha");

    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glEnable(GL_BLEND);

    auto t_start = std::chrono::high_resolution_clock::now();

    while (!glfwWindowShouldClose(mainWindow)) {
        auto t_now = std::chrono::high_resolution_clock::now();
        float time = std::chrono::duration_cast<std::chrono::duration<float>>(t_now - t_start).count();
        float alval = (std::sin(time * 4.0f) + 1.0f) / 2.0f;

        glUniform1f(unialpha, alval);

        glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        glDrawElements(GL_TRIANGLES, elec, GL_UNSIGNED_INT, 0);

        glfwSwapBuffers(mainWindow);
        glfwPollEvents();
    }

    glfwDestroyWindow(mainWindow);
}

auto GlContext::run() -> void
{
    mainWindow();
}

}

<commit_msg>Added ability to toggle triangle/square (space)<commit_after>#define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h>

#include <iostream>
#include <string>
#include <thread>
#include <cmath>

#include "glcxt.hpp"
#include "myshaders.hpp"

namespace mbwk {

static auto
createWindow(int width, int height, std::string title) -> GLFWwindow*
{
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
    glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);

    return glfwCreateWindow(width, height, title.c_str(), nullptr, nullptr);
}

static GLsizei elec = 3;

auto static selectElements() -> void;

static auto
keyCallbackFunc(GLFWwindow *window, int key, int scancode, int action, int mods) -> void
{
    if (action == GLFW_PRESS) return;

    switch (key) {
        case GLFW_KEY_Q:
        case GLFW_KEY_ESCAPE:
            glfwSetWindowShouldClose(window, GL_TRUE);
            break;
        case GLFW_KEY_SPACE:
            if (elec == 3) {
                elec = 6;
            } else {
                elec = 3;
            }
            selectElements();
            break;
    }
}

GlContext::GlContext()
{
    glfwInit();
}

GlContext::~GlContext()
{
    glfwTerminate();
}

auto static
loadShaders() -> GLuint
{
    GLuint shaderProgram = glCreateProgram();

    GLuint vertShader = glCreateShader(GL_VERTEX_SHADER);
    auto vsrc = vertsrc();
    glShaderSource(vertShader, 1, &vsrc, NULL);
    glCompileShader(vertShader);

    GLuint fragShader = glCreateShader(GL_FRAGMENT_SHADER);
    auto fsrc = fragsrc();
    glShaderSource(fragShader, 1, &fsrc, NULL);
    glCompileShader(fragShader);

    glAttachShader(shaderProgram, vertShader);
    glAttachShader(shaderProgram, fragShader);

    glBindFragDataLocation(shaderProgram, 0, "outColor");

    glLinkProgram(shaderProgram);
    glUseProgram(shaderProgram);

    return shaderProgram;
}

GLfloat vertices[] = {
    -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
     0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
     0.0f,  0.5f, 0.0f, 0.0f, 1.0f,
     0.5f,  0.5f, 0.0f, 0.0f, 1.0f,
    -0.5f,  0.5f, 1.0f, 1.0f, 0.0f
};

GLuint tri_elements[] = {
    0, 1, 2
};

GLuint sqr_elements[] = {
    0, 1, 3,
    0, 3, 4
};

auto static
selectElements() -> void
{
    switch (elec) {
        case 6:
            glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(sqr_elements), sqr_elements, GL_STATIC_DRAW);
            break;
        case 3:
        default:
            glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(tri_elements), tri_elements, GL_STATIC_DRAW);
            break;
    }

}

auto static
mainWindow() -> void
{
    auto mainWindow = createWindow(800, 600, "main window");
    glfwMakeContextCurrent(mainWindow);
    glewExperimental = GL_TRUE;
    glewInit();

    glfwSetKeyCallback(mainWindow, keyCallbackFunc);

    GLuint vbo, vao, ebo, tex;

    glGenBuffers(1, &vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

    glGenBuffers(1, &ebo);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
    selectElements();

    glGenTextures(1, &tex);
    glBindTexture(GL_TEXTURE_2D, tex);

    GLuint shaderProgram = loadShaders();

    GLint posAttrib = glGetAttribLocation(shaderProgram, "position");
    glEnableVertexAttribArray(posAttrib);
    glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), 0);

    GLint colAttrib = glGetAttribLocation(shaderProgram, "color");
    glEnableVertexAttribArray(colAttrib);
    glVertexAttribPointer(colAttrib, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (void*)(2 * sizeof(GLfloat)));

    GLfloat unialpha = glGetUniformLocation(shaderProgram, "alpha");

    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glEnable(GL_BLEND);

    auto t_start = std::chrono::high_resolution_clock::now();

    while (!glfwWindowShouldClose(mainWindow)) {
        auto t_now = std::chrono::high_resolution_clock::now();
        float time = std::chrono::duration_cast<std::chrono::duration<float>>(t_now - t_start).count();
        float alval = (std::sin(time * 4.0f) + 1.0f) / 2.0f;

        glUniform1f(unialpha, alval);

        glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        glDrawElements(GL_TRIANGLES, elec, GL_UNSIGNED_INT, 0);

        glfwSwapBuffers(mainWindow);
        glfwPollEvents();
    }

    glfwDestroyWindow(mainWindow);
}

auto GlContext::run() -> void
{
    mainWindow();
}

}

<|endoftext|>


<commit_before>/** @file */
#include "clientmanager.h"

/**
 * Gets the icon structure which is owns the given window.
 * @param window The window to find.
 * @return Either the owning Icon, or NULL.
 */
Icon *ClientManager::get_icon_of_client(Window window)
{
    for (ClientIconIterator icon_iter = m_icons.begin();
            icon_iter != m_icons.end();
            icon_iter++)
    {
        if (icon_iter->second && icon_iter->second->client == window)
            return icon_iter->second;
    }

    return NULL;
}

/**
 * Gets an icon from the icon's window.
 * @param window The icon window.
 * @return An Icon*, or NULL.
 */
Icon *ClientManager::get_icon_of_icon(Window window)
{
    return m_icons[window];
}

/**
 * Creates a new icon window, and then reorganizes all the icons.
 * @param window The client window to make an icon for.
 */
void ClientManager::make_icon(Window window)
{
    Icon *icon = new Icon;
    icon->window = XCreateSimpleWindow(m_shared.display, m_shared.root,
            -200, -200, DIM2D_WIDTH(m_shared.icon_size),
            DIM2D_HEIGHT(m_shared.icon_size), 1,
            BlackPixel(m_shared.display, m_shared.screen),
            WhitePixel(m_shared.display, m_shared.screen));
    icon->client = window;

    // Ensure that this icon is not treated as a client
    XSetWindowAttributes attr;
    attr.override_redirect = true;
    XChangeWindowAttributes(m_shared.display, icon->window, CWOverrideRedirect,
            &attr);

    XSelectInput(m_shared.display, icon->window,
            ButtonPressMask | ButtonReleaseMask | ExposureMask);
    XMapWindow(m_shared.display, icon->window);

    icon->gc = XCreateGC(m_shared.display, icon->window, 0, NULL);

    // Gets the pixmap for this icon, if one actually exists, as well as its
    // dimensions
    XWMHints *hints = XGetWMHints(m_shared.display, icon->client);
    if (m_shared.show_icons && hints && hints->flags & IconPixmapHint)
    {
        icon->has_pixmap = true;
        icon->pixmap = hints->icon_pixmap;

        Window _u1;
        int _u2;
        unsigned int _u3;

        Dimension pix_width, pix_height;
        XGetGeometry(m_shared.display, icon->pixmap, &_u1, &_u2, &_u2,
                &pix_width, &pix_height, &_u3, &_u3);
        icon->pixmap_size = Dimension2D(pix_width, pix_height);
    }
    else
    {
        icon->has_pixmap = false;
    }

    XFree(hints);

    m_icons[icon->window] = icon;

    // Move all the icons into the proper location
    reflow_icons();
}

/**
 * Repositions icon windows, to avoid gaps and to make all icons visible.
 */
void ClientManager::reflow_icons()
{
    Dimension x = 0, y = 0;
    Dimension icon_width = DIM2D_WIDTH(m_shared.icon_size),
              icon_height = DIM2D_HEIGHT(m_shared.icon_size),
              screen_width = DIM2D_WIDTH(m_shared.screen_size);

    for (ClientIconIterator icon_iter = m_icons.begin();
            icon_iter != m_icons.end();
            icon_iter++)
    {
        if (!icon_iter->second)
            continue;

        if (x + icon_width > screen_width)
        {
            x = 0;
            y += icon_height;
        }

        XMoveWindow(m_shared.display, icon_iter->second->window, x, y);
        x += icon_width;
    }
}

/**
 * Redraws an individual icon window.
 * @param window The icon window to redraw.
 */
void ClientManager::redraw_icon(Window window)
{

    Icon *icon = m_icons[window];
    if (!icon)
        return;

    // Find out the client's request icon name, or use the name of the client itself
    char *title;

    XGetIconName(m_shared.display, icon->client, &title);
    if (!title)
        XFetchName(m_shared.display, icon->client, &title);

    int text_offset = (icon->has_pixmap ?
            DIM2D_WIDTH(icon->pixmap_size) :
            0);

    XClearWindow(m_shared.display, window);
    if (title)
        XDrawString(m_shared.display, window, icon->gc, text_offset,
                DIM2D_HEIGHT(m_shared.icon_size), title, std::strlen(title));

    if (icon->has_pixmap)
        XCopyArea(m_shared.display, icon->pixmap, window, icon->gc, 0, 0,
                DIM2D_WIDTH(icon->pixmap_size), DIM2D_HEIGHT(icon->pixmap_size),
                0, 0);

    XFree(title);
}

/**
 * Removes an icon from the icon row and reflows all the icons.
 * @param window The window representing the icon itself
 */
void ClientManager::delete_icon(Icon *icon)
{
    XUnmapWindow(m_shared.display, icon->window);
    XDestroyWindow(m_shared.display, icon->window);
    XFreeGC(m_shared.display, icon->gc);
    m_icons.erase(icon->window);
    delete icon;

    reflow_icons();
}
<commit_msg>Removed the old icon handling code.<commit_after><|endoftext|>


<commit_before>#include "valuedlg.h"
#include "ui_valuedlg.h"

#include "logtab.h"
#include "themeutils.h"
#include "tokenizer.h"

#include <QDebug>
#include <QDesktopServices>
#include <QFile>
#include <QFontDatabase>
#include <QHttpMultiPart>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QShortcut>
#include <QString>
#include <QTextDocument>
#include <QTextStream>
#include <QWebEngineView>

QByteArray ValueDlg::sm_savedGeometry { QByteArray() };
qreal ValueDlg::sm_savedFontPointSize { 0 };
bool ValueDlg::sm_savedWrapText { true };
QJsonUtils::Notation ValueDlg::sm_notation { QJsonUtils::Notation::YAML };

ValueDlg::ValueDlg(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::ValueDlg)
{
    ui->setupUi(this);
    setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
    restoreGeometry(sm_savedGeometry);

    // Set a monospaced font.
    QFont fixedFont = QFontDatabase::systemFont(QFontDatabase::FixedFont);
    fixedFont.setPointSizeF(sm_savedFontPointSize);
    ui->textEdit->setFont(fixedFont);

    auto prevKey = QKeySequence(Qt::CTRL + Qt::Key_Up);
    ui->prevButton->setShortcut(prevKey);
    ui->prevButton->setToolTip(QString("Go to previous event (%1)").arg(prevKey.toString(QKeySequence::NativeText)));
    auto nextKey = QKeySequence(Qt::CTRL + Qt::Key_Down);
    ui->nextButton->setShortcut(nextKey);
    ui->nextButton->setToolTip(QString("Go to next event (%1)").arg(nextKey.toString(QKeySequence::NativeText)));

    QShortcut *shortcutPlus = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Plus), this);
    connect(shortcutPlus, &QShortcut::activated, this, &ValueDlg::on_zoomIn);
    QShortcut *shortcutEqual = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Equal), this);
    connect(shortcutEqual, &QShortcut::activated, this, &ValueDlg::on_zoomIn);
    QShortcut *shortcutMinus = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Minus), this);
    connect(shortcutMinus, &QShortcut::activated, this, &ValueDlg::on_zoomOut);

    m_id = QString("");
    m_key = QString("");
    m_queryPlan = QString("");
    Options& options = Options::GetInstance();
    m_visualizationServiceEnable = options.getVisualizationServiceEnable();
    m_visualizationServiceURL = options.getVisualizationServiceURL();

    ui->prevButton->setIcon(QIcon(ThemeUtils::GetThemedIcon(":/value-previous.png")));
    ui->nextButton->setIcon(QIcon(ThemeUtils::GetThemedIcon(":/value-next.png")));
    ui->wrapTextCheck->setChecked(sm_savedWrapText);
    SetWrapping(sm_savedWrapText);

    {
        const QSignalBlocker blocker(ui->notationComboBox);
        ui->notationComboBox->addItems(QJsonUtils::GetNotationNames());
        ui->notationComboBox->setCurrentText(QJsonUtils::GetNameForNotation(sm_notation));
    }

    QFile sqlsyntaxcss(":/sqlsyntax.css");
    sqlsyntaxcss.open(QIODevice::ReadOnly);
    QTextStream textStream(&sqlsyntaxcss);
    QString styleSheet = textStream.readAll();
    sqlsyntaxcss.close();

    QTextDocument * textDoc = new QTextDocument(ui->textEdit);
    textDoc->setDefaultStyleSheet(styleSheet);
    textDoc->setDefaultFont(fixedFont);
    ui->textEdit->setDocument(textDoc);
}

ValueDlg::~ValueDlg()
{
    delete ui;
}

void ValueDlg::on_zoomIn()
{
    ui->textEdit->zoomIn(1);
}

void ValueDlg::on_zoomOut()
{
    ui->textEdit->zoomOut(1);
}

static QString HighlightSyntax(QString in)
{
    in = in.replace("; ", "\n");
    Tokenizer sqlLexer;
    sqlLexer.SetSQL();
    QList<Tokenizer::Token> tokens = sqlLexer.Tokenize(in);
    if (tokens.size() == 0)
        return in;

    QString out;

    QHash<Tokenizer::TokenType, QString> TokenTypeToCSSClass = {
        {Tokenizer::TokenType::Keyword, "k"},
        {Tokenizer::TokenType::String, "s"},
        {Tokenizer::TokenType::Tag, "t"},
        {Tokenizer::TokenType::Whitespace, "w"},
        {Tokenizer::TokenType::Identifier, "i"},
        {Tokenizer::TokenType::Symbol, "sy"},
        {Tokenizer::TokenType::OpenParan, "op"},
        {Tokenizer::TokenType::CloseParan, "cp"},
        {Tokenizer::TokenType::Operator, "o"},
        {Tokenizer::TokenType::NoMatch, "n"},
        {Tokenizer::TokenType::Integer, "in"},
        {Tokenizer::TokenType::Float, "f"}
    };

    // Build the html, grouping concurrent same token items in the same span.
    Tokenizer::TokenType prevType = tokens[0].type;
    out += "";
    for (Tokenizer::Token token : tokens)
    {
        QString word = in.mid(token.start, token.length);
        word = word.toHtmlEscaped();
        // Use HTML safe spacing
        word.replace(" ", " ");
        word.replace("\t", "    ");
        word.replace("\n", "
");
        if(token.type != prevType)
        {
            out += "";
            prevType = token.type;
        }
        out += word;
    }
    out += "";
    return out;
}

void ValueDlg::SetContent(QString id, QString key, QJsonValue value)
{
    m_id = id;
    m_key = key;
    m_value = value;

    setWindowTitle(QString("ID: %1 - Key: %2").arg(m_id, m_key));

    UpdateValueBox();

    // Recognize query plans
    m_queryPlan = "";
    if (value.isObject()) {
        if (m_key.startsWith("logical-query") ||
            m_key == "federate-query" ||
            m_key == "remote-query-planning" ||
            m_key == "begin-query" ||
            m_key == "end-query")
        {
            // Assume that queries starting with < have query function trees or logical-query.
            // They normally start with "<?xml ...>", "<sqlproxy>" or "<query-function ...>"
            auto queryText = value.toObject()["query"].toString();
            if (queryText.startsWith("<"))
            {
                m_queryPlan = queryText;
            }
        }
        else if (m_key.startsWith("query-plan") || m_key == "optimizer-step")
        {
            auto plan = value.toObject()["plan"];
            if (plan.isObject()) {
                QJsonDocument doc(plan.toObject());
                m_queryPlan = doc.toJson(QJsonDocument::Compact);
            }
        }
    }
    // Setup UI for query plan
    if (!m_queryPlan.isEmpty())
    {
        ui->visualizeButton->setEnabled(true);
        ui->visualizeLabel->setText("");
    }
    else
    {
        ui->visualizeButton->setEnabled(false);
        ui->visualizeLabel->setText("Nothing to visualize");
    }
}

void ValueDlg::UpdateValueBox() {
    QString value = QJsonUtils::Format(m_value, sm_notation);

    int syntaxHighlightLimit = Options::GetInstance().getSyntaxHighlightLimit();
    bool syntaxHighlight = (m_key != "msg" &&
                            !m_key.isEmpty() &&
                            syntaxHighlightLimit &&
                            value.size() <= syntaxHighlightLimit);
    if (syntaxHighlight)
    {
        QString htmlText(QString("") + HighlightSyntax(value) + QString(""));
        ui->textEdit->setHtml(htmlText);
    }
    else
    {
        ui->textEdit->setPlainText(value);
    }
    ui->textEdit->moveCursor(QTextCursor::Start);
    ui->textEdit->ensureCursorVisible();
}

void ValueDlg::on_nextButton_clicked()
{
    emit next();
}

void ValueDlg::on_prevButton_clicked()
{
    emit prev();
}

void ValueDlg::on_wrapTextCheck_clicked()
{
    SetWrapping(ui->wrapTextCheck->isChecked());
}

void ValueDlg::on_notationComboBox_currentIndexChanged(const QString& newValue)
{
    sm_notation = QJsonUtils::GetNotationFromName(newValue);
    UpdateValueBox();
}

void ValueDlg::SetWrapping(const bool wrapText)
{
    sm_savedWrapText = wrapText;
    if (sm_savedWrapText)
    {
        ui->textEdit->setLineWrapMode(QTextEdit::WidgetWidth);
    }
    else
    {
        ui->textEdit->setLineWrapMode(QTextEdit::NoWrap);
    }
}

QUrl ValueDlg::GetUploadURL()
{
    return QUrl(m_visualizationServiceURL);
}

QUrl ValueDlg::GetVisualizeURL(QNetworkReply * const reply)
{
    // The URL to visualize the query should be in the response.
    //
    // Sample response:
    //http://localhost:3000/d3/query-graphs.html?upload=y&file=31480681.xml
    auto response = QString(reply->readAll());
    qDebug() << "Response from visualization service:\n" << response;
    return QUrl(response);
}

void ValueDlg::UploadQuery()
{
    QHttpMultiPart *multipart = new QHttpMultiPart(QHttpMultiPart::FormDataType, this);
    QHttpPart filePart;
    filePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"queryfile\"; filename=\"yeah.xml\""));
    filePart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("text/xml"));

    filePart.setBody(m_queryPlan.toUtf8());

    multipart->append(filePart);

    QNetworkRequest request(GetUploadURL());
    QNetworkAccessManager *networkManager = new QNetworkAccessManager(this);
    QNetworkReply *reply = networkManager->post(request, multipart);
    // Set the parent of the multipart to the reply, so that we delete the multiPart with the reply
    multipart->setParent(reply);

    connect(networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(on_uploadFinished(QNetworkReply*)));
}

void ValueDlg::on_visualizeButton_clicked()
{
    if (m_visualizationServiceEnable)
    {
        UploadQuery();
    }
    else
    {
        VisualizeQuery();
    }
}

void ValueDlg::on_uploadFinished(QNetworkReply* reply)
{
    if (reply->error() == QNetworkReply::NetworkError::NoError)
    {
        ui->visualizeLabel->setText("Visualization uploaded, check your browser...");
        QDesktopServices::openUrl(GetVisualizeURL(reply));
    }
    else
    {
        ui->visualizeLabel->setText(QString("Failed to upload to URL '%1'").arg(reply->url().toString()));
        qDebug() << "Failed to upload query";
    }
    ui->visualizeButton->setEnabled(false);
}

void ValueDlg::VisualizeQuery()
{
    // Conditionally enable QtWebEngine debugging via Chromium-based browser at http://localhost:9000
#ifdef QT_DEBUG
    qputenv("QTWEBENGINE_REMOTE_DEBUGGING", "9000");
#endif

    m_view = new QWebEngineView(this);
    m_view->setAttribute(Qt::WA_DeleteOnClose);

    // Set Qt::Dialog rather than Qt::Window to disable zoom and avoid a Qt bug with unresponsive zoomed views on OSX
    m_view->setWindowFlags(Qt::Dialog | Qt::WindowMaximizeButtonHint | Qt::WindowCloseButtonHint);
    m_view->setWindowTitle(QString("Query Visualization - ID: %1 - Key: %2").arg(m_id, m_key));

    QDesktopWidget widget;
    int screenId = widget.screenNumber(this);
    QRect screenRect = widget.availableGeometry(screenId);
    int width = screenRect.width() - 400;
    int height = screenRect.height() - 200;
    int x = screenRect.left() + 200;
    int y = screenRect.top() + 80;
    m_view->resize(width, height);
    m_view->move(x, y);

    // Add keyboard shortcut for reloading the view
    QShortcut *shortcut = new QShortcut(QKeySequence("Ctrl+r"), m_view);
    QObject::connect(shortcut, &QShortcut::activated, m_view, &QWebEngineView::reload);

    // Reload the view one time to work around a Qt bug causing left justified alignment
    m_reload = true;
    connect(m_view, &QWebEngineView::loadFinished, this, &ValueDlg::on_loadFinished);
    m_view->load(QUrl("qrc:///query-graphs/query-graphs.tlv.html?inline=" + QUrl::toPercentEncoding(m_queryPlan)));
}

void ValueDlg::on_loadFinished(bool loaded)
{
    if (!loaded)
    {
        ui->visualizeLabel->setText(QString("Failed to load query visualization"));
        qDebug() << "Failed to load query visualization";
    }
    if (m_reload)
    {
        m_reload = false;
        m_view->reload();
    }
    m_view->show();
}

void ValueDlg::reject()
{
    sm_savedGeometry = saveGeometry();
    sm_savedFontPointSize = ui->textEdit->document()->defaultFont().pointSize();
    QDialog::reject();
}

// Persist the dialog state into QSettings.
//
// WriteSettings and ReadSettings should only be called once during app start and close,
// so the dialog state between multiple instances will not interfere each other.
//
void ValueDlg::WriteSettings(QSettings& settings)
{
    settings.beginGroup("ValueDialog");
    settings.setValue("geometry", sm_savedGeometry);
    settings.setValue("fontPointSize", sm_savedFontPointSize);
    settings.setValue("wrapText", sm_savedWrapText);
    settings.setValue("notation", QJsonUtils::GetNameForNotation(sm_notation));
    settings.endGroup();
}

void ValueDlg::ReadSettings(QSettings& settings)
{
    settings.beginGroup("ValueDialog");
    sm_savedGeometry = settings.value("geometry").toByteArray();
    sm_savedFontPointSize = settings.value("fontPointSize").toReal();
    sm_savedWrapText = settings.value("wrapText").toBool();
    sm_notation = QJsonUtils::GetNotationFromName(settings.value("notation").toString());
    settings.endGroup();
}
<commit_msg>Force the value dialog text edit control to redraw itself when its contents are updated (#95)<commit_after>#include "valuedlg.h"
#include "ui_valuedlg.h"

#include "logtab.h"
#include "themeutils.h"
#include "tokenizer.h"

#include <QDebug>
#include <QDesktopServices>
#include <QFile>
#include <QFontDatabase>
#include <QHttpMultiPart>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QShortcut>
#include <QString>
#include <QTextDocument>
#include <QTextStream>
#include <QWebEngineView>

QByteArray ValueDlg::sm_savedGeometry { QByteArray() };
qreal ValueDlg::sm_savedFontPointSize { 0 };
bool ValueDlg::sm_savedWrapText { true };
QJsonUtils::Notation ValueDlg::sm_notation { QJsonUtils::Notation::YAML };

ValueDlg::ValueDlg(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::ValueDlg)
{
    ui->setupUi(this);
    setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
    restoreGeometry(sm_savedGeometry);

    // Set a monospaced font.
    QFont fixedFont = QFontDatabase::systemFont(QFontDatabase::FixedFont);
    fixedFont.setPointSizeF(sm_savedFontPointSize);
    ui->textEdit->setFont(fixedFont);

    auto prevKey = QKeySequence(Qt::CTRL + Qt::Key_Up);
    ui->prevButton->setShortcut(prevKey);
    ui->prevButton->setToolTip(QString("Go to previous event (%1)").arg(prevKey.toString(QKeySequence::NativeText)));
    auto nextKey = QKeySequence(Qt::CTRL + Qt::Key_Down);
    ui->nextButton->setShortcut(nextKey);
    ui->nextButton->setToolTip(QString("Go to next event (%1)").arg(nextKey.toString(QKeySequence::NativeText)));

    QShortcut *shortcutPlus = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Plus), this);
    connect(shortcutPlus, &QShortcut::activated, this, &ValueDlg::on_zoomIn);
    QShortcut *shortcutEqual = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Equal), this);
    connect(shortcutEqual, &QShortcut::activated, this, &ValueDlg::on_zoomIn);
    QShortcut *shortcutMinus = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Minus), this);
    connect(shortcutMinus, &QShortcut::activated, this, &ValueDlg::on_zoomOut);

    m_id = QString("");
    m_key = QString("");
    m_queryPlan = QString("");
    Options& options = Options::GetInstance();
    m_visualizationServiceEnable = options.getVisualizationServiceEnable();
    m_visualizationServiceURL = options.getVisualizationServiceURL();

    ui->prevButton->setIcon(QIcon(ThemeUtils::GetThemedIcon(":/value-previous.png")));
    ui->nextButton->setIcon(QIcon(ThemeUtils::GetThemedIcon(":/value-next.png")));
    ui->wrapTextCheck->setChecked(sm_savedWrapText);
    SetWrapping(sm_savedWrapText);

    {
        const QSignalBlocker blocker(ui->notationComboBox);
        ui->notationComboBox->addItems(QJsonUtils::GetNotationNames());
        ui->notationComboBox->setCurrentText(QJsonUtils::GetNameForNotation(sm_notation));
    }

    QFile sqlsyntaxcss(":/sqlsyntax.css");
    sqlsyntaxcss.open(QIODevice::ReadOnly);
    QTextStream textStream(&sqlsyntaxcss);
    QString styleSheet = textStream.readAll();
    sqlsyntaxcss.close();

    QTextDocument * textDoc = new QTextDocument(ui->textEdit);
    textDoc->setDefaultStyleSheet(styleSheet);
    textDoc->setDefaultFont(fixedFont);
    ui->textEdit->setDocument(textDoc);
}

ValueDlg::~ValueDlg()
{
    delete ui;
}

void ValueDlg::on_zoomIn()
{
    ui->textEdit->zoomIn(1);
}

void ValueDlg::on_zoomOut()
{
    ui->textEdit->zoomOut(1);
}

static QString HighlightSyntax(QString in)
{
    in = in.replace("; ", "\n");
    Tokenizer sqlLexer;
    sqlLexer.SetSQL();
    QList<Tokenizer::Token> tokens = sqlLexer.Tokenize(in);
    if (tokens.size() == 0)
        return in;

    QString out;

    QHash<Tokenizer::TokenType, QString> TokenTypeToCSSClass = {
        {Tokenizer::TokenType::Keyword, "k"},
        {Tokenizer::TokenType::String, "s"},
        {Tokenizer::TokenType::Tag, "t"},
        {Tokenizer::TokenType::Whitespace, "w"},
        {Tokenizer::TokenType::Identifier, "i"},
        {Tokenizer::TokenType::Symbol, "sy"},
        {Tokenizer::TokenType::OpenParan, "op"},
        {Tokenizer::TokenType::CloseParan, "cp"},
        {Tokenizer::TokenType::Operator, "o"},
        {Tokenizer::TokenType::NoMatch, "n"},
        {Tokenizer::TokenType::Integer, "in"},
        {Tokenizer::TokenType::Float, "f"}
    };

    // Build the html, grouping concurrent same token items in the same span.
    Tokenizer::TokenType prevType = tokens[0].type;
    out += "";
    for (Tokenizer::Token token : tokens)
    {
        QString word = in.mid(token.start, token.length);
        word = word.toHtmlEscaped();
        // Use HTML safe spacing
        word.replace(" ", " ");
        word.replace("\t", "    ");
        word.replace("\n", "
");
        if(token.type != prevType)
        {
            out += "";
            prevType = token.type;
        }
        out += word;
    }
    out += "";
    return out;
}

void ValueDlg::SetContent(QString id, QString key, QJsonValue value)
{
    m_id = id;
    m_key = key;
    m_value = value;

    setWindowTitle(QString("ID: %1 - Key: %2").arg(m_id, m_key));

    UpdateValueBox();

    // Recognize query plans
    m_queryPlan = "";
    if (value.isObject()) {
        if (m_key.startsWith("logical-query") ||
            m_key == "federate-query" ||
            m_key == "remote-query-planning" ||
            m_key == "begin-query" ||
            m_key == "end-query")
        {
            // Assume that queries starting with < have query function trees or logical-query.
            // They normally start with "<?xml ...>", "<sqlproxy>" or "<query-function ...>"
            auto queryText = value.toObject()["query"].toString();
            if (queryText.startsWith("<"))
            {
                m_queryPlan = queryText;
            }
        }
        else if (m_key.startsWith("query-plan") || m_key == "optimizer-step")
        {
            auto plan = value.toObject()["plan"];
            if (plan.isObject()) {
                QJsonDocument doc(plan.toObject());
                m_queryPlan = doc.toJson(QJsonDocument::Compact);
            }
        }
    }
    // Setup UI for query plan
    if (!m_queryPlan.isEmpty())
    {
        ui->visualizeButton->setEnabled(true);
        ui->visualizeLabel->setText("");
    }
    else
    {
        ui->visualizeButton->setEnabled(false);
        ui->visualizeLabel->setText("Nothing to visualize");
    }
}

void ValueDlg::UpdateValueBox() {
    QString value = QJsonUtils::Format(m_value, sm_notation);

    int syntaxHighlightLimit = Options::GetInstance().getSyntaxHighlightLimit();
    bool syntaxHighlight = (m_key != "msg" &&
                            !m_key.isEmpty() &&
                            syntaxHighlightLimit &&
                            value.size() <= syntaxHighlightLimit);
    if (syntaxHighlight)
    {
        QString htmlText(QString("") + HighlightSyntax(value) + QString(""));
        ui->textEdit->setHtml(htmlText);
    }
    else
    {
        ui->textEdit->setPlainText(value);
    }
    ui->textEdit->moveCursor(QTextCursor::Start);
    ui->textEdit->ensureCursorVisible();
    ui->textEdit->repaint();
}

void ValueDlg::on_nextButton_clicked()
{
    emit next();
}

void ValueDlg::on_prevButton_clicked()
{
    emit prev();
}

void ValueDlg::on_wrapTextCheck_clicked()
{
    SetWrapping(ui->wrapTextCheck->isChecked());
}

void ValueDlg::on_notationComboBox_currentIndexChanged(const QString& newValue)
{
    sm_notation = QJsonUtils::GetNotationFromName(newValue);
    UpdateValueBox();
}

void ValueDlg::SetWrapping(const bool wrapText)
{
    sm_savedWrapText = wrapText;
    if (sm_savedWrapText)
    {
        ui->textEdit->setLineWrapMode(QTextEdit::WidgetWidth);
    }
    else
    {
        ui->textEdit->setLineWrapMode(QTextEdit::NoWrap);
    }
}

QUrl ValueDlg::GetUploadURL()
{
    return QUrl(m_visualizationServiceURL);
}

QUrl ValueDlg::GetVisualizeURL(QNetworkReply * const reply)
{
    // The URL to visualize the query should be in the response.
    //
    // Sample response:
    //http://localhost:3000/d3/query-graphs.html?upload=y&file=31480681.xml
    auto response = QString(reply->readAll());
    qDebug() << "Response from visualization service:\n" << response;
    return QUrl(response);
}

void ValueDlg::UploadQuery()
{
    QHttpMultiPart *multipart = new QHttpMultiPart(QHttpMultiPart::FormDataType, this);
    QHttpPart filePart;
    filePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"queryfile\"; filename=\"yeah.xml\""));
    filePart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("text/xml"));

    filePart.setBody(m_queryPlan.toUtf8());

    multipart->append(filePart);

    QNetworkRequest request(GetUploadURL());
    QNetworkAccessManager *networkManager = new QNetworkAccessManager(this);
    QNetworkReply *reply = networkManager->post(request, multipart);
    // Set the parent of the multipart to the reply, so that we delete the multiPart with the reply
    multipart->setParent(reply);

    connect(networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(on_uploadFinished(QNetworkReply*)));
}

void ValueDlg::on_visualizeButton_clicked()
{
    if (m_visualizationServiceEnable)
    {
        UploadQuery();
    }
    else
    {
        VisualizeQuery();
    }
}

void ValueDlg::on_uploadFinished(QNetworkReply* reply)
{
    if (reply->error() == QNetworkReply::NetworkError::NoError)
    {
        ui->visualizeLabel->setText("Visualization uploaded, check your browser...");
        QDesktopServices::openUrl(GetVisualizeURL(reply));
    }
    else
    {
        ui->visualizeLabel->setText(QString("Failed to upload to URL '%1'").arg(reply->url().toString()));
        qDebug() << "Failed to upload query";
    }
    ui->visualizeButton->setEnabled(false);
}

void ValueDlg::VisualizeQuery()
{
    // Conditionally enable QtWebEngine debugging via Chromium-based browser at http://localhost:9000
#ifdef QT_DEBUG
    qputenv("QTWEBENGINE_REMOTE_DEBUGGING", "9000");
#endif

    m_view = new QWebEngineView(this);
    m_view->setAttribute(Qt::WA_DeleteOnClose);

    // Set Qt::Dialog rather than Qt::Window to disable zoom and avoid a Qt bug with unresponsive zoomed views on OSX
    m_view->setWindowFlags(Qt::Dialog | Qt::WindowMaximizeButtonHint | Qt::WindowCloseButtonHint);
    m_view->setWindowTitle(QString("Query Visualization - ID: %1 - Key: %2").arg(m_id, m_key));

    QDesktopWidget widget;
    int screenId = widget.screenNumber(this);
    QRect screenRect = widget.availableGeometry(screenId);
    int width = screenRect.width() - 400;
    int height = screenRect.height() - 200;
    int x = screenRect.left() + 200;
    int y = screenRect.top() + 80;
    m_view->resize(width, height);
    m_view->move(x, y);

    // Add keyboard shortcut for reloading the view
    QShortcut *shortcut = new QShortcut(QKeySequence("Ctrl+r"), m_view);
    QObject::connect(shortcut, &QShortcut::activated, m_view, &QWebEngineView::reload);

    // Reload the view one time to work around a Qt bug causing left justified alignment
    m_reload = true;
    connect(m_view, &QWebEngineView::loadFinished, this, &ValueDlg::on_loadFinished);
    m_view->load(QUrl("qrc:///query-graphs/query-graphs.tlv.html?inline=" + QUrl::toPercentEncoding(m_queryPlan)));
}

void ValueDlg::on_loadFinished(bool loaded)
{
    if (!loaded)
    {
        ui->visualizeLabel->setText(QString("Failed to load query visualization"));
        qDebug() << "Failed to load query visualization";
    }
    if (m_reload)
    {
        m_reload = false;
        m_view->reload();
    }
    m_view->show();
}

void ValueDlg::reject()
{
    sm_savedGeometry = saveGeometry();
    sm_savedFontPointSize = ui->textEdit->document()->defaultFont().pointSize();
    QDialog::reject();
}

// Persist the dialog state into QSettings.
//
// WriteSettings and ReadSettings should only be called once during app start and close,
// so the dialog state between multiple instances will not interfere each other.
//
void ValueDlg::WriteSettings(QSettings& settings)
{
    settings.beginGroup("ValueDialog");
    settings.setValue("geometry", sm_savedGeometry);
    settings.setValue("fontPointSize", sm_savedFontPointSize);
    settings.setValue("wrapText", sm_savedWrapText);
    settings.setValue("notation", QJsonUtils::GetNameForNotation(sm_notation));
    settings.endGroup();
}

void ValueDlg::ReadSettings(QSettings& settings)
{
    settings.beginGroup("ValueDialog");
    sm_savedGeometry = settings.value("geometry").toByteArray();
    sm_savedFontPointSize = settings.value("fontPointSize").toReal();
    sm_savedWrapText = settings.value("wrapText").toBool();
    sm_notation = QJsonUtils::GetNotationFromName(settings.value("notation").toString());
    settings.endGroup();
}
<|endoftext|>


<commit_before>// ComDirver.cpp: implementation of the CComDirver class.
//
//////////////////////////////////////////////////////////////////////

#include "vmlua.h"
#include "lua/lua.hpp"

#include <stdio.h>
#include <string.h>
#include <assert.h>

#include "hash.h"
#include "key.h"
#include "main.h"
#include <openssl/des.h>
#include <vector>
#include "vmrunevn.h"
#include "tx.h"
//#include "Typedef.h"

#if 0
typedef struct NumArray{
	int size;          // С
	double values[1];  //黺
}NumArray;

/*
 * ȡuserdatum*/
static NumArray *checkarray(lua_State *L){
	//ջָλõĶǷΪиֵmetatableuserdatum
    void *ud = luaL_checkudata(L,1,"LuaBook.array");
    luaL_argcheck(L,ud != NULL,1,"'array' expected");
    return (NumArray *)ud;
}
/*
 * ȡָ*/
static double *getelem(lua_State *L){
    NumArray *a = checkarray(L);
    int index = luaL_checkint(L,2);
    luaL_argcheck(L,1 <= index && index <= a->size,2,"index out of range");
    /*return element address*/
    return &a->values[index - 1];
}
/*
 * */
int newarray(lua_State *L){
   int n = luaL_checkint(L,1);   //֤ʵluaL_checknumberı
   size_t nbytes = sizeof(NumArray) + (n -1) * sizeof(double);

	/*һuserdatum ṩһLuaûԤrawڴ
          ָĴСһڴ棬Ӧuserdatumŵջ,ڴĵַ*/
   NumArray *a = (NumArray *)lua_newuserdata(L,nbytes);
   luaL_getmetatable(L,"LuaBook.array");   //ȡregistryеtnameӦmetatable
   lua_setmetatable(L,-2);   //ջΪλõĶmetatable  µuserdatum
   a->size = n;
   return 1; /*new userdatnum is already on the statck*/
}
/*
 * 洢Ԫ,array.set(array,index,value)*/
int setarray(lua_State *L){
#if 0
	NumArray *a = (NumArray *)lua_touserdata(L,1);
	int index = luaL_checkint(L,2);
    double value = luaL_checknumber(L,3);

    luaL_argcheck(L,a != NULL,1,"'array' expected");
    luaL_argcheck(L,1 <= index && index <= a->size,2,"index out of range");
    a->values[index -1] = value;
#else
    double newvalue = luaL_checknumber(L,3);
    *getelem(L) = newvalue;
#endif
	return 0;
}
/*
 * ȡһԪ*/
int getarray(lua_State *L){
#if 0
	NumArray *a = (NumArray *)lua_touserdata(L,1);
    int index = luaL_checkint(L,2);

    luaL_argcheck(L,a != NULL,1,"'array' expected");
    luaL_argcheck(L,1 <= index && index <= a->size,2,"index out of range");
    lua_pushnumber(L,a->values[index - 1]);
#else
    lua_pushnumber(L,*getelem(L));
#endif
    return 1;
}
/*
 * ȡĴС*/
int getsize(lua_State *L){
#if 0
	NumArray *a = (NumArray *)lua_touserdata(L,1);
	luaL_argcheck(L,a != NULL,1,"'array' expected");
#else
	NumArray *a = checkarray(L);
#endif
	lua_pushnumber(L,a->size);
	return 1;
}
static const struct luaL_Reg arraylib[] = {
		{"new",newarray},
		{"set",setarray},
		{"get",getarray},
		{"size",getsize},
		{NULL,NULL}
};
static int luaopen_array(lua_State *L){
	/*userdataҪõmetatable*/
	luaL_newmetatable(L,"LuaBook.array");
	luaL_openlib(L,"array",arraylib,0);

	/*now the statck has the metatable at index 1 and
	 * 'array' at index 2*/
    lua_pushstring(L,"__index");
    lua_pushstring(L,"get");
    lua_gettable(L,2); /*get array.get*/
    lua_settable(L,1); /*metatable.__index - array.get*/

    lua_pushstring(L,"__newindex");
    lua_pushstring(L,"set");
    lua_gettable(L,2); /*get array.get*/
    lua_settable(L,1); /*metatable.__newindex - array.get*/
	return 0;
}

#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CVmlua::CVmlua(const vector<unsigned char> & vRom, const vector<unsigned char> &InputData){
	unsigned long len = 0;
	/*vRom script,InputData contract*/
    memset(m_ExRam,0,sizeof(m_ExRam));
    memset(m_ExeFile,0,sizeof(m_ExeFile));

    len = vRom.size();
    if(len >= sizeof(m_ExeFile)){
    	throw runtime_error("CVmlua::CVmlua() length of vRom exceptions");
    }
	memcpy(m_ExeFile, &vRom[0], len);
	unsigned short count = InputData.size();//С4096ֽ
	if(count > sizeof(m_ExRam) - 2){
		throw runtime_error("CVmlua::CVmlua() length of contract > 4094");
	}
	memcpy(m_ExRam, &count, 2);
	memcpy(&m_ExRam[2], &InputData[0],count);
}

CVmlua::~CVmlua() {

}

#ifdef WIN_DLL
extern "C" __declspec(dllexport) int luaopen_mylib(lua_State *L);
#else
LUAMOD_API int luaopen_mylib(lua_State *L);
#endif

void vm_openlibs (lua_State *L) {

	static const luaL_Reg lualibs[] = {
			{ "base", luaopen_base },
			{ LUA_LOADLIBNAME, luaopen_package },
			{ LUA_TABLIBNAME, luaopen_table },
			{ LUA_MATHLIBNAME, luaopen_math },
			{ LUA_STRLIBNAME, luaopen_string},
			{ NULL, NULL }
	};

	const luaL_Reg *lib;

	for (lib = lualibs; lib->func; lib++) {
		luaL_requiref(L, lib->name, lib->func, 1);
		lua_pop(L, 1); /* remove lib */
	}
}

tuple<bool,string> CVmlua::syntaxcheck(const char* filePath) {
	//1.Luaл
	lua_State *lua_state = luaL_newstate();
	if (NULL == lua_state) {
		LogPrint("vm", "luaL_newstate error\n");
		return std::make_tuple(false, string("luaL_newstate error\n"));
	}

	vm_openlibs(lua_state);
	//3.עԶģ
	luaL_requiref(lua_state, "mylib", luaopen_mylib, 1);

	int nRet = luaL_loadfile(lua_state, filePath);
	if (nRet) {
		lua_close(lua_state);
		return std::make_tuple (false, string(lua_tostring(lua_state, -1)));
	}

	lua_close(lua_state);

	return std::make_tuple (true, string("OK"));
}

int64_t CVmlua::run(uint64_t maxstep,CVmRunEvn *pVmScriptRun) {
	 long long step = 0;
	 unsigned short count = 0;

	if((maxstep == 0) || (NULL == pVmScriptRun)){
		return -1;
	}

	//1.Luaл
   lua_State *lua_state = luaL_newstate();
   if(NULL == lua_state){
	   LogPrint("vm", "luaL_newstate error\n");
	   return -1;
   }
/*
   //2.ôעLua׼
   static const luaL_Reg lualibs[] =
   {
	   {"base",luaopen_base},
	   {LUA_LOADLIBNAME, luaopen_package},
//	   {LUA_COLIBNAME, luaopen_coroutine},
	   {LUA_TABLIBNAME, luaopen_table},
//	   {LUA_IOLIBNAME, luaopen_io},
//	   {LUA_OSLIBNAME, luaopen_os},
//	   {LUA_STRLIBNAME, luaopen_string},
//	   {LUA_MATHLIBNAME, luaopen_math},
//	   {LUA_UTF8LIBNAME, luaopen_utf8},
//	   {LUA_DBLIBNAME, luaopen_debug},
	   {NULL,NULL}
   };
   //3.עLua׼Ⲣջ

   const luaL_Reg *lib = lualibs;
   for(;lib->func != NULL;lib++)
   {
	   lib->func(lua_state);
	   lua_settop(lua_state,0);
   }

   //ҪĿ
   //luaL_openlibs(lua_state);
*/
   vm_openlibs(lua_state);
   //3.עԶģ
   luaL_requiref(lua_state,"mylib",luaopen_mylib,1);

   //4.luaűݺԼ
	lua_newtable(lua_state);    //½һ,ѹջ
	lua_pushnumber(lua_state,-1);
	lua_rawseti(lua_state,-2,0);
	memcpy(&count,m_ExRam,  2);//ƣԼС4096ֽ
    for(unsigned short n = 0;n < count;n++)
    {
        lua_pushinteger(lua_state,m_ExRam[2 + n]);// valueֵ
        lua_rawseti(lua_state,-2,n+1);  //set table at key 'n + 1'
    }
    lua_setglobal(lua_state,"contract");

    //pVmScriptRunָ룬Աãȥʹȫֱָ
    lua_pushlightuserdata(lua_state, pVmScriptRun);
    lua_setglobal(lua_state,"VmScriptRun");

    LogPrint("vm", "pVmScriptRun=%p\n",pVmScriptRun);

   //5.ؽű
    step = maxstep;

    if(luaL_loadbuffer(lua_state,(char *)m_ExeFile,strlen((char *)m_ExeFile),"line") || lua_pcallk(lua_state,0,0,0,0,NULL,&step))
    {
	   LogPrint("vm", "luaL_loadbuffer fail:%s\n", lua_tostring(lua_state,-1));
	   step = -1;
	   lua_close(lua_state);
	   LogPrint("vm", "run step=%ld\n",step);
	   return step;
    }

    //6.ƽãĬϹرգűûøñ
	pVmScriptRun->SetCheckAccount(false);
	int res = lua_getglobal(lua_state, "gCheckAccount");
	LogPrint("vm", "lua_getglobal:%d\n", res);

    if(LUA_TBOOLEAN == res)
    {
    	if(lua_isboolean(lua_state,-1))
    	{
    		bool bCheck = lua_toboolean(lua_state,-1);
    		LogPrint("vm", "lua_toboolean:%d\n", bCheck);
    		pVmScriptRun->SetCheckAccount(bCheck);
    	}
    }
    lua_pop(lua_state, 1);

    //7.رLua
	lua_close(lua_state);
	LogPrint("vm", "run step=%ld\n",step);
	return step;
}

<commit_msg>修改CVmlua::syntaxcheck错误输出<commit_after>// ComDirver.cpp: implementation of the CComDirver class.
//
//////////////////////////////////////////////////////////////////////

#include "vmlua.h"
#include "lua/lua.hpp"

#include <stdio.h>
#include <string.h>
#include <assert.h>

#include "hash.h"
#include "key.h"
#include "main.h"
#include <openssl/des.h>
#include <vector>
#include "vmrunevn.h"
#include "tx.h"
//#include "Typedef.h"

#if 0
typedef struct NumArray{
	int size;          // С
	double values[1];  //黺
}NumArray;

/*
 * ȡuserdatum*/
static NumArray *checkarray(lua_State *L){
	//ջָλõĶǷΪиֵmetatableuserdatum
    void *ud = luaL_checkudata(L,1,"LuaBook.array");
    luaL_argcheck(L,ud != NULL,1,"'array' expected");
    return (NumArray *)ud;
}
/*
 * ȡָ*/
static double *getelem(lua_State *L){
    NumArray *a = checkarray(L);
    int index = luaL_checkint(L,2);
    luaL_argcheck(L,1 <= index && index <= a->size,2,"index out of range");
    /*return element address*/
    return &a->values[index - 1];
}
/*
 * */
int newarray(lua_State *L){
   int n = luaL_checkint(L,1);   //֤ʵluaL_checknumberı
   size_t nbytes = sizeof(NumArray) + (n -1) * sizeof(double);

	/*һuserdatum ṩһLuaûԤrawڴ
          ָĴСһڴ棬Ӧuserdatumŵջ,ڴĵַ*/
   NumArray *a = (NumArray *)lua_newuserdata(L,nbytes);
   luaL_getmetatable(L,"LuaBook.array");   //ȡregistryеtnameӦmetatable
   lua_setmetatable(L,-2);   //ջΪλõĶmetatable  µuserdatum
   a->size = n;
   return 1; /*new userdatnum is already on the statck*/
}
/*
 * 洢Ԫ,array.set(array,index,value)*/
int setarray(lua_State *L){
#if 0
	NumArray *a = (NumArray *)lua_touserdata(L,1);
	int index = luaL_checkint(L,2);
    double value = luaL_checknumber(L,3);

    luaL_argcheck(L,a != NULL,1,"'array' expected");
    luaL_argcheck(L,1 <= index && index <= a->size,2,"index out of range");
    a->values[index -1] = value;
#else
    double newvalue = luaL_checknumber(L,3);
    *getelem(L) = newvalue;
#endif
	return 0;
}
/*
 * ȡһԪ*/
int getarray(lua_State *L){
#if 0
	NumArray *a = (NumArray *)lua_touserdata(L,1);
    int index = luaL_checkint(L,2);

    luaL_argcheck(L,a != NULL,1,"'array' expected");
    luaL_argcheck(L,1 <= index && index <= a->size,2,"index out of range");
    lua_pushnumber(L,a->values[index - 1]);
#else
    lua_pushnumber(L,*getelem(L));
#endif
    return 1;
}
/*
 * ȡĴС*/
int getsize(lua_State *L){
#if 0
	NumArray *a = (NumArray *)lua_touserdata(L,1);
	luaL_argcheck(L,a != NULL,1,"'array' expected");
#else
	NumArray *a = checkarray(L);
#endif
	lua_pushnumber(L,a->size);
	return 1;
}
static const struct luaL_Reg arraylib[] = {
		{"new",newarray},
		{"set",setarray},
		{"get",getarray},
		{"size",getsize},
		{NULL,NULL}
};
static int luaopen_array(lua_State *L){
	/*userdataҪõmetatable*/
	luaL_newmetatable(L,"LuaBook.array");
	luaL_openlib(L,"array",arraylib,0);

	/*now the statck has the metatable at index 1 and
	 * 'array' at index 2*/
    lua_pushstring(L,"__index");
    lua_pushstring(L,"get");
    lua_gettable(L,2); /*get array.get*/
    lua_settable(L,1); /*metatable.__index - array.get*/

    lua_pushstring(L,"__newindex");
    lua_pushstring(L,"set");
    lua_gettable(L,2); /*get array.get*/
    lua_settable(L,1); /*metatable.__newindex - array.get*/
	return 0;
}

#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CVmlua::CVmlua(const vector<unsigned char> & vRom, const vector<unsigned char> &InputData){
	unsigned long len = 0;
	/*vRom script,InputData contract*/
    memset(m_ExRam,0,sizeof(m_ExRam));
    memset(m_ExeFile,0,sizeof(m_ExeFile));

    len = vRom.size();
    if(len >= sizeof(m_ExeFile)){
    	throw runtime_error("CVmlua::CVmlua() length of vRom exceptions");
    }
	memcpy(m_ExeFile, &vRom[0], len);
	unsigned short count = InputData.size();//С4096ֽ
	if(count > sizeof(m_ExRam) - 2){
		throw runtime_error("CVmlua::CVmlua() length of contract > 4094");
	}
	memcpy(m_ExRam, &count, 2);
	memcpy(&m_ExRam[2], &InputData[0],count);
}

CVmlua::~CVmlua() {

}

#ifdef WIN_DLL
extern "C" __declspec(dllexport) int luaopen_mylib(lua_State *L);
#else
LUAMOD_API int luaopen_mylib(lua_State *L);
#endif

void vm_openlibs (lua_State *L) {

	static const luaL_Reg lualibs[] = {
			{ "base", luaopen_base },
			{ LUA_LOADLIBNAME, luaopen_package },
			{ LUA_TABLIBNAME, luaopen_table },
			{ LUA_MATHLIBNAME, luaopen_math },
			{ LUA_STRLIBNAME, luaopen_string},
			{ NULL, NULL }
	};

	const luaL_Reg *lib;

	for (lib = lualibs; lib->func; lib++) {
		luaL_requiref(L, lib->name, lib->func, 1);
		lua_pop(L, 1); /* remove lib */
	}
}

tuple<bool,string> CVmlua::syntaxcheck(const char* filePath) {
	//1.Luaл
	lua_State *lua_state = luaL_newstate();
	if (NULL == lua_state) {
		LogPrint("vm", "luaL_newstate error\n");
		return std::make_tuple(false, string("luaL_newstate error\n"));
	}

	vm_openlibs(lua_state);
	//3.עԶģ
	luaL_requiref(lua_state, "mylib", luaopen_mylib, 1);

	int nRet = luaL_loadfile(lua_state, filePath);
	if (nRet) {
		const char* errStr = lua_tostring(lua_state, -1);
		lua_close(lua_state);
		return std::make_tuple (false, string(errStr));
	}

	lua_close(lua_state);

	return std::make_tuple (true, string("OK"));
}

int64_t CVmlua::run(uint64_t maxstep,CVmRunEvn *pVmScriptRun) {
	 long long step = 0;
	 unsigned short count = 0;

	if((maxstep == 0) || (NULL == pVmScriptRun)){
		return -1;
	}

	//1.Luaл
   lua_State *lua_state = luaL_newstate();
   if(NULL == lua_state){
	   LogPrint("vm", "luaL_newstate error\n");
	   return -1;
   }
/*
   //2.ôעLua׼
   static const luaL_Reg lualibs[] =
   {
	   {"base",luaopen_base},
	   {LUA_LOADLIBNAME, luaopen_package},
//	   {LUA_COLIBNAME, luaopen_coroutine},
	   {LUA_TABLIBNAME, luaopen_table},
//	   {LUA_IOLIBNAME, luaopen_io},
//	   {LUA_OSLIBNAME, luaopen_os},
//	   {LUA_STRLIBNAME, luaopen_string},
//	   {LUA_MATHLIBNAME, luaopen_math},
//	   {LUA_UTF8LIBNAME, luaopen_utf8},
//	   {LUA_DBLIBNAME, luaopen_debug},
	   {NULL,NULL}
   };
   //3.עLua׼Ⲣջ

   const luaL_Reg *lib = lualibs;
   for(;lib->func != NULL;lib++)
   {
	   lib->func(lua_state);
	   lua_settop(lua_state,0);
   }

   //ҪĿ
   //luaL_openlibs(lua_state);
*/
   vm_openlibs(lua_state);
   //3.עԶģ
   luaL_requiref(lua_state,"mylib",luaopen_mylib,1);

   //4.luaűݺԼ
	lua_newtable(lua_state);    //½һ,ѹջ
	lua_pushnumber(lua_state,-1);
	lua_rawseti(lua_state,-2,0);
	memcpy(&count,m_ExRam,  2);//ƣԼС4096ֽ
    for(unsigned short n = 0;n < count;n++)
    {
        lua_pushinteger(lua_state,m_ExRam[2 + n]);// valueֵ
        lua_rawseti(lua_state,-2,n+1);  //set table at key 'n + 1'
    }
    lua_setglobal(lua_state,"contract");

    //pVmScriptRunָ룬Աãȥʹȫֱָ
    lua_pushlightuserdata(lua_state, pVmScriptRun);
    lua_setglobal(lua_state,"VmScriptRun");

    LogPrint("vm", "pVmScriptRun=%p\n",pVmScriptRun);

   //5.ؽű
    step = maxstep;

    if(luaL_loadbuffer(lua_state,(char *)m_ExeFile,strlen((char *)m_ExeFile),"line") || lua_pcallk(lua_state,0,0,0,0,NULL,&step))
    {
	   LogPrint("vm", "luaL_loadbuffer fail:%s\n", lua_tostring(lua_state,-1));
	   step = -1;
	   lua_close(lua_state);
	   LogPrint("vm", "run step=%ld\n",step);
	   return step;
    }

    //6.ƽãĬϹرգűûøñ
	pVmScriptRun->SetCheckAccount(false);
	int res = lua_getglobal(lua_state, "gCheckAccount");
	LogPrint("vm", "lua_getglobal:%d\n", res);

    if(LUA_TBOOLEAN == res)
    {
    	if(lua_isboolean(lua_state,-1))
    	{
    		bool bCheck = lua_toboolean(lua_state,-1);
    		LogPrint("vm", "lua_toboolean:%d\n", bCheck);
    		pVmScriptRun->SetCheckAccount(bCheck);
    	}
    }
    lua_pop(lua_state, 1);

    //7.رLua
	lua_close(lua_state);
	LogPrint("vm", "run step=%ld\n",step);
	return step;
}

<|endoftext|>