<commit_before>//
//  calcPWP.cpp
//
//
//  Created by Evan McCartney-Melstad on 1/10/15.
//
//

#include "calcPWP.h"
#include <iostream>
#include <vector>
#include <fstream>
#include <thread>
#include <string>

int calcPWPfromBinaryFile (std::string binaryFile, unsigned long long int numLoci, const int numIndividuals, std::string outFile, int numThreads) {

    //****MODIFY THIS TO ONLY READ IN N LOCI AT A TIME, INSTEAD OF USING THE ENTIRE FILE****

    std::cout << "Number of threads: " << numThreads << std::endl;
    std::streampos size;
    std::ifstream file (binaryFile, std::ios::in|std::ios::binary|std::ios::ate);
    //ifstream file ("test500k.binary8bitunsigned", ios::in|ios::binary|ios::ate);
    if (file.is_open()) {
        size = file.tellg(); // Just a variable that shows position of stream--at end since ios::ate, so it's the file size. PROBABLY WON'T WORK FOR FILES LARGER THAN ~ 2GB!
        file.seekg (0, std::ios::beg); // Go back to the beginning of the file
        //file.read((char*)readCounts, size); // cast to a char* to give to file.read

        //unsigned char* readCounts;
        //readCounts = new unsigned char[size];
        std::vector<unsigned char> readCounts(size);
        file.read((char*) &readCounts[0], size);
        file.close();

        std::cout << "the entire file content is in memory" << std::endl;
        std::cout << "the total size of the file is " << size << std::endl;
        std::cout << "the number of elements in the readCounts vector is: " << readCounts.size() << std::endl; // Will give the total size bytes divided by the size of one element--so it gives the number of elements

        // We now have an array of numIndividuals * 2 (major and minor allele) * 1million (loci)
        //int totalLoci = (int)size / (numIndividuals*2); // The 1 million locus file has 999,999 sites in it (because of header line)
        //int totalLoci = size/(272*2);
        //std::vector< std::vector<long double> > pwp(numIndividuals, std::vector<long double>(numIndividuals,0));
        //std::vector< std::vector<unsigned long long int> > weightings(numIndividuals, std::vector<unsigned long long int>(numIndividuals,0));
        //long double pwp[numIndividuals][numIndividuals] = {0.0}; // This is the matrix that will hold the pwp estimates
        //unsigned long long int weightings[numIndividuals][numIndividuals] = {0.0}; // This is the matrix that will hold the weightings--need to use a long long because the values are basically equal to the coverage squared by the end

        /* We are going to split the loci between numThreads threads. Each thread will modify two multidimensional
         vectors of the forms std::vector< std::vector<long double> > pwp(numIndividuals, std::vector<long double>(numIndividuals,0))    and   std::vector< std::vector<unsigned long long int> > weightings(numIndividuals, std::vector<unsigned long long int>(numIndividuals,0))

         First, we'll generate all of these vectors, which apparently in C++ needs to be constructed of a
         vector of two-dimensional vectors...
         */
        std::vector<std::vector<std::vector<long double>>> pwpThreads(numThreads, std::vector<std::vector<long double>> (numIndividuals, std::vector<long double> (numIndividuals,0) ) ); //pwpThreads[0] is the first 2D array for the first thread, etc...
        std::vector<std::vector<std::vector<unsigned long long int>>> weightingsThreads(numThreads, std::vector<std::vector<unsigned long long int> > (numIndividuals, std::vector<unsigned long long int> (numIndividuals,0) ) );

        std::cout << "Initialized the 3d vectors" << std::endl;

        // Now we need to determine how many loci for each thread. If we want to use the entire binary file, instead of numLoci loci, then change this to lociPerThread = (size/(numIndividuals*2))/numThreads
        //unsigned long long int lociPerThread = numLoci / numThreads;
        unsigned long long int lociPerThread = (readCounts.size()-1)/numThreads; // loci starts with 0, so need to subtract 1 from numLoci

        std::cout << "Initialized lociPerThread with " << numLoci << std::endl;

        std::vector<std::thread> threadsVec;
        for (int threadRunning = 0; threadRunning < numThreads; threadRunning++) {
            std::cout << "Got to the function call. Running thread # " << threadRunning << std::endl;
            unsigned long long int firstLocus = (unsigned long long int) threadRunning * lociPerThread;
            unsigned long long int finishingLocus = ((unsigned long long int) threadRunning * lociPerThread) + lociPerThread - (unsigned long long)1.0;
            std::cout << "Set firstLocus to " << firstLocus << " and finishingLocus to " << finishingLocus << std::endl;

            threadsVec.push_back(std::thread(calcPWPforRange, firstLocus, finishingLocus, numIndividuals, std::ref(readCounts), std::ref(pwpThreads[threadRunning]), std::ref(weightingsThreads[threadRunning])));
        }

        std::cout << "All threads completed launching" << std::endl;

        // Wait on threads to finish
        for (int i = 0; i < numThreads; ++i) {
            threadsVec[i].join();
            std::cout << "Joined thread " << i << std::endl;
        }
        std::cout << "All threads completed running" << std::endl;

        // Now aggregate the results of the threads and print final results
        std::vector<std::vector<long double>> weightingsSum(272, std::vector<long double>(272,0));
        std::vector<std::vector<long double>> pwpSum(272, std::vector<long double>(272,0));
        for (int element = 0; element < 272; element++) {
            for (int comparisonElement = 0; comparisonElement <= element; comparisonElement++) {
                for (int threadVector = 0; threadVector <= numThreads; threadVector++) {
                    weightingsSum[element][comparisonElement] += weightingsThreads[threadVector][element][comparisonElement];
                    pwpSum[element][comparisonElement] += pwpThreads[threadVector][element][comparisonElement];
                }
            }
        }

        // Now print out the final output to the pairwise pi file:
        std::ofstream pwpOUT (outFile);
        int rowCounter = 0;
        if (!pwpOUT) {
            std::cerr << "Crap, " << outFile << "didn't open!" << std::endl;
        } else {
            for (int tortoise=0; tortoise <= (numIndividuals-1); tortoise++) {
                for (int comparisonTortoise = 0; comparisonTortoise <= tortoise; comparisonTortoise++) {
                    rowCounter++;

                    //std::cout << "Made it past the beginning of the last end for loop" << std::endl;
                    //std::cout << "Tortoise numbers: " << tortoise << " and " << comparisonTortoise << std::endl;
                    if (weightingsSum[tortoise][comparisonTortoise] > 0) {
                        //std::cout << weightings[tortoise][comparisonTortoise] << std::endl;
                        //std::cout << pwp[tortoise][comparisonTortoise] / weightings[tortoise][comparisonTortoise] << std::endl;
                        pwpOUT << pwpSum[tortoise][comparisonTortoise] / weightingsSum[tortoise][comparisonTortoise] << std::endl;
                    } else {
                        pwpOUT << "NA" << std::endl;
                    }
                }
            }
        }
    } else std::cout << "Unable to open file";

    return 0;
}

//int calcPWPforRange (unsigned long long startingLocus, unsigned long long endingLocus, int numIndividuals, const std::vector<BYTE>& mainReadCountVector, std::vector< std::vector<long double> > & threadPWP, std::vector< std::vector<long double> > & threadWeightings) {
int calcPWPforRange (unsigned long long startingLocus, unsigned long long endingLocus, int numIndividuals, std::vector<unsigned char>& mainReadCountVector, std::vector<std::vector<long double>>& threadPWP, std::vector<std::vector<unsigned long long int>>& threadWeightings) {

     std::cout << "Calculating PWP for the following locus range: " << startingLocus << " to " << endingLocus << std::endl;
     for( unsigned long long locus = startingLocus; locus < endingLocus; locus++) {
     //std::cout << "Processing locus # " << locus << std::endl;
         if (locus % 100000 == 0) {
             std::cout << locus << " loci processed through calcPWPfromBinaryFile" << std::endl;
         }

         int coverages[numIndividuals];
         double *majorAlleleFreqs = new double[numIndividuals]; // This will hold the major allele frequencies for that locus for each tortoise

         for( int tortoise = 0; tortoise <= (numIndividuals-1); tortoise++ ) {
             unsigned long long majorIndex = locus * (numIndividuals*2) + 2 * tortoise;
             unsigned long long minorIndex = locus * (numIndividuals*2) + 2 * tortoise + 1;

             coverages[tortoise] = int(mainReadCountVector[majorIndex]) + int(mainReadCountVector[minorIndex]); // Hold the coverages for each locus
             if ( coverages[tortoise] > 0 ) {
                 //std::cout << "Made it to line 222 for locus " << locus << std::endl;
                 majorAlleleFreqs[tortoise] = (double)mainReadCountVector[majorIndex] / (double)coverages[tortoise]; // Not necessarily an int, but could be 0 or 1

                 if (coverages[tortoise] > 1) {
                     unsigned long long locusWeighting = coverages[tortoise]*(coverages[tortoise]-1);
                     threadWeightings[tortoise][tortoise] += (unsigned long long)locusWeighting; // This is an int--discrete number of reads

                     threadPWP[tortoise][tortoise] += double(locusWeighting) * (2.0 * majorAlleleFreqs[tortoise] * (double(coverages[tortoise]) - double(mainReadCountVector[majorIndex]))) / (double((coverages[tortoise])-1.0));
                 }

                 for( int comparisonTortoise = 0; comparisonTortoise < tortoise; comparisonTortoise++) {
                     if (coverages[comparisonTortoise] > 0) {
                         double locusWeighting = (double)coverages[tortoise] * (double)coverages[comparisonTortoise];

                         threadWeightings[tortoise][comparisonTortoise] += locusWeighting;
                         threadPWP[tortoise][comparisonTortoise] += (double)locusWeighting * (majorAlleleFreqs[tortoise] * (1.0-majorAlleleFreqs[comparisonTortoise]) + majorAlleleFreqs[comparisonTortoise] * (1.0-majorAlleleFreqs[tortoise]));
                    }
                }
            }
        }
        std::cout << "Made it to deleting majorAlleleFreqs" << std::endl;
        delete[] majorAlleleFreqs; // Needed to avoid memory leaks
    }
    std::cout << "Finished thread ending on locus " << endingLocus << std::endl;
    return 0;
}
<commit_msg>Minor changes<commit_after>//
//  calcPWP.cpp
//
//
//  Created by Evan McCartney-Melstad on 1/10/15.
//
//

#include "calcPWP.h"
#include <iostream>
#include <vector>
#include <fstream>
#include <thread>
#include <string>

