<commit_before>AliAnalysisTaskSEXic2eleXifromAODtracks *AddTaskXic2eleXifromAODtracks(TString finname="",
								   Bool_t theMCon=kFALSE,
								   Int_t iscoltype= 0,
								   Bool_t writeVariableTree=kTRUE,
								   Bool_t domixing=kFALSE,
								   Bool_t reconstructPrimVert=kFALSE,
								   Bool_t writeEachVariableTree=kFALSE,
								   Bool_t writeMCVariableTree=kFALSE,
				                   TString estimatorFilename="",
								   Int_t nTour=0
								   )

{

  AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
  if (!mgr) {
    ::Error("AddTaskLc2V0YW", "No analysis manager to connect to.");
    return NULL;
  }

  Bool_t stdcuts=kFALSE;
  TFile* filecuts;
  if( finname.EqualTo("") ) {
    stdcuts=kTRUE;
  } else {
    filecuts=TFile::Open(finname.Data());
    if(!filecuts ||(filecuts&& !filecuts->IsOpen())){
      Printf("FATAL: Input file not found : check your cut object");
      return NULL;
    }
  }

  AliRDHFCutsXictoeleXifromAODtracks* RDHFCutsXic2eleXianal = new AliRDHFCutsXictoeleXifromAODtracks();
  if (stdcuts) RDHFCutsXic2eleXianal->SetStandardCutsPP2010();
  else RDHFCutsXic2eleXianal = (AliRDHFCutsXictoeleXifromAODtracks*)filecuts->Get("eleXiAnalysisCuts");
  RDHFCutsXic2eleXianal->SetName("eleXiAnalysisCuts");
  RDHFCutsXic2eleXianal->SetMinPtCandidate(-1.);
  RDHFCutsXic2eleXianal->SetMaxPtCandidate(10000.);
  if (!RDHFCutsXic2eleXianal) {
    cout << "Specific AliRDHFCutsXic2eleXianal not found\n";
    return NULL;
  }

  //CREATE THE TASK

  printf("CREATE TASK\n");
  AliAnalysisTaskSEXic2eleXifromAODtracks *task = new AliAnalysisTaskSEXic2eleXifromAODtracks("AliAnalysisTaskSEXic2eleXifromAODtracks",RDHFCutsXic2eleXianal,writeVariableTree);
  task->SetMC(theMCon);
	if(iscoltype==0){
		task->SetUseCentralityV0M(kFALSE);
		task->SetUseCentralitySPDTracklet(kFALSE);
	}else{
		task->SetUseCentralityV0M(kTRUE);
		task->SetUseEventPlane(4);
	}
  task->SetDebugLevel(1);
  task->SetReconstructPrimVert(reconstructPrimVert);
  task->SetWriteEachVariableTree(writeEachVariableTree);
  task->SetWriteMCVariableTree(writeMCVariableTree);
  if(domixing)
    task->SetEventMixingWithPools();
  else
    task->SetEventMixingOff();

	//PVz Binning for pool PP or PbPb
	Double_t pvzbinlimits[] = {-12,-10,-8,-6,-4,-2,0,2,4,6,8,10,12};
	Int_t pvzbinnumb = sizeof(pvzbinlimits)/sizeof(Double_t) - 1;

	//Cent Binning for pool	pPb
	Double_t cent_mult_binlimitspPb[] = { 0,10,20,30,40,50,60,70,80,90,100};
	Int_t cent_mult_bin_numbpPb = sizeof(cent_mult_binlimitspPb)/sizeof(Double_t) - 1;
	Double_t cent_mult_binlimitspp[] = { 0,100};
	Int_t cent_mult_bin_numbpp = sizeof(cent_mult_binlimitspp)/sizeof(Double_t) - 1;
	Double_t cent_mult_binlimitsPbPb[] = { 0,2.5,5,7.5,10,20,30,40,50,60,70,80,90,100};
	Int_t cent_mult_bin_numbPbPb = sizeof(cent_mult_binlimitsPbPb)/sizeof(Double_t) - 1;

	task->SetPoolPVzBinLimits(pvzbinnumb,pvzbinlimits);
	if(iscoltype==0){
		task->SetPoolCentBinLimits(cent_mult_bin_numbpp,cent_mult_binlimitspp);
		task->SetNumberOfEventsForMixing(10);//pp
  }else if(iscoltype==0){
		task->SetPoolCentBinLimits(cent_mult_bin_numbpPb,cent_mult_binlimitspPb);
		task->SetNumberOfEventsForMixing(10);//pPb
	}else{
		task->SetPoolCentBinLimits(cent_mult_bin_numbPbPb,cent_mult_binlimitsPbPb);
		task->SetNumberOfEventsForMixing(10);//PbPb
	}

  if(iscoltype==0 || iscoltype==1){
    Int_t nrpbin = 1.;
    Double_t rpbinlimits[2] = {-3.2,3.2};
    task->SetPoolRPBinLimits(nrpbin,rpbinlimits);
  }else{
    Int_t nrpbin = 8;
    Double_t rpbinlimits[9];
    Double_t steprp = TMath::Pi()/(Double_t)nrpbin;
    for(Int_t ir=0;ir<9;ir++){
      rpbinlimits[ir] = -1.*TMath::Pi()/2. + steprp * (Double_t) ir;
    }
    task->SetPoolRPBinLimits(nrpbin,rpbinlimits);
  }

  //multiplicity study
  if(iscoltype==0){
    if(estimatorFilename.EqualTo("") ) {
      printf("Estimator file not provided, multiplcity corrected histograms will not be filled\n");
    } else{
      TFile* fileEstimator=TFile::Open(estimatorFilename.Data());
      if(!fileEstimator)  {
        Printf("FATAL: File with multiplicity estimator not found\n");
        return NULL;
      }
      task->SetReferenceMultiplcity(9.26);
      const Char_t* profilebasename="SPDmult10";
      const Char_t* periodNames[4] = {"LHC10b", "LHC10c", "LHC10d", "LHC10e"};
      TProfile* multEstimatorAvg[4];
      for(Int_t ip=0; ip<4; ip++) {
        multEstimatorAvg[ip] = (TProfile*)(fileEstimator->Get(Form("%s_%s",profilebasename,periodNames[ip]))->Clone(Form("%s_%s_clone",profilebasename,periodNames[ip])));
        if (!multEstimatorAvg[ip]) {
          Printf("Multiplicity estimator for %s not found! Please check your estimator file",periodNames[ip]);
          return NULL;
        }
      }
      task->SetMultiplVsZProfileLHC10b(multEstimatorAvg[0]);
      task->SetMultiplVsZProfileLHC10c(multEstimatorAvg[1]);
      task->SetMultiplVsZProfileLHC10d(multEstimatorAvg[2]);
      task->SetMultiplVsZProfileLHC10e(multEstimatorAvg[3]);
    }
  }

	TF1 * weightfit = new TF1("weightfit","expo");
	weightfit -> SetParameter(0,7.39393e-01);
	weightfit -> SetParameter(1,-2.03822e-01);
    task -> SetFunction(weightfit);

	//============== weight process for the acceptance phi distribution
	// =========== electron =================================
	  TF1 * AccWeight = new TF1("AccWeight","expo+pol4(2)");
      AccWeight -> SetParameter(0,7.25182e+00);
      AccWeight -> SetParameter(1,-1.59753e+01);
      AccWeight -> SetParameter(2,1.48939e-01);
      AccWeight -> SetParameter(3,-2.29063e-01);
      AccWeight -> SetParameter(4,1.78563e-01);
      AccWeight -> SetParameter(5,-5.70464e-02);
      AccWeight -> SetParameter(6,6.25614e-03);
      task -> SetFunctionElectron(AccWeight);
   // ============== positron ================================
      TF1 * AccWeightPositron = new TF1("AccWeightPositron","expo+pol4(2)");
      AccWeightPositron -> SetParameter(0,7.23466e+00);
      AccWeightPositron -> SetParameter(1,-1.59978e+01);
      AccWeightPositron -> SetParameter(2,1.25472e-01);
      AccWeightPositron -> SetParameter(3,-1.80599e-01);
      AccWeightPositron -> SetParameter(4,1.43474e-01);
      AccWeightPositron -> SetParameter(5,-4.66011e-02);
      AccWeightPositron -> SetParameter(6,5.17285e-03);

      task -> SetFunctionPositron(AccWeightPositron);

	mgr->AddTask(task);

  // Create and connect containers for input/output
  TString outputfile = AliAnalysisManager::GetCommonFileName();
  outputfile += ":PWG3_D2H_Xic2eleXi_";
  outputfile += nTour;

  mgr->ConnectInput(task,0,mgr->GetCommonInputContainer());

  // ----- output data -----
  AliAnalysisDataContainer *coutput1   = mgr->CreateContainer(Form("Xichist%1d",nTour),TList::Class(),AliAnalysisManager::kOutputContainer,outputfile.Data()); // general histos
  mgr->ConnectOutput(task,1,coutput1);
  AliAnalysisDataContainer *coutputLc2 = mgr->CreateContainer(Form("Xic2eleXiCuts%1d",nTour),TList::Class(),AliAnalysisManager::kOutputContainer,outputfile.Data()); // cuts
  mgr->ConnectOutput(task,2,coutputLc2);

  AliAnalysisDataContainer *coutputLc3 = mgr->CreateContainer(Form("eleXiHisto%1d",nTour),TList::Class(),AliAnalysisManager::kOutputContainer,outputfile.Data()); // variables tree
  mgr->ConnectOutput(task,3,coutputLc3);

  AliAnalysisDataContainer *coutputLc4 = mgr->CreateContainer(Form("eleXivariables%1d",nTour),TTree::Class(),AliAnalysisManager::kOutputContainer,outputfile.Data()); // variables tree
  mgr->ConnectOutput(task,4,coutputLc4);
  AliAnalysisDataContainer *coutputLc5 = mgr->CreateContainer(Form("eleXi_elevariables%1d",nTour),TTree::Class(),AliAnalysisManager::kOutputContainer,outputfile.Data()); // variables tree
  mgr->ConnectOutput(task,5,coutputLc5);
  AliAnalysisDataContainer *coutputLc6 = mgr->CreateContainer(Form("eleXi_cascvariables%1d",nTour),TTree::Class(),AliAnalysisManager::kOutputContainer,outputfile.Data()); // variables tree
  mgr->ConnectOutput(task,6,coutputLc6);
  AliAnalysisDataContainer *coutputLc7 = mgr->CreateContainer(Form("eleXi_mcvariables%1d",nTour),TTree::Class(),AliAnalysisManager::kOutputContainer,outputfile.Data()); // variables tree
  mgr->ConnectOutput(task,7,coutputLc7);
  AliAnalysisDataContainer *coutputLc8 = mgr->CreateContainer(Form("eleXiCounter%1d",nTour),AliNormalizationCounter::Class(),AliAnalysisManager::kOutputContainer, outputfile.Data()); //counter
  mgr->ConnectOutput(task,8,coutputLc8);
  AliAnalysisDataContainer *coutputLc9 = mgr->CreateContainer(Form("eleXi_mcelevariables%1d",nTour),TTree::Class(),AliAnalysisManager::kOutputContainer,outputfile.Data()); // variables tree
  mgr->ConnectOutput(task,9,coutputLc9);
  AliAnalysisDataContainer *coutputLc10 = mgr->CreateContainer(Form("eleXi_mccascvariables%1d",nTour),TTree::Class(),AliAnalysisManager::kOutputContainer,outputfile.Data()); // variables tree
  mgr->ConnectOutput(task,10,coutputLc10);
  //AliAnalysisDataContainer *coutputLc11 = mgr->CreateContainer(Form("eleXi_mcgenpairvariables%1d",nTour),TTree::Class(),AliAnalysisManager::kOutputContainer,outputfile.Data()); // variables tree
  //mgr->ConnectOutput(task,11,coutputLc11);
  AliAnalysisDataContainer *coutputLc11 = mgr->CreateContainer(Form("eleXi_singlevariables%1d",nTour),TTree::Class(),AliAnalysisManager::kOutputContainer,outputfile.Data()); // variables tree
  mgr->ConnectOutput(task,11,coutputLc11);
  AliAnalysisDataContainer *coutputLc12 = mgr->CreateContainer(Form("eleXi_correlationvariables%1d",nTour),TTree::Class(),AliAnalysisManager::kOutputContainer,outputfile.Data()); // variables tree
  mgr->ConnectOutput(task,12,coutputLc12);

  return task;

}
<commit_msg>new weight factor since efficiency correction<commit_after>AliAnalysisTaskSEXic2eleXifromAODtracks *AddTaskXic2eleXifromAODtracks(TString finname="",
								   Bool_t theMCon=kFALSE,
								   Int_t iscoltype= 0,
								   Bool_t writeVariableTree=kTRUE,
								   Bool_t domixing=kFALSE,
								   Bool_t reconstructPrimVert=kFALSE,
								   Bool_t writeEachVariableTree=kFALSE,
								   Bool_t writeMCVariableTree=kFALSE,
				                   TString estimatorFilename="",
								   Int_t nTour=0
								   )