int calcPWPfromBinaryFile (std::string binaryFile, unsigned long long int numLoci, const int numIndividuals, std::string outFile, int numThreads) {

    //****MODIFY THIS TO ONLY READ IN N LOCI AT A TIME, INSTEAD OF USING THE ENTIRE FILE****

    std::cout << "Number of threads: " << numThreads << std::endl;
    std::streampos size;
    std::ifstream file (binaryFile, std::ios::in|std::ios::binary|std::ios::ate);
    //ifstream file ("test500k.binary8bitunsigned", ios::in|ios::binary|ios::ate);
    if (file.is_open()) {
        size = file.tellg(); // Just a variable that shows position of stream--at end since ios::ate, so it's the file size. PROBABLY WON'T WORK FOR FILES LARGER THAN ~ 2GB!
        file.seekg (0, std::ios::beg); // Go back to the beginning of the file
        //file.read((char*)readCounts, size); // cast to a char* to give to file.read

        //unsigned char* readCounts;
        //readCounts = new unsigned char[size];
        std::vector<unsigned char> readCounts(size);
        file.read((char*) &readCounts[0], size);
        file.close();

        std::cout << "the entire file content is in memory" << std::endl;
        std::cout << "the total size of the file is " << size << std::endl;
        std::cout << "the number of elements in the readCounts vector is: " << readCounts.size() << std::endl; // Will give the total size bytes divided by the size of one element--so it gives the number of elements

        // We now have an array of numIndividuals * 2 (major and minor allele) * 1million (loci)
        //int totalLoci = (int)size / (numIndividuals*2); // The 1 million locus file has 999,999 sites in it (because of header line)
        //int totalLoci = size/(272*2);
        //std::vector< std::vector<long double> > pwp(numIndividuals, std::vector<long double>(numIndividuals,0));
        //std::vector< std::vector<unsigned long long int> > weightings(numIndividuals, std::vector<unsigned long long int>(numIndividuals,0));
        //long double pwp[numIndividuals][numIndividuals] = {0.0}; // This is the matrix that will hold the pwp estimates
        //unsigned long long int weightings[numIndividuals][numIndividuals] = {0.0}; // This is the matrix that will hold the weightings--need to use a long long because the values are basically equal to the coverage squared by the end

        /* We are going to split the loci between numThreads threads. Each thread will modify two multidimensional
         vectors of the forms std::vector< std::vector<long double> > pwp(numIndividuals, std::vector<long double>(numIndividuals,0))    and   std::vector< std::vector<unsigned long long int> > weightings(numIndividuals, std::vector<unsigned long long int>(numIndividuals,0))

         First, we'll generate all of these vectors, which apparently in C++ needs to be constructed of a
         vector of two-dimensional vectors...
         */
        std::vector<std::vector<std::vector<long double>>> pwpThreads(numThreads, std::vector<std::vector<long double>> (numIndividuals, std::vector<long double> (numIndividuals,0) ) ); //pwpThreads[0] is the first 2D array for the first thread, etc...
        std::vector<std::vector<std::vector<unsigned long long int>>> weightingsThreads(numThreads, std::vector<std::vector<unsigned long long int> > (numIndividuals, std::vector<unsigned long long int> (numIndividuals,0) ) );

        std::cout << "Initialized the 3d vectors" << std::endl;

        // Now we need to determine how many loci for each thread. If we want to use the entire binary file, instead of numLoci loci, then change this to lociPerThread = (size/(numIndividuals*2))/numThreads
        //unsigned long long int lociPerThread = numLoci / numThreads;

        //unsigned long long int lociPerThread = (readCounts.size()-1)/numThreads; // loci starts with 0, so need to subtract 1 from numLoci
        unsigned long long int lociPerThread = (numLoci-1)/numThreads;

        std::cout << "Initialized lociPerThread with " << numLoci << std::endl;

        std::vector<std::thread> threadsVec;
        for (int threadRunning = 0; threadRunning < numThreads; threadRunning++) {
            std::cout << "Got to the function call. Running thread # " << threadRunning << std::endl;
            unsigned long long int firstLocus = (unsigned long long int) threadRunning * lociPerThread;
            unsigned long long int finishingLocus = ((unsigned long long int) threadRunning * lociPerThread) + lociPerThread - (unsigned long long)1.0;
            std::cout << "Set firstLocus to " << firstLocus << " and finishingLocus to " << finishingLocus << std::endl;

            threadsVec.push_back(std::thread(calcPWPforRange, firstLocus, finishingLocus, numIndividuals, std::ref(readCounts), std::ref(pwpThreads[threadRunning]), std::ref(weightingsThreads[threadRunning])));
        }

        std::cout << "All threads completed launching" << std::endl;

        // Wait on threads to finish
        for (int i = 0; i < numThreads; ++i) {
            threadsVec[i].join();
            std::cout << "Joined thread " << i << std::endl;
        }
        std::cout << "All threads completed running" << std::endl;

        // Now aggregate the results of the threads and print final results
        std::vector<std::vector<long double>> weightingsSum(272, std::vector<long double>(272,0));
        std::vector<std::vector<long double>> pwpSum(272, std::vector<long double>(272,0));
        for (int element = 0; element < 272; element++) {
            for (int comparisonElement = 0; comparisonElement <= element; comparisonElement++) {
                for (int threadVector = 0; threadVector <= numThreads; threadVector++) {
                    weightingsSum[element][comparisonElement] += weightingsThreads[threadVector][element][comparisonElement];
                    pwpSum[element][comparisonElement] += pwpThreads[threadVector][element][comparisonElement];
                }
            }
        }

        // Now print out the final output to the pairwise pi file:
        std::ofstream pwpOUT (outFile);
        int rowCounter = 0;
        if (!pwpOUT) {
            std::cerr << "Crap, " << outFile << "didn't open!" << std::endl;
        } else {
            for (int tortoise=0; tortoise <= (numIndividuals-1); tortoise++) {
                for (int comparisonTortoise = 0; comparisonTortoise <= tortoise; comparisonTortoise++) {
                    rowCounter++;

                    //std::cout << "Made it past the beginning of the last end for loop" << std::endl;
                    //std::cout << "Tortoise numbers: " << tortoise << " and " << comparisonTortoise << std::endl;
                    if (weightingsSum[tortoise][comparisonTortoise] > 0) {
                        //std::cout << weightings[tortoise][comparisonTortoise] << std::endl;
                        //std::cout << pwp[tortoise][comparisonTortoise] / weightings[tortoise][comparisonTortoise] << std::endl;
                        pwpOUT << pwpSum[tortoise][comparisonTortoise] / weightingsSum[tortoise][comparisonTortoise] << std::endl;
                    } else {
                        pwpOUT << "NA" << std::endl;
                    }
                }
            }
        }
    } else std::cout << "Unable to open file";

    return 0;
}

//int calcPWPforRange (unsigned long long startingLocus, unsigned long long endingLocus, int numIndividuals, const std::vector<BYTE>& mainReadCountVector, std::vector< std::vector<long double> > & threadPWP, std::vector< std::vector<long double> > & threadWeightings) {
int calcPWPforRange (unsigned long long startingLocus, unsigned long long endingLocus, int numIndividuals, std::vector<unsigned char>& mainReadCountVector, std::vector<std::vector<long double>>& threadPWP, std::vector<std::vector<unsigned long long int>>& threadWeightings) {

     std::cout << "Calculating PWP for the following locus range: " << startingLocus << " to " << endingLocus << std::endl;
     for( unsigned long long locus = startingLocus; locus < endingLocus; locus++) {
     //std::cout << "Processing locus # " << locus << std::endl;
         if (locus % 100000 == 0) {
             std::cout << locus << " loci processed through calcPWPfromBinaryFile" << std::endl;
         }

         int coverages[numIndividuals];
         double *majorAlleleFreqs = new double[numIndividuals]; // This will hold the major allele frequencies for that locus for each tortoise

         for( int tortoise = 0; tortoise <= (numIndividuals-1); tortoise++ ) {
             unsigned long long majorIndex = locus * (numIndividuals*2) + 2 * tortoise;
             unsigned long long minorIndex = locus * (numIndividuals*2) + 2 * tortoise + 1;

             coverages[tortoise] = int(mainReadCountVector[majorIndex]) + int(mainReadCountVector[minorIndex]); // Hold the coverages for each locus
             if ( coverages[tortoise] > 0 ) {
                 //std::cout << "Made it to line 222 for locus " << locus << std::endl;
                 majorAlleleFreqs[tortoise] = (double)mainReadCountVector[majorIndex] / (double)coverages[tortoise]; // Not necessarily an int, but could be 0 or 1

                 if (coverages[tortoise] > 1) {
                     unsigned long long locusWeighting = coverages[tortoise]*(coverages[tortoise]-1);
                     threadWeightings[tortoise][tortoise] += (unsigned long long)locusWeighting; // This is an int--discrete number of reads

                     threadPWP[tortoise][tortoise] += double(locusWeighting) * (2.0 * majorAlleleFreqs[tortoise] * (double(coverages[tortoise]) - double(mainReadCountVector[majorIndex]))) / (double((coverages[tortoise])-1.0));
                 }

                 for( int comparisonTortoise = 0; comparisonTortoise < tortoise; comparisonTortoise++) {
                     if (coverages[comparisonTortoise] > 0) {
                         double locusWeighting = (double)coverages[tortoise] * (double)coverages[comparisonTortoise];

                         threadWeightings[tortoise][comparisonTortoise] += locusWeighting;
                         threadPWP[tortoise][comparisonTortoise] += (double)locusWeighting * (majorAlleleFreqs[tortoise] * (1.0-majorAlleleFreqs[comparisonTortoise]) + majorAlleleFreqs[comparisonTortoise] * (1.0-majorAlleleFreqs[tortoise]));
                    }
                }
            }
        }
        std::cout << "Made it to deleting majorAlleleFreqs" << std::endl;
        delete[] majorAlleleFreqs; // Needed to avoid memory leaks
    }
    std::cout << "Finished thread ending on locus " << endingLocus << std::endl;
    return 0;
}
<|endoftext|>


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

#include <boost/numeric/ublas/vector.hpp>

#include <fstream>
//include the schema that was sent
#include "cpx.hh"

#include <avro/ValidSchema.hh>
#include <avro/Compiler.hh>

#include <avro/Encoder.hh>
#include <avro/Decoder.hh>

#include "avro/Specific.hh"
#include "avro/Generic.hh"
#include "avro/Node.hh"
#include "avro/DataFile.hh"
#include <avro/Stream.hh>
#include <avro/DataStream.hh>

#include <iostream>
#include <fstream>
# include <stdio.h>
#include <pthread.h>

using namespace v8;

Persistent<String> on_schema;
Persistent<String> on_datum;
Persistent<String> on_error;

Persistent<Object> module_handle;

Handle<Value> DecodeAvro (const avro::GenericDatum& datum);
avro::GenericDatum& EncodeAvro (Handle<Value> datum);

void OnSchema();
void OnDatum(Handle<Value> datum);
void OnError(const char *error);

std::auto_ptr<avro::OutputStream> output = avro::memoryOutputStream();
avro::StreamWriter writer = avro::StreamWriter(*output);
avro::ValidSchema schema;

/*
Handle<Value> Decode(const Arguments& args){
  HandleScope scope;
  Local<Array> datumArray = Array::New();

  //std::cout << "after schema" << std::endl;

  std::auto_ptr<avro::InputStream> in = avro::memoryInputStream(*output);
  avro::DecoderPtr d = avro::binaryDecoder();
  d->init(*in);
  try
  {
    std::auto_ptr<avro::DataStreamReaderBase> dfrb(new avro::DataStreamReaderBase(in));
    std::cout << dfrb.get() << std::endl;
    avro::DataStreamReader<avro::GenericDatum> dfr(dfrb);
    std::cout << &dfr.base_ << std::endl;
    //avro::DataFileReader<avro::GenericDatum> dfr("test.bin");
    // we can derive the schema from the data file like so.
    if(schema == NULL){
      std::cout << "no schema yet." << std::endl;
      schema = &(dfr.dataSchema());

    }

    avro::GenericDatum datum(dfr.dataSchema());
    int i = 0;
    while(dfr.read(datum)){
      datumArray->Set(i, DecodeAvro(datum));
      //size_t outputLen = dfrb->stream_->byteCount();
      //std::cout << outputLen << std::endl;
      i++;
    }
  }
  catch (std::exception &e) {
      std::cerr<< "error" << e.what() << std::endl;
  }

  return scope.Close(datumArray);
}
*/