{

  AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
  if (!mgr) {
    ::Error("AddTaskLc2V0YW", "No analysis manager to connect to.");
    return NULL;
  }

  Bool_t stdcuts=kFALSE;
  TFile* filecuts;
  if( finname.EqualTo("") ) {
    stdcuts=kTRUE;
  } else {
    filecuts=TFile::Open(finname.Data());
    if(!filecuts ||(filecuts&& !filecuts->IsOpen())){
      Printf("FATAL: Input file not found : check your cut object");
      return NULL;
    }
  }

  AliRDHFCutsXictoeleXifromAODtracks* RDHFCutsXic2eleXianal = new AliRDHFCutsXictoeleXifromAODtracks();
  if (stdcuts) RDHFCutsXic2eleXianal->SetStandardCutsPP2010();
  else RDHFCutsXic2eleXianal = (AliRDHFCutsXictoeleXifromAODtracks*)filecuts->Get("eleXiAnalysisCuts");
  RDHFCutsXic2eleXianal->SetName("eleXiAnalysisCuts");
  RDHFCutsXic2eleXianal->SetMinPtCandidate(-1.);
  RDHFCutsXic2eleXianal->SetMaxPtCandidate(10000.);
  if (!RDHFCutsXic2eleXianal) {
    cout << "Specific AliRDHFCutsXic2eleXianal not found\n";
    return NULL;
  }

  //CREATE THE TASK

  printf("CREATE TASK\n");
  AliAnalysisTaskSEXic2eleXifromAODtracks *task = new AliAnalysisTaskSEXic2eleXifromAODtracks("AliAnalysisTaskSEXic2eleXifromAODtracks",RDHFCutsXic2eleXianal,writeVariableTree);
  task->SetMC(theMCon);
	if(iscoltype==0){
		task->SetUseCentralityV0M(kFALSE);
		task->SetUseCentralitySPDTracklet(kFALSE);
	}else{
		task->SetUseCentralityV0M(kTRUE);
		task->SetUseEventPlane(4);
	}
  task->SetDebugLevel(1);
  task->SetReconstructPrimVert(reconstructPrimVert);
  task->SetWriteEachVariableTree(writeEachVariableTree);
  task->SetWriteMCVariableTree(writeMCVariableTree);
  if(domixing)
    task->SetEventMixingWithPools();
  else
    task->SetEventMixingOff();

	//PVz Binning for pool PP or PbPb
	Double_t pvzbinlimits[] = {-12,-10,-8,-6,-4,-2,0,2,4,6,8,10,12};
	Int_t pvzbinnumb = sizeof(pvzbinlimits)/sizeof(Double_t) - 1;

	//Cent Binning for pool	pPb
	Double_t cent_mult_binlimitspPb[] = { 0,10,20,30,40,50,60,70,80,90,100};
	Int_t cent_mult_bin_numbpPb = sizeof(cent_mult_binlimitspPb)/sizeof(Double_t) - 1;
	Double_t cent_mult_binlimitspp[] = { 0,100};
	Int_t cent_mult_bin_numbpp = sizeof(cent_mult_binlimitspp)/sizeof(Double_t) - 1;
	Double_t cent_mult_binlimitsPbPb[] = { 0,2.5,5,7.5,10,20,30,40,50,60,70,80,90,100};
	Int_t cent_mult_bin_numbPbPb = sizeof(cent_mult_binlimitsPbPb)/sizeof(Double_t) - 1;

	task->SetPoolPVzBinLimits(pvzbinnumb,pvzbinlimits);
	if(iscoltype==0){
		task->SetPoolCentBinLimits(cent_mult_bin_numbpp,cent_mult_binlimitspp);
		task->SetNumberOfEventsForMixing(10);//pp
  }else if(iscoltype==0){
		task->SetPoolCentBinLimits(cent_mult_bin_numbpPb,cent_mult_binlimitspPb);
		task->SetNumberOfEventsForMixing(10);//pPb
	}else{
		task->SetPoolCentBinLimits(cent_mult_bin_numbPbPb,cent_mult_binlimitsPbPb);
		task->SetNumberOfEventsForMixing(10);//PbPb
	}

  if(iscoltype==0 || iscoltype==1){
    Int_t nrpbin = 1.;
    Double_t rpbinlimits[2] = {-3.2,3.2};
    task->SetPoolRPBinLimits(nrpbin,rpbinlimits);
  }else{
    Int_t nrpbin = 8;
    Double_t rpbinlimits[9];
    Double_t steprp = TMath::Pi()/(Double_t)nrpbin;
    for(Int_t ir=0;ir<9;ir++){
      rpbinlimits[ir] = -1.*TMath::Pi()/2. + steprp * (Double_t) ir;
    }
    task->SetPoolRPBinLimits(nrpbin,rpbinlimits);
  }

  //multiplicity study
  if(iscoltype==0){
    if(estimatorFilename.EqualTo("") ) {
      printf("Estimator file not provided, multiplcity corrected histograms will not be filled\n");
    } else{
      TFile* fileEstimator=TFile::Open(estimatorFilename.Data());
      if(!fileEstimator)  {
        Printf("FATAL: File with multiplicity estimator not found\n");
        return NULL;
      }
      task->SetReferenceMultiplcity(9.26);
      const Char_t* profilebasename="SPDmult10";
      const Char_t* periodNames[4] = {"LHC10b", "LHC10c", "LHC10d", "LHC10e"};
      TProfile* multEstimatorAvg[4];
      for(Int_t ip=0; ip<4; ip++) {
        multEstimatorAvg[ip] = (TProfile*)(fileEstimator->Get(Form("%s_%s",profilebasename,periodNames[ip]))->Clone(Form("%s_%s_clone",profilebasename,periodNames[ip])));
        if (!multEstimatorAvg[ip]) {
          Printf("Multiplicity estimator for %s not found! Please check your estimator file",periodNames[ip]);
          return NULL;
        }
      }
      task->SetMultiplVsZProfileLHC10b(multEstimatorAvg[0]);
      task->SetMultiplVsZProfileLHC10c(multEstimatorAvg[1]);
      task->SetMultiplVsZProfileLHC10d(multEstimatorAvg[2]);
      task->SetMultiplVsZProfileLHC10e(multEstimatorAvg[3]);
    }
  }

	TF1 * weightfit = new TF1("weightfit","expo");
	weightfit -> SetParameter(0,9.60710e-01);
	weightfit -> SetParameter(1,-2.76085e-01);
    task -> SetFunction(weightfit);

	//============== weight process for the acceptance phi distribution
	// =========== electron =================================
	  TF1 * AccWeight = new TF1("AccWeight","expo+pol4(2)");
      AccWeight -> SetParameter(0,7.25182e+00);
      AccWeight -> SetParameter(1,-1.59753e+01);
      AccWeight -> SetParameter(2,1.48939e-01);
      AccWeight -> SetParameter(3,-2.29063e-01);
      AccWeight -> SetParameter(4,1.78563e-01);
      AccWeight -> SetParameter(5,-5.70464e-02);
      AccWeight -> SetParameter(6,6.25614e-03);
      task -> SetFunctionElectron(AccWeight);
   // ============== positron ================================
      TF1 * AccWeightPositron = new TF1("AccWeightPositron","expo+pol4(2)");
      AccWeightPositron -> SetParameter(0,7.23466e+00);
      AccWeightPositron -> SetParameter(1,-1.59978e+01);
      AccWeightPositron -> SetParameter(2,1.25472e-01);
      AccWeightPositron -> SetParameter(3,-1.80599e-01);
      AccWeightPositron -> SetParameter(4,1.43474e-01);
      AccWeightPositron -> SetParameter(5,-4.66011e-02);
      AccWeightPositron -> SetParameter(6,5.17285e-03);

      task -> SetFunctionPositron(AccWeightPositron);

	mgr->AddTask(task);

  // Create and connect containers for input/output
  TString outputfile = AliAnalysisManager::GetCommonFileName();
  outputfile += ":PWG3_D2H_Xic2eleXi_";
  outputfile += nTour;

  mgr->ConnectInput(task,0,mgr->GetCommonInputContainer());

  // ----- output data -----
  AliAnalysisDataContainer *coutput1   = mgr->CreateContainer(Form("Xichist%1d",nTour),TList::Class(),AliAnalysisManager::kOutputContainer,outputfile.Data()); // general histos
  mgr->ConnectOutput(task,1,coutput1);
  AliAnalysisDataContainer *coutputLc2 = mgr->CreateContainer(Form("Xic2eleXiCuts%1d",nTour),TList::Class(),AliAnalysisManager::kOutputContainer,outputfile.Data()); // cuts
  mgr->ConnectOutput(task,2,coutputLc2);

  AliAnalysisDataContainer *coutputLc3 = mgr->CreateContainer(Form("eleXiHisto%1d",nTour),TList::Class(),AliAnalysisManager::kOutputContainer,outputfile.Data()); // variables tree
  mgr->ConnectOutput(task,3,coutputLc3);

  AliAnalysisDataContainer *coutputLc4 = mgr->CreateContainer(Form("eleXivariables%1d",nTour),TTree::Class(),AliAnalysisManager::kOutputContainer,outputfile.Data()); // variables tree
  mgr->ConnectOutput(task,4,coutputLc4);
  AliAnalysisDataContainer *coutputLc5 = mgr->CreateContainer(Form("eleXi_elevariables%1d",nTour),TTree::Class(),AliAnalysisManager::kOutputContainer,outputfile.Data()); // variables tree
  mgr->ConnectOutput(task,5,coutputLc5);
  AliAnalysisDataContainer *coutputLc6 = mgr->CreateContainer(Form("eleXi_cascvariables%1d",nTour),TTree::Class(),AliAnalysisManager::kOutputContainer,outputfile.Data()); // variables tree
  mgr->ConnectOutput(task,6,coutputLc6);
  AliAnalysisDataContainer *coutputLc7 = mgr->CreateContainer(Form("eleXi_mcvariables%1d",nTour),TTree::Class(),AliAnalysisManager::kOutputContainer,outputfile.Data()); // variables tree
  mgr->ConnectOutput(task,7,coutputLc7);
  AliAnalysisDataContainer *coutputLc8 = mgr->CreateContainer(Form("eleXiCounter%1d",nTour),AliNormalizationCounter::Class(),AliAnalysisManager::kOutputContainer, outputfile.Data()); //counter
  mgr->ConnectOutput(task,8,coutputLc8);
  AliAnalysisDataContainer *coutputLc9 = mgr->CreateContainer(Form("eleXi_mcelevariables%1d",nTour),TTree::Class(),AliAnalysisManager::kOutputContainer,outputfile.Data()); // variables tree
  mgr->ConnectOutput(task,9,coutputLc9);
  AliAnalysisDataContainer *coutputLc10 = mgr->CreateContainer(Form("eleXi_mccascvariables%1d",nTour),TTree::Class(),AliAnalysisManager::kOutputContainer,outputfile.Data()); // variables tree
  mgr->ConnectOutput(task,10,coutputLc10);
  //AliAnalysisDataContainer *coutputLc11 = mgr->CreateContainer(Form("eleXi_mcgenpairvariables%1d",nTour),TTree::Class(),AliAnalysisManager::kOutputContainer,outputfile.Data()); // variables tree
  //mgr->ConnectOutput(task,11,coutputLc11);
  AliAnalysisDataContainer *coutputLc11 = mgr->CreateContainer(Form("eleXi_singlevariables%1d",nTour),TTree::Class(),AliAnalysisManager::kOutputContainer,outputfile.Data()); // variables tree
  mgr->ConnectOutput(task,11,coutputLc11);
  AliAnalysisDataContainer *coutputLc12 = mgr->CreateContainer(Form("eleXi_correlationvariables%1d",nTour),TTree::Class(),AliAnalysisManager::kOutputContainer,outputfile.Data()); // variables tree
  mgr->ConnectOutput(task,12,coutputLc12);

  return task;

}
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2015-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#include "TouchEventEmitter.h"