void DecodeFile(const char* filename){
  try{
    avro::DataFileReader<avro::GenericDatum> dfr(filename);
    schema = dfr.dataSchema();
    OnSchema();
    avro::GenericDatum datum(dfr.dataSchema());

    while(dfr.read(datum)){
      OnDatum(DecodeAvro(datum));
    }
  }catch(std::exception &e){
    OnError(e.what());
  }

}

void EncodeFile(const char* filename, Local<Function> cb, Local<Object> data){

}

/**
 * [A callback for when the schema has been set. Can be set either by a stream, file or by manually setting
 * the Schema by SetSchema(filename)]
 */
void OnSchema(){
  HandleScope scope;
  // locate callback from the module context if defined by script
  // example = require('example')
  // example.onschema = function( ... ) { ..
  Local<Value> callback_v = module_handle->Get(on_schema);
  if (!callback_v->IsFunction()) {
    // callback not defined, ignore
    return;
  }

  Local<Function> callback = Local<Function>::Cast(callback_v);

  std::ostringstream oss(std::ios_base::out);
  schema.toJson(oss);
  // prepare arguments for the callback
  Local<Value> argv[1];
  argv[0] = Local<Value>::New(String::New(oss.str().c_str()));

  callback->Call(module_handle, 1, argv);
}

/**
 * [OnDatum callback for when a datum has been created from either file or stream decode]
 * @param datum [description]
 */
void OnDatum(Handle<Value> datum){
  HandleScope scope;
  // locate callback from the module context if defined by script
  // example = require('example')
  // example.onschema = function( ... ) { ..
  Local<Value> callback_v = module_handle->Get(on_datum);
  if (!callback_v->IsFunction()) {
    // callback not defined, ignore
    return;
  }

  Local<Function> callback = Local<Function>::Cast(callback_v);

  // prepare arguments for the callback
  Local<Value> argv[1];
  argv[0] = Local<Value>::New(datum);

  callback->Call(module_handle, 1, argv);
}

/**
 * [OnError description]
 * @param error [description]
 */
void OnError(const char *error){
  HandleScope scope;
  // locate callback from the module context if defined by script
  // example = require('example')
  // example.onschema = function( ... ) { ..
  Local<Value> callback_v = module_handle->Get(on_error);
  //If no function is defined in the javascript for handling error
  // we throw an error.
  if (!callback_v->IsFunction()) {
    ThrowException(Exception::TypeError(String::New(error)));
    return;
  }

  Local<Function> callback = Local<Function>::Cast(callback_v);

  // prepare arguments for the callback
  Local<Value> argv[1];
  argv[0] = Local<Value>::New(String::New(error));

  callback->Call(module_handle, 1, argv);
}

Handle<Value> SetSchema(const Arguments& args){
  HandleScope scope;

  if (args.Length() != 1) {
    ThrowException(Exception::TypeError(String::New("Wrong number of arguments")));
    return scope.Close(Undefined());
  }

  if(args[0]->IsString()){
    // get the param
    v8::String::Utf8Value param1(args[0]->ToString());
    std::ifstream ifs(*param1);
    avro::compileJsonSchema(ifs, schema);
    OnSchema();

  }else{
    ThrowException(Exception::TypeError(String::New("Schema Must be a string")));
    return scope.Close(Undefined());
  }
  return scope.Close(Undefined());
}

Handle<Value> GetSchema(const Arguments& args){

  HandleScope scope;
  std::ostringstream oss(std::ios_base::out);
  schema.toJson(oss);
  return scope.Close(String::New(oss.str().c_str()));
}

Handle<Value> Decode(const Arguments& args) {
  HandleScope scope;

  if (args.Length() > 2) {
    ThrowException(Exception::TypeError(String::New("Wrong number of arguments")));
    return scope.Close(Undefined());
  }

  Local<Function> cb = Local<Function>::Cast(args[1]);

  if(args[0]->IsString()){
    // get the param
    v8::String::Utf8Value param1(args[0]->ToString());

    DecodeFile(*param1);
  }

  if(args[0]->IsObject()){
    Local<Object> obj = args[0]->ToObject();

    //get length of array
    int len = obj->GetIndexedPropertiesExternalArrayDataLength();
    const uint8_t *buffer = static_cast<uint8_t*>(obj->GetIndexedPropertiesExternalArrayData());
  }

/*
  writer.writeBytes(buffer, len);
  writer.flush();
*/

  return scope.Close(Undefined());
}

Handle<Value> Encode(const Arguments& args){
  HandleScope scope;
  std::ifstream ifs("cpx.json");

  avro::ValidSchema cpxSchema;
  avro::compileJsonSchema(ifs, cpxSchema);  //std::ifstream in("cpx.json");

  //avro::ValidSchema cpxSchema;
  //avro::compileJsonSchema(in, cpxSchema);

  std::auto_ptr<avro::OutputStream> out = avro::memoryOutputStream();
  avro::EncoderPtr e = avro::binaryEncoder();
  e->init(*out);
  avro::DataFileWriter<c::cpx> dfw("test.bin", cpxSchema);
  c::cpx c1;
  for(int i = 0;i<100; i++){
    c1.im = i;
    //setup array test
    std::vector<std::string> vec ;

    vec.push_back("16");
    vec.push_back("2");
    vec.push_back("77");
    vec.push_back("29");
    c1.array.set_array(vec);

    //setup map test
    std::map<std::string, int> map ;
    map.insert(std::make_pair("first",1));
    map.insert(std::make_pair("second",2));
    map.insert(std::make_pair("third",3));

    c1.map.set_map(map);

    avro::encode(*e, c1);

    dfw.write(c1);
  }

  dfw.close();

  return scope.Close(Object::New());
}

avro::GenericDatum& EncodeAvro(Handle<Value> datum){

}

/**
 * converts a GenericDatum into a v8 object that can be passed back to javascript
 */
Handle<Value> DecodeAvro(const avro::GenericDatum& datum){
    Handle<Object> obj = Object::New();

  //return this Object
  if(datum.type() == avro::AVRO_RECORD){
    const avro::GenericRecord& record = datum.value<avro::GenericRecord>();
    const avro::NodePtr& node = record.schema();
    Handle<Object> obj = Object::New();
    for(uint i = 0; i<record.fieldCount(); i++){
      //Add values
      Local<String> datumName = String::New(node->nameAt(i).c_str(), node->nameAt(i).size());
      const avro::GenericDatum& subDatum = record.fieldAt(i);
      obj->Set(datumName, DecodeAvro(subDatum));
    }
    return obj;
  }else if(datum.type() == avro::AVRO_STRING){
    return  String::New(
      datum.value<std::string>().c_str(),
      datum.value<std::string>().size()
    );
  }else if(datum.type() == avro::AVRO_BYTES){
    //obj->Set(datumName, );
  }else if(datum.type() == avro::AVRO_INT){
    return Number::New(datum.value<int>());
  }else if(datum.type() == avro::AVRO_LONG){
    return Number::New(datum.value<long>());
  }else if(datum.type() == avro::AVRO_FLOAT){
    return Number::New(datum.value<float>());
  }else if(datum.type() == avro::AVRO_DOUBLE){
    return Number::New(datum.value<double>());
  }else if(datum.type() == avro::AVRO_BOOL){
    return Boolean::New(datum.value<bool>());
  }else if(datum.type() == avro::AVRO_NULL){
    return v8::Null();
  }else if(datum.type() == avro::AVRO_RECORD){
    return DecodeAvro(datum.value<avro::GenericDatum>());
  }else if(datum.type() == avro::AVRO_ENUM){
    return v8::Null();
  }else if(datum.type() == avro::AVRO_ARRAY){
    const avro::GenericArray &genArray = datum.value<avro::GenericArray>();

    const std::vector<avro::GenericDatum> &v = genArray.value();
    Local<Array> datumArray = Array::New();
    int i = 0;
    for(std::vector<avro::GenericDatum>::const_iterator it = v.begin(); it != v.end(); ++it) {
      const avro::GenericDatum &itDatum = * it;
      datumArray->Set(i, DecodeAvro(itDatum));
      i++;
      //DecodeAvro(*it);
    }
    return datumArray;
  }else if(datum.type() == avro::AVRO_MAP){
    const avro::GenericMap &genMap = datum.value<avro::GenericMap>();

    const std::vector < std::pair < std::string, avro::GenericDatum > > &v = genMap.value();
    Local<Array> datumArray = Array::New();
    int i = 0;
    for(std::vector< std::pair < std::string, avro::GenericDatum> >::const_iterator it = v.begin(); it != v.end(); ++it) {
      const std::pair < std::string, avro::GenericDatum> &itDatum = * it;
      datumArray->Set(String::New(
        itDatum.first.c_str(),
        itDatum.first.size()
        ),DecodeAvro(itDatum.second));

      i++;
    }
    return datumArray;
  }else if(datum.type() == avro::AVRO_UNION){
    std::cout << "in union" << std::endl;
  }else if(datum.type() == avro::AVRO_FIXED){

  }else if(datum.type() == avro::AVRO_NUM_TYPES){

  }else if(datum.type() == avro::AVRO_SYMBOLIC){

  }else if(datum.type() == avro::AVRO_UNKNOWN){

  }
  return obj;
}

Handle<Value> convertAvro(const avro::GenericDatum& datum){

}
void init(Handle<Object> target) {

  NODE_SET_METHOD(target, "decode", Decode);

  NODE_SET_METHOD(target, "encode", Encode);

  NODE_SET_METHOD(target, "setSchema", SetSchema);

  NODE_SET_METHOD(target, "getSchema", GetSchema);

  on_schema = NODE_PSYMBOL("onschema");

  on_datum = NODE_PSYMBOL("ondatum");

  on_error = NODE_PSYMBOL("onerror");

  module_handle = Persistent<Object>::New(target);

}

NODE_MODULE(avro, init)<commit_msg>changing the api a little bit. Hopefully to make it simplier<commit_after>#include <node.h>
#include <v8.h>

#include <boost/numeric/ublas/vector.hpp>

#include <fstream>
//include the schema that was sent
#include "cpx.hh"

#include <avro/ValidSchema.hh>
#include <avro/Compiler.hh>

#include <avro/Encoder.hh>
#include <avro/Decoder.hh>

#include "avro/Specific.hh"
#include "avro/Generic.hh"
#include "avro/Node.hh"
#include "avro/DataFile.hh"
#include <avro/Stream.hh>
#include <avro/DataStream.hh>

#include <iostream>
#include <fstream>
# include <stdio.h>
#include <pthread.h>

using namespace v8;

Persistent<String> on_schema;
Persistent<String> on_datum;
Persistent<String> on_error;

Persistent<Object> module_handle;

Handle<Value> DecodeAvro (const avro::GenericDatum& datum);

void OnSchema();
void OnDatum(Handle<Value> datum);
void OnError(const char *error);