namespace facebook {
namespace react {

#pragma mark - Touches

static folly::dynamic touchPayload(const Touch &touch) {
  folly::dynamic object = folly::dynamic::object();
  object["locationX"] = touch.offsetPoint.x;
  object["locationY"] = touch.offsetPoint.x;
  object["pageX"] = touch.pagePoint.x;
  object["pageY"] = touch.pagePoint.x;
  object["screenX"] = touch.screenPoint.x;
  object["screenY"] = touch.screenPoint.x;
  object["identifier"] = touch.identifier;
  object["target"] = touch.target;
  object["timestamp"] = touch.timestamp * 1000;
  object["force"] = touch.force;
  return object;
}

static folly::dynamic touchesPayload(const Touches &touches) {
  folly::dynamic array = folly::dynamic::array();
  for (const auto &touch : touches) {
    array.push_back(touchPayload(touch));
  }
  return array;
}

static folly::dynamic touchEventPayload(const TouchEvent &event) {
  folly::dynamic object = folly::dynamic::object();
  object["touches"] = touchesPayload(event.touches);
  object["changedTouches"] = touchesPayload(event.changedTouches);
  object["targetTouches"] = touchesPayload(event.targetTouches);
  return object;
}

void TouchEventEmitter::onTouchStart(const TouchEvent &event) const {
  dispatchEvent(
      "touchStart",
      touchEventPayload(event),
      EventPriority::SynchronousUnbatched);
}

void TouchEventEmitter::onTouchMove(const TouchEvent &event) const {
  dispatchEvent(
      "touchMove", touchEventPayload(event), EventPriority::SynchronousBatched);
}

void TouchEventEmitter::onTouchEnd(const TouchEvent &event) const {
  dispatchEvent(
      "touchEnd", touchEventPayload(event), EventPriority::SynchronousBatched);
}

void TouchEventEmitter::onTouchCancel(const TouchEvent &event) const {
  dispatchEvent(
      "touchCancel",
      touchEventPayload(event),
      EventPriority::SynchronousBatched);
}

} // namespace react
} // namespace facebook
<commit_msg>TouchEventEmitter: Fix assignment of Y coordinates (#22160)<commit_after>/**
 * Copyright (c) 2015-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#include "TouchEventEmitter.h"

namespace facebook {
namespace react {

#pragma mark - Touches

static folly::dynamic touchPayload(const Touch &touch) {
  folly::dynamic object = folly::dynamic::object();
  object["locationX"] = touch.offsetPoint.x;
  object["locationY"] = touch.offsetPoint.y;
  object["pageX"] = touch.pagePoint.x;
  object["pageY"] = touch.pagePoint.y;
  object["screenX"] = touch.screenPoint.x;
  object["screenY"] = touch.screenPoint.y;
  object["identifier"] = touch.identifier;
  object["target"] = touch.target;
  object["timestamp"] = touch.timestamp * 1000;
  object["force"] = touch.force;
  return object;
}

static folly::dynamic touchesPayload(const Touches &touches) {
  folly::dynamic array = folly::dynamic::array();
  for (const auto &touch : touches) {
    array.push_back(touchPayload(touch));
  }
  return array;
}

static folly::dynamic touchEventPayload(const TouchEvent &event) {
  folly::dynamic object = folly::dynamic::object();
  object["touches"] = touchesPayload(event.touches);
  object["changedTouches"] = touchesPayload(event.changedTouches);
  object["targetTouches"] = touchesPayload(event.targetTouches);
  return object;
}

void TouchEventEmitter::onTouchStart(const TouchEvent &event) const {
  dispatchEvent(
      "touchStart",
      touchEventPayload(event),
      EventPriority::SynchronousUnbatched);
}

void TouchEventEmitter::onTouchMove(const TouchEvent &event) const {
  dispatchEvent(
      "touchMove", touchEventPayload(event), EventPriority::SynchronousBatched);
}

void TouchEventEmitter::onTouchEnd(const TouchEvent &event) const {
  dispatchEvent(
      "touchEnd", touchEventPayload(event), EventPriority::SynchronousBatched);
}

void TouchEventEmitter::onTouchCancel(const TouchEvent &event) const {
  dispatchEvent(
      "touchCancel",
      touchEventPayload(event),
      EventPriority::SynchronousBatched);
}

} // namespace react
} // namespace facebook
<|endoftext|>


<commit_before>#include <v8.h>
#include <node.h>
#include <unistd.h>
#include <string>
#include <map>
#include <exiv2/image.hpp>
#include <exiv2/exif.hpp>

using namespace node;
using namespace v8;

/* structure for passing our various objects around libuv */
typedef std::map<std::string, std::string> tag_map_t;
struct exiv2node_thread_data_t {
  uv_work_t request;
  Exiv2::Image::AutoPtr image;
  Persistent<Function> cb;
  std::string fileName;
  tag_map_t *tags;
  std::string exifException;

  exiv2node_thread_data_t(Local<String> fn_, Handle<Function> cb_) {
    uv_ref(uv_default_loop());
    request.data = this;
    cb = Persistent<Function>::New(cb_);
    fileName = std::string(*String::AsciiValue(fn_));
    tags = new tag_map_t();
    exifException = std::string();
  }
  virtual ~exiv2node_thread_data_t() {
    uv_unref(uv_default_loop());
    cb.Dispose();
    delete tags;
    // Assuming std::auto_ptr does it's job here and Exiv2::Image::AutoPtr is
    // destroyed when it goes out of scope here..
  }
};

static void GetImageTagsWorker(uv_work_t* req);
static void AfterGetImageTags(uv_work_t* req);
static void SetImageTagsWorker(uv_work_t *req);
static void AfterSetImageTags(uv_work_t *req);

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

  /* Usage arguments */
  if (args.Length() <= (1) || !args[1]->IsFunction())
    return ThrowException(Exception::TypeError(String::New("Usage: <filename> <callback function>")));

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

  /* Set up our thread data struct, pass off to the libuv thread pool */
  exiv2node_thread_data_t *thread_data = new exiv2node_thread_data_t(fileName, cb);

  int status = uv_queue_work(uv_default_loop(), &thread_data->request, GetImageTagsWorker, AfterGetImageTags);
  assert(status == 0);

  return Undefined();
}

static void GetImageTagsWorker(uv_work_t* req) {
  exiv2node_thread_data_t *thread_data = static_cast<exiv2node_thread_data_t *> (req->data);

  /* Exiv2 processing of the file.. */
  try {
    thread_data->image = Exiv2::ImageFactory::open(thread_data->fileName);
    thread_data->image->readMetadata();
  } catch (Exiv2::AnyError& e) {
    thread_data->exifException.append(e.what());
  }
}

/* Thread complete callback.. */
static void AfterGetImageTags(uv_work_t* req) {
  HandleScope scope;
  exiv2node_thread_data_t *thread_data = static_cast<exiv2node_thread_data_t *> (req->data);

  Local<Value> argv[2];
  if (!thread_data->exifException.empty()){
    argv[0] = Local<String>::New(String::New(thread_data->exifException.c_str()));
    argv[1] = Local<Value>::New(Null());
  } else {
    argv[0] = Local<Value>::New(Null());

    // Create a V8 object with all the image tags and their corresponding
    // values.
    Exiv2::ExifData &exifData = thread_data->image->exifData();
    Exiv2::IptcData &iptcData = thread_data->image->iptcData();
    Exiv2::XmpData &xmpData = thread_data->image->xmpData();

    argv[1] = Local<Value>::New(Null());
    if (exifData.empty() == false || iptcData.empty() == false || xmpData.empty() == false) {
      Local<Object> tags = Object::New();

      if (exifData.empty() == false) {
        Exiv2::ExifData::const_iterator end = exifData.end();
        for (Exiv2::ExifData::const_iterator i = exifData.begin(); i != end; ++i) {
          tags->Set(String::New(i->key().c_str()), String::New(i->value().toString().c_str()), ReadOnly);
        }
      }

      if (iptcData.empty() == false) {
        Exiv2::IptcData::const_iterator end = iptcData.end();
        for (Exiv2::IptcData::const_iterator i = iptcData.begin(); i != end; ++i) {
          tags->Set(String::New(i->key().c_str()), String::New(i->value().toString().c_str()), ReadOnly);
        }
      }

      if (xmpData.empty() == false) {
        Exiv2::XmpData::const_iterator end = xmpData.end();
        for (Exiv2::XmpData::const_iterator i = xmpData.begin(); i != end; ++i) {
          tags->Set(String::New(i->key().c_str()), String::New(i->value().toString().c_str()), ReadOnly);
        }
      }
      argv[1] = tags;
    }
  }

  /* Pass the argv array object to our callback function */
  TryCatch try_catch;
  thread_data->cb->Call(Context::GetCurrent()->Global(), 2, argv);
  if (try_catch.HasCaught()) {
    FatalException(try_catch);
  }

  delete thread_data;
}

/* Set Image Tag support.. */
static Handle<Value> SetImageTags(const Arguments& args) {
  HandleScope scope;

  /* Usage arguments */
  if (args.Length() <= 2 || !args[2]->IsFunction())
    return ThrowException(Exception::TypeError(String::New("Usage: <filename> <tags> <callback function>")));

  Local<String> fileName = Local<String>::Cast(args[0]);
  Local<Object> tags = Local<Object>::Cast(args[1]);
  Local<Function> cb = Local<Function>::Cast(args[2]);

  /* Set up our thread data struct, pass off to the libuv thread pool */
  exiv2node_thread_data_t *thread_data = new exiv2node_thread_data_t(fileName, cb);

  Local<Array> keys = tags->GetPropertyNames();
  for (unsigned i = 0; i < keys->Length(); i++) {
    Handle<v8::Value> key = keys->Get(i);
    thread_data->tags->insert(std::pair<std::string, std::string> (
      *String::AsciiValue(key),
      *String::AsciiValue(tags->Get(key)))
    );
  }

  int status = uv_queue_work(uv_default_loop(), &thread_data->request, SetImageTagsWorker, AfterSetImageTags);
  assert(status == 0);

  return Undefined();
}

static void SetImageTagsWorker(uv_work_t *req) {
  exiv2node_thread_data_t *thread_data = static_cast<exiv2node_thread_data_t*> (req->data);

  /* Read existing metadata.. TODO: also handle IPTC and XMP data here.. */
  try {
    thread_data->image = Exiv2::ImageFactory::open(thread_data->fileName);
    thread_data->image->readMetadata();
    Exiv2::ExifData &exifData = thread_data->image->exifData();

    // Assign the tags.
    for (tag_map_t::iterator i = thread_data->tags->begin(); i != thread_data->tags->end(); ++i) {
      exifData[i->first].setValue(i->second);
    }

    /* Write the Exif data to the image file */
    thread_data->image->setExifData(exifData);
    thread_data->image->writeMetadata();
  } catch (Exiv2::AnyError& e) {
    thread_data->exifException.append(e.what());
  }
}

/* Thread complete callback.. */
static void AfterSetImageTags(uv_work_t *req) {
  HandleScope scope;
  exiv2node_thread_data_t *thread_data = static_cast<exiv2node_thread_data_t*> (req->data);

  Local<Value> argv[1];

  /* Create a V8 array with all the image tags and their corresponding values */
  if (thread_data->exifException.empty()) {
    argv[0] = Local<Value>::New(Null());
  } else {
    argv[0] = Local<String>::New(String::New(thread_data->exifException.c_str()));
  }

  /* Pass the argv array object to our callback function */
  TryCatch try_catch;
  thread_data->cb->Call(Context::GetCurrent()->Global(), 1, argv);
  if (try_catch.HasCaught()) {
    FatalException(try_catch);
  }

  delete thread_data;
}

void InitAll(Handle<Object> target) {
  target->Set(String::NewSymbol("getImageTags"), FunctionTemplate::New(GetImageTags)->GetFunction());
  target->Set(String::NewSymbol("setImageTags"), FunctionTemplate::New(SetImageTags)->GetFunction());
}
NODE_MODULE(exiv2, InitAll)
<commit_msg>Call it a baton again.<commit_after>#include <v8.h>
#include <node.h>
#include <unistd.h>
#include <string>
#include <map>
#include <exiv2/image.hpp>
#include <exiv2/exif.hpp>

using namespace node;
using namespace v8;

// Base structure for passing data to and from our libuv workers.
struct Baton {
  uv_work_t request;
  Exiv2::Image::AutoPtr image;
  Persistent<Function> cb;
  std::string fileName;
  std::string exifException;

  Baton(Local<String> fn_, Handle<Function> cb_) {
    uv_ref(uv_default_loop());
    request.data = this;
    cb = Persistent<Function>::New(cb_);
    fileName = std::string(*String::AsciiValue(fn_));
    exifException = std::string();
  }
  virtual ~Baton() {
    uv_unref(uv_default_loop());
    cb.Dispose();
    // Assuming std::auto_ptr does it's job here and Exiv2::Image::AutoPtr is
    // destroyed when it goes out of scope here..
  }
};

// For writing tags, we need to copy the strings out of the V8 types since they
// cannot be read from the other thread.
typedef std::map<std::string, std::string> tag_map_t;
struct SetTagsBaton : Baton {
  tag_map_t *tags;
  SetTagsBaton(Local<String> fn_, Handle<Function> cb_) : Baton(fn_, cb_) {
    tags = new tag_map_t();
  }
  virtual ~SetTagsBaton() {
    delete tags;
  }
};

static void GetImageTagsWorker(uv_work_t* req);
static void AfterGetImageTags(uv_work_t* req);
static void SetImageTagsWorker(uv_work_t *req);
static void AfterSetImageTags(uv_work_t *req);

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

  /* Usage arguments */
  if (args.Length() <= (1) || !args[1]->IsFunction())
    return ThrowException(Exception::TypeError(String::New("Usage: <filename> <callback function>")));

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

  /* Set up our thread data struct, pass off to the libuv thread pool */
  Baton *thread_data = new Baton(fileName, cb);

  int status = uv_queue_work(uv_default_loop(), &thread_data->request, GetImageTagsWorker, AfterGetImageTags);
  assert(status == 0);

  return Undefined();
}

static void GetImageTagsWorker(uv_work_t* req) {
  Baton *thread_data = static_cast<Baton *> (req->data);

  /* Exiv2 processing of the file.. */
  try {
    thread_data->image = Exiv2::ImageFactory::open(thread_data->fileName);
    thread_data->image->readMetadata();
  } catch (Exiv2::AnyError& e) {
    thread_data->exifException.append(e.what());
  }
}

/* Thread complete callback.. */
static void AfterGetImageTags(uv_work_t* req) {
  HandleScope scope;
  Baton *thread_data = static_cast<Baton *> (req->data);

  Local<Value> argv[2];
  if (!thread_data->exifException.empty()){
    argv[0] = Local<String>::New(String::New(thread_data->exifException.c_str()));
    argv[1] = Local<Value>::New(Null());
  } else {
    argv[0] = Local<Value>::New(Null());

    // Create a V8 object with all the image tags and their corresponding
    // values.
    Exiv2::ExifData &exifData = thread_data->image->exifData();
    Exiv2::IptcData &iptcData = thread_data->image->iptcData();
    Exiv2::XmpData &xmpData = thread_data->image->xmpData();

    argv[1] = Local<Value>::New(Null());
    if (exifData.empty() == false || iptcData.empty() == false || xmpData.empty() == false) {
      Local<Object> tags = Object::New();

      if (exifData.empty() == false) {
        Exiv2::ExifData::const_iterator end = exifData.end();
        for (Exiv2::ExifData::const_iterator i = exifData.begin(); i != end; ++i) {
          tags->Set(String::New(i->key().c_str()), String::New(i->value().toString().c_str()), ReadOnly);
        }
      }

      if (iptcData.empty() == false) {
        Exiv2::IptcData::const_iterator end = iptcData.end();
        for (Exiv2::IptcData::const_iterator i = iptcData.begin(); i != end; ++i) {
          tags->Set(String::New(i->key().c_str()), String::New(i->value().toString().c_str()), ReadOnly);
        }
      }

      if (xmpData.empty() == false) {
        Exiv2::XmpData::const_iterator end = xmpData.end();
        for (Exiv2::XmpData::const_iterator i = xmpData.begin(); i != end; ++i) {
          tags->Set(String::New(i->key().c_str()), String::New(i->value().toString().c_str()), ReadOnly);
        }
      }
      argv[1] = tags;
    }
  }

  /* Pass the argv array object to our callback function */
  TryCatch try_catch;
  thread_data->cb->Call(Context::GetCurrent()->Global(), 2, argv);
  if (try_catch.HasCaught()) {
    FatalException(try_catch);
  }

  delete thread_data;
}

/* Set Image Tag support.. */
static Handle<Value> SetImageTags(const Arguments& args) {
  HandleScope scope;

  /* Usage arguments */
  if (args.Length() <= 2 || !args[2]->IsFunction())
    return ThrowException(Exception::TypeError(String::New("Usage: <filename> <tags> <callback function>")));

  Local<String> fileName = Local<String>::Cast(args[0]);
  Local<Object> tags = Local<Object>::Cast(args[1]);
  Local<Function> cb = Local<Function>::Cast(args[2]);

  /* Set up our thread data struct, pass off to the libuv thread pool */
  SetTagsBaton *thread_data = new SetTagsBaton(fileName, cb);

  Local<Array> keys = tags->GetPropertyNames();
  for (unsigned i = 0; i < keys->Length(); i++) {
    Handle<v8::Value> key = keys->Get(i);
    thread_data->tags->insert(std::pair<std::string, std::string> (
      *String::AsciiValue(key),
      *String::AsciiValue(tags->Get(key)))
    );
  }

  int status = uv_queue_work(uv_default_loop(), &thread_data->request, SetImageTagsWorker, AfterSetImageTags);
  assert(status == 0);

  return Undefined();
}

static void SetImageTagsWorker(uv_work_t *req) {
  SetTagsBaton *thread_data = static_cast<SetTagsBaton*> (req->data);

  /* Read existing metadata.. TODO: also handle IPTC and XMP data here.. */
  try {
    thread_data->image = Exiv2::ImageFactory::open(thread_data->fileName);
    thread_data->image->readMetadata();
    Exiv2::ExifData &exifData = thread_data->image->exifData();

    // Assign the tags.
    for (tag_map_t::iterator i = thread_data->tags->begin(); i != thread_data->tags->end(); ++i) {
      exifData[i->first].setValue(i->second);
    }

    /* Write the Exif data to the image file */
    thread_data->image->setExifData(exifData);
    thread_data->image->writeMetadata();
  } catch (Exiv2::AnyError& e) {
    thread_data->exifException.append(e.what());
  }
}

/* Thread complete callback.. */
static void AfterSetImageTags(uv_work_t *req) {
  HandleScope scope;
  SetTagsBaton *thread_data = static_cast<SetTagsBaton*> (req->data);

  Local<Value> argv[1];

  /* Create a V8 array with all the image tags and their corresponding values */
  if (thread_data->exifException.empty()) {
    argv[0] = Local<Value>::New(Null());
  } else {
    argv[0] = Local<String>::New(String::New(thread_data->exifException.c_str()));
  }

  /* Pass the argv array object to our callback function */
  TryCatch try_catch;
  thread_data->cb->Call(Context::GetCurrent()->Global(), 1, argv);
  if (try_catch.HasCaught()) {
    FatalException(try_catch);
  }

  delete thread_data;
}

void InitAll(Handle<Object> target) {
  target->Set(String::NewSymbol("getImageTags"), FunctionTemplate::New(GetImageTags)->GetFunction());
  target->Set(String::NewSymbol("setImageTags"), FunctionTemplate::New(SetImageTags)->GetFunction());
}
NODE_MODULE(exiv2, InitAll)
<|endoftext|>


<commit_before>#include "country_info.hpp"
#include "country_polygon.hpp"
#include "country.hpp"

#include "../indexer/geometry_serialization.hpp"

#include "../geometry/region2d.hpp"

#include "../coding/read_write_utils.hpp"

#include "../base/string_utils.hpp"

namespace storage
{
  /*
  class LessCountryDef
  {
    bool CompareStrings(string const & s1, string const & s2) const
    {
      // Do this stuff because of 'Guinea-Bissau.mwm' goes before 'Guinea.mwm'
      // in file system (and in PACKED_POLYGONS_FILE also).
      size_t n = min(s1.size(), s2.size());
      return lexicographical_compare(s1.begin(), s1.begin() + n,
                                     s2.begin(), s2.begin() + n);
    }

  public:
    bool operator() (CountryDef const & r1, string const & r2) const
    {
      return CompareStrings(r1.m_name, r2);
    }
    bool operator() (string const & r1, CountryDef const & r2) const
    {
      return CompareStrings(r1, r2.m_name);
    }
    bool operator() (CountryDef const & r1, CountryDef const & r2) const
    {
      return CompareStrings(r1.m_name, r2.m_name);
    }
  };
  */

  CountryInfoGetter::CountryInfoGetter(ModelReaderPtr polyR, ModelReaderPtr countryR)
    : m_reader(polyR), m_cache(2)
  {
    ReaderSource<ModelReaderPtr> src(m_reader.GetReader(PACKED_POLYGONS_INFO_TAG));
    rw::Read(src, m_countries);

/*
    // We can't change the order of countries.
#ifdef DEBUG
    LessCountryDef check;
    for (size_t i = 0; i < m_countries.size() - 1; ++i)
      ASSERT ( !check(m_countries[i+1], m_countries[i]),
               (m_countries[i].m_name, m_countries[i+1].m_name) );
#endif
*/

    string buffer;
    countryR.ReadAsString(buffer);
    LoadCountryFile2CountryInfo(buffer, m_id2info);
  }

  template <class ToDo>
  void CountryInfoGetter::ForEachCountry(m2::PointD const & pt, ToDo & toDo) const
  {
    for (size_t i = 0; i < m_countries.size(); ++i)
      if (m_countries[i].m_rect.IsPointInside(pt))
        if (!toDo(i))
          return;
  }

  bool CountryInfoGetter::GetByPoint::operator() (size_t id)
  {
    vector<m2::RegionD> const & rgnV = m_info.GetRegions(id);

    for (size_t i = 0; i < rgnV.size(); ++i)
    {
      if (rgnV[i].Contains(m_pt))
      {
        m_res = id;
        return false;
      }
    }

    return true;
  }

  vector<m2::RegionD> const & CountryInfoGetter::GetRegions(size_t id) const
  {
    bool isFound = false;
    vector<m2::RegionD> & rgnV = m_cache.Find(id, isFound);

    if (!isFound)
    {
      rgnV.clear();

      // load regions from file
      ReaderSource<ModelReaderPtr> src(m_reader.GetReader(strings::to_string(id)));

      uint32_t const count = ReadVarUint<uint32_t>(src);
      for (size_t i = 0; i < count; ++i)
      {
        vector<m2::PointD> points;
        serial::LoadOuterPath(src, serial::CodingParams(), points);

        rgnV.push_back(m2::RegionD());
        rgnV.back().Assign(points.begin(), points.end());
      }
    }

    return rgnV;
  }

  string CountryInfoGetter::GetRegionFile(m2::PointD const & pt) const
  {
    GetByPoint doGet(*this, pt);
    ForEachCountry(pt, doGet);

    if (doGet.m_res != -1)
      return m_countries[doGet.m_res].m_name;
    else
      return string();
  }

  void CountryInfoGetter::GetRegionInfo(m2::PointD const & pt, CountryInfo & info) const
  {
    GetByPoint doGet(*this, pt);
    ForEachCountry(pt, doGet);

    if (doGet.m_res != -1)
      GetRegionInfo(m_countries[doGet.m_res].m_name, info);
  }

  void CountryInfoGetter::GetRegionInfo(string const & id, CountryInfo & info) const
  {
    map<string, CountryInfo>::const_iterator i = m_id2info.find(id);

    // Take into account 'minsk-pass'.
    if (i == m_id2info.end()) return;
    //ASSERT ( i != m_id2info.end(), () );

    info = i->second;

    if (info.m_name.empty())
      info.m_name = id;

    CountryInfo::FileName2FullName(info.m_name);
  }

  template <class ToDo> void CountryInfoGetter::ForEachCountry(string const & prefix, ToDo toDo) const
  {
    typedef vector<CountryDef>::const_iterator IterT;

    for (IterT i = m_countries.begin(); i != m_countries.end(); ++i)
    {
      if (i->m_name.find(prefix) != string::npos)
        toDo(*i);
    }

    /// @todo Store sorted list of polygons in PACKED_POLYGONS_FILE.
    /*
    pair<IterT, IterT> r = equal_range(m_countries.begin(), m_countries.end(), file, LessCountryDef());
    while (r.first != r.second)
    {
      toDo(r.first->m_name);
      ++r.first;
    }
    */
  }

  namespace
  {
    class DoCalcUSA
    {
      m2::RectD * m_rects;
    public:
      DoCalcUSA(m2::RectD * rects) : m_rects(rects) {}
      void operator() (CountryDef const & c)
      {
        if (c.m_name == "USA_Alaska")
          m_rects[1] = c.m_rect;
        else if (c.m_name == "USA_Hawaii")
          m_rects[2] = c.m_rect;
        else
          m_rects[0].Add(c.m_rect);
      }
    };

    void AddRect(m2::RectD & r, CountryDef const & c)
    {
      r.Add(c.m_rect);
    }
  }

  void CountryInfoGetter::CalcUSALimitRect(m2::RectD rects[3]) const
  {
    ForEachCountry("USA_", DoCalcUSA(rects));
  }

  m2::RectD CountryInfoGetter::CalcLimitRect(string const & prefix) const
  {
    m2::RectD r;
    ForEachCountry(prefix, bind(&AddRect, ref(r), _1));
    return r;
  }
}
<commit_msg>Fix bug with country matching by prefix name.<commit_after>#include "country_info.hpp"
#include "country_polygon.hpp"
#include "country.hpp"

#include "../indexer/geometry_serialization.hpp"

#include "../geometry/region2d.hpp"

#include "../coding/read_write_utils.hpp"

#include "../base/string_utils.hpp"

namespace storage
{
  /*
  class LessCountryDef
  {
    bool CompareStrings(string const & s1, string const & s2) const
    {
      // Do this stuff because of 'Guinea-Bissau.mwm' goes before 'Guinea.mwm'
      // in file system (and in PACKED_POLYGONS_FILE also).
      size_t n = min(s1.size(), s2.size());
      return lexicographical_compare(s1.begin(), s1.begin() + n,
                                     s2.begin(), s2.begin() + n);
    }

  public:
    bool operator() (CountryDef const & r1, string const & r2) const
    {
      return CompareStrings(r1.m_name, r2);
    }
    bool operator() (string const & r1, CountryDef const & r2) const
    {
      return CompareStrings(r1, r2.m_name);
    }
    bool operator() (CountryDef const & r1, CountryDef const & r2) const
    {
      return CompareStrings(r1.m_name, r2.m_name);
    }
  };
  */