std::auto_ptr<avro::OutputStream> output = avro::memoryOutputStream();
avro::StreamWriter writer = avro::StreamWriter(*output);
avro::ValidSchema schema;

/*
Handle<Value> Decode(const Arguments& args){
  HandleScope scope;
  Local<Array> datumArray = Array::New();

  //std::cout << "after schema" << std::endl;

  std::auto_ptr<avro::InputStream> in = avro::memoryInputStream(*output);
  avro::DecoderPtr d = avro::binaryDecoder();
  d->init(*in);
  try
  {
    std::auto_ptr<avro::DataStreamReaderBase> dfrb(new avro::DataStreamReaderBase(in));
    std::cout << dfrb.get() << std::endl;
    avro::DataStreamReader<avro::GenericDatum> dfr(dfrb);
    std::cout << &dfr.base_ << std::endl;
    //avro::DataFileReader<avro::GenericDatum> dfr("test.bin");
    // we can derive the schema from the data file like so.
    if(schema == NULL){
      std::cout << "no schema yet." << std::endl;
      schema = &(dfr.dataSchema());

    }

    avro::GenericDatum datum(dfr.dataSchema());
    int i = 0;
    while(dfr.read(datum)){
      datumArray->Set(i, DecodeAvro(datum));
      //size_t outputLen = dfrb->stream_->byteCount();
      //std::cout << outputLen << std::endl;
      i++;
    }
  }
  catch (std::exception &e) {
      std::cerr<< "error" << e.what() << std::endl;
  }

  return scope.Close(datumArray);
}
*/

void EncodeFile(const char* filename, Local<Function> cb, Local<Object> data){

}

/**
 * [A callback for when the schema has been set. Can be set either by a stream, file or by manually setting
 * the Schema by SetSchema(filename)]
 */
void OnSchema(){
  HandleScope scope;
  // locate callback from the module context if defined by script
  // example = require('example')
  // example.onschema = function( ... ) { ..
  Local<Value> callback_v = module_handle->Get(on_schema);
  if (!callback_v->IsFunction()) {
    // callback not defined, ignore
    return;
  }

  Local<Function> callback = Local<Function>::Cast(callback_v);

  std::ostringstream oss(std::ios_base::out);
  schema.toJson(oss);
  // prepare arguments for the callback
  Local<Value> argv[1];
  argv[0] = Local<Value>::New(String::New(oss.str().c_str()));

  callback->Call(module_handle, 1, argv);
}

/**
 * [OnDatum callback for when a datum has been created from either file or stream decode]
 * @param datum [description]
 */
void OnDatum(Handle<Value> datum){
  HandleScope scope;
  // locate callback from the module context if defined by script
  // example = require('example')
  // example.onschema = function( ... ) { ..
  Local<Value> callback_v = module_handle->Get(on_datum);
  if (!callback_v->IsFunction()) {
    // callback not defined, ignore
    return;
  }

  Local<Function> callback = Local<Function>::Cast(callback_v);

  // prepare arguments for the callback
  Local<Value> argv[1];
  argv[0] = Local<Value>::New(datum);

  callback->Call(module_handle, 1, argv);
}

/**
 * [OnError description]
 * @param error [description]
 */
void OnError(const char *error){
  HandleScope scope;
  // locate callback from the module context if defined by script
  // example = require('example')
  // example.onschema = function( ... ) { ..
  Local<Value> callback_v = module_handle->Get(on_error);
  //If no function is defined in the javascript for handling error
  // we throw an error.
  if (!callback_v->IsFunction()) {
    ThrowException(Exception::TypeError(String::New(error)));
    return;
  }

  Local<Function> callback = Local<Function>::Cast(callback_v);

  // prepare arguments for the callback
  Local<Value> argv[1];
  argv[0] = Local<Value>::New(String::New(error));

  callback->Call(module_handle, 1, argv);
}

Handle<Value> SetSchema(const Arguments& args){
  HandleScope scope;

  if (args.Length() != 1) {
    ThrowException(Exception::TypeError(String::New("Wrong number of arguments")));
    return scope.Close(Undefined());
  }

  if(args[0]->IsString()){
    // get the param
    v8::String::Utf8Value param1(args[0]->ToString());
    std::ifstream ifs(*param1);
    avro::compileJsonSchema(ifs, schema);
    OnSchema();

  }else{
    ThrowException(Exception::TypeError(String::New("Schema Must be a string")));
    return scope.Close(Undefined());
  }
  return scope.Close(Undefined());
}

Handle<Value> GetSchema(const Arguments& args){
  HandleScope scope;
  std::ostringstream oss(std::ios_base::out);
  schema.toJson(oss);
  return scope.Close(String::New(oss.str().c_str()));
}

Handle<Value> DecodeFile(const Arguments& args) {
  HandleScope scope;

  if (args.Length() > 1) {
    ThrowException(Exception::TypeError(String::New("Wrong number of arguments")));
    return scope.Close(Undefined());
  }

  Local<Function> cb = Local<Function>::Cast(args[1]);

  if(args[0]->IsString()){
    // get the param
    v8::String::Utf8Value filename(args[0]->ToString());

    try{
      avro::DataFileReader<avro::GenericDatum> dfr(*filename);
      schema = dfr.dataSchema();
      OnSchema();
      avro::GenericDatum datum(dfr.dataSchema());

      while(dfr.read(datum)){
        OnDatum(DecodeAvro(datum));
      }
    }catch(std::exception &e){
      OnError(e.what());
    }
  }else{
    OnError("Wrong Argument. Must be string for filename");
  }

  return scope.Close(Undefined());
}

Handle<Value> Encode(const Arguments& args){
  HandleScope scope;

  std::auto_ptr<avro::OutputStream> out = avro::memoryOutputStream();
  avro::EncoderPtr e = avro::binaryEncoder();
  e->init(*out);
  avro::DataFileWriter<c::cpx> dfw("test.bin", schema);
  c::cpx c1;
  for(int i = 0;i<100; i++){
    c1.im = i;
    //setup array test
    std::vector<std::string> vec ;

    vec.push_back("16");
    vec.push_back("2");
    vec.push_back("77");
    vec.push_back("29");
    c1.array.set_array(vec);

    //setup map test
    std::map<std::string, int> map ;
    map.insert(std::make_pair("first",1));
    map.insert(std::make_pair("second",2));
    map.insert(std::make_pair("third",3));

    c1.map.set_map(map);

    avro::encode(*e, c1);

    dfw.write(c1);
  }

  dfw.close();

  return scope.Close(Object::New());
}

/**
 * converts a GenericDatum into a v8 object that can be passed back to javascript
 */
Handle<Value> DecodeAvro(const avro::GenericDatum& datum){
    Handle<Object> obj = Object::New();

  //return this Object
  if(datum.type() == avro::AVRO_RECORD){
    const avro::GenericRecord& record = datum.value<avro::GenericRecord>();
    const avro::NodePtr& node = record.schema();
    Handle<Object> obj = Object::New();
    for(uint i = 0; i<record.fieldCount(); i++){
      //Add values
      Local<String> datumName = String::New(node->nameAt(i).c_str(), node->nameAt(i).size());
      const avro::GenericDatum& subDatum = record.fieldAt(i);
      obj->Set(datumName, DecodeAvro(subDatum));
    }
    return obj;
  }else if(datum.type() == avro::AVRO_STRING){
    return  String::New(
      datum.value<std::string>().c_str(),
      datum.value<std::string>().size()
    );
  }else if(datum.type() == avro::AVRO_BYTES){
    //obj->Set(datumName, );
  }else if(datum.type() == avro::AVRO_INT){
    return Number::New(datum.value<int>());
  }else if(datum.type() == avro::AVRO_LONG){
    return Number::New(datum.value<long>());
  }else if(datum.type() == avro::AVRO_FLOAT){
    return Number::New(datum.value<float>());
  }else if(datum.type() == avro::AVRO_DOUBLE){
    return Number::New(datum.value<double>());
  }else if(datum.type() == avro::AVRO_BOOL){
    return Boolean::New(datum.value<bool>());
  }else if(datum.type() == avro::AVRO_NULL){
    return v8::Null();
  }else if(datum.type() == avro::AVRO_RECORD){
    return DecodeAvro(datum.value<avro::GenericDatum>());
  }else if(datum.type() == avro::AVRO_ENUM){
    return v8::Null();
  }else if(datum.type() == avro::AVRO_ARRAY){
    const avro::GenericArray &genArray = datum.value<avro::GenericArray>();

    const std::vector<avro::GenericDatum> &v = genArray.value();
    Local<Array> datumArray = Array::New();
    int i = 0;
    for(std::vector<avro::GenericDatum>::const_iterator it = v.begin(); it != v.end(); ++it) {
      const avro::GenericDatum &itDatum = * it;
      datumArray->Set(i, DecodeAvro(itDatum));
      i++;
    }
    return datumArray;
  }else if(datum.type() == avro::AVRO_MAP){
    const avro::GenericMap &genMap = datum.value<avro::GenericMap>();

    const std::vector < std::pair < std::string, avro::GenericDatum > > &v = genMap.value();
    Local<Array> datumArray = Array::New();
    int i = 0;
    for(std::vector< std::pair < std::string, avro::GenericDatum> >::const_iterator it = v.begin(); it != v.end(); ++it) {
      const std::pair < std::string, avro::GenericDatum> &itDatum = * it;
      datumArray->Set(String::New(
        itDatum.first.c_str(),
        itDatum.first.size()
        ),DecodeAvro(itDatum.second));

      i++;
    }
    return datumArray;
  }else if(datum.type() == avro::AVRO_UNION){
    std::cout << "in union" << std::endl;
  }else if(datum.type() == avro::AVRO_FIXED){

  }else if(datum.type() == avro::AVRO_NUM_TYPES){

  }else if(datum.type() == avro::AVRO_SYMBOLIC){

  }else if(datum.type() == avro::AVRO_UNKNOWN){

  }
  return obj;
}

Handle<Value> DecodeBytes(const Arguments& args){
  HandleScope scope;

  return scope.Close(Undefined());
}

/**
 *
 */
Handle<Value> EncodeBytes(const Arguments& args){
  HandleScope scope;

  return scope.Close(Undefined());
}

void init(Handle<Object> target) {

  NODE_SET_METHOD(target, "decode", DecodeFile);

  NODE_SET_METHOD(target, "encode", Encode);

  NODE_SET_METHOD(target, "setSchema", SetSchema);

  NODE_SET_METHOD(target, "getSchema", GetSchema);

  NODE_SET_METHOD(target, "decodeBytes", DecodeBytes);

  NODE_SET_METHOD(target, "encodeBytes", EncodeBytes);

  on_schema = NODE_PSYMBOL("onschema");

  on_datum = NODE_PSYMBOL("ondatum");

  on_error = NODE_PSYMBOL("onerror");

  module_handle = Persistent<Object>::New(target);

}

NODE_MODULE(avro, init)<|endoftext|>


<commit_before>/**
 * Copyright (c) 2015 - The CM Authors <legal@clickmatcher.com>
 *   All Rights Reserved.
 *
 * This file is CONFIDENTIAL -- Distribution or duplication of this material or
 * the information contained herein is strictly forbidden unless prior written
 * permission is obtained.
 */
#include "DocumentDBServlet.h"

using namespace stx;

namespace zbase {

DocumentDBServlet::DocumentDBServlet(
    DocumentDB* docdb) :
    docdb_(docdb) {}

void DocumentDBServlet::handle(
    const AnalyticsSession& session,
    const stx::http::HTTPRequest* req,
    stx::http::HTTPResponse* res) {
  static const String kPathPrefix = "/api/v1/documents";
  URI uri(req->uri());

  // LIST
  if (req->method() == http::HTTPMessage::M_GET &&
      uri.path() == kPathPrefix) {
    listDocuments(session, req, res);
    return;
  }

  // GET
  if (req->method() == http::HTTPMessage::M_GET &&
      StringUtil::beginsWith(uri.path(), kPathPrefix)) {
    auto docid = SHA1Hash::fromHexString(
        uri.path().substr(kPathPrefix.size() + 1));

    fetchDocument(docid, uri, session, req, res);
    return;
  }

  // CREATE
  if (req->method() == http::HTTPMessage::M_POST &&
      uri.path() == kPathPrefix) {
    createDocument(uri, session, req, res);
    return;
  }

  // UPDATE
  if (req->method() == http::HTTPMessage::M_POST &&
      StringUtil::beginsWith(uri.path(), kPathPrefix)) {
    auto docid = SHA1Hash::fromHexString(
        uri.path().substr(kPathPrefix.size() + 1));

    updateDocument(docid, uri, session, req, res);
    return;
  }

  res->setStatus(stx::http::kStatusNotFound);
  res->addBody("not found");
}

void DocumentDBServlet::fetchDocument(
    const SHA1Hash& uuid,
    const URI& uri,
    const AnalyticsSession& session,
    const http::HTTPRequest* req,
    http::HTTPResponse* res) {
  const auto& params = uri.queryParams();

  bool return_content = true;
  String no_content_str;
  if (URI::getParam(params, "no_content", &no_content_str)) {
    return_content = false;
  }

  Document doc;
  if (docdb_->fetchDocument(session.customer(), session.userid(), uuid, &doc)) {
    Buffer buf;
    json::JSONOutputStream json(BufferOutputStream::fromBuffer(&buf));
    renderDocument(session, doc, &json, return_content);
    res->setStatus(http::kStatusOK);
    res->addBody(buf);
  } else {
    res->setStatus(http::kStatusNotFound);
    res->addBody("not found");
  }
}

void DocumentDBServlet::createDocument(
    const URI& uri,
    const AnalyticsSession& session,
    const http::HTTPRequest* req,
    http::HTTPResponse* res) {
  URI::ParamList params;
  URI::parseQueryString(req->body().toString(), &params);

  String name;
  if (!URI::getParam(params, "name", &name)) {
    res->setStatus(http::kStatusBadRequest);
    res->addBody("missing ?name=... parameter");
  }

  String type;
  if (!URI::getParam(params, "type", &type)) {
    res->setStatus(http::kStatusBadRequest);
    res->addBody("missing ?type=... parameter");
  }

  auto now = WallClock::unixMicros();

  Document doc;
  doc.set_uuid(Random::singleton()->sha1().toString());
  doc.set_name(name);
  doc.set_type(type);
  doc.set_version(0);
  doc.set_ctime(now);
  doc.set_mtime(now);
  doc.set_atime(now);

  setDefaultDocumentACLs(&doc, session.userid());

  docdb_->createDocument(session.customer(), doc);

  Buffer buf;
  json::JSONOutputStream json(BufferOutputStream::fromBuffer(&buf));
  renderDocument(session, doc, &json);
  res->setStatus(http::kStatusCreated);
  res->addBody(buf);
}

void DocumentDBServlet::updateDocument(
    const SHA1Hash& uuid,
    const URI& uri,
    const AnalyticsSession& session,
    const http::HTTPRequest* req,
    http::HTTPResponse* res) {
  URI::ParamList params;
  URI::parseQueryString(req->body().toString(), &params);

  Vector<Function<void ()>> tx;

  for (const auto& p : params) {

    if (p.first == "content") {
      if (!p.second.empty()) {
        tx.emplace_back([this, &session, &uuid, p] () {
          docdb_->updateDocumentContent(
              session.customer(),
              session.userid(),
              uuid,
              p.second);
        });
      }

      continue;
    }

    if (p.first == "name") {
      if (!p.second.empty()) {
        tx.emplace_back([this, &session, &uuid, p] () {
          docdb_->updateDocumentName(
              session.customer(),
              session.userid(),
              uuid,
              p.second);
        });
      }

      continue;
    }

    if (p.first == "acl_policy") {
      if (!p.second.empty()) {
        DocumentACLPolicy policy;
        if (!DocumentACLPolicy_Parse(p.second, &policy)) {
          res->setStatus(http::kStatusBadRequest);
          res->addBody(StringUtil::format("invalid policy: '$0'", p.second));
          return;
        }

        tx.emplace_back([this, &session, &uuid, policy] () {
          docdb_->updateDocumentACLPolicy(
              session.customer(),
              session.userid(),
              uuid,
              policy);
        });
      }

      continue;
    }

    res->setStatus(http::kStatusBadRequest);
    res->addBody(StringUtil::format("invalid parameter: '$0'", p.first));
    return;
  }

  for (const auto& fn : tx) {
    fn();
  }

  res->setStatus(http::kStatusCreated);
}

void DocumentDBServlet::listDocuments(
    const AnalyticsSession& session,
    const http::HTTPRequest* req,
    http::HTTPResponse* res) {
  Buffer buf;
  json::JSONOutputStream json(BufferOutputStream::fromBuffer(&buf));

  json.beginObject();
  json.addObjectEntry("documents");
  json.beginArray();

  size_t i = 0;
  docdb_->listDocuments(
      session.customer(),
      session.userid(),
      [this, &i, &json, &session] (const Document& doc) -> bool {
    if (++i > 1) {
      json.addComma();
    }

    renderDocument(
        session,
        doc,
        &json,
        false);

    return true;
  });

  json.endArray();
  json.endObject();

  res->setStatus(http::kStatusOK);
  res->setHeader("Content-Type", "application/json; charset=utf-8");
  res->addBody(buf);
}

void DocumentDBServlet::renderDocument(
    const AnalyticsSession& session,
    const Document& doc,
    json::JSONOutputStream* json,
    bool return_content /* = true */) {
  json->beginObject();

  json->addObjectEntry("uuid");
  json->addString(doc.uuid());
  json->addComma();

  json->addObjectEntry("name");
  json->addString(doc.name());
  json->addComma();

  json->addObjectEntry("acl_policy");
  json->addString(DocumentACLPolicy_Name(doc.acl_policy()));
  json->addComma();

  json->addObjectEntry("is_readable");
  json->addBool(isDocumentReadableForUser(doc, session.userid()));
  json->addComma();

  json->addObjectEntry("is_writable");
  json->addBool(isDocumentWritableForUser(doc, session.userid()));
  json->addComma();

  json->addObjectEntry("ctime");
  json->addInteger(doc.ctime());
  json->addComma();

  json->addObjectEntry("mtime");
  json->addInteger(doc.mtime());
  json->addComma();

  json->addObjectEntry("atime");
  json->addInteger(doc.atime());

  if (return_content) {
    json->addComma();
    json->addObjectEntry("content");
    json->addString(doc.content());
  }

  json->endObject();
}

} // namespace zbase
<commit_msg>include type in document json<commit_after>/**
 * Copyright (c) 2015 - The CM Authors <legal@clickmatcher.com>
 *   All Rights Reserved.
 *
 * This file is CONFIDENTIAL -- Distribution or duplication of this material or
 * the information contained herein is strictly forbidden unless prior written
 * permission is obtained.
 */
#include "DocumentDBServlet.h"

using namespace stx;

namespace zbase {

DocumentDBServlet::DocumentDBServlet(
    DocumentDB* docdb) :
    docdb_(docdb) {}

void DocumentDBServlet::handle(
    const AnalyticsSession& session,
    const stx::http::HTTPRequest* req,
    stx::http::HTTPResponse* res) {
  static const String kPathPrefix = "/api/v1/documents";
  URI uri(req->uri());

  // LIST
  if (req->method() == http::HTTPMessage::M_GET &&
      uri.path() == kPathPrefix) {
    listDocuments(session, req, res);
    return;
  }

  // GET
  if (req->method() == http::HTTPMessage::M_GET &&
      StringUtil::beginsWith(uri.path(), kPathPrefix)) {
    auto docid = SHA1Hash::fromHexString(
        uri.path().substr(kPathPrefix.size() + 1));

    fetchDocument(docid, uri, session, req, res);
    return;
  }

  // CREATE
  if (req->method() == http::HTTPMessage::M_POST &&
      uri.path() == kPathPrefix) {
    createDocument(uri, session, req, res);
    return;
  }

  // UPDATE
  if (req->method() == http::HTTPMessage::M_POST &&
      StringUtil::beginsWith(uri.path(), kPathPrefix)) {
    auto docid = SHA1Hash::fromHexString(
        uri.path().substr(kPathPrefix.size() + 1));

    updateDocument(docid, uri, session, req, res);
    return;
  }

  res->setStatus(stx::http::kStatusNotFound);
  res->addBody("not found");
}

void DocumentDBServlet::fetchDocument(
    const SHA1Hash& uuid,
    const URI& uri,
    const AnalyticsSession& session,
    const http::HTTPRequest* req,
    http::HTTPResponse* res) {
  const auto& params = uri.queryParams();

  bool return_content = true;
  String no_content_str;
  if (URI::getParam(params, "no_content", &no_content_str)) {
    return_content = false;
  }

  Document doc;
  if (docdb_->fetchDocument(session.customer(), session.userid(), uuid, &doc)) {
    Buffer buf;
    json::JSONOutputStream json(BufferOutputStream::fromBuffer(&buf));
    renderDocument(session, doc, &json, return_content);
    res->setStatus(http::kStatusOK);
    res->addBody(buf);
  } else {
    res->setStatus(http::kStatusNotFound);
    res->addBody("not found");
  }
}

void DocumentDBServlet::createDocument(
    const URI& uri,
    const AnalyticsSession& session,
    const http::HTTPRequest* req,
    http::HTTPResponse* res) {
  URI::ParamList params;
  URI::parseQueryString(req->body().toString(), &params);

  String name;
  if (!URI::getParam(params, "name", &name)) {
    res->setStatus(http::kStatusBadRequest);
    res->addBody("missing ?name=... parameter");
  }

  String type;
  if (!URI::getParam(params, "type", &type)) {
    res->setStatus(http::kStatusBadRequest);
    res->addBody("missing ?type=... parameter");
  }

  auto now = WallClock::unixMicros();

  Document doc;
  doc.set_uuid(Random::singleton()->sha1().toString());
  doc.set_name(name);
  doc.set_type(type);
  doc.set_version(0);
  doc.set_ctime(now);
  doc.set_mtime(now);
  doc.set_atime(now);

  setDefaultDocumentACLs(&doc, session.userid());

  docdb_->createDocument(session.customer(), doc);

  Buffer buf;
  json::JSONOutputStream json(BufferOutputStream::fromBuffer(&buf));
  renderDocument(session, doc, &json);
  res->setStatus(http::kStatusCreated);
  res->addBody(buf);
}

void DocumentDBServlet::updateDocument(
    const SHA1Hash& uuid,
    const URI& uri,
    const AnalyticsSession& session,
    const http::HTTPRequest* req,
    http::HTTPResponse* res) {
  URI::ParamList params;
  URI::parseQueryString(req->body().toString(), &params);

  Vector<Function<void ()>> tx;

  for (const auto& p : params) {

    if (p.first == "content") {
      if (!p.second.empty()) {
        tx.emplace_back([this, &session, &uuid, p] () {
          docdb_->updateDocumentContent(
              session.customer(),
              session.userid(),
              uuid,
              p.second);
        });
      }

      continue;
    }

    if (p.first == "name") {
      if (!p.second.empty()) {
        tx.emplace_back([this, &session, &uuid, p] () {
          docdb_->updateDocumentName(
              session.customer(),
              session.userid(),
              uuid,
              p.second);
        });
      }

      continue;
    }

    if (p.first == "acl_policy") {
      if (!p.second.empty()) {
        DocumentACLPolicy policy;
        if (!DocumentACLPolicy_Parse(p.second, &policy)) {
          res->setStatus(http::kStatusBadRequest);
          res->addBody(StringUtil::format("invalid policy: '$0'", p.second));
          return;
        }

        tx.emplace_back([this, &session, &uuid, policy] () {
          docdb_->updateDocumentACLPolicy(
              session.customer(),
              session.userid(),
              uuid,
              policy);
        });
      }

      continue;
    }

    res->setStatus(http::kStatusBadRequest);
    res->addBody(StringUtil::format("invalid parameter: '$0'", p.first));
    return;
  }

  for (const auto& fn : tx) {
    fn();
  }

  res->setStatus(http::kStatusCreated);
}

void DocumentDBServlet::listDocuments(
    const AnalyticsSession& session,
    const http::HTTPRequest* req,
    http::HTTPResponse* res) {
  Buffer buf;
  json::JSONOutputStream json(BufferOutputStream::fromBuffer(&buf));

  json.beginObject();
  json.addObjectEntry("documents");
  json.beginArray();

  size_t i = 0;
  docdb_->listDocuments(
      session.customer(),
      session.userid(),
      [this, &i, &json, &session] (const Document& doc) -> bool {
    if (++i > 1) {
      json.addComma();
    }

    renderDocument(
        session,
        doc,
        &json,
        false);

    return true;
  });

  json.endArray();
  json.endObject();

  res->setStatus(http::kStatusOK);
  res->setHeader("Content-Type", "application/json; charset=utf-8");
  res->addBody(buf);
}

void DocumentDBServlet::renderDocument(
    const AnalyticsSession& session,
    const Document& doc,
    json::JSONOutputStream* json,
    bool return_content /* = true */) {
  json->beginObject();

  json->addObjectEntry("uuid");
  json->addString(doc.uuid());
  json->addComma();

  json->addObjectEntry("name");
  json->addString(doc.name());
  json->addComma();

  json->addObjectEntry("type");
  json->addString(doc.type());
  json->addComma();

  json->addObjectEntry("acl_policy");
  json->addString(DocumentACLPolicy_Name(doc.acl_policy()));
  json->addComma();

  json->addObjectEntry("is_readable");
  json->addBool(isDocumentReadableForUser(doc, session.userid()));
  json->addComma();

  json->addObjectEntry("is_writable");
  json->addBool(isDocumentWritableForUser(doc, session.userid()));
  json->addComma();

  json->addObjectEntry("ctime");
  json->addInteger(doc.ctime());
  json->addComma();

  json->addObjectEntry("mtime");
  json->addInteger(doc.mtime());
  json->addComma();

  json->addObjectEntry("atime");
  json->addInteger(doc.atime());

  if (return_content) {
    json->addComma();
    json->addObjectEntry("content");
    json->addString(doc.content());
  }

  json->endObject();
}

} // namespace zbase
<|endoftext|>