  CountryInfoGetter::CountryInfoGetter(ModelReaderPtr polyR, ModelReaderPtr countryR)
    : m_reader(polyR), m_cache(2)
  {
    ReaderSource<ModelReaderPtr> src(m_reader.GetReader(PACKED_POLYGONS_INFO_TAG));
    rw::Read(src, m_countries);

/*
    // We can't change the order of countries.
#ifdef DEBUG
    LessCountryDef check;
    for (size_t i = 0; i < m_countries.size() - 1; ++i)
      ASSERT ( !check(m_countries[i+1], m_countries[i]),
               (m_countries[i].m_name, m_countries[i+1].m_name) );
#endif
*/

    string buffer;
    countryR.ReadAsString(buffer);
    LoadCountryFile2CountryInfo(buffer, m_id2info);
  }

  template <class ToDo>
  void CountryInfoGetter::ForEachCountry(m2::PointD const & pt, ToDo & toDo) const
  {
    for (size_t i = 0; i < m_countries.size(); ++i)
      if (m_countries[i].m_rect.IsPointInside(pt))
        if (!toDo(i))
          return;
  }

  bool CountryInfoGetter::GetByPoint::operator() (size_t id)
  {
    vector<m2::RegionD> const & rgnV = m_info.GetRegions(id);

    for (size_t i = 0; i < rgnV.size(); ++i)
    {
      if (rgnV[i].Contains(m_pt))
      {
        m_res = id;
        return false;
      }
    }

    return true;
  }

  vector<m2::RegionD> const & CountryInfoGetter::GetRegions(size_t id) const
  {
    bool isFound = false;
    vector<m2::RegionD> & rgnV = m_cache.Find(id, isFound);

    if (!isFound)
    {
      rgnV.clear();

      // load regions from file
      ReaderSource<ModelReaderPtr> src(m_reader.GetReader(strings::to_string(id)));

      uint32_t const count = ReadVarUint<uint32_t>(src);
      for (size_t i = 0; i < count; ++i)
      {
        vector<m2::PointD> points;
        serial::LoadOuterPath(src, serial::CodingParams(), points);

        rgnV.push_back(m2::RegionD());
        rgnV.back().Assign(points.begin(), points.end());
      }
    }

    return rgnV;
  }

  string CountryInfoGetter::GetRegionFile(m2::PointD const & pt) const
  {
    GetByPoint doGet(*this, pt);
    ForEachCountry(pt, doGet);

    if (doGet.m_res != -1)
      return m_countries[doGet.m_res].m_name;
    else
      return string();
  }

  void CountryInfoGetter::GetRegionInfo(m2::PointD const & pt, CountryInfo & info) const
  {
    GetByPoint doGet(*this, pt);
    ForEachCountry(pt, doGet);

    if (doGet.m_res != -1)
      GetRegionInfo(m_countries[doGet.m_res].m_name, info);
  }

  void CountryInfoGetter::GetRegionInfo(string const & id, CountryInfo & info) const
  {
    map<string, CountryInfo>::const_iterator i = m_id2info.find(id);

    // Take into account 'minsk-pass'.
    if (i == m_id2info.end()) return;
    //ASSERT ( i != m_id2info.end(), () );

    info = i->second;

    if (info.m_name.empty())
      info.m_name = id;

    CountryInfo::FileName2FullName(info.m_name);
  }

  template <class ToDo> void CountryInfoGetter::ForEachCountry(string const & prefix, ToDo toDo) const
  {
    typedef vector<CountryDef>::const_iterator IterT;

    for (IterT i = m_countries.begin(); i != m_countries.end(); ++i)
    {
      if (i->m_name.find(prefix) == 0)
        toDo(*i);
    }

    /// @todo Store sorted list of polygons in PACKED_POLYGONS_FILE.
    /*
    pair<IterT, IterT> r = equal_range(m_countries.begin(), m_countries.end(), file, LessCountryDef());
    while (r.first != r.second)
    {
      toDo(r.first->m_name);
      ++r.first;
    }
    */
  }

  namespace
  {
    class DoCalcUSA
    {
      m2::RectD * m_rects;
    public:
      DoCalcUSA(m2::RectD * rects) : m_rects(rects) {}
      void operator() (CountryDef const & c)
      {
        if (c.m_name == "USA_Alaska")
          m_rects[1] = c.m_rect;
        else if (c.m_name == "USA_Hawaii")
          m_rects[2] = c.m_rect;
        else
          m_rects[0].Add(c.m_rect);
      }
    };

    void AddRect(m2::RectD & r, CountryDef const & c)
    {
      r.Add(c.m_rect);
    }
  }

  void CountryInfoGetter::CalcUSALimitRect(m2::RectD rects[3]) const
  {
    ForEachCountry("USA_", DoCalcUSA(rects));
  }

  m2::RectD CountryInfoGetter::CalcLimitRect(string const & prefix) const
  {
    m2::RectD r;
    ForEachCountry(prefix, bind(&AddRect, ref(r), _1));
    return r;
  }
}
<|endoftext|>


<commit_before>/***************************************************************
 *
 * Copyright (C) 1990-2007, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you
 * may not use this file except in compliance with the License.  You may
 * obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ***************************************************************/

#include "condor_common.h"
#include "../condor_daemon_core.V6/condor_daemon_core.h"
#include "HookClient.h"
#include "status_string.h"

HookClient::HookClient(HookType hook_type, const char* hook_path,
					   bool wants_output)
{
	m_hook_path = strdup(hook_path);
	m_hook_type = hook_type;
	m_pid = -1;
	m_exit_status = -1;
	m_has_exited = false;
	m_wants_output = wants_output;
}

HookClient::~HookClient() {
	if (m_hook_path) {
		free(m_hook_path);
		m_hook_path = NULL;
	}
	if (m_pid != -1 && !m_has_exited) {
		daemonCore->Close_Stdin_Pipe(m_pid);
			// TODO
			// kill -9 m_pid
	}
}

MyString*
HookClient::getStdOut() {
	if (m_has_exited) {
		return &m_std_out;
	}
	return daemonCore->Read_Std_Pipe(m_pid, 1);
}

MyString*
HookClient::getStdErr() {
	if (m_has_exited) {
		return &m_std_err;
	}
	return daemonCore->Read_Std_Pipe(m_pid, 2);
}

void
HookClient::hookExited(int exit_status) {
	m_has_exited = true;
	m_exit_status = exit_status;

	MyString status_txt;
	status_txt.sprintf("HookClient %s (pid %d) ", m_hook_path, m_pid);
	statusString(exit_status, status_txt);
	dprintf(D_FULLDEBUG, "%s\n", status_txt.Value());

	MyString* std_out = daemonCore->Read_Std_Pipe(m_pid, 1);
	if (std_out) {
		m_std_out = *std_out;
	}
	MyString* std_err = daemonCore->Read_Std_Pipe(m_pid, 2);
	if (std_err) {
		m_std_err = *std_err;
	}
	if (m_pid != -1) {
		daemonCore->Close_Stdin_Pipe(m_pid);
	}
}
<commit_msg>Revert "Ticket #422: the stdin of a job hook is explicitly closed when a hook" This patch was closing stdin prematurely, preventing data from making it to the hook's stdin.<commit_after>/***************************************************************
 *
 * Copyright (C) 1990-2007, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you
 * may not use this file except in compliance with the License.  You may
 * obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ***************************************************************/

#include "condor_common.h"
#include "../condor_daemon_core.V6/condor_daemon_core.h"
#include "HookClient.h"
#include "status_string.h"

HookClient::HookClient(HookType hook_type, const char* hook_path,
					   bool wants_output)
{
	m_hook_path = strdup(hook_path);
	m_hook_type = hook_type;
	m_pid = -1;
	m_exit_status = -1;
	m_has_exited = false;
	m_wants_output = wants_output;
}

HookClient::~HookClient() {
	if (m_hook_path) {
		free(m_hook_path);
		m_hook_path = NULL;
	}
	if (m_pid != -1 && !m_has_exited) {
			// TODO
			// kill -9 m_pid
	}
}

MyString*
HookClient::getStdOut() {
	if (m_has_exited) {
		return &m_std_out;
	}
	return daemonCore->Read_Std_Pipe(m_pid, 1);
}

MyString*
HookClient::getStdErr() {
	if (m_has_exited) {
		return &m_std_err;
	}
	return daemonCore->Read_Std_Pipe(m_pid, 2);
}

void
HookClient::hookExited(int exit_status) {
	m_has_exited = true;
	m_exit_status = exit_status;

	MyString status_txt;
	status_txt.sprintf("HookClient %s (pid %d) ", m_hook_path, m_pid);
	statusString(exit_status, status_txt);
	dprintf(D_FULLDEBUG, "%s\n", status_txt.Value());

	MyString* std_out = daemonCore->Read_Std_Pipe(m_pid, 1);
	if (std_out) {
		m_std_out = *std_out;
	}
	MyString* std_err = daemonCore->Read_Std_Pipe(m_pid, 2);
	if (std_err) {
		m_std_err = *std_err;
	}
}
<|endoftext|>


<commit_before>// Copyright (C) 2017 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., University of Heidelberg, and University of
// of Connecticut School of Medicine.
// All rights reserved.

// Copyright (C) 2010 - 2016 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., University of Heidelberg, and The University
// of Manchester.
// All rights reserved.

/*
 * CQNotes.cpp
 *
 *  Created on: Aug 11, 2010
 *      Author: shoops
 */

#include <QtWebKit/QWebFrame>
#include <QtXml/QXmlInputSource>
#include <QtXml/QXmlSimpleReader>
#include <QDesktopServices>

#include "CQNotes.h"
#include "resourcesUI/CQIconResource.h"
#include "CQMessageBox.h"
#include "qtUtilities.h"

#include "model/CModelValue.h"
#include "model/CReaction.h"
#include "model/CEvent.h"
#include "function/CFunction.h"
#include "report/CKeyFactory.h"
#include "report/CReportDefinition.h"
#include "copasi/report/CCopasiRootContainer.h"
#include "commandline/CConfigurationFile.h"

#include <copasi/UI/copasiui3window.h>
#include <copasi/UI/CQCopasiApplication.h>
#include <copasi/undoFramework/ChangeNotesCommand.h>

CQValidatorXML::CQValidatorXML(QPlainTextEdit * parent, const char * name):
  CQValidator< QPlainTextEdit >(parent, &QPlainTextEdit::toPlainText, name),
  mIsFreeText(true),
  mNeedsWrap(false)
{}

// virtual
QValidator::State CQValidatorXML::validate(QString & input, int & pos) const
{
  QXmlSimpleReader Validator;
  QXmlInputSource Input;
  CQNotesContentHandler ContentHandler;

  Validator.setContentHandler(&ContentHandler);

  // We like to allow free text and therefore wrap the text to create valid XML.
  Input.setData("<Validate:XML xmlns:Validate=\"http://www.copasi.org/Validate\">" + input + "</Validate:XML>");

  if (Validator.parse(Input))
    {
      mIsFreeText = ContentHandler.isFreeText();
      mNeedsWrap = ContentHandler.needsWrap();
      return CQValidator< QPlainTextEdit >::validate(input, pos);
    }

  mIsFreeText = true;
  mNeedsWrap = false;
  setColor(Invalid);
  return Intermediate;
}

const bool & CQValidatorXML::isFreeText() const
{
  return mIsFreeText;
}

const bool & CQValidatorXML::needsWrap() const
{
  return mNeedsWrap;
}

CQNotesContentHandler::CQNotesContentHandler():
  QXmlDefaultHandler(),
  mIsFreeText(true),
  mNeedsWrap(true),
  mLevel(0)
{}

CQNotesContentHandler:: ~CQNotesContentHandler()
{}

// virtual
bool CQNotesContentHandler::startDocument()
{
  mIsFreeText = true;
  mNeedsWrap = true;
  mLevel = 0;
  return true;
}

// virtual
bool CQNotesContentHandler::startElement(const QString & namespaceURI,
    const QString & localName,
    const QString & qName,
    const QXmlAttributes & atts)
{
  if (namespaceURI != "http://www.copasi.org/Validate" ||
      qName != "Validate:XML")
    mIsFreeText = false;

  if (mLevel == 1 &&
      namespaceURI == "http://www.w3.org/1999/xhtml" &&
      (localName == "html" || localName == "body"))
    mNeedsWrap = false;

  mLevel++;

  return QXmlDefaultHandler::startElement(namespaceURI, localName, qName, atts);
}

// virtual
bool CQNotesContentHandler::endElement(const QString & namespaceURI,
                                       const QString & localName,
                                       const QString & qName)
{
  mLevel--;

  return QXmlDefaultHandler::endElement(namespaceURI, localName, qName);
}

const bool & CQNotesContentHandler::isFreeText() const
{
  return mIsFreeText;
}

bool CQNotesContentHandler::needsWrap() const
{
  return (mNeedsWrap && !mIsFreeText);
}

CQNotes::CQNotes(QWidget* parent, const char* name) :
  CopasiWidget(parent, name),
  mEditMode(false),
  mChanged(false),
  mpValidatorXML(NULL),
  mValidity(QValidator::Acceptable),
  mKeyToCopy("")