<commit_before>
/****************************************************************************
** Copyright (c) 2006 - 2011, the LibQxt project.
** See the Qxt AUTHORS file for a list of authors and copyright holders.
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are met:
**     * Redistributions of source code must retain the above copyright
**       notice, this list of conditions and the following disclaimer.
**     * Redistributions in binary form must reproduce the above copyright
**       notice, this list of conditions and the following disclaimer in the
**       documentation and/or other materials provided with the distribution.
**     * Neither the name of the LibQxt project nor the
**       names of its contributors may be used to endorse or promote products
**       derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
** DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
** <http://libqxt.org>  <foundation@libqxt.org>
*****************************************************************************/

#include "qxtmdns_avahi.h"
#include "qxtmdns_avahi_p.h"
#include <qxtmetaobject.h>
#include <QDebug>
#include <QNetworkInterface>
#include <QNetworkAddressEntry>
#include <QtEndian>
#include <avahi-common/error.h>

QxtMDNS::QxtMDNS(int id, QObject* parent)
		: QObject(parent)
{
	QXT_INIT_PRIVATE(QxtMDNS);
	qxt_d().info = id;
	qxt_d().client = NULL;
	qxt_d().recordbrowser = NULL;
	qxt_d().sent = false;
}

void QxtMDNS::doLookup(QString n, QObject * r, const char * m)
{
	qxt_d().name = n;
	qxt_d().receiver = r;
	qxt_d().member = QxtMetaObject::methodName(m);
	int error;
	qxt_d().client = avahi_client_new(
	                     qxtAvahiPoll(), // use the qt event loop
	                     (AvahiClientFlags)0,
	                     QxtMDNSPrivate::avahiClientCallback,
	                     &(qxt_d()),
	                     &error
	                 );
}

void QxtMDNSPrivate::avahiClientCallback(AvahiClient *s, AvahiClientState state, void *userdata)
{
	QxtMDNSPrivate* self = static_cast<QxtMDNSPrivate*>(userdata);
	self->client = s;
	if (state == AVAHI_CLIENT_S_RUNNING)
	{
		self->recordbrowser = avahi_record_browser_new(
		                          s,
		                          AVAHI_IF_UNSPEC,
		                          AVAHI_PROTO_INET,
		                          self->name.toAscii().constData(),
		                          AVAHI_DNS_CLASS_IN,
		                          AVAHI_DNS_TYPE_A,
		                          (AvahiLookupFlags)0,
					   QxtMDNSPrivate::avahiRecordBrowserCallback,
		                          self);
		if (self->recordbrowser == NULL)
		{
			self->info.setError(QHostInfo::UnknownError);
			self->info.setErrorString(avahi_strerror(avahi_client_errno(self->client)));
			QMetaObject::invokeMethod(self->receiver, self->member, Q_ARG(QHostInfo, self->info));
			self->sent = true;
			self->qxt_p().cancelLookup();
		}
	}
}

void QxtMDNSPrivate::avahiRecordBrowserCallback(AvahiRecordBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char *name, uint16_t clazz, uint16_t type, const void *rdata, size_t size, AvahiLookupResultFlags flags, void *userdata)
{
	///@TODO Support IPv6
	Q_UNUSED(interface);
	Q_UNUSED(protocol);
	Q_UNUSED(name);
	Q_UNUSED(clazz);
	Q_UNUSED(type);
	Q_UNUSED(size);
	Q_UNUSED(flags);
	QxtMDNSPrivate* self = static_cast<QxtMDNSPrivate*>(userdata);
	self->recordbrowser = b;
// 	qDebug() << "Return thing" << md->name << name << size;
	switch (event)
	{
		case AVAHI_BROWSER_NEW:
		{
			//Found an entry!
			uint32_t ip = qFromBigEndian(*static_cast<const uint32_t*>(rdata));
			if (self->sent)
			{
				QHostInfo info(self->info.lookupId());
				info.setAddresses(QList<QHostAddress>() << QHostAddress(ip));
				QMetaObject::invokeMethod(self->receiver, self->member, Q_ARG(QHostInfo, info));
			}
			else
			{
				self->addresses << QHostAddress(ip);
			}
			break;
		}
		case AVAHI_BROWSER_REMOVE:
		{
			uint32_t ip = qFromBigEndian(*static_cast<const uint32_t*>(rdata));
			self->addresses.removeAll(QHostAddress(ip));
			break;
		}
		case AVAHI_BROWSER_CACHE_EXHAUSTED:
			break;
		case AVAHI_BROWSER_ALL_FOR_NOW:
			if (self->addresses.count() == 0)
			{
				self->info.setError(QHostInfo::HostNotFound);
				self->info.setErrorString("The host was not found.");
			}
			else
			{
				self->info.setAddresses(self->addresses);
				self->addresses.clear();
			}
			QMetaObject::invokeMethod(self->receiver, self->member, Q_ARG(QHostInfo, self->info));
			self->sent = true;
			break;
		case AVAHI_BROWSER_FAILURE:

			if (self->sent)
			{
				QHostInfo info(self->info.lookupId());
				info.setError(QHostInfo::UnknownError);
				info.setErrorString(avahi_strerror(avahi_client_errno(self->client)));
				info.setAddresses(self->addresses);
				QMetaObject::invokeMethod(self->receiver, self->member, Q_ARG(QHostInfo, info));
			}
			else
			{
				self->info.setError(QHostInfo::UnknownError);
				self->info.setErrorString(avahi_strerror(avahi_client_errno(self->client)));
				self->info.setAddresses(self->addresses);
				self->addresses.clear();
				QMetaObject::invokeMethod(self->receiver, self->member, Q_ARG(QHostInfo, self->info));
				self->sent = true;
			}
			break;
	}
}

void QxtMDNS::cancelLookup()
{
	if (qxt_d().recordbrowser != NULL)
		avahi_record_browser_free(qxt_d().recordbrowser);

	if (qxt_d().client != NULL)
		avahi_client_free(qxt_d().client);

	deleteLater();
}

<commit_msg>Apparently Qt has removed the toAscii function from qt5, this replaces that function call with a call to toLocal8Bit<commit_after>
/****************************************************************************
** Copyright (c) 2006 - 2011, the LibQxt project.
** See the Qxt AUTHORS file for a list of authors and copyright holders.
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are met:
**     * Redistributions of source code must retain the above copyright
**       notice, this list of conditions and the following disclaimer.
**     * Redistributions in binary form must reproduce the above copyright
**       notice, this list of conditions and the following disclaimer in the
**       documentation and/or other materials provided with the distribution.
**     * Neither the name of the LibQxt project nor the
**       names of its contributors may be used to endorse or promote products
**       derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
** DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
** <http://libqxt.org>  <foundation@libqxt.org>
*****************************************************************************/

#include "qxtmdns_avahi.h"
#include "qxtmdns_avahi_p.h"
#include <qxtmetaobject.h>
#include <QDebug>
#include <QNetworkInterface>
#include <QNetworkAddressEntry>
#include <QtEndian>
#include <avahi-common/error.h>

QxtMDNS::QxtMDNS(int id, QObject* parent)
		: QObject(parent)
{
	QXT_INIT_PRIVATE(QxtMDNS);
	qxt_d().info = id;
	qxt_d().client = NULL;
	qxt_d().recordbrowser = NULL;
	qxt_d().sent = false;
}

void QxtMDNS::doLookup(QString n, QObject * r, const char * m)
{
	qxt_d().name = n;
	qxt_d().receiver = r;
	qxt_d().member = QxtMetaObject::methodName(m);
	int error;
	qxt_d().client = avahi_client_new(
	                     qxtAvahiPoll(), // use the qt event loop
	                     (AvahiClientFlags)0,
	                     QxtMDNSPrivate::avahiClientCallback,
	                     &(qxt_d()),
	                     &error
	                 );
}

void QxtMDNSPrivate::avahiClientCallback(AvahiClient *s, AvahiClientState state, void *userdata)
{
	QxtMDNSPrivate* self = static_cast<QxtMDNSPrivate*>(userdata);
	self->client = s;
	if (state == AVAHI_CLIENT_S_RUNNING)
	{
		self->recordbrowser = avahi_record_browser_new(
		                          s,
		                          AVAHI_IF_UNSPEC,
		                          AVAHI_PROTO_INET,
		                          self->name.toLocal8Bit().constData(),
		                          AVAHI_DNS_CLASS_IN,
		                          AVAHI_DNS_TYPE_A,
		                          (AvahiLookupFlags)0,
					   QxtMDNSPrivate::avahiRecordBrowserCallback,
		                          self);
		if (self->recordbrowser == NULL)
		{
			self->info.setError(QHostInfo::UnknownError);
			self->info.setErrorString(avahi_strerror(avahi_client_errno(self->client)));
			QMetaObject::invokeMethod(self->receiver, self->member, Q_ARG(QHostInfo, self->info));
			self->sent = true;
			self->qxt_p().cancelLookup();
		}
	}
}

void QxtMDNSPrivate::avahiRecordBrowserCallback(AvahiRecordBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char *name, uint16_t clazz, uint16_t type, const void *rdata, size_t size, AvahiLookupResultFlags flags, void *userdata)
{
	///@TODO Support IPv6
	Q_UNUSED(interface);
	Q_UNUSED(protocol);
	Q_UNUSED(name);
	Q_UNUSED(clazz);
	Q_UNUSED(type);
	Q_UNUSED(size);
	Q_UNUSED(flags);
	QxtMDNSPrivate* self = static_cast<QxtMDNSPrivate*>(userdata);
	self->recordbrowser = b;
// 	qDebug() << "Return thing" << md->name << name << size;
	switch (event)
	{
		case AVAHI_BROWSER_NEW:
		{
			//Found an entry!
			uint32_t ip = qFromBigEndian(*static_cast<const uint32_t*>(rdata));
			if (self->sent)
			{
				QHostInfo info(self->info.lookupId());
				info.setAddresses(QList<QHostAddress>() << QHostAddress(ip));
				QMetaObject::invokeMethod(self->receiver, self->member, Q_ARG(QHostInfo, info));
			}
			else
			{
				self->addresses << QHostAddress(ip);
			}
			break;
		}
		case AVAHI_BROWSER_REMOVE:
		{
			uint32_t ip = qFromBigEndian(*static_cast<const uint32_t*>(rdata));
			self->addresses.removeAll(QHostAddress(ip));
			break;
		}
		case AVAHI_BROWSER_CACHE_EXHAUSTED:
			break;
		case AVAHI_BROWSER_ALL_FOR_NOW:
			if (self->addresses.count() == 0)
			{
				self->info.setError(QHostInfo::HostNotFound);
				self->info.setErrorString("The host was not found.");
			}
			else
			{
				self->info.setAddresses(self->addresses);
				self->addresses.clear();
			}
			QMetaObject::invokeMethod(self->receiver, self->member, Q_ARG(QHostInfo, self->info));
			self->sent = true;
			break;
		case AVAHI_BROWSER_FAILURE:

			if (self->sent)
			{
				QHostInfo info(self->info.lookupId());
				info.setError(QHostInfo::UnknownError);
				info.setErrorString(avahi_strerror(avahi_client_errno(self->client)));
				info.setAddresses(self->addresses);
				QMetaObject::invokeMethod(self->receiver, self->member, Q_ARG(QHostInfo, info));
			}
			else
			{
				self->info.setError(QHostInfo::UnknownError);
				self->info.setErrorString(avahi_strerror(avahi_client_errno(self->client)));
				self->info.setAddresses(self->addresses);
				self->addresses.clear();
				QMetaObject::invokeMethod(self->receiver, self->member, Q_ARG(QHostInfo, self->info));
				self->sent = true;
			}
			break;
	}
}

void QxtMDNS::cancelLookup()
{
	if (qxt_d().recordbrowser != NULL)
		avahi_record_browser_free(qxt_d().recordbrowser);

	if (qxt_d().client != NULL)
		avahi_client_free(qxt_d().client);

	deleteLater();
}

<|endoftext|>


<commit_before>//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#include "Backend.h"

IR::Instr *Lowerer::PreLowerPeepInstr(IR::Instr *instr, IR::Instr **pInstrPrev)
{
    if (!PHASE_OFF(Js::PreLowererPeepsPhase, this->m_func))
    {
        return instr;
    }

    switch (instr->m_opcode)
    {
    case Js::OpCode::Shl_I4:
        instr = this->PeepShl(instr);
        *pInstrPrev = instr->m_prev;
        break;

    case Js::OpCode::BrTrue_I4:
    case Js::OpCode::BrFalse_I4:
        instr = this->PeepBrBool(instr);
        *pInstrPrev = instr->m_prev;
        break;
    }

    return instr;
}

IR::Instr *Lowerer::PeepShl(IR::Instr *instrShl)
{
    IR::Opnd *src1;
    IR::Opnd *src2;
    IR::Instr *instrDef;

    src1 = instrShl->GetSrc1();
    src2 = instrShl->GetSrc2();

    // Peep:
    //    t1 = SHR X, cst
    //    t2 = SHL t1, cst
    //
    // Into:
    //    t2 = AND X, mask

    if (!src1->IsRegOpnd() || !src2->IsIntConstOpnd())
    {
        return instrShl;
    }
    if (!src1->AsRegOpnd()->m_sym->IsSingleDef())
    {
        return instrShl;
    }
    if (instrShl->HasBailOutInfo())
    {
        return instrShl;
    }
    instrDef = src1->AsRegOpnd()->m_sym->GetInstrDef();
    if (instrDef->m_opcode != Js::OpCode::Shr_I4 || !instrDef->GetSrc2()->IsIntConstOpnd()
        || instrDef->GetSrc2()->AsIntConstOpnd()->GetValue() != src2->AsIntConstOpnd()->GetValue()
        || !instrDef->GetSrc1()->IsRegOpnd())
    {
        return instrShl;
    }
    if (!src1->GetIsDead())
    {
        return instrShl;
    }
    if (instrDef->HasBailOutInfo())
    {
        return instrShl;
    }
    if (IR::Instr::FindRegUseInRange(src1->AsRegOpnd()->m_sym, instrDef->m_next, instrShl->m_prev))
    {
        return instrShl;
    }

    FOREACH_INSTR_IN_RANGE(instrIter, instrDef->m_next, instrShl->m_prev)
    {
        if (instrIter->HasBailOutInfo())
        {
            return instrShl;
        }
        if (instrIter->FindRegDef(instrDef->GetSrc1()->AsRegOpnd()->m_sym))
        {
            return instrShl;
        }
        if (instrIter->FindRegUse(src1->AsRegOpnd()->m_sym))
        {
            return instrShl;
        }
    } NEXT_INSTR_IN_RANGE;

    instrShl->FreeSrc1();
    instrShl->SetSrc1(instrDef->UnlinkSrc1());
    instrDef->Remove();

    IntConstType oldValue = src2->AsIntConstOpnd()->GetValue();
    oldValue = ~((1 << oldValue) - 1);
    src2->AsIntConstOpnd()->SetValue(oldValue);

    instrShl->m_opcode = Js::OpCode::And_I4;

    return instrShl;
}

IR::Instr *Lowerer::PeepBrBool(IR::Instr *instrBr)
{
    IR::Opnd *src1;
    IR::Instr *instrBinOp, *instrCm1, *instrCm2;

    // Peep:
    //    t1 = CmCC_I4 a, b
    //    t2 = CmCC_i4 c, d
    //    t3 = AND/OR t1, t2
    //    BrTrue/False t3, $L_true
    //
    // Into:
    //    BrCC a, b,  $L_true/false
    //    BrCC c, d,  $L_true
    //$L_false:

    src1 = instrBr->GetSrc1();
    if (!src1->IsRegOpnd())
    {
        return instrBr;
    }
    Assert(!instrBr->HasBailOutInfo());

    instrBinOp = instrBr->GetPrevRealInstrOrLabel();
    if (instrBinOp->m_opcode != Js::OpCode::And_I4 && instrBinOp->m_opcode != Js::OpCode::Or_I4)
    {
        return instrBr;
    }
    if (!instrBinOp->GetDst()->IsEqual(src1))
    {
        return instrBr;
    }
    IR::RegOpnd *src1Reg = src1->AsRegOpnd();
    if (!src1Reg->m_sym->IsSingleDef() || !src1Reg->GetIsDead())
    {
        return instrBr;
    }
    Assert(!instrBinOp->HasBailOutInfo());

    instrCm2 = instrBinOp->GetPrevRealInstrOrLabel();
    if (!instrCm2->IsCmCC_I4())
    {
        return instrBr;
    }
    IR::RegOpnd *cm2DstReg = instrCm2->GetDst()->AsRegOpnd();
    if (!cm2DstReg->m_sym->IsSingleDef())
    {
        return instrBr;
    }
    if (cm2DstReg->IsEqual(instrBinOp->GetSrc1()))
    {
        if (!instrBinOp->GetSrc1()->AsRegOpnd()->GetIsDead())
        {
            return instrBr;
        }
    }
    else if (cm2DstReg->IsEqual(instrBinOp->GetSrc2()))
    {
        if (!instrBinOp->GetSrc2()->AsRegOpnd()->GetIsDead())
        {
            return instrBr;
        }
    }
    else
    {
        return instrBr;
    }

    Assert(!instrCm2->HasBailOutInfo());

    instrCm1 = instrCm2->GetPrevRealInstrOrLabel();
    if (!instrCm1->IsCmCC_I4())
    {
        return instrBr;
    }
    Assert(!instrCm1->GetDst()->IsEqual(instrCm2->GetDst()));

    IR::RegOpnd *cm1DstReg = instrCm1->GetDst()->AsRegOpnd();
    if (!cm1DstReg->m_sym->IsSingleDef())
    {
        return instrBr;
    }
    if (cm1DstReg->IsEqual(instrBinOp->GetSrc1()))
    {
        if (!instrBinOp->GetSrc1()->AsRegOpnd()->GetIsDead())
        {
            return instrBr;
        }
    }
    else if (cm1DstReg->IsEqual(instrBinOp->GetSrc2()))
    {
        if (!instrBinOp->GetSrc2()->AsRegOpnd()->GetIsDead())
        {
            return instrBr;
        }
    }
    else
    {
        return instrBr;
    }

    Assert(!instrCm1->HasBailOutInfo());

    IR::LabelInstr *falseLabel = instrBr->AsBranchInstr()->GetTarget();
    IR::LabelInstr *trueLabel = IR::LabelInstr::New(Js::OpCode::Label, this->m_func);
    instrBr->InsertAfter(trueLabel);
    IR::BranchInstr *instrBr1;
    IR::BranchInstr *instrBr2;

    if (instrBinOp->m_opcode == Js::OpCode::And_I4)
    {
        instrBr1 = instrCm1->ChangeCmCCToBranchInstr(instrBr->m_opcode == Js::OpCode::BrFalse_I4 ? falseLabel : trueLabel);
        instrBr1->Invert();
        instrBr2 = instrCm2->ChangeCmCCToBranchInstr(falseLabel);
        if (instrBr->m_opcode == Js::OpCode::BrFalse_I4)
        {
            instrBr2->Invert();
        }
    }
    else
    {
        Assert(instrBinOp->m_opcode == Js::OpCode::Or_I4);

        instrBr1 = instrCm1->ChangeCmCCToBranchInstr(instrBr->m_opcode == Js::OpCode::BrTrue_I4 ? falseLabel : trueLabel);
        instrBr2 = instrCm2->ChangeCmCCToBranchInstr(falseLabel);
        if (instrBr->m_opcode == Js::OpCode::BrFalse_I4)
        {
            instrBr2->Invert();
        }
    }

    instrBinOp->Remove();
    instrBr->Remove();

    return instrBr2;
}
<commit_msg>Correct flip logic to PrelowererPeeps<commit_after>//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#include "Backend.h"