{
  setupUi(this);

  mpValidatorXML = new CQValidatorXML(mpEdit);

  mEditMode = false;
  mpEdit->hide();
  mpWebView->show();
  mpBtnToggleEdit->setIcon(CQIconResource::icon(CQIconResource::edit));

  mpWebView->page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks);

  mpUndoStack = NULL;
}

CQNotes::~CQNotes()
{}

void CQNotes::slotBtnCopy()
{
  mKeyToCopy = mKey;
}

// virtual
bool CQNotes::update(ListViews::ObjectType objectType, ListViews::Action action, const std::string & key)
{
  switch (action)
    {
      case ListViews::CHANGE:

        if (key == mKey)
          {
            load();
          }

        break;

      case ListViews::DELETE:

        if (key == mKey || objectType == ListViews::MODEL)
          {
            mpObject = NULL;
            mKey = "";
          }

        break;

      default:
        break;
    }

  if (objectType == ListViews::MODEL &&
      action == ListViews::DELETE)
    {
      mEditMode = false;
    }

  return true;
}

// virtual
bool CQNotes::leave()
{
  mpBtnToggleEdit->setFocus();

  mpObject = CCopasiRootContainer::getKeyFactory()->get(mKey);

  if (mpObject != NULL)
    {
      save();
    }
  else
    {
      mKey = "";
      mpDataModel = NULL;
    }

  return true;
}

// virtual
bool CQNotes::enterProtected()
{
  if (mKeyToCopy == "")
    {
      load();
    }
  else
    {
      mpObject = CCopasiRootContainer::getKeyFactory()->get(mKeyToCopy);
      load();
      mpObject = CCopasiRootContainer::getKeyFactory()->get(mKey);
      save();
      mKeyToCopy = "";
    }

  return true;
}

void CQNotes::slotToggleMode()
{
  mEditMode = !mEditMode;

  if (mEditMode)
    {
      mpWebView->hide();
      mpEdit->show();
      mpBtnToggleEdit->setIcon(CQIconResource::icon(CQIconResource::renderMarkup));
    }
  else
    {
      save();
      load();

      mpEdit->hide();
      mpWebView->show();
      mpBtnToggleEdit->setIcon(CQIconResource::icon(CQIconResource::edit));
    }
}

void CQNotes::slotValidateXML()
{
  QString Input = mpEdit->toPlainText();
  int pos = 0;

  mValidity = mpValidatorXML->validate(Input, pos);

  if (mpValidatorXML->isFreeText())
    {
      mEditMode = true;
      mpBtnToggleEdit->hide();
    }
  else
    {
      mpBtnToggleEdit->show();
    }

  if (mEditMode)
    {
      mpWebView->hide();
      mpEdit->show();
      mpBtnToggleEdit->setIcon(CQIconResource::icon(CQIconResource::renderMarkup));
    }
  else
    {
      mpEdit->hide();
      mpWebView->show();
      mpBtnToggleEdit->setIcon(CQIconResource::icon(CQIconResource::edit));
    }
}

void CQNotes::load()
{
  mpObject = CCopasiRootContainer::getKeyFactory()->get(mKey);

  if (mpObject != NULL)
    {
      QString Notes;

      CAnnotation * pAnnotation = CAnnotation::castObject(mpObject);
      CReportDefinition * pReportDefinition = static_cast< CReportDefinition * >(mpObject);

      if (pAnnotation != NULL)
        {
          Notes = FROM_UTF8(pAnnotation->getNotes());
        }
      else if (pReportDefinition != NULL)
        {
          Notes = FROM_UTF8(pReportDefinition->getComment());
        }

      // The notes are UTF8 encoded however the html does not specify an encoding
      // thus Qt uses locale settings.
      mpWebView->setHtml(Notes);
      mpEdit->setPlainText(Notes);
      mpValidatorXML->saved();
      slotValidateXML();

      if (!mpValidatorXML->isFreeText() && mEditMode)
        {
          slotToggleMode();
        }

      mValidity = QValidator::Acceptable;
    }

  mChanged = false;

  return;
}

void CQNotes::save()
{
  if (mpObject == NULL ||
      mValidity != QValidator::Acceptable)
    return;

  CAnnotation * pAnnotation = CAnnotation::castObject(mpObject);
  CReportDefinition * pReportDefinition = static_cast<CReportDefinition *>(mpObject);

  std::string notes;

  if (pAnnotation != NULL)
    {
      notes = pAnnotation->getNotes();
    }
  else if (pReportDefinition != NULL)
    {
      notes = pReportDefinition->getComment();
    }

  std::string plainText = TO_UTF8(mpEdit->toPlainText());

  if (plainText == notes)
    return;

  if (mpValidatorXML->needsWrap())
    {
      // We wrap the HTML in a body element if it does not contain a top level html or body element.
      plainText = "" + plainText + "";
    }

  if (mpUndoStack == NULL)
    {
      CopasiUI3Window *  pWindow = static_cast<CQCopasiApplication*>(qApp)->getMainWindow();

      if (pWindow)
        mpUndoStack = pWindow->getUndoStack();
    }

  mpUndoStack->push(new ChangeNotesCommand(mpObject, notes, plainText, this));
}

void CQNotes::slotOpenUrl(const QUrl & url)
{
  QDesktopServices::openUrl(url);
  return;
}

void CQNotes::changeNotes(const std::string& key, const std::string& notes)
{
  if (mpListView->getCurrentItemKey() != mKey || key != mKey)
    {
      mpListView->switchToOtherWidget(C_INVALID_INDEX, key);
    }

  mKey = key;
  load();

  CAnnotation * pAnnotation = CAnnotation::castObject(mpObject);
  CReportDefinition * pReportDefinition = static_cast< CReportDefinition * >(mpObject);

  if (pAnnotation != NULL)
    {
      pAnnotation->setNotes(notes);
    }
  else if (pReportDefinition != NULL)
    {
      pReportDefinition->setComment(notes);
    }

  mChanged = true;

  if (mIgnoreUpdates)
    return;

  if (mpDataModel != NULL)
    {
      mpDataModel->changed();
    }

  protectedNotify(ListViews::MODEL, ListViews::CHANGE, mKey);

  mChanged = false;
}
<commit_msg> - issue 2373: fix compilation on ubuntu<commit_after>// Copyright (C) 2017 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., University of Heidelberg, and University of
// of Connecticut School of Medicine.
// All rights reserved.

// Copyright (C) 2010 - 2016 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., University of Heidelberg, and The University
// of Manchester.
// All rights reserved.

/*
 * CQNotes.cpp
 *
 *  Created on: Aug 11, 2010
 *      Author: shoops
 */

#include <QWebFrame>
#include <QtXml/QXmlInputSource>
#include <QtXml/QXmlSimpleReader>
#include <QDesktopServices>

#include "CQNotes.h"
#include "resourcesUI/CQIconResource.h"
#include "CQMessageBox.h"
#include "qtUtilities.h"

#include "model/CModelValue.h"
#include "model/CReaction.h"
#include "model/CEvent.h"
#include "function/CFunction.h"
#include "report/CKeyFactory.h"
#include "report/CReportDefinition.h"
#include "copasi/report/CCopasiRootContainer.h"
#include "commandline/CConfigurationFile.h"

#include <copasi/UI/copasiui3window.h>
#include <copasi/UI/CQCopasiApplication.h>
#include <copasi/undoFramework/ChangeNotesCommand.h>

CQValidatorXML::CQValidatorXML(QPlainTextEdit * parent, const char * name):
  CQValidator< QPlainTextEdit >(parent, &QPlainTextEdit::toPlainText, name),
  mIsFreeText(true),
  mNeedsWrap(false)
{}

// virtual
QValidator::State CQValidatorXML::validate(QString & input, int & pos) const
{
  QXmlSimpleReader Validator;
  QXmlInputSource Input;
  CQNotesContentHandler ContentHandler;

  Validator.setContentHandler(&ContentHandler);

  // We like to allow free text and therefore wrap the text to create valid XML.
  Input.setData("<Validate:XML xmlns:Validate=\"http://www.copasi.org/Validate\">" + input + "</Validate:XML>");

  if (Validator.parse(Input))
    {
      mIsFreeText = ContentHandler.isFreeText();
      mNeedsWrap = ContentHandler.needsWrap();
      return CQValidator< QPlainTextEdit >::validate(input, pos);
    }

  mIsFreeText = true;
  mNeedsWrap = false;
  setColor(Invalid);
  return Intermediate;
}

const bool & CQValidatorXML::isFreeText() const
{
  return mIsFreeText;
}

const bool & CQValidatorXML::needsWrap() const
{
  return mNeedsWrap;
}

CQNotesContentHandler::CQNotesContentHandler():
  QXmlDefaultHandler(),
  mIsFreeText(true),
  mNeedsWrap(true),
  mLevel(0)
{}

CQNotesContentHandler:: ~CQNotesContentHandler()
{}

// virtual
bool CQNotesContentHandler::startDocument()
{
  mIsFreeText = true;
  mNeedsWrap = true;
  mLevel = 0;
  return true;
}

// virtual
bool CQNotesContentHandler::startElement(const QString & namespaceURI,
    const QString & localName,
    const QString & qName,
    const QXmlAttributes & atts)
{
  if (namespaceURI != "http://www.copasi.org/Validate" ||
      qName != "Validate:XML")
    mIsFreeText = false;

  if (mLevel == 1 &&
      namespaceURI == "http://www.w3.org/1999/xhtml" &&
      (localName == "html" || localName == "body"))
    mNeedsWrap = false;

  mLevel++;

  return QXmlDefaultHandler::startElement(namespaceURI, localName, qName, atts);
}

// virtual
bool CQNotesContentHandler::endElement(const QString & namespaceURI,
                                       const QString & localName,
                                       const QString & qName)
{
  mLevel--;

  return QXmlDefaultHandler::endElement(namespaceURI, localName, qName);
}

const bool & CQNotesContentHandler::isFreeText() const
{
  return mIsFreeText;
}

bool CQNotesContentHandler::needsWrap() const
{
  return (mNeedsWrap && !mIsFreeText);
}

CQNotes::CQNotes(QWidget* parent, const char* name) :
  CopasiWidget(parent, name),
  mEditMode(false),
  mChanged(false),
  mpValidatorXML(NULL),
  mValidity(QValidator::Acceptable),
  mKeyToCopy("")

{
  setupUi(this);

  mpValidatorXML = new CQValidatorXML(mpEdit);

  mEditMode = false;
  mpEdit->hide();
  mpWebView->show();
  mpBtnToggleEdit->setIcon(CQIconResource::icon(CQIconResource::edit));

  mpWebView->page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks);

  mpUndoStack = NULL;
}

CQNotes::~CQNotes()
{}

void CQNotes::slotBtnCopy()
{
  mKeyToCopy = mKey;
}

// virtual
bool CQNotes::update(ListViews::ObjectType objectType, ListViews::Action action, const std::string & key)
{
  switch (action)
    {
      case ListViews::CHANGE:

        if (key == mKey)
          {
            load();
          }

        break;

      case ListViews::DELETE:

        if (key == mKey || objectType == ListViews::MODEL)
          {
            mpObject = NULL;
            mKey = "";
          }

        break;

      default:
        break;
    }

  if (objectType == ListViews::MODEL &&
      action == ListViews::DELETE)
    {
      mEditMode = false;
    }

  return true;
}

// virtual
bool CQNotes::leave()
{
  mpBtnToggleEdit->setFocus();

  mpObject = CCopasiRootContainer::getKeyFactory()->get(mKey);

  if (mpObject != NULL)
    {
      save();
    }
  else
    {
      mKey = "";
      mpDataModel = NULL;
    }

  return true;
}

// virtual
bool CQNotes::enterProtected()
{
  if (mKeyToCopy == "")
    {
      load();
    }
  else
    {
      mpObject = CCopasiRootContainer::getKeyFactory()->get(mKeyToCopy);
      load();
      mpObject = CCopasiRootContainer::getKeyFactory()->get(mKey);
      save();
      mKeyToCopy = "";
    }

  return true;
}

void CQNotes::slotToggleMode()
{
  mEditMode = !mEditMode;

  if (mEditMode)
    {
      mpWebView->hide();
      mpEdit->show();
      mpBtnToggleEdit->setIcon(CQIconResource::icon(CQIconResource::renderMarkup));
    }
  else
    {
      save();
      load();

      mpEdit->hide();
      mpWebView->show();
      mpBtnToggleEdit->setIcon(CQIconResource::icon(CQIconResource::edit));
    }
}

void CQNotes::slotValidateXML()
{
  QString Input = mpEdit->toPlainText();
  int pos = 0;

  mValidity = mpValidatorXML->validate(Input, pos);

  if (mpValidatorXML->isFreeText())
    {
      mEditMode = true;
      mpBtnToggleEdit->hide();
    }
  else
    {
      mpBtnToggleEdit->show();
    }

  if (mEditMode)
    {
      mpWebView->hide();
      mpEdit->show();
      mpBtnToggleEdit->setIcon(CQIconResource::icon(CQIconResource::renderMarkup));
    }
  else
    {
      mpEdit->hide();
      mpWebView->show();
      mpBtnToggleEdit->setIcon(CQIconResource::icon(CQIconResource::edit));
    }
}