IR::Instr *Lowerer::PreLowerPeepInstr(IR::Instr *instr, IR::Instr **pInstrPrev)
{
    if (PHASE_OFF(Js::PreLowererPeepsPhase, this->m_func))
    {
        return instr;
    }

    switch (instr->m_opcode)
    {
    case Js::OpCode::Shl_I4:
        instr = this->PeepShl(instr);
        *pInstrPrev = instr->m_prev;
        break;

    case Js::OpCode::BrTrue_I4:
    case Js::OpCode::BrFalse_I4:
        instr = this->PeepBrBool(instr);
        *pInstrPrev = instr->m_prev;
        break;
    }

    return instr;
}

IR::Instr *Lowerer::PeepShl(IR::Instr *instrShl)
{
    IR::Opnd *src1;
    IR::Opnd *src2;
    IR::Instr *instrDef;

    src1 = instrShl->GetSrc1();
    src2 = instrShl->GetSrc2();

    // Peep:
    //    t1 = SHR X, cst
    //    t2 = SHL t1, cst
    //
    // Into:
    //    t2 = AND X, mask

    if (!src1->IsRegOpnd() || !src2->IsIntConstOpnd())
    {
        return instrShl;
    }
    if (!src1->AsRegOpnd()->m_sym->IsSingleDef())
    {
        return instrShl;
    }
    if (instrShl->HasBailOutInfo())
    {
        return instrShl;
    }
    instrDef = src1->AsRegOpnd()->m_sym->GetInstrDef();
    if (instrDef->m_opcode != Js::OpCode::Shr_I4 || !instrDef->GetSrc2()->IsIntConstOpnd()
        || instrDef->GetSrc2()->AsIntConstOpnd()->GetValue() != src2->AsIntConstOpnd()->GetValue()
        || !instrDef->GetSrc1()->IsRegOpnd())
    {
        return instrShl;
    }
    if (!src1->GetIsDead())
    {
        return instrShl;
    }
    if (instrDef->HasBailOutInfo())
    {
        return instrShl;
    }
    if (IR::Instr::FindRegUseInRange(src1->AsRegOpnd()->m_sym, instrDef->m_next, instrShl->m_prev))
    {
        return instrShl;
    }

    FOREACH_INSTR_IN_RANGE(instrIter, instrDef->m_next, instrShl->m_prev)
    {
        if (instrIter->HasBailOutInfo())
        {
            return instrShl;
        }
        if (instrIter->FindRegDef(instrDef->GetSrc1()->AsRegOpnd()->m_sym))
        {
            return instrShl;
        }
        if (instrIter->FindRegUse(src1->AsRegOpnd()->m_sym))
        {
            return instrShl;
        }
    } NEXT_INSTR_IN_RANGE;

    instrShl->FreeSrc1();
    instrShl->SetSrc1(instrDef->UnlinkSrc1());
    instrDef->Remove();

    IntConstType oldValue = src2->AsIntConstOpnd()->GetValue();
    oldValue = ~((1 << oldValue) - 1);
    src2->AsIntConstOpnd()->SetValue(oldValue);

    instrShl->m_opcode = Js::OpCode::And_I4;

    return instrShl;
}

IR::Instr *Lowerer::PeepBrBool(IR::Instr *instrBr)
{
    IR::Opnd *src1;
    IR::Instr *instrBinOp, *instrCm1, *instrCm2;

    // Peep:
    //    t1 = CmCC_I4 a, b
    //    t2 = CmCC_i4 c, d
    //    t3 = AND/OR t1, t2
    //    BrTrue/False t3, $L_true
    //
    // Into:
    //    BrCC a, b,  $L_true/false
    //    BrCC c, d,  $L_true
    //$L_false:

    src1 = instrBr->GetSrc1();
    if (!src1->IsRegOpnd())
    {
        return instrBr;
    }
    Assert(!instrBr->HasBailOutInfo());

    instrBinOp = instrBr->GetPrevRealInstrOrLabel();
    if (instrBinOp->m_opcode != Js::OpCode::And_I4 && instrBinOp->m_opcode != Js::OpCode::Or_I4)
    {
        return instrBr;
    }
    if (!instrBinOp->GetDst()->IsEqual(src1))
    {
        return instrBr;
    }
    IR::RegOpnd *src1Reg = src1->AsRegOpnd();
    if (!src1Reg->m_sym->IsSingleDef() || !src1Reg->GetIsDead())
    {
        return instrBr;
    }
    Assert(!instrBinOp->HasBailOutInfo());

    instrCm2 = instrBinOp->GetPrevRealInstrOrLabel();
    if (!instrCm2->IsCmCC_I4())
    {
        return instrBr;
    }
    IR::RegOpnd *cm2DstReg = instrCm2->GetDst()->AsRegOpnd();
    if (!cm2DstReg->m_sym->IsSingleDef())
    {
        return instrBr;
    }
    if (cm2DstReg->IsEqual(instrBinOp->GetSrc1()))
    {
        if (!instrBinOp->GetSrc1()->AsRegOpnd()->GetIsDead())
        {
            return instrBr;
        }
    }
    else if (cm2DstReg->IsEqual(instrBinOp->GetSrc2()))
    {
        if (!instrBinOp->GetSrc2()->AsRegOpnd()->GetIsDead())
        {
            return instrBr;
        }
    }
    else
    {
        return instrBr;
    }

    Assert(!instrCm2->HasBailOutInfo());

    instrCm1 = instrCm2->GetPrevRealInstrOrLabel();
    if (!instrCm1->IsCmCC_I4())
    {
        return instrBr;
    }
    Assert(!instrCm1->GetDst()->IsEqual(instrCm2->GetDst()));

    IR::RegOpnd *cm1DstReg = instrCm1->GetDst()->AsRegOpnd();
    if (!cm1DstReg->m_sym->IsSingleDef())
    {
        return instrBr;
    }
    if (cm1DstReg->IsEqual(instrBinOp->GetSrc1()))
    {
        if (!instrBinOp->GetSrc1()->AsRegOpnd()->GetIsDead())
        {
            return instrBr;
        }
    }
    else if (cm1DstReg->IsEqual(instrBinOp->GetSrc2()))
    {
        if (!instrBinOp->GetSrc2()->AsRegOpnd()->GetIsDead())
        {
            return instrBr;
        }
    }
    else
    {
        return instrBr;
    }

    Assert(!instrCm1->HasBailOutInfo());

    IR::LabelInstr *falseLabel = instrBr->AsBranchInstr()->GetTarget();
    IR::LabelInstr *trueLabel = IR::LabelInstr::New(Js::OpCode::Label, this->m_func);
    instrBr->InsertAfter(trueLabel);
    IR::BranchInstr *instrBr1;
    IR::BranchInstr *instrBr2;

    if (instrBinOp->m_opcode == Js::OpCode::And_I4)
    {
        instrBr1 = instrCm1->ChangeCmCCToBranchInstr(instrBr->m_opcode == Js::OpCode::BrFalse_I4 ? falseLabel : trueLabel);
        instrBr1->Invert();
        instrBr2 = instrCm2->ChangeCmCCToBranchInstr(falseLabel);
        if (instrBr->m_opcode == Js::OpCode::BrFalse_I4)
        {
            instrBr2->Invert();
        }
    }
    else
    {
        Assert(instrBinOp->m_opcode == Js::OpCode::Or_I4);

        instrBr1 = instrCm1->ChangeCmCCToBranchInstr(instrBr->m_opcode == Js::OpCode::BrTrue_I4 ? falseLabel : trueLabel);
        instrBr2 = instrCm2->ChangeCmCCToBranchInstr(falseLabel);
        if (instrBr->m_opcode == Js::OpCode::BrFalse_I4)
        {
            instrBr2->Invert();
        }
    }

    instrBinOp->Remove();
    instrBr->Remove();

    return instrBr2;
}
<|endoftext|>


<commit_before>struct Date{
    int d,m,y;
    static int month[], monthsum[];
    Date() : d(1), m(1), y(1) {}
    Date(int d, int m, int y) : d(d), m(m), y(y) {}
    Date(int days) : d(1), m(1), y(1) {
        advance(days);
    }
    int mdays() {
        if(m!=2)
            return month[m];
        return 28+bissexto();
    }
    int ydays() {
        return 365+bissexto();
    }
    int msum() {
        return monthsum[m]+(bissexto() and m>2);
    }
    bool bissexto() {
        return (y%4 == 0 and y%100) or (y%400 == 0);
    }
    int count() {
        int ans = d-1 + msum();

        ans += 365*(y-1);
        ans += (y-1)/4;
        ans -= (y-1)/100;
        ans += (y-1)/400;

        return ans;
    }
    void advance(int days) {
        days += count();
        d = m = 1;
        y = 1 + days/366;
        days -= count();
        while(days >= ydays())
            days -= ydays(), y++;
        while(days >= mdays())
            days -= mdays(), m++;
        d += days;
    }
};
int Date::month[] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
int Date::monthsum[] = {0,0,31,59,90,120,151,181,212,243,273,304,334,365};
<commit_msg>Made Date code less verbose and less error prone.<commit_after>struct Date {
  int d, m, y;
  static int mnt[], mntsum[];

  Date() : d(1), m(1), y(1) {}
  Date(int d, int m, int y) : d(d), m(m), y(y) {}
  Date(int days) : d(1), m(1), y(1) { advance(days); }

  bool bissexto() { return (y%4 == 0 and y%100) or (y%400 == 0); }

  int mdays() { return mnt[m] + (m == 2)*bissexto(); }
  int ydays() { return 365+bissexto(); }

  int msum()  { return mntsum[m-1] + (m > 2)*bissexto(); }
  int ysum()  { return 365*(y-1) + (y-1)/4 - (y-1)/100 + (y-1)/400; }

  int count() { return (d-1) + msum() + ysum(); }

  int day() {
    int x = y - (m<3);
    return (x + x/4 - x/100 + x/400 + mntsum[m-1] + d + 6)%7;
  }

  void advance(int days) {
    days += count();
    d = m = 1, y = 1 + days/366;
    days -= count();
    while(days >= ydays()) days -= ydays(), y++;
    while(days >= mdays()) days -= mdays(), m++;
    d += days;
  }
};

int Date::mnt[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int Date::mntsum[13] = {};
for(int i=1; i<13; ++i) Date::mntsum[i] = Date::mntsum[i-1] + Date::mnt[i];
<|endoftext|>