void CQNotes::load()
{
  mpObject = CCopasiRootContainer::getKeyFactory()->get(mKey);

  if (mpObject != NULL)
    {
      QString Notes;

      CAnnotation * pAnnotation = CAnnotation::castObject(mpObject);
      CReportDefinition * pReportDefinition = static_cast< CReportDefinition * >(mpObject);

      if (pAnnotation != NULL)
        {
          Notes = FROM_UTF8(pAnnotation->getNotes());
        }
      else if (pReportDefinition != NULL)
        {
          Notes = FROM_UTF8(pReportDefinition->getComment());
        }

      // The notes are UTF8 encoded however the html does not specify an encoding
      // thus Qt uses locale settings.
      mpWebView->setHtml(Notes);
      mpEdit->setPlainText(Notes);
      mpValidatorXML->saved();
      slotValidateXML();

      if (!mpValidatorXML->isFreeText() && mEditMode)
        {
          slotToggleMode();
        }

      mValidity = QValidator::Acceptable;
    }

  mChanged = false;

  return;
}

void CQNotes::save()
{
  if (mpObject == NULL ||
      mValidity != QValidator::Acceptable)
    return;

  CAnnotation * pAnnotation = CAnnotation::castObject(mpObject);
  CReportDefinition * pReportDefinition = static_cast<CReportDefinition *>(mpObject);

  std::string notes;

  if (pAnnotation != NULL)
    {
      notes = pAnnotation->getNotes();
    }
  else if (pReportDefinition != NULL)
    {
      notes = pReportDefinition->getComment();
    }

  std::string plainText = TO_UTF8(mpEdit->toPlainText());

  if (plainText == notes)
    return;

  if (mpValidatorXML->needsWrap())
    {
      // We wrap the HTML in a body element if it does not contain a top level html or body element.
      plainText = "" + plainText + "";
    }

  if (mpUndoStack == NULL)
    {
      CopasiUI3Window *  pWindow = static_cast<CQCopasiApplication*>(qApp)->getMainWindow();

      if (pWindow)
        mpUndoStack = pWindow->getUndoStack();
    }

  mpUndoStack->push(new ChangeNotesCommand(mpObject, notes, plainText, this));
}

void CQNotes::slotOpenUrl(const QUrl & url)
{
  QDesktopServices::openUrl(url);
  return;
}

void CQNotes::changeNotes(const std::string& key, const std::string& notes)
{
  if (mpListView->getCurrentItemKey() != mKey || key != mKey)
    {
      mpListView->switchToOtherWidget(C_INVALID_INDEX, key);
    }

  mKey = key;
  load();

  CAnnotation * pAnnotation = CAnnotation::castObject(mpObject);
  CReportDefinition * pReportDefinition = static_cast< CReportDefinition * >(mpObject);

  if (pAnnotation != NULL)
    {
      pAnnotation->setNotes(notes);
    }
  else if (pReportDefinition != NULL)
    {
      pReportDefinition->setComment(notes);
    }

  mChanged = true;

  if (mIgnoreUpdates)
    return;

  if (mpDataModel != NULL)
    {
      mpDataModel->changed();
    }

  protectedNotify(ListViews::MODEL, ListViews::CHANGE, mKey);

  mChanged = false;
}
<|endoftext|>


<commit_before>/*
 *
 * Copyright 2016, Google Inc.
 * 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 Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

/* Benchmark gRPC end2end in various configurations */

#include <benchmark/benchmark.h>
#include <gflags/gflags.h>
#include <fstream>
#include "src/core/lib/profiling/timers.h"
#include "src/cpp/client/create_channel_internal.h"
#include "src/proto/grpc/testing/echo.grpc.pb.h"
#include "test/cpp/microbenchmarks/fullstack_context_mutators.h"
#include "test/cpp/microbenchmarks/fullstack_fixtures.h"
extern "C" {
#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
#include "src/core/ext/transport/chttp2/transport/internal.h"
#include "test/core/util/trickle_endpoint.h"
}

DEFINE_bool(log, false, "Log state to CSV files");

namespace grpc {
namespace testing {

static void* tag(intptr_t x) { return reinterpret_cast<void*>(x); }

template <class A0>
static void write_csv(std::ostream* out, A0&& a0) {
  if (!out) return;
  (*out) << a0 << "\n";
}

template <class A0, class... Arg>
static void write_csv(std::ostream* out, A0&& a0, Arg&&... arg) {
  if (!out) return;
  (*out) << a0 << ",";
  write_csv(out, std::forward<Arg>(arg)...);
}

class TrickledCHTTP2 : public EndpointPairFixture {
 public:
  TrickledCHTTP2(Service* service, size_t message_size,
                 size_t megabits_per_second)
      : EndpointPairFixture(service, MakeEndpoints(megabits_per_second),
                            FixtureConfiguration()) {
    if (FLAGS_log) {
      std::ostringstream fn;
      fn << "trickle." << message_size << "." << megabits_per_second << ".csv";
      log_.reset(new std::ofstream(fn.str().c_str()));
      write_csv(log_.get(), "t", "iteration", "client_backlog",
                "server_backlog", "client_t_stall", "client_s_stall",
                "server_t_stall", "server_s_stall", "client_t_outgoing",
                "server_t_outgoing", "client_t_incoming", "server_t_incoming",
                "client_s_outgoing_delta", "server_s_outgoing_delta",
                "client_s_incoming_delta", "server_s_incoming_delta",
                "client_s_announce_window", "server_s_announce_window",
                "client_peer_iws", "client_local_iws", "client_sent_iws",
                "client_acked_iws", "server_peer_iws", "server_local_iws",
                "server_sent_iws", "server_acked_iws");
    }
  }

  void AddToLabel(std::ostream& out, benchmark::State& state) {
    out << " writes/iter:"
        << ((double)stats_.num_writes / (double)state.iterations())
        << " cli_transport_stalls/iter:"
        << ((double)
                client_stats_.streams_stalled_due_to_transport_flow_control /
            (double)state.iterations())
        << " cli_stream_stalls/iter:"
        << ((double)client_stats_.streams_stalled_due_to_stream_flow_control /
            (double)state.iterations())
        << " svr_transport_stalls/iter:"
        << ((double)
                server_stats_.streams_stalled_due_to_transport_flow_control /
            (double)state.iterations())
        << " svr_stream_stalls/iter:"
        << ((double)server_stats_.streams_stalled_due_to_stream_flow_control /
            (double)state.iterations());
  }

  void Log(int64_t iteration) {
    auto now = gpr_time_sub(gpr_now(GPR_CLOCK_MONOTONIC), start_);
    grpc_chttp2_transport* client =
        reinterpret_cast<grpc_chttp2_transport*>(client_transport_);
    grpc_chttp2_transport* server =
        reinterpret_cast<grpc_chttp2_transport*>(server_transport_);
    grpc_chttp2_stream* client_stream =
        client->stream_map.count == 1
            ? static_cast<grpc_chttp2_stream*>(client->stream_map.values[0])
            : nullptr;
    grpc_chttp2_stream* server_stream =
        server->stream_map.count == 1
            ? static_cast<grpc_chttp2_stream*>(server->stream_map.values[0])
            : nullptr;
    write_csv(
        log_.get(), static_cast<double>(now.tv_sec) +
                        1e-9 * static_cast<double>(now.tv_nsec),
        iteration, grpc_trickle_get_backlog(endpoint_pair_.client),
        grpc_trickle_get_backlog(endpoint_pair_.server),
        client->lists[GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT].head != nullptr,
        client->lists[GRPC_CHTTP2_LIST_STALLED_BY_STREAM].head != nullptr,
        server->lists[GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT].head != nullptr,
        server->lists[GRPC_CHTTP2_LIST_STALLED_BY_STREAM].head != nullptr,
        client->outgoing_window, server->outgoing_window,
        client->incoming_window, server->incoming_window,
        client_stream ? client_stream->outgoing_window_delta : -1,
        server_stream ? server_stream->outgoing_window_delta : -1,
        client_stream ? client_stream->incoming_window_delta : -1,
        server_stream ? server_stream->incoming_window_delta : -1,
        client_stream ? client_stream->announce_window : -1,
        server_stream ? server_stream->announce_window : -1,
        client->settings[GRPC_PEER_SETTINGS]
                        [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE],
        client->settings[GRPC_LOCAL_SETTINGS]
                        [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE],
        client->settings[GRPC_SENT_SETTINGS]
                        [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE],
        client->settings[GRPC_ACKED_SETTINGS]
                        [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE],
        server->settings[GRPC_PEER_SETTINGS]
                        [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE],
        server->settings[GRPC_LOCAL_SETTINGS]
                        [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE],
        server->settings[GRPC_SENT_SETTINGS]
                        [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE],
        server->settings[GRPC_ACKED_SETTINGS]
                        [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]);
  }

  void Step() {
    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
    size_t client_backlog =
        grpc_trickle_endpoint_trickle(&exec_ctx, endpoint_pair_.client);
    size_t server_backlog =
        grpc_trickle_endpoint_trickle(&exec_ctx, endpoint_pair_.server);
    grpc_exec_ctx_finish(&exec_ctx);

    UpdateStats((grpc_chttp2_transport*)client_transport_, &client_stats_,
                client_backlog);
    UpdateStats((grpc_chttp2_transport*)server_transport_, &server_stats_,
                server_backlog);
  }

 private:
  grpc_passthru_endpoint_stats stats_;
  struct Stats {
    int streams_stalled_due_to_stream_flow_control = 0;
    int streams_stalled_due_to_transport_flow_control = 0;
  };
  Stats client_stats_;
  Stats server_stats_;
  std::unique_ptr<std::ofstream> log_;
  gpr_timespec start_ = gpr_now(GPR_CLOCK_MONOTONIC);

  grpc_endpoint_pair MakeEndpoints(size_t kilobits) {
    grpc_endpoint_pair p;
    grpc_passthru_endpoint_create(&p.client, &p.server, Library::get().rq(),
                                  &stats_);
    double bytes_per_second = 125.0 * kilobits;
    p.client = grpc_trickle_endpoint_create(p.client, bytes_per_second);
    p.server = grpc_trickle_endpoint_create(p.server, bytes_per_second);
    return p;
  }

  void UpdateStats(grpc_chttp2_transport* t, Stats* s, size_t backlog) {
    if (backlog == 0) {
      if (t->lists[GRPC_CHTTP2_LIST_STALLED_BY_STREAM].head != NULL) {
        s->streams_stalled_due_to_stream_flow_control++;
      }
      if (t->lists[GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT].head != NULL) {
        s->streams_stalled_due_to_transport_flow_control++;
      }
    }
  }
};

// force library initialization
auto& force_library_initialization = Library::get();

static void TrickleCQNext(TrickledCHTTP2* fixture, void** t, bool* ok,
                          int64_t iteration) {
  while (true) {
    fixture->Log(iteration);
    switch (fixture->cq()->AsyncNext(
        t, ok, gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
                            gpr_time_from_micros(100, GPR_TIMESPAN)))) {
      case CompletionQueue::TIMEOUT:
        fixture->Step();
        break;
      case CompletionQueue::SHUTDOWN:
        GPR_ASSERT(false);
        break;
      case CompletionQueue::GOT_EVENT:
        return;
    }
  }
}

static void BM_PumpStreamServerToClient_Trickle(benchmark::State& state) {
  EchoTestService::AsyncService service;
  std::unique_ptr<TrickledCHTTP2> fixture(
      new TrickledCHTTP2(&service, state.range(0), state.range(1)));
  {
    EchoResponse send_response;
    EchoResponse recv_response;
    if (state.range(0) > 0) {
      send_response.set_message(std::string(state.range(0), 'a'));
    }
    Status recv_status;
    ServerContext svr_ctx;
    ServerAsyncReaderWriter<EchoResponse, EchoRequest> response_rw(&svr_ctx);
    service.RequestBidiStream(&svr_ctx, &response_rw, fixture->cq(),
                              fixture->cq(), tag(0));
    std::unique_ptr<EchoTestService::Stub> stub(
        EchoTestService::NewStub(fixture->channel()));
    ClientContext cli_ctx;
    auto request_rw = stub->AsyncBidiStream(&cli_ctx, fixture->cq(), tag(1));
    int need_tags = (1 << 0) | (1 << 1);
    void* t;
    bool ok;
    while (need_tags) {
      TrickleCQNext(fixture.get(), &t, &ok, -1);
      GPR_ASSERT(ok);
      int i = (int)(intptr_t)t;
      GPR_ASSERT(need_tags & (1 << i));
      need_tags &= ~(1 << i);
    }
    request_rw->Read(&recv_response, tag(0));
    while (state.KeepRunning()) {
      GPR_TIMER_SCOPE("BenchmarkCycle", 0);
      response_rw.Write(send_response, tag(1));
      while (true) {
        TrickleCQNext(fixture.get(), &t, &ok, state.iterations());
        if (t == tag(0)) {
          request_rw->Read(&recv_response, tag(0));
        } else if (t == tag(1)) {
          break;
        } else {
          GPR_ASSERT(false);
        }
      }
    }
    response_rw.Finish(Status::OK, tag(1));
    need_tags = (1 << 0) | (1 << 1);
    while (need_tags) {
      TrickleCQNext(fixture.get(), &t, &ok, -1);
      int i = (int)(intptr_t)t;
      GPR_ASSERT(need_tags & (1 << i));
      need_tags &= ~(1 << i);
    }
  }
  fixture->Finish(state);
  fixture.reset();
  state.SetBytesProcessed(state.range(0) * state.iterations());
}

/*******************************************************************************
 * CONFIGURATIONS
 */

static void TrickleArgs(benchmark::internal::Benchmark* b) {
  for (int i = 1; i <= 128 * 1024 * 1024; i *= 8) {
    for (int j = 1; j <= 128 * 1024 * 1024; j *= 8) {
      double expected_time =
          static_cast<double>(14 + i) / (125.0 * static_cast<double>(j));
      if (expected_time > 0.01) continue;
      b->Args({i, j});
    }
  }
}

BENCHMARK(BM_PumpStreamServerToClient_Trickle)->Apply(TrickleArgs);
}
}

int main(int argc, char** argv) {
  ::benchmark::Initialize(&argc, argv);
  ::google::ParseCommandLineFlags(&argc, &argv, false);
  ::benchmark::RunSpecifiedBenchmarks();
}
<commit_msg>more stats<commit_after>/*
 *
 * Copyright 2016, Google Inc.
 * 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 Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

/* Benchmark gRPC end2end in various configurations */

#include <benchmark/benchmark.h>
#include <gflags/gflags.h>
#include <fstream>
#include "src/core/lib/profiling/timers.h"
#include "src/cpp/client/create_channel_internal.h"
#include "src/proto/grpc/testing/echo.grpc.pb.h"
#include "test/cpp/microbenchmarks/fullstack_context_mutators.h"
#include "test/cpp/microbenchmarks/fullstack_fixtures.h"
extern "C" {
#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
#include "src/core/ext/transport/chttp2/transport/internal.h"
#include "test/core/util/trickle_endpoint.h"
}

DEFINE_bool(log, false, "Log state to CSV files");

namespace grpc {
namespace testing {

static void* tag(intptr_t x) { return reinterpret_cast<void*>(x); }

template <class A0>
static void write_csv(std::ostream* out, A0&& a0) {
  if (!out) return;
  (*out) << a0 << "\n";
}

template <class A0, class... Arg>
static void write_csv(std::ostream* out, A0&& a0, Arg&&... arg) {
  if (!out) return;
  (*out) << a0 << ",";
  write_csv(out, std::forward<Arg>(arg)...);
}

class TrickledCHTTP2 : public EndpointPairFixture {
 public:
  TrickledCHTTP2(Service* service, size_t message_size,
                 size_t megabits_per_second)
      : EndpointPairFixture(service, MakeEndpoints(megabits_per_second),
                            FixtureConfiguration()) {
    if (FLAGS_log) {
      std::ostringstream fn;
      fn << "trickle." << message_size << "." << megabits_per_second << ".csv";
      log_.reset(new std::ofstream(fn.str().c_str()));
      write_csv(log_.get(), "t", "iteration", "client_backlog",
                "server_backlog", "client_t_stall", "client_s_stall",
                "server_t_stall", "server_s_stall", "client_t_outgoing",
                "server_t_outgoing", "client_t_incoming", "server_t_incoming",
                "client_s_outgoing_delta", "server_s_outgoing_delta",
                "client_s_incoming_delta", "server_s_incoming_delta",
                "client_s_announce_window", "server_s_announce_window",
                "client_peer_iws", "client_local_iws", "client_sent_iws",
                "client_acked_iws", "server_peer_iws", "server_local_iws",
                "server_sent_iws", "server_acked_iws", "client_queued_bytes",
                "server_queued_bytes");
    }
  }

  void AddToLabel(std::ostream& out, benchmark::State& state) {
    out << " writes/iter:"
        << ((double)stats_.num_writes / (double)state.iterations())
        << " cli_transport_stalls/iter:"
        << ((double)
                client_stats_.streams_stalled_due_to_transport_flow_control /
            (double)state.iterations())
        << " cli_stream_stalls/iter:"
        << ((double)client_stats_.streams_stalled_due_to_stream_flow_control /
            (double)state.iterations())
        << " svr_transport_stalls/iter:"
        << ((double)
                server_stats_.streams_stalled_due_to_transport_flow_control /
            (double)state.iterations())
        << " svr_stream_stalls/iter:"
        << ((double)server_stats_.streams_stalled_due_to_stream_flow_control /
            (double)state.iterations());
  }

  void Log(int64_t iteration) {
    auto now = gpr_time_sub(gpr_now(GPR_CLOCK_MONOTONIC), start_);
    grpc_chttp2_transport* client =
        reinterpret_cast<grpc_chttp2_transport*>(client_transport_);
    grpc_chttp2_transport* server =
        reinterpret_cast<grpc_chttp2_transport*>(server_transport_);
    grpc_chttp2_stream* client_stream =
        client->stream_map.count == 1
            ? static_cast<grpc_chttp2_stream*>(client->stream_map.values[0])
            : nullptr;
    grpc_chttp2_stream* server_stream =
        server->stream_map.count == 1
            ? static_cast<grpc_chttp2_stream*>(server->stream_map.values[0])
            : nullptr;
    write_csv(
        log_.get(), static_cast<double>(now.tv_sec) +
                        1e-9 * static_cast<double>(now.tv_nsec),
        iteration, grpc_trickle_get_backlog(endpoint_pair_.client),
        grpc_trickle_get_backlog(endpoint_pair_.server),
        client->lists[GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT].head != nullptr,
        client->lists[GRPC_CHTTP2_LIST_STALLED_BY_STREAM].head != nullptr,
        server->lists[GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT].head != nullptr,
        server->lists[GRPC_CHTTP2_LIST_STALLED_BY_STREAM].head != nullptr,
        client->outgoing_window, server->outgoing_window,
        client->incoming_window, server->incoming_window,
        client_stream ? client_stream->outgoing_window_delta : -1,
        server_stream ? server_stream->outgoing_window_delta : -1,
        client_stream ? client_stream->incoming_window_delta : -1,
        server_stream ? server_stream->incoming_window_delta : -1,
        client_stream ? client_stream->announce_window : -1,
        server_stream ? server_stream->announce_window : -1,
        client->settings[GRPC_PEER_SETTINGS]
                        [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE],
        client->settings[GRPC_LOCAL_SETTINGS]
                        [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE],
        client->settings[GRPC_SENT_SETTINGS]
                        [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE],
        client->settings[GRPC_ACKED_SETTINGS]
                        [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE],
        server->settings[GRPC_PEER_SETTINGS]
                        [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE],
        server->settings[GRPC_LOCAL_SETTINGS]
                        [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE],
        server->settings[GRPC_SENT_SETTINGS]
                        [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE],
        server->settings[GRPC_ACKED_SETTINGS]
                        [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE],
        client_stream ? client_stream->flow_controlled_buffer.length : 0,
        server_stream ? server_stream->flow_controlled_buffer.length : 0);
  }

  void Step() {
    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
    size_t client_backlog =
        grpc_trickle_endpoint_trickle(&exec_ctx, endpoint_pair_.client);
    size_t server_backlog =
        grpc_trickle_endpoint_trickle(&exec_ctx, endpoint_pair_.server);
    grpc_exec_ctx_finish(&exec_ctx);

    UpdateStats((grpc_chttp2_transport*)client_transport_, &client_stats_,
                client_backlog);
    UpdateStats((grpc_chttp2_transport*)server_transport_, &server_stats_,
                server_backlog);
  }

 private:
  grpc_passthru_endpoint_stats stats_;
  struct Stats {
    int streams_stalled_due_to_stream_flow_control = 0;
    int streams_stalled_due_to_transport_flow_control = 0;
  };
  Stats client_stats_;
  Stats server_stats_;
  std::unique_ptr<std::ofstream> log_;
  gpr_timespec start_ = gpr_now(GPR_CLOCK_MONOTONIC);

  grpc_endpoint_pair MakeEndpoints(size_t kilobits) {
    grpc_endpoint_pair p;
    grpc_passthru_endpoint_create(&p.client, &p.server, Library::get().rq(),
                                  &stats_);
    double bytes_per_second = 125.0 * kilobits;
    p.client = grpc_trickle_endpoint_create(p.client, bytes_per_second);
    p.server = grpc_trickle_endpoint_create(p.server, bytes_per_second);
    return p;
  }

  void UpdateStats(grpc_chttp2_transport* t, Stats* s, size_t backlog) {
    if (backlog == 0) {
      if (t->lists[GRPC_CHTTP2_LIST_STALLED_BY_STREAM].head != NULL) {
        s->streams_stalled_due_to_stream_flow_control++;
      }
      if (t->lists[GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT].head != NULL) {
        s->streams_stalled_due_to_transport_flow_control++;
      }
    }
  }
};

// force library initialization
auto& force_library_initialization = Library::get();

static void TrickleCQNext(TrickledCHTTP2* fixture, void** t, bool* ok,
                          int64_t iteration) {
  while (true) {
    fixture->Log(iteration);
    switch (fixture->cq()->AsyncNext(
        t, ok, gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
                            gpr_time_from_micros(100, GPR_TIMESPAN)))) {
      case CompletionQueue::TIMEOUT:
        fixture->Step();
        break;
      case CompletionQueue::SHUTDOWN:
        GPR_ASSERT(false);
        break;
      case CompletionQueue::GOT_EVENT:
        return;
    }
  }
}

static void BM_PumpStreamServerToClient_Trickle(benchmark::State& state) {
  EchoTestService::AsyncService service;
  std::unique_ptr<TrickledCHTTP2> fixture(
      new TrickledCHTTP2(&service, state.range(0), state.range(1)));
  {
    EchoResponse send_response;
    EchoResponse recv_response;
    if (state.range(0) > 0) {
      send_response.set_message(std::string(state.range(0), 'a'));
    }
    Status recv_status;
    ServerContext svr_ctx;
    ServerAsyncReaderWriter<EchoResponse, EchoRequest> response_rw(&svr_ctx);
    service.RequestBidiStream(&svr_ctx, &response_rw, fixture->cq(),
                              fixture->cq(), tag(0));
    std::unique_ptr<EchoTestService::Stub> stub(
        EchoTestService::NewStub(fixture->channel()));
    ClientContext cli_ctx;
    auto request_rw = stub->AsyncBidiStream(&cli_ctx, fixture->cq(), tag(1));
    int need_tags = (1 << 0) | (1 << 1);
    void* t;
    bool ok;
    while (need_tags) {
      TrickleCQNext(fixture.get(), &t, &ok, -1);
      GPR_ASSERT(ok);
      int i = (int)(intptr_t)t;
      GPR_ASSERT(need_tags & (1 << i));
      need_tags &= ~(1 << i);
    }
    request_rw->Read(&recv_response, tag(0));
    while (state.KeepRunning()) {
      GPR_TIMER_SCOPE("BenchmarkCycle", 0);
      response_rw.Write(send_response, tag(1));
      while (true) {
        TrickleCQNext(fixture.get(), &t, &ok, state.iterations());
        if (t == tag(0)) {
          request_rw->Read(&recv_response, tag(0));
        } else if (t == tag(1)) {
          break;
        } else {
          GPR_ASSERT(false);
        }
      }
    }
    response_rw.Finish(Status::OK, tag(1));
    need_tags = (1 << 0) | (1 << 1);
    while (need_tags) {
      TrickleCQNext(fixture.get(), &t, &ok, -1);
      int i = (int)(intptr_t)t;
      GPR_ASSERT(need_tags & (1 << i));
      need_tags &= ~(1 << i);
    }
  }
  fixture->Finish(state);
  fixture.reset();
  state.SetBytesProcessed(state.range(0) * state.iterations());
}

/*******************************************************************************
 * CONFIGURATIONS
 */

static void TrickleArgs(benchmark::internal::Benchmark* b) {
  for (int i = 1; i <= 128 * 1024 * 1024; i *= 8) {
    for (int j = 1; j <= 128 * 1024 * 1024; j *= 8) {
      double expected_time =
          static_cast<double>(14 + i) / (125.0 * static_cast<double>(j));
      if (expected_time > 0.01) continue;
      b->Args({i, j});
    }
  }
}

BENCHMARK(BM_PumpStreamServerToClient_Trickle)->Apply(TrickleArgs);
}
}

int main(int argc, char** argv) {
  ::benchmark::Initialize(&argc, argv);
  ::google::ParseCommandLineFlags(&argc, &argv, false);
  ::benchmark::RunSpecifiedBenchmarks();
}
<|endoftext|>