<commit_before>AliAnalysisTaskElectronEfficiencyV2* AddTask_dsekihat_ElectronEfficiencyV2_PbPb(
    Bool_t getFromAlien = kFALSE,
    TString configFile="Config_dsekihat_ElectronEfficiencyV2_PbPb.C",
    TString libFile="LMEECutLib_dsekihat.C",
    UInt_t trigger = AliVEvent::kINT7,
    const Int_t CenMin =  0,
    const Int_t CenMax = 10,
    const Bool_t applyPairCut = kTRUE,
    const TString pileupcut = "_woPU",//can be "_woPU", "_onlyPU",""
    const TString generators = "pizero_0;eta_1;etaprime_2;rho_3;omega_4;phi_5;jpsi_6;EvtGenDecay;Pythia CC_0;Pythia BB_0;Pythia B_0;",
    const TString calibFileName = "",
    const std::string resolutionFilename ="",
    const std::string cocktailFilename   ="",
    const std::string centralityFilename ="",
		const TString outname = "LMEE.root"
    ){

  // Configuring Analysis Manager
  AliAnalysisManager* mgr = AliAnalysisManager::GetAnalysisManager();

	TString suffix = "";
	if(generators.Contains("Pythia CC") && (generators.Contains("Pythia BB") || generators.Contains("Pythia B"))) suffix = "_CC_BB";
	else if(generators.Contains("Pythia CC")) suffix = "_CC";
	else if(generators.Contains("Pythia BB") || generators.Contains("Pythia B")) suffix = "_BB";
	else if(generators.Contains("pizero")) suffix = "_LF";
	else suffix = "";

  // Creating an instance of the task
  AliAnalysisTaskElectronEfficiencyV2* task = new AliAnalysisTaskElectronEfficiencyV2(Form("TaskElectronEfficiencyV2%s_Cen%d_%d_kINT7%s",suffix.Data(),CenMin,CenMax,pileupcut.Data()));
  gROOT->GetListOfSpecials()->Add(task);//this is only for ProcessLine(AddMCSignal);

  //TString configBasePath("$ALICE_PHYSICS/PWGDQ/dielectron/macrosLMEE/");
	TString configBasePath("./");
	if(getFromAlien
			&& (!gSystem->Exec(Form("alien_cp alien:///alice/cern.ch/user/d/dsekihat/PWGDQ/dielectron/macrosLMEE/%s .",configFile.Data())))
			&& (!gSystem->Exec(Form("alien_cp alien:///alice/cern.ch/user/d/dsekihat/PWGDQ/dielectron/macrosLMEE/%s .",libFile.Data())))
		){
		configBasePath=Form("%s/",gSystem->pwd());
	}
	TString configFilePath(configBasePath + configFile);

  //load cut library first
  TString libFilePath(configBasePath + libFile);
  std::cout << "Configpath:  " << configFilePath << std::endl;
  std::cout << "Libpath:  " << libFilePath << std::endl;

  gROOT->LoadMacro(libFilePath.Data());//library first
  gROOT->LoadMacro(configFilePath.Data());

  const Int_t nTC  = Int_t(gROOT->ProcessLine("GetNTC()") );
  const Int_t nPID = Int_t(gROOT->ProcessLine("GetNPID()"));
  const Int_t nPF  = Int_t(gROOT->ProcessLine("GetNPF()") );

	for (Int_t itc=0; itc<nTC; ++itc){
		for (Int_t ipid=0; ipid<nPID; ++ipid){
			for (Int_t ipf=0; ipf<nPF; ++ipf){
				AliAnalysisFilter *filter = reinterpret_cast<AliAnalysisFilter*>(gROOT->ProcessLine(Form("Config_dsekihat_ElectronEfficiencyV2_PbPb(%d,%d,%d,%d)",itc,ipid,ipf,applyPairCut)));
				task->AddTrackCuts(filter);
			}
		}
	}

  //It is important to apply pileup cuts at "task" level in M.C. for efficiency. (i.e. Both denominator and nominator has to be taken into account in exactly the same events.)

  // Event selection. Is the same for all the different cutsettings
  task->SetEnablePhysicsSelection(kTRUE);//always ON in Run2 analyses for both data and MC.
  task->SetTriggerMask(trigger);
  task->SetEventFilter(reinterpret_cast<AliDielectronEventCuts*>(gROOT->ProcessLine(Form("LMEECutLib::SetupEventCuts(%f,%f,%d,\"%s\")",(Float_t)CenMin,(Float_t)CenMax,kTRUE,"V0M"))));//kTRUE is for Run2
  if(pileupcut == ""){
    printf("analyze all events in M.C.\n");
  }
  else if(pileupcut.Contains("woPU")){
    printf("analyze only in clean events in M.C.\n");
    TF1 *f1pu = reinterpret_cast<TF1*>(gROOT->ProcessLine("LMEECutLib::SetupPileupCuts()"));
    dynamic_cast<AliDielectronEventCuts*>(task->GetEventFilter())->SetMinCorrCutFunction(f1pu, AliDielectronVarManager::kNTPCclsEvent, AliDielectronVarManager::kNSDDSSDclsEvent);
  }
  else if(pileupcut.Contains("onlyPU")){
    printf("analyze only in pileup events in M.C.\n");
    TF1 *f1pu = reinterpret_cast<TF1*>(gROOT->ProcessLine("LMEECutLib::SetupPileupCuts()"));
    dynamic_cast<AliDielectronEventCuts*>(task->GetEventFilter())->SetMaxCorrCutFunction(f1pu, AliDielectronVarManager::kNTPCclsEvent, AliDielectronVarManager::kNSDDSSDclsEvent);
  }
  else{
    printf("Nothing with pileup cut in M.C.\n");
    printf("analyze all events in M.C.\n");
  }
  dynamic_cast<AliDielectronEventCuts*>(task->GetEventFilter())->Print();

  // Set minimum and maximum values of generated tracks. Only used to save computing power.
  // Do not set here your analysis pt-cuts
  task->SetMinPtGen(0.1);
  task->SetMaxPtGen(1e+10);
  task->SetMinEtaGen(-1.5);
  task->SetMaxEtaGen(+1.5);

  // Set minimum and maximum values for pairing
  task->SetKinematicCuts(0.2, 10, -0.8, +0.8);

  // Set Binning
  task->SetPtBinsLinear   (0, 10, 100);
  task->SetEtaBinsLinear  (-1, +1, 20);
  task->SetPhiBinsLinear  (0, TMath::TwoPi(), 36);
  task->SetThetaBinsLinear(0, TMath::TwoPi(), 60);

  const Int_t Nmee = 150;
  Double_t mee[Nmee] = {};
  for(Int_t i=0  ;i<110 ;i++) mee[i] = 0.01 * (i-  0) +  0.0;//from 0 to 1.1 GeV/c2, every 0.01 GeV/c2
  for(Int_t i=110;i<Nmee;i++) mee[i] = 0.1  * (i-110) +  1.1;//from 1.1 to 5 GeV/c2, evety 0.1 GeV/c2
	std::vector<double> v_mee(mee,std::end(mee));

  const Int_t NpTee = 121;
  Double_t pTee[NpTee] = {};
  for(Int_t i=0  ;i<10   ;i++) pTee[i] = 0.01 * (i-  0) +  0.0;//from 0 to 0.09 GeV/c, every 0.01 GeV/c
  for(Int_t i=10 ;i<110  ;i++) pTee[i] = 0.1  * (i- 10) +  0.1;//from 0.1 to 10 GeV/c, evety 0.1 GeV/c
  for(Int_t i=110;i<NpTee;i++) pTee[i] = 1.0  * (i-110) + 10.0;//from 10 to 20 GeV/c, evety 1.0 GeV/c
	std::vector<double> v_pTee(pTee,std::end(pTee));

  task->SetMassBins(v_mee);
  task->SetPairPtBins(v_pTee);
  task->SetPhiVBinsLinear(0, TMath::Pi(), 100);
  task->SetFillPhiV(kFALSE);

  task->SetSmearGenerated(kFALSE);
  task->SetResolutionDeltaPtBinsLinear( -10,  +10, 2000);
  task->SetResolutionRelPtBinsLinear  (   0,    2,  400);
  task->SetResolutionEtaBinsLinear    (-0.4, +0.4,  200);
  task->SetResolutionPhiBinsLinear    (-0.4, +0.4,  200);
  task->SetResolutionThetaBinsLinear  (-0.4, +0.4,  200);

  // Set MCSignal and Cutsetting to fill the support histograms
  task->SetSupportHistoMCSignalAndCutsetting(0,0);//fill support histograms for first MCsignal and first cutsetting

  // Pairing related config
  task->SetDoPairing(kTRUE);
  task->SetULSandLS(kTRUE);
  task->SetDeactivateLS(kFALSE);

  //TString generators = "pizero_0;eta_1;etaprime_2;rho_3;omega_4;phi_5;jpsi_6;";
  //TString generators = "pizero_0;eta_1;etaprime_2;rho_3;omega_4;phi_5;jpsi_6;Pythia CC_0;Pythia BB_0;Pythia B_0;";
  //TString generators = "Pythia CC_0;Pythia BB_0;Pythia B_0;";
  //TString generators = "Pythia CC_0;";
  //TString generators = "Pythia BB_0;Pythia B_0;";
  //TString generators = "Pythia BB_0;";
  //TString generators = "Pythia B_0";

  cout<<"Efficiency based on MC generators: " << generators <<endl;
  TString generatorsPair=generators;
  task->SetGeneratorMCSignalName(generatorsPair);
  task->SetGeneratorULSSignalName(generators);
  //task->SetLHC19f2MC(isLHC19f2);

	//if(resolutionFilename != "") gSystem->Exec(Form("alien_cp alien:///alice/cern.ch/user/d/dsekihat/PWGDQ/dielectron/resolution/%s .",resolutionFilename.c_str()));//this is to avoid unnecessary call of alien_cp in task.
	//if(cocktailFilename   != "") gSystem->Exec(Form("alien_cp alien:///alice/cern.ch/user/d/dsekihat/PWGDQ/dielectron/cocktail/%s ."    ,cocktailFilename.c_str()));//this is to avoid unnecessary call of alien_cp in task.
	//if(centralityFilename != "") gSystem->Exec(Form("alien_cp alien:///alice/cern.ch/user/d/dsekihat/PWGDQ/dielectron/centrality/%s .",centralityFilename.c_str()));//this is to avoid unnecessary call of alien_cp in task.
	//gSystem->Exec(Form("alien_cp alien:///alice/cern.ch/user/d/dsekihat/PWGDQ/dielectron/resolution/%s .",resolutionFilename.c_str()));//this is to avoid unnecessary call of alien_cp in task.
	//gSystem->Exec(Form("alien_cp alien:///alice/cern.ch/user/d/dsekihat/PWGDQ/dielectron/cocktail/%s ."    ,cocktailFilename.c_str()));//this is to avoid unnecessary call of alien_cp in task.
	//gSystem->Exec(Form("alien_cp alien:///alice/cern.ch/user/d/dsekihat/PWGDQ/dielectron/centrality/%s .",centralityFilename.c_str()));//this is to avoid unnecessary call of alien_cp in task.

  // Resolution File, If resoFilename = "" no correction is applied
  task->SetResolutionFile(resolutionFilename);
  task->SetResolutionFileFromAlien("/alice/cern.ch/user/d/dsekihat/PWGDQ/dielectron/resolution/" + resolutionFilename);
  task->SetCocktailWeighting(cocktailFilename);
  task->SetCocktailWeightingFromAlien("/alice/cern.ch/user/d/dsekihat/PWGDQ/dielectron/cocktail/" + cocktailFilename);
  task->SetCentralityFile(centralityFilename);

  // Add MCSignals. Can be set to see differences of:
  // e.g. secondaries and primaries. or primaries from charm and resonances
  gROOT->ProcessLine(Form("AddSingleLegMCSignal(%s)",task->GetName()));//not task itself, task name
  gROOT->ProcessLine(Form("AddPairMCSignal(%s)"     ,task->GetName()));//not task itself, task name

  //set PID map for ITS TOF in MC.
  TFile *rootfile = 0x0;
  if(calibFileName != "") rootfile = TFile::Open(calibFileName,"READ");
  if(rootfile && rootfile->IsOpen()){
    TH3D *h3mean_ITS  = (TH3D*)rootfile->Get("h3mean_ITS");
    TH3D *h3width_ITS = (TH3D*)rootfile->Get("h3width_ITS");
    h3mean_ITS ->SetDirectory(0);
    h3width_ITS->SetDirectory(0);
    task->SetCentroidCorrFunction(AliAnalysisTaskElectronEfficiencyV2::kITS, h3mean_ITS, AliDielectronVarManager::kNSDDSSDclsEvent, AliDielectronVarManager::kPIn,  AliDielectronVarManager::kEta);
    task->SetWidthCorrFunction(AliAnalysisTaskElectronEfficiencyV2::kITS, h3width_ITS, AliDielectronVarManager::kNSDDSSDclsEvent, AliDielectronVarManager::kPIn,  AliDielectronVarManager::kEta );

    TH3D *h3mean_TOF = (TH3D*)rootfile->Get("h3mean_TOF");
    TH3D *h3width_TOF = (TH3D*)rootfile->Get("h3width_TOF");
    h3mean_TOF ->SetDirectory(0);
    h3width_TOF->SetDirectory(0);
    task->SetCentroidCorrFunction(AliAnalysisTaskElectronEfficiencyV2::kTOF, h3mean_TOF, AliDielectronVarManager::kNSDDSSDclsEvent, AliDielectronVarManager::kPIn,  AliDielectronVarManager::kEta);
    task->SetWidthCorrFunction(AliAnalysisTaskElectronEfficiencyV2::kTOF, h3width_TOF, AliDielectronVarManager::kNSDDSSDclsEvent, AliDielectronVarManager::kPIn,  AliDielectronVarManager::kEta);

    rootfile->Close();
  }
	TString outlistname = Form("Efficiency_dsekihat%s_Cen%d_%d_kINT7%s",suffix.Data(),CenMin,CenMax,pileupcut.Data());

  //const TString fileName = AliAnalysisManager::GetCommonFileName();
  const TString fileName = outname;
	//const TString dirname = Form("PWGDQ_LMEE_ElectronEfficiencyV2_Cen%d_%d_kINT7",CenMin,CenMax);
  mgr->AddTask(task);
  mgr->ConnectInput(task,  0, mgr->GetCommonInputContainer());
  mgr->ConnectOutput(task, 1, mgr->CreateContainer(outlistname, TList::Class(), AliAnalysisManager::kOutputContainer, Form("%s",fileName.Data())));
  return task;
}

<commit_msg>PWGDQ/LMEE: change mee,pTee binning in MC<commit_after>AliAnalysisTaskElectronEfficiencyV2* AddTask_dsekihat_ElectronEfficiencyV2_PbPb(
    Bool_t getFromAlien = kFALSE,
    TString configFile="Config_dsekihat_ElectronEfficiencyV2_PbPb.C",
    TString libFile="LMEECutLib_dsekihat.C",
    UInt_t trigger = AliVEvent::kINT7,
    const Int_t CenMin =  0,
    const Int_t CenMax = 10,
    const Bool_t applyPairCut = kTRUE,
    const TString pileupcut = "_woPU",//can be "_woPU", "_onlyPU",""
    const TString generators = "pizero_0;eta_1;etaprime_2;rho_3;omega_4;phi_5;jpsi_6;EvtGenDecay;Pythia CC_0;Pythia BB_0;Pythia B_0;",
    const TString calibFileName = "",
    const std::string resolutionFilename ="",
    const std::string cocktailFilename   ="",
    const std::string centralityFilename ="",
		const TString outname = "LMEE.root"
    ){

  // Configuring Analysis Manager
  AliAnalysisManager* mgr = AliAnalysisManager::GetAnalysisManager();

	TString suffix = "";
	if(generators.Contains("Pythia CC") && (generators.Contains("Pythia BB") || generators.Contains("Pythia B"))) suffix = "_CC_BB";
	else if(generators.Contains("Pythia CC")) suffix = "_CC";
	else if(generators.Contains("Pythia BB") || generators.Contains("Pythia B")) suffix = "_BB";
	else if(generators.Contains("pizero")) suffix = "_LF";
	else suffix = "";

  // Creating an instance of the task
  AliAnalysisTaskElectronEfficiencyV2* task = new AliAnalysisTaskElectronEfficiencyV2(Form("TaskElectronEfficiencyV2%s_Cen%d_%d_kINT7%s",suffix.Data(),CenMin,CenMax,pileupcut.Data()));
  gROOT->GetListOfSpecials()->Add(task);//this is only for ProcessLine(AddMCSignal);

  //TString configBasePath("$ALICE_PHYSICS/PWGDQ/dielectron/macrosLMEE/");
	TString configBasePath("./");
	if(getFromAlien
			&& (!gSystem->Exec(Form("alien_cp alien:///alice/cern.ch/user/d/dsekihat/PWGDQ/dielectron/macrosLMEE/%s .",configFile.Data())))
			&& (!gSystem->Exec(Form("alien_cp alien:///alice/cern.ch/user/d/dsekihat/PWGDQ/dielectron/macrosLMEE/%s .",libFile.Data())))
		){
		configBasePath=Form("%s/",gSystem->pwd());
	}
	TString configFilePath(configBasePath + configFile);

  //load cut library first
  TString libFilePath(configBasePath + libFile);
  std::cout << "Configpath:  " << configFilePath << std::endl;
  std::cout << "Libpath:  " << libFilePath << std::endl;

  gROOT->LoadMacro(libFilePath.Data());//library first
  gROOT->LoadMacro(configFilePath.Data());

  const Int_t nTC  = Int_t(gROOT->ProcessLine("GetNTC()") );
  const Int_t nPID = Int_t(gROOT->ProcessLine("GetNPID()"));
  const Int_t nPF  = Int_t(gROOT->ProcessLine("GetNPF()") );

	for (Int_t itc=0; itc<nTC; ++itc){
		for (Int_t ipid=0; ipid<nPID; ++ipid){
			for (Int_t ipf=0; ipf<nPF; ++ipf){
				AliAnalysisFilter *filter = reinterpret_cast<AliAnalysisFilter*>(gROOT->ProcessLine(Form("Config_dsekihat_ElectronEfficiencyV2_PbPb(%d,%d,%d,%d)",itc,ipid,ipf,applyPairCut)));
				task->AddTrackCuts(filter);
			}
		}
	}

  //It is important to apply pileup cuts at "task" level in M.C. for efficiency. (i.e. Both denominator and nominator has to be taken into account in exactly the same events.)

  // Event selection. Is the same for all the different cutsettings
  task->SetEnablePhysicsSelection(kTRUE);//always ON in Run2 analyses for both data and MC.
  task->SetTriggerMask(trigger);
  task->SetEventFilter(reinterpret_cast<AliDielectronEventCuts*>(gROOT->ProcessLine(Form("LMEECutLib::SetupEventCuts(%f,%f,%d,\"%s\")",(Float_t)CenMin,(Float_t)CenMax,kTRUE,"V0M"))));//kTRUE is for Run2
  if(pileupcut == ""){
    printf("analyze all events in M.C.\n");
  }
  else if(pileupcut.Contains("woPU")){
    printf("analyze only in clean events in M.C.\n");
    TF1 *f1pu = reinterpret_cast<TF1*>(gROOT->ProcessLine("LMEECutLib::SetupPileupCuts()"));
    dynamic_cast<AliDielectronEventCuts*>(task->GetEventFilter())->SetMinCorrCutFunction(f1pu, AliDielectronVarManager::kNTPCclsEvent, AliDielectronVarManager::kNSDDSSDclsEvent);
  }
  else if(pileupcut.Contains("onlyPU")){
    printf("analyze only in pileup events in M.C.\n");
    TF1 *f1pu = reinterpret_cast<TF1*>(gROOT->ProcessLine("LMEECutLib::SetupPileupCuts()"));
    dynamic_cast<AliDielectronEventCuts*>(task->GetEventFilter())->SetMaxCorrCutFunction(f1pu, AliDielectronVarManager::kNTPCclsEvent, AliDielectronVarManager::kNSDDSSDclsEvent);
  }
  else{
    printf("Nothing with pileup cut in M.C.\n");
    printf("analyze all events in M.C.\n");
  }
  dynamic_cast<AliDielectronEventCuts*>(task->GetEventFilter())->Print();

  // Set minimum and maximum values of generated tracks. Only used to save computing power.
  // Do not set here your analysis pt-cuts
  task->SetMinPtGen(0.1);
  task->SetMaxPtGen(1e+10);
  task->SetMinEtaGen(-1.5);
  task->SetMaxEtaGen(+1.5);

  // Set minimum and maximum values for pairing
  task->SetKinematicCuts(0.2, 10, -0.8, +0.8);

  // Set Binning
  task->SetPtBinsLinear   (0, 10, 100);
  task->SetEtaBinsLinear  (-1, +1, 20);
  task->SetPhiBinsLinear  (0, TMath::TwoPi(), 36);
  task->SetThetaBinsLinear(0, TMath::TwoPi(), 60);

  const Int_t Nmee = 150;
  Double_t mee[Nmee] = {};
  for(Int_t i=0  ;i<110 ;i++) mee[i] = 0.01 * (i-  0) +  0.0;//from 0 to 1.1 GeV/c2, every 0.01 GeV/c2
  for(Int_t i=110;i<Nmee;i++) mee[i] = 0.1  * (i-110) +  1.1;//from 1.1 to 5 GeV/c2, evety 0.1 GeV/c2
	std::vector<double> v_mee(mee,std::end(mee));

  const Int_t NpTee = 146;
  Double_t pTee[NpTee] = {};
  for(Int_t i=0  ;i<50    ;i++) pTee[i] = 0.01 * (i-  0) +  0.0;//from 0 to 0.49 GeV/c, every 0.01 GeV/c
  for(Int_t i=50 ;i<NpTee ;i++) pTee[i] = 0.1  * (i- 50) +  0.5;//from 0.5 to 10 GeV/c, evety 0.1 GeV/c
  std::vector<double> v_pTee(pTee,std::end(pTee));

  task->SetMassBins(v_mee);
  task->SetPairPtBins(v_pTee);
  task->SetPhiVBinsLinear(0, TMath::Pi(), 100);
  task->SetFillPhiV(kFALSE);

  task->SetSmearGenerated(kFALSE);
  task->SetResolutionDeltaPtBinsLinear( -10,  +10, 2000);
  task->SetResolutionRelPtBinsLinear  (   0,    2,  400);
  task->SetResolutionEtaBinsLinear    (-0.4, +0.4,  200);
  task->SetResolutionPhiBinsLinear    (-0.4, +0.4,  200);
  task->SetResolutionThetaBinsLinear  (-0.4, +0.4,  200);

  // Set MCSignal and Cutsetting to fill the support histograms
  task->SetSupportHistoMCSignalAndCutsetting(0,0);//fill support histograms for first MCsignal and first cutsetting

  // Pairing related config
  task->SetDoPairing(kTRUE);
  task->SetULSandLS(kTRUE);
  task->SetDeactivateLS(kFALSE);

  //TString generators = "pizero_0;eta_1;etaprime_2;rho_3;omega_4;phi_5;jpsi_6;";
  //TString generators = "pizero_0;eta_1;etaprime_2;rho_3;omega_4;phi_5;jpsi_6;Pythia CC_0;Pythia BB_0;Pythia B_0;";
  //TString generators = "Pythia CC_0;Pythia BB_0;Pythia B_0;";
  //TString generators = "Pythia CC_0;";
  //TString generators = "Pythia BB_0;Pythia B_0;";
  //TString generators = "Pythia BB_0;";
  //TString generators = "Pythia B_0";

  cout<<"Efficiency based on MC generators: " << generators <<endl;
  TString generatorsPair=generators;
  task->SetGeneratorMCSignalName(generatorsPair);
  task->SetGeneratorULSSignalName(generators);
  //task->SetLHC19f2MC(isLHC19f2);

	//if(resolutionFilename != "") gSystem->Exec(Form("alien_cp alien:///alice/cern.ch/user/d/dsekihat/PWGDQ/dielectron/resolution/%s .",resolutionFilename.c_str()));//this is to avoid unnecessary call of alien_cp in task.
	//if(cocktailFilename   != "") gSystem->Exec(Form("alien_cp alien:///alice/cern.ch/user/d/dsekihat/PWGDQ/dielectron/cocktail/%s ."    ,cocktailFilename.c_str()));//this is to avoid unnecessary call of alien_cp in task.
	//if(centralityFilename != "") gSystem->Exec(Form("alien_cp alien:///alice/cern.ch/user/d/dsekihat/PWGDQ/dielectron/centrality/%s .",centralityFilename.c_str()));//this is to avoid unnecessary call of alien_cp in task.
	//gSystem->Exec(Form("alien_cp alien:///alice/cern.ch/user/d/dsekihat/PWGDQ/dielectron/resolution/%s .",resolutionFilename.c_str()));//this is to avoid unnecessary call of alien_cp in task.
	//gSystem->Exec(Form("alien_cp alien:///alice/cern.ch/user/d/dsekihat/PWGDQ/dielectron/cocktail/%s ."    ,cocktailFilename.c_str()));//this is to avoid unnecessary call of alien_cp in task.
	//gSystem->Exec(Form("alien_cp alien:///alice/cern.ch/user/d/dsekihat/PWGDQ/dielectron/centrality/%s .",centralityFilename.c_str()));//this is to avoid unnecessary call of alien_cp in task.

  // Resolution File, If resoFilename = "" no correction is applied
  task->SetResolutionFile(resolutionFilename);
  task->SetResolutionFileFromAlien("/alice/cern.ch/user/d/dsekihat/PWGDQ/dielectron/resolution/" + resolutionFilename);
  task->SetCocktailWeighting(cocktailFilename);
  task->SetCocktailWeightingFromAlien("/alice/cern.ch/user/d/dsekihat/PWGDQ/dielectron/cocktail/" + cocktailFilename);
  task->SetCentralityFile(centralityFilename);

  // Add MCSignals. Can be set to see differences of:
  // e.g. secondaries and primaries. or primaries from charm and resonances
  gROOT->ProcessLine(Form("AddSingleLegMCSignal(%s)",task->GetName()));//not task itself, task name
  gROOT->ProcessLine(Form("AddPairMCSignal(%s)"     ,task->GetName()));//not task itself, task name

  //set PID map for ITS TOF in MC.
  TFile *rootfile = 0x0;
  if(calibFileName != "") rootfile = TFile::Open(calibFileName,"READ");
  if(rootfile && rootfile->IsOpen()){
    TH3D *h3mean_ITS  = (TH3D*)rootfile->Get("h3mean_ITS");
    TH3D *h3width_ITS = (TH3D*)rootfile->Get("h3width_ITS");
    h3mean_ITS ->SetDirectory(0);
    h3width_ITS->SetDirectory(0);
    task->SetCentroidCorrFunction(AliAnalysisTaskElectronEfficiencyV2::kITS, h3mean_ITS, AliDielectronVarManager::kNSDDSSDclsEvent, AliDielectronVarManager::kPIn,  AliDielectronVarManager::kEta);
    task->SetWidthCorrFunction(AliAnalysisTaskElectronEfficiencyV2::kITS, h3width_ITS, AliDielectronVarManager::kNSDDSSDclsEvent, AliDielectronVarManager::kPIn,  AliDielectronVarManager::kEta );

    TH3D *h3mean_TOF = (TH3D*)rootfile->Get("h3mean_TOF");
    TH3D *h3width_TOF = (TH3D*)rootfile->Get("h3width_TOF");
    h3mean_TOF ->SetDirectory(0);
    h3width_TOF->SetDirectory(0);
    task->SetCentroidCorrFunction(AliAnalysisTaskElectronEfficiencyV2::kTOF, h3mean_TOF, AliDielectronVarManager::kNSDDSSDclsEvent, AliDielectronVarManager::kPIn,  AliDielectronVarManager::kEta);
    task->SetWidthCorrFunction(AliAnalysisTaskElectronEfficiencyV2::kTOF, h3width_TOF, AliDielectronVarManager::kNSDDSSDclsEvent, AliDielectronVarManager::kPIn,  AliDielectronVarManager::kEta);

    rootfile->Close();
  }
	TString outlistname = Form("Efficiency_dsekihat%s_Cen%d_%d_kINT7%s",suffix.Data(),CenMin,CenMax,pileupcut.Data());

  //const TString fileName = AliAnalysisManager::GetCommonFileName();
  const TString fileName = outname;
	//const TString dirname = Form("PWGDQ_LMEE_ElectronEfficiencyV2_Cen%d_%d_kINT7",CenMin,CenMax);
  mgr->AddTask(task);
  mgr->ConnectInput(task,  0, mgr->GetCommonInputContainer());
  mgr->ConnectOutput(task, 1, mgr->CreateContainer(outlistname, TList::Class(), AliAnalysisManager::kOutputContainer, Form("%s",fileName.Data())));
  return task;
}

<|endoftext|>


<commit_before>
/*
 * Copyright 2014 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "src/gpu/GrContextPriv.h"
#include "tools/gpu/GrContextFactory.h"
#ifdef SK_GL
#include "tools/gpu/gl/GLTestContext.h"
#endif

#if SK_ANGLE
#include "tools/gpu/gl/angle/GLTestContext_angle.h"
#endif
#include "tools/gpu/gl/command_buffer/GLTestContext_command_buffer.h"
#ifdef SK_VULKAN
#include "tools/gpu/vk/VkTestContext.h"
#endif
#ifdef SK_METAL
#include "tools/gpu/mtl/MtlTestContext.h"
#endif
#ifdef SK_DIRECT3D
#include "tools/gpu/d3d/D3DTestContext.h"
#endif
#ifdef SK_DAWN
#include "tools/gpu/dawn/DawnTestContext.h"
#endif
#include "src/gpu/GrCaps.h"
#include "src/gpu/gl/GrGLGpu.h"
#include "tools/gpu/mock/MockTestContext.h"

#if defined(SK_BUILD_FOR_WIN) && defined(SK_ENABLE_DISCRETE_GPU)
extern "C" {
    // NVIDIA documents that the presence and value of this symbol programmatically enable the high
    // performance GPU in laptops with switchable graphics.
    //   https://docs.nvidia.com/gameworks/content/technologies/desktop/optimus.htm
    // From testing, including this symbol, even if it is set to 0, we still get the NVIDIA GPU.
    _declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001;

    // AMD has a similar mechanism, although I don't have an AMD laptop, so this is untested.
    //   https://community.amd.com/thread/169965
    __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
}
#endif

namespace sk_gpu_test {
GrContextFactory::GrContextFactory() { }

GrContextFactory::GrContextFactory(const GrContextOptions& opts)
    : fGlobalOptions(opts) {
}

GrContextFactory::~GrContextFactory() {
    this->destroyContexts();
}

void GrContextFactory::destroyContexts() {
    // We must delete the test contexts in reverse order so that any child context is finished and
    // deleted before a parent context. This relies on the fact that when we make a new context we
    // append it to the end of fContexts array.
    // TODO: Look into keeping a dependency dag for contexts and deletion order
    for (int i = fContexts.count() - 1; i >= 0; --i) {
        Context& context = fContexts[i];
        SkScopeExit restore(nullptr);
        if (context.fTestContext) {
            restore = context.fTestContext->makeCurrentAndAutoRestore();
        }
        if (!context.fGrContext->unique()) {
            context.fGrContext->releaseResourcesAndAbandonContext();
            context.fAbandoned = true;
        }
        context.fGrContext->unref();
        delete context.fTestContext;
    }
    fContexts.reset();
}

void GrContextFactory::abandonContexts() {
    // We must abandon the test contexts in reverse order so that any child context is finished and
    // abandoned before a parent context. This relies on the fact that when we make a new context we
    // append it to the end of fContexts array.
    // TODO: Look into keeping a dependency dag for contexts and deletion order
    for (int i = fContexts.count() - 1; i >= 0; --i) {
        Context& context = fContexts[i];
        if (!context.fAbandoned) {
            if (context.fTestContext) {
                auto restore = context.fTestContext->makeCurrentAndAutoRestore();
                context.fTestContext->testAbandon();
            }
            bool requiresEarlyAbandon = (context.fGrContext->backend() == GrBackendApi::kVulkan);
            if (requiresEarlyAbandon) {
                context.fGrContext->abandonContext();
            }
            if (context.fTestContext) {
                delete(context.fTestContext);
                context.fTestContext = nullptr;
            }
            if (!requiresEarlyAbandon) {
                context.fGrContext->abandonContext();
            }
            context.fAbandoned = true;
        }
    }
}

void GrContextFactory::releaseResourcesAndAbandonContexts() {
    // We must abandon the test contexts in reverse order so that any child context is finished and
    // abandoned before a parent context. This relies on the fact that when we make a new context we
    // append it to the end of fContexts array.
    // TODO: Look into keeping a dependency dag for contexts and deletion order
    for (int i = fContexts.count() - 1; i >= 0; --i) {
        Context& context = fContexts[i];
        SkScopeExit restore(nullptr);
        if (!context.fAbandoned) {
            if (context.fTestContext) {
                restore = context.fTestContext->makeCurrentAndAutoRestore();
            }
            context.fGrContext->releaseResourcesAndAbandonContext();
            if (context.fTestContext) {
                delete context.fTestContext;
                context.fTestContext = nullptr;
            }
            context.fAbandoned = true;
        }
    }
}

GrContext* GrContextFactory::get(ContextType type, ContextOverrides overrides) {
    return this->getContextInfo(type, overrides).grContext();
}

ContextInfo GrContextFactory::getContextInfoInternal(ContextType type, ContextOverrides overrides,
                                                     GrContext* shareContext, uint32_t shareIndex) {
    // (shareIndex != 0) -> (shareContext != nullptr)
    SkASSERT((shareIndex == 0) || (shareContext != nullptr));

    for (int i = 0; i < fContexts.count(); ++i) {
        Context& context = fContexts[i];
        if (context.fType == type &&
            context.fOverrides == overrides &&
            context.fShareContext == shareContext &&
            context.fShareIndex == shareIndex &&
            !context.fAbandoned) {
            context.fTestContext->makeCurrent();
            return ContextInfo(context.fType, context.fTestContext, context.fGrContext,
                               context.fOptions);
        }
    }

    // If we're trying to create a context in a share group, find the master context
    Context* masterContext = nullptr;
    if (shareContext) {
        for (int i = 0; i < fContexts.count(); ++i) {
            if (!fContexts[i].fAbandoned && fContexts[i].fGrContext == shareContext) {
                masterContext = &fContexts[i];
                break;
            }
        }
        SkASSERT(masterContext && masterContext->fType == type);
    }

    std::unique_ptr<TestContext> testCtx;
    GrBackendApi backend = ContextTypeBackend(type);
    switch (backend) {
#ifdef SK_GL
        case GrBackendApi::kOpenGL: {
            GLTestContext* glShareContext = masterContext
                    ? static_cast<GLTestContext*>(masterContext->fTestContext) : nullptr;
            GLTestContext* glCtx;
            switch (type) {
                case kGL_ContextType:
                    glCtx = CreatePlatformGLTestContext(kGL_GrGLStandard, glShareContext);
                    break;
                case kGLES_ContextType:
                    glCtx = CreatePlatformGLTestContext(kGLES_GrGLStandard, glShareContext);
                    break;
#if SK_ANGLE
                case kANGLE_D3D9_ES2_ContextType:
                    glCtx = MakeANGLETestContext(ANGLEBackend::kD3D9, ANGLEContextVersion::kES2,
                                                 glShareContext).release();
                    // Chrome will only run on D3D9 with NVIDIA for 2012 and earlier drivers.
                    // (<= 269.73). We get shader link failures when testing on recent drivers
                    // using this backend.
                    if (glCtx) {
                        auto [backend, vendor, renderer] = GrGLGetANGLEInfo(glCtx->gl());
                        if (vendor == GrGLANGLEVendor::kNVIDIA) {
                            delete glCtx;
                            return ContextInfo();
                        }
                    }
                    break;
                case kANGLE_D3D11_ES2_ContextType:
                    glCtx = MakeANGLETestContext(ANGLEBackend::kD3D11, ANGLEContextVersion::kES2,
                                                 glShareContext).release();
                    break;
                case kANGLE_D3D11_ES3_ContextType:
                    glCtx = MakeANGLETestContext(ANGLEBackend::kD3D11, ANGLEContextVersion::kES3,
                                                 glShareContext).release();
                    break;
                case kANGLE_GL_ES2_ContextType:
                    glCtx = MakeANGLETestContext(ANGLEBackend::kOpenGL, ANGLEContextVersion::kES2,
                                                 glShareContext).release();
                    break;
                case kANGLE_GL_ES3_ContextType:
                    glCtx = MakeANGLETestContext(ANGLEBackend::kOpenGL, ANGLEContextVersion::kES3,
                                                 glShareContext).release();
                    break;
#endif
#ifndef SK_NO_COMMAND_BUFFER
                case kCommandBuffer_ContextType:
                    glCtx = CommandBufferGLTestContext::Create(glShareContext);
                    break;
#endif
                default:
                    return ContextInfo();
            }
            if (!glCtx) {
                return ContextInfo();
            }
            testCtx.reset(glCtx);
            break;
        }
#endif  // SK_GL
#ifdef SK_VULKAN
        case GrBackendApi::kVulkan: {
            VkTestContext* vkSharedContext = masterContext
                    ? static_cast<VkTestContext*>(masterContext->fTestContext) : nullptr;
            SkASSERT(kVulkan_ContextType == type);
            testCtx.reset(CreatePlatformVkTestContext(vkSharedContext));
            if (!testCtx) {
                return ContextInfo();
            }

            // We previously had an issue where the VkDevice destruction would occasionally hang
            // on systems with NVIDIA GPUs and having an existing GL context fixed it. Now (March
            // 2020) we still need the GL context to keep Vulkan/TSAN bots from running incredibly
            // slow. Perhaps this prevents repeated driver loading/unloading? Note that keeping
            // a persistent VkTestContext around instead was tried and did not work.
            if (!fSentinelGLContext) {
                fSentinelGLContext.reset(CreatePlatformGLTestContext(kGL_GrGLStandard));
                if (!fSentinelGLContext) {
                    fSentinelGLContext.reset(CreatePlatformGLTestContext(kGLES_GrGLStandard));
                }
            }
            break;
        }
#endif
#ifdef SK_METAL
        case GrBackendApi::kMetal: {
            MtlTestContext* mtlSharedContext = masterContext
                    ? static_cast<MtlTestContext*>(masterContext->fTestContext) : nullptr;
            SkASSERT(kMetal_ContextType == type);
            testCtx.reset(CreatePlatformMtlTestContext(mtlSharedContext));
            if (!testCtx) {
                return ContextInfo();
            }
            break;
        }
#endif
#ifdef SK_DIRECT3D
        case GrBackendApi::kDirect3D: {
            D3DTestContext* d3dSharedContext = masterContext
                    ? static_cast<D3DTestContext*>(masterContext->fTestContext) : nullptr;
            SkASSERT(kDirect3D_ContextType == type);
            testCtx.reset(CreatePlatformD3DTestContext(d3dSharedContext));
            if (!testCtx) {
                return ContextInfo();
            }
            break;
        }
#endif
#ifdef SK_DAWN
        case GrBackendApi::kDawn: {
            DawnTestContext* dawnSharedContext = masterContext
                    ? static_cast<DawnTestContext*>(masterContext->fTestContext) : nullptr;
            testCtx.reset(CreatePlatformDawnTestContext(dawnSharedContext));
            if (!testCtx) {
                return ContextInfo();
            }
            break;
        }
#endif
        case GrBackendApi::kMock: {
            TestContext* sharedContext = masterContext ? masterContext->fTestContext : nullptr;
            SkASSERT(kMock_ContextType == type);
            testCtx.reset(CreateMockTestContext(sharedContext));
            if (!testCtx) {
                return ContextInfo();
            }
            break;
        }
        default:
            return ContextInfo();
    }

    SkASSERT(testCtx && testCtx->backend() == backend);
    GrContextOptions grOptions = fGlobalOptions;
    if (ContextOverrides::kAvoidStencilBuffers & overrides) {
        grOptions.fAvoidStencilBuffers = true;
    }
    sk_sp<GrContext> grCtx;
    {
        auto restore = testCtx->makeCurrentAndAutoRestore();
        grCtx = testCtx->makeGrContext(grOptions);
    }
    if (!grCtx.get()) {
        return ContextInfo();
    }

    // We must always add new contexts by pushing to the back so that when we delete them we delete
    // them in reverse order in which they were made.
    Context& context = fContexts.push_back();
    context.fBackend = backend;
    context.fTestContext = testCtx.release();
    context.fGrContext = SkRef(grCtx.get());
    context.fType = type;
    context.fOverrides = overrides;
    context.fAbandoned = false;
    context.fShareContext = shareContext;
    context.fShareIndex = shareIndex;
    context.fOptions = grOptions;
    context.fTestContext->makeCurrent();
    return ContextInfo(context.fType, context.fTestContext, context.fGrContext, context.fOptions);
}

ContextInfo GrContextFactory::getContextInfo(ContextType type, ContextOverrides overrides) {
    return this->getContextInfoInternal(type, overrides, nullptr, 0);
}

ContextInfo GrContextFactory::getSharedContextInfo(GrContext* shareContext, uint32_t shareIndex) {
    SkASSERT(shareContext);
    for (int i = 0; i < fContexts.count(); ++i) {
        if (!fContexts[i].fAbandoned && fContexts[i].fGrContext == shareContext) {
            return this->getContextInfoInternal(fContexts[i].fType, fContexts[i].fOverrides,
                                                shareContext, shareIndex);
        }
    }

    return ContextInfo();
}

}  // namespace sk_gpu_test
<commit_msg>Dawn: fix for crash on GrContextFactory_sharedContexts unit test.<commit_after>
/*
 * Copyright 2014 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "src/gpu/GrContextPriv.h"
#include "tools/gpu/GrContextFactory.h"
#ifdef SK_GL
#include "tools/gpu/gl/GLTestContext.h"
#endif

#if SK_ANGLE
#include "tools/gpu/gl/angle/GLTestContext_angle.h"
#endif
#include "tools/gpu/gl/command_buffer/GLTestContext_command_buffer.h"
#ifdef SK_VULKAN
#include "tools/gpu/vk/VkTestContext.h"
#endif
#ifdef SK_METAL
#include "tools/gpu/mtl/MtlTestContext.h"
#endif
#ifdef SK_DIRECT3D
#include "tools/gpu/d3d/D3DTestContext.h"
#endif
#ifdef SK_DAWN
#include "tools/gpu/dawn/DawnTestContext.h"
#endif
#include "src/gpu/GrCaps.h"
#include "src/gpu/gl/GrGLGpu.h"
#include "tools/gpu/mock/MockTestContext.h"

#if defined(SK_BUILD_FOR_WIN) && defined(SK_ENABLE_DISCRETE_GPU)
extern "C" {
    // NVIDIA documents that the presence and value of this symbol programmatically enable the high
    // performance GPU in laptops with switchable graphics.
    //   https://docs.nvidia.com/gameworks/content/technologies/desktop/optimus.htm
    // From testing, including this symbol, even if it is set to 0, we still get the NVIDIA GPU.
    _declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001;

    // AMD has a similar mechanism, although I don't have an AMD laptop, so this is untested.
    //   https://community.amd.com/thread/169965
    __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
}
#endif

namespace sk_gpu_test {
GrContextFactory::GrContextFactory() { }

GrContextFactory::GrContextFactory(const GrContextOptions& opts)
    : fGlobalOptions(opts) {
}

GrContextFactory::~GrContextFactory() {
    this->destroyContexts();
}

void GrContextFactory::destroyContexts() {
    // We must delete the test contexts in reverse order so that any child context is finished and
    // deleted before a parent context. This relies on the fact that when we make a new context we
    // append it to the end of fContexts array.
    // TODO: Look into keeping a dependency dag for contexts and deletion order
    for (int i = fContexts.count() - 1; i >= 0; --i) {
        Context& context = fContexts[i];
        SkScopeExit restore(nullptr);
        if (context.fTestContext) {
            restore = context.fTestContext->makeCurrentAndAutoRestore();
        }
        if (!context.fGrContext->unique()) {
            context.fGrContext->releaseResourcesAndAbandonContext();
            context.fAbandoned = true;
        }
        context.fGrContext->unref();
        delete context.fTestContext;
    }
    fContexts.reset();
}

void GrContextFactory::abandonContexts() {
    // We must abandon the test contexts in reverse order so that any child context is finished and
    // abandoned before a parent context. This relies on the fact that when we make a new context we
    // append it to the end of fContexts array.
    // TODO: Look into keeping a dependency dag for contexts and deletion order
    for (int i = fContexts.count() - 1; i >= 0; --i) {
        Context& context = fContexts[i];
        if (!context.fAbandoned) {
            if (context.fTestContext) {
                auto restore = context.fTestContext->makeCurrentAndAutoRestore();
                context.fTestContext->testAbandon();
            }
            GrBackendApi api = context.fGrContext->backend();
            bool requiresEarlyAbandon = api == GrBackendApi::kVulkan || api == GrBackendApi::kDawn;
            if (requiresEarlyAbandon) {
                context.fGrContext->abandonContext();
            }
            if (context.fTestContext) {
                delete(context.fTestContext);
                context.fTestContext = nullptr;
            }
            if (!requiresEarlyAbandon) {
                context.fGrContext->abandonContext();
            }
            context.fAbandoned = true;
        }
    }
}

void GrContextFactory::releaseResourcesAndAbandonContexts() {
    // We must abandon the test contexts in reverse order so that any child context is finished and
    // abandoned before a parent context. This relies on the fact that when we make a new context we
    // append it to the end of fContexts array.
    // TODO: Look into keeping a dependency dag for contexts and deletion order
    for (int i = fContexts.count() - 1; i >= 0; --i) {
        Context& context = fContexts[i];
        SkScopeExit restore(nullptr);
        if (!context.fAbandoned) {
            if (context.fTestContext) {
                restore = context.fTestContext->makeCurrentAndAutoRestore();
            }
            context.fGrContext->releaseResourcesAndAbandonContext();
            if (context.fTestContext) {
                delete context.fTestContext;
                context.fTestContext = nullptr;
            }
            context.fAbandoned = true;
        }
    }
}

GrContext* GrContextFactory::get(ContextType type, ContextOverrides overrides) {
    return this->getContextInfo(type, overrides).grContext();
}

ContextInfo GrContextFactory::getContextInfoInternal(ContextType type, ContextOverrides overrides,
                                                     GrContext* shareContext, uint32_t shareIndex) {
    // (shareIndex != 0) -> (shareContext != nullptr)
    SkASSERT((shareIndex == 0) || (shareContext != nullptr));

    for (int i = 0; i < fContexts.count(); ++i) {
        Context& context = fContexts[i];
        if (context.fType == type &&
            context.fOverrides == overrides &&
            context.fShareContext == shareContext &&
            context.fShareIndex == shareIndex &&
            !context.fAbandoned) {
            context.fTestContext->makeCurrent();
            return ContextInfo(context.fType, context.fTestContext, context.fGrContext,
                               context.fOptions);
        }
    }

    // If we're trying to create a context in a share group, find the master context
    Context* masterContext = nullptr;
    if (shareContext) {
        for (int i = 0; i < fContexts.count(); ++i) {
            if (!fContexts[i].fAbandoned && fContexts[i].fGrContext == shareContext) {
                masterContext = &fContexts[i];
                break;
            }
        }
        SkASSERT(masterContext && masterContext->fType == type);
    }

    std::unique_ptr<TestContext> testCtx;
    GrBackendApi backend = ContextTypeBackend(type);
    switch (backend) {
#ifdef SK_GL
        case GrBackendApi::kOpenGL: {
            GLTestContext* glShareContext = masterContext
                    ? static_cast<GLTestContext*>(masterContext->fTestContext) : nullptr;
            GLTestContext* glCtx;
            switch (type) {
                case kGL_ContextType:
                    glCtx = CreatePlatformGLTestContext(kGL_GrGLStandard, glShareContext);
                    break;
                case kGLES_ContextType:
                    glCtx = CreatePlatformGLTestContext(kGLES_GrGLStandard, glShareContext);
                    break;
#if SK_ANGLE
                case kANGLE_D3D9_ES2_ContextType:
                    glCtx = MakeANGLETestContext(ANGLEBackend::kD3D9, ANGLEContextVersion::kES2,
                                                 glShareContext).release();
                    // Chrome will only run on D3D9 with NVIDIA for 2012 and earlier drivers.
                    // (<= 269.73). We get shader link failures when testing on recent drivers
                    // using this backend.
                    if (glCtx) {
                        auto [backend, vendor, renderer] = GrGLGetANGLEInfo(glCtx->gl());
                        if (vendor == GrGLANGLEVendor::kNVIDIA) {
                            delete glCtx;
                            return ContextInfo();
                        }
                    }
                    break;
                case kANGLE_D3D11_ES2_ContextType:
                    glCtx = MakeANGLETestContext(ANGLEBackend::kD3D11, ANGLEContextVersion::kES2,
                                                 glShareContext).release();
                    break;
                case kANGLE_D3D11_ES3_ContextType:
                    glCtx = MakeANGLETestContext(ANGLEBackend::kD3D11, ANGLEContextVersion::kES3,
                                                 glShareContext).release();
                    break;
                case kANGLE_GL_ES2_ContextType:
                    glCtx = MakeANGLETestContext(ANGLEBackend::kOpenGL, ANGLEContextVersion::kES2,
                                                 glShareContext).release();
                    break;
                case kANGLE_GL_ES3_ContextType:
                    glCtx = MakeANGLETestContext(ANGLEBackend::kOpenGL, ANGLEContextVersion::kES3,
                                                 glShareContext).release();
                    break;
#endif
#ifndef SK_NO_COMMAND_BUFFER
                case kCommandBuffer_ContextType:
                    glCtx = CommandBufferGLTestContext::Create(glShareContext);
                    break;
#endif
                default:
                    return ContextInfo();
            }
            if (!glCtx) {
                return ContextInfo();
            }
            testCtx.reset(glCtx);
            break;
        }
#endif  // SK_GL
#ifdef SK_VULKAN
        case GrBackendApi::kVulkan: {
            VkTestContext* vkSharedContext = masterContext
                    ? static_cast<VkTestContext*>(masterContext->fTestContext) : nullptr;
            SkASSERT(kVulkan_ContextType == type);
            testCtx.reset(CreatePlatformVkTestContext(vkSharedContext));
            if (!testCtx) {
                return ContextInfo();
            }

            // We previously had an issue where the VkDevice destruction would occasionally hang
            // on systems with NVIDIA GPUs and having an existing GL context fixed it. Now (March
            // 2020) we still need the GL context to keep Vulkan/TSAN bots from running incredibly
            // slow. Perhaps this prevents repeated driver loading/unloading? Note that keeping
            // a persistent VkTestContext around instead was tried and did not work.
            if (!fSentinelGLContext) {
                fSentinelGLContext.reset(CreatePlatformGLTestContext(kGL_GrGLStandard));
                if (!fSentinelGLContext) {
                    fSentinelGLContext.reset(CreatePlatformGLTestContext(kGLES_GrGLStandard));
                }
            }
            break;
        }
#endif
#ifdef SK_METAL
        case GrBackendApi::kMetal: {
            MtlTestContext* mtlSharedContext = masterContext
                    ? static_cast<MtlTestContext*>(masterContext->fTestContext) : nullptr;
            SkASSERT(kMetal_ContextType == type);
            testCtx.reset(CreatePlatformMtlTestContext(mtlSharedContext));
            if (!testCtx) {
                return ContextInfo();
            }
            break;
        }
#endif
#ifdef SK_DIRECT3D
        case GrBackendApi::kDirect3D: {
            D3DTestContext* d3dSharedContext = masterContext
                    ? static_cast<D3DTestContext*>(masterContext->fTestContext) : nullptr;
            SkASSERT(kDirect3D_ContextType == type);
            testCtx.reset(CreatePlatformD3DTestContext(d3dSharedContext));
            if (!testCtx) {
                return ContextInfo();
            }
            break;
        }
#endif
#ifdef SK_DAWN
        case GrBackendApi::kDawn: {
            DawnTestContext* dawnSharedContext = masterContext
                    ? static_cast<DawnTestContext*>(masterContext->fTestContext) : nullptr;
            testCtx.reset(CreatePlatformDawnTestContext(dawnSharedContext));
            if (!testCtx) {
                return ContextInfo();
            }
            break;
        }
#endif
        case GrBackendApi::kMock: {
            TestContext* sharedContext = masterContext ? masterContext->fTestContext : nullptr;
            SkASSERT(kMock_ContextType == type);
            testCtx.reset(CreateMockTestContext(sharedContext));
            if (!testCtx) {
                return ContextInfo();
            }
            break;
        }
        default:
            return ContextInfo();
    }

    SkASSERT(testCtx && testCtx->backend() == backend);
    GrContextOptions grOptions = fGlobalOptions;
    if (ContextOverrides::kAvoidStencilBuffers & overrides) {
        grOptions.fAvoidStencilBuffers = true;
    }
    sk_sp<GrContext> grCtx;
    {
        auto restore = testCtx->makeCurrentAndAutoRestore();
        grCtx = testCtx->makeGrContext(grOptions);
    }
    if (!grCtx.get()) {
        return ContextInfo();
    }

    // We must always add new contexts by pushing to the back so that when we delete them we delete
    // them in reverse order in which they were made.
    Context& context = fContexts.push_back();
    context.fBackend = backend;
    context.fTestContext = testCtx.release();
    context.fGrContext = SkRef(grCtx.get());
    context.fType = type;
    context.fOverrides = overrides;
    context.fAbandoned = false;
    context.fShareContext = shareContext;
    context.fShareIndex = shareIndex;
    context.fOptions = grOptions;
    context.fTestContext->makeCurrent();
    return ContextInfo(context.fType, context.fTestContext, context.fGrContext, context.fOptions);
}

ContextInfo GrContextFactory::getContextInfo(ContextType type, ContextOverrides overrides) {
    return this->getContextInfoInternal(type, overrides, nullptr, 0);
}

ContextInfo GrContextFactory::getSharedContextInfo(GrContext* shareContext, uint32_t shareIndex) {
    SkASSERT(shareContext);
    for (int i = 0; i < fContexts.count(); ++i) {
        if (!fContexts[i].fAbandoned && fContexts[i].fGrContext == shareContext) {
            return this->getContextInfoInternal(fContexts[i].fType, fContexts[i].fOverrides,
                                                shareContext, shareIndex);
        }
    }

    return ContextInfo();
}

}  // namespace sk_gpu_test
<|endoftext|>


<commit_before>#include "fonts.h"

#include "fonts/utf8-utils.h"
#include "fonts/shader.h"

#include <cmath>

#define DEBUG_FONTS false

//
// AminoFonts
//

AminoFonts::AminoFonts(): AminoJSObject(getFactory()->name) {
    //empty
}

AminoFonts::~AminoFonts() {
    //empty
}

/**
 * Get factory instance.
 */
AminoFontsFactory* AminoFonts::getFactory() {
    static AminoFontsFactory *aminoFontsFactory = NULL;

    if (!aminoFontsFactory) {
        aminoFontsFactory = new AminoFontsFactory(New);
    }

    return aminoFontsFactory;
}

/**
 * Add class template to module exports.
 */
NAN_MODULE_INIT(AminoFonts::Init) {
    AminoFontsFactory *factory = getFactory();
    v8::Local<v8::FunctionTemplate> tpl = AminoJSObject::createTemplate(factory);

    //prototype methods

    // -> no native methods
    Nan::SetTemplate(tpl, "Font", AminoFont::GetInitFunction());
    Nan::SetTemplate(tpl, "FontSize", AminoFontSize::GetInitFunction());

    //global template instance
    Nan::Set(target, Nan::New(factory->name).ToLocalChecked(), Nan::GetFunction(tpl).ToLocalChecked());
}

/**
 * JS object construction.
 */
NAN_METHOD(AminoFonts::New) {
    AminoJSObject::createInstance(info, getFactory());
}

//
//  AminoFontsFactory
//

/**
 * Create AminoFonts factory.
 */
AminoFontsFactory::AminoFontsFactory(Nan::FunctionCallback callback): AminoJSObjectFactory("AminoFonts", callback) {
    //empty
}

/**
 * Create AminoFonts instance.
 */
AminoJSObject* AminoFontsFactory::create() {
    return new AminoFonts();
}

//
// AminoFont
//

AminoFont::AminoFont(): AminoJSObject(getFactory()->name) {
    //empty
}

AminoFont::~AminoFont() {
    //empty
}

/**
 * Destroy font data.
 */
void AminoFont::destroy() {
    AminoJSObject::destroy();

    //font sizes
    for (std::map<int, texture_font_t *>::iterator it = fontSizes.begin(); it != fontSizes.end(); it++) {
        texture_font_delete(it->second);
    }

    fontSizes.clear();

    //atlas
    if (atlas) {
        texture_atlas_delete(atlas);
        atlas = NULL;
    }

    //font data
    fontData.Reset();
}

/**
 * Get factory instance.
 */
AminoFontFactory* AminoFont::getFactory() {
    static AminoFontFactory *aminoFontFactory = NULL;

    if (!aminoFontFactory) {
        aminoFontFactory = new AminoFontFactory(New);
    }

    return aminoFontFactory;
}

/**
 * Initialize Group template.
 */
v8::Local<v8::Function> AminoFont::GetInitFunction() {
    v8::Local<v8::FunctionTemplate> tpl = AminoJSObject::createTemplate(getFactory());

    //no methods

    //template function
    return Nan::GetFunction(tpl).ToLocalChecked();
}

/**
 * JS object construction.
 */
NAN_METHOD(AminoFont::New) {
    AminoJSObject::createInstance(info, getFactory());
}

/**
 * Initialize fonts instance.
 */
void AminoFont::preInit(Nan::NAN_METHOD_ARGS_TYPE info) {
    AminoFonts *fonts = Nan::ObjectWrap::Unwrap<AminoFonts>(info[0]->ToObject());
    v8::Local<v8::Object> fontData = info[1]->ToObject();

    assert(fonts);

    this->fonts = fonts;

    //store font (in memory)
    v8::Local<v8::Object> bufferObj =  Nan::Get(fontData, Nan::New<v8::String>("data").ToLocalChecked()).ToLocalChecked()->ToObject();

    this->fontData.Reset(bufferObj);

    //create atlas
    atlas = texture_atlas_new(512, 512, 1); //depth must be 1

    if (!atlas) {
        Nan::ThrowTypeError("could not create atlas");
        return;
    }

    //metadata
    v8::Local<v8::Value> nameValue = Nan::Get(fontData, Nan::New<v8::String>("name").ToLocalChecked()).ToLocalChecked();
    v8::Local<v8::Value> styleValue = Nan::Get(fontData, Nan::New<v8::String>("style").ToLocalChecked()).ToLocalChecked();

    fontName = AminoJSObject::toString(nameValue);
    fontWeight = Nan::Get(fontData, Nan::New<v8::String>("weight").ToLocalChecked()).ToLocalChecked()->NumberValue();
    fontStyle = AminoJSObject::toString(styleValue);

    if (DEBUG_FONTS) {
        printf("-> new font: name=%s, style=%s, weight=%i\n", fontName.c_str(), fontStyle.c_str(), fontWeight);
    }
}

/**
 * Load font size.
 *
 * Note: has to be called in v8 thread.
 */
texture_font_t *AminoFont::getFontWithSize(int size) {
    //check cache
    std::map<int, texture_font_t *>::iterator it = fontSizes.find(size);
    texture_font_t *fontSize;

    if (it == fontSizes.end()) {
        //add new size
        v8::Local<v8::Object> bufferObj = Nan::New(fontData);
        char *buffer = node::Buffer::Data(bufferObj);
        size_t bufferLen = node::Buffer::Length(bufferObj);

        //Note: has texture id but we use our own handling
        fontSize = texture_font_new_from_memory(atlas, size, buffer, bufferLen);

        if (fontSize) {
            fontSizes[size] = fontSize;
        }

        if (DEBUG_FONTS) {
            printf("-> new font size: %i (%s/%s/%i)\n", size, fontName.c_str(), fontStyle.c_str(), fontWeight);
        }
    } else {
        fontSize = it->second;
    }

    return fontSize;
}

//
//  AminoFontFactory
//

/**
 * Create AminoFont factory.
 */
AminoFontFactory::AminoFontFactory(Nan::FunctionCallback callback): AminoJSObjectFactory("AminoFont", callback) {
    //empty
}

/**
 * Create AminoFonts instance.
 */
AminoJSObject* AminoFontFactory::create() {
    return new AminoFont();
}

//
// AminoFontSize
//

AminoFontSize::AminoFontSize(): AminoJSObject(getFactory()->name) {
    //empty
}

AminoFontSize::~AminoFontSize() {
    //empty
}

/**
 * Get factory instance.
 */
AminoFontSizeFactory* AminoFontSize::getFactory() {
    static AminoFontSizeFactory *aminoFontSizeFactory = NULL;

    if (!aminoFontSizeFactory) {
        aminoFontSizeFactory = new AminoFontSizeFactory(New);
    }

    return aminoFontSizeFactory;
}

/**
 * Initialize AminoFontSize template.
 */
v8::Local<v8::Function> AminoFontSize::GetInitFunction() {
    v8::Local<v8::FunctionTemplate> tpl = AminoJSObject::createTemplate(getFactory());

    //methods
    Nan::SetPrototypeMethod(tpl, "_calcTextWidth", CalcTextWidth);
    Nan::SetPrototypeMethod(tpl, "getFontMetrics", GetFontMetrics);

    //template function
    return Nan::GetFunction(tpl).ToLocalChecked();
}

/**
 * JS object construction.
 */
NAN_METHOD(AminoFontSize::New) {
    AminoJSObject::createInstance(info, getFactory());
}

/**
 * Initialize constructor values.
 */
void AminoFontSize::preInit(Nan::NAN_METHOD_ARGS_TYPE info) {
    AminoFont *font = Nan::ObjectWrap::Unwrap<AminoFont>(info[0]->ToObject());
    int size = (int)round(info[1]->NumberValue());

    assert(font);

    this->font = font;
    fontTexture = font->getFontWithSize(size);

    if (!fontTexture) {
        Nan::ThrowTypeError("could not create font size");
    }

    //font properties
    v8::Local<v8::Object> obj = handle();

    Nan::Set(obj, Nan::New("name").ToLocalChecked(), Nan::New<v8::String>(font->fontName).ToLocalChecked());
    Nan::Set(obj, Nan::New("size").ToLocalChecked(), Nan::New<v8::Number>(size));
    Nan::Set(obj, Nan::New("weight").ToLocalChecked(), Nan::New<v8::Number>(font->fontWeight));
    Nan::Set(obj, Nan::New("style").ToLocalChecked(), Nan::New<v8::String>(font->fontStyle).ToLocalChecked());
}

/**
 * Calculate text width.
 */
NAN_METHOD(AminoFontSize::CalcTextWidth) {
    AminoFontSize *obj = Nan::ObjectWrap::Unwrap<AminoFontSize>(info.This());
    v8::String::Utf8Value str(info[0]);

    assert(obj);

    info.GetReturnValue().Set(obj->getTextWidth(*str));
}

/**
 * Calculate text width.
 */
float AminoFontSize::getTextWidth(const char *text) {
    size_t len = utf8_strlen(text);
    char *textPos = (char *)text;
    char *lastTextPos = NULL;
    float w = 0;

    for (std::size_t i = 0; i < len; i++) {
        texture_glyph_t *glyph = texture_font_get_glyph(fontTexture, textPos);

        if (!glyph) {
            printf("Error: got empty glyph from texture_font_get_glyph\n");
            continue;
        }

        //kerning
        if (lastTextPos) {
            w += texture_glyph_get_kerning(glyph, lastTextPos);
        }

        //char width
        w += glyph->advance_x;

        //next
        size_t charLen = utf8_surrogate_len(textPos);

        lastTextPos = textPos;
        textPos += charLen;
    }

    return w;
}

/**
 * Get font metrics (height, ascender, descender).
 */
NAN_METHOD(AminoFontSize::GetFontMetrics) {
    AminoFontSize *obj = Nan::ObjectWrap::Unwrap<AminoFontSize>(info.This());

    assert(obj);

    //metrics
    v8::Local<v8::Object> metricsObj = Nan::New<v8::Object>();

    Nan::Set(metricsObj, Nan::New("height").ToLocalChecked(), Nan::New<v8::Number>(obj->fontTexture->ascender - obj->fontTexture->descender));
    Nan::Set(metricsObj, Nan::New("ascender").ToLocalChecked(), Nan::New<v8::Number>(obj->fontTexture->ascender));
    Nan::Set(metricsObj, Nan::New("descender").ToLocalChecked(), Nan::New<v8::Number>(obj->fontTexture->descender));

    info.GetReturnValue().Set(metricsObj);
}

//
//  AminoFontSizeFactory
//

/**
 * Create AminoFontSize factory.
 */
AminoFontSizeFactory::AminoFontSizeFactory(Nan::FunctionCallback callback): AminoJSObjectFactory("AminoFontSize", callback) {
    //empty
}

/**
 * Create AminoFonts instance.
 */
AminoJSObject* AminoFontSizeFactory::create() {
    return new AminoFontSize();
}

//
// AminoFontShader
//

AminoFontShader::AminoFontShader() : TextureShader() {
    //shader

    //Note: using unmodified vertex shader
    fragmentShader = R"(
        #ifdef GL_ES
            precision mediump float;
        #endif

        uniform float opacity;
        uniform vec3 color;
        uniform sampler2D tex;

        varying vec2 uv;

        void main() {
            float a = texture2D(tex, uv).a;

            gl_FragColor = vec4(color, opacity * a);
        }
    )";
}

/**
 * Initialize the font shader.
 */
void AminoFontShader::initShader() {
    TextureShader::initShader();

    //uniforms
    uColor = getUniformLocation("color");
}

/**
 * Set color.
 */
void AminoFontShader::setColor(GLfloat color[3]) {
    glUniform3f(uColor, color[0], color[1], color[2]);
}

/**
 * Get texture for atlas.
 *
 * Note: has to be called on OpenGL thread.
 */
amino_atlas_t AminoFontShader::getAtlasTexture(texture_atlas_t *atlas) {
    std::map<texture_atlas_t *, amino_atlas_t>::iterator it = atlasTextures.find(atlas);

    if (it == atlasTextures.end()) {
        //create new one
        GLuint id;

        //see https://webcache.googleusercontent.com/search?q=cache:EZ3HLutV3zwJ:https://github.com/rougier/freetype-gl/blob/master/texture-atlas.c+&cd=1&hl=de&ct=clnk&gl=ch
        glGenTextures(1, &id);
        glBindTexture(GL_TEXTURE_2D, id);

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

        //FIXME seeing vertical lines on macOS retina displays!
        //subpixel error on Mac retina display at edges
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

        //worse quality on macOS retina (still a few pixels errors)
        //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

        amino_atlas_t item;

        item.textureId = id;
        item.lastGlyphUpdate = 0;

        atlasTextures[atlas] = item;

        //debug
        //printf("create new atlas texture: %i\n", id);

        return item;
    }

    return it->second;
}
<commit_msg>added issue URL<commit_after>#include "fonts.h"

#include "fonts/utf8-utils.h"
#include "fonts/shader.h"

#include <cmath>

#define DEBUG_FONTS false

//
// AminoFonts
//

AminoFonts::AminoFonts(): AminoJSObject(getFactory()->name) {
    //empty
}

AminoFonts::~AminoFonts() {
    //empty
}

/**
 * Get factory instance.
 */
AminoFontsFactory* AminoFonts::getFactory() {
    static AminoFontsFactory *aminoFontsFactory = NULL;

    if (!aminoFontsFactory) {
        aminoFontsFactory = new AminoFontsFactory(New);
    }

    return aminoFontsFactory;
}

/**
 * Add class template to module exports.
 */
NAN_MODULE_INIT(AminoFonts::Init) {
    AminoFontsFactory *factory = getFactory();
    v8::Local<v8::FunctionTemplate> tpl = AminoJSObject::createTemplate(factory);

    //prototype methods

    // -> no native methods
    Nan::SetTemplate(tpl, "Font", AminoFont::GetInitFunction());
    Nan::SetTemplate(tpl, "FontSize", AminoFontSize::GetInitFunction());

    //global template instance
    Nan::Set(target, Nan::New(factory->name).ToLocalChecked(), Nan::GetFunction(tpl).ToLocalChecked());
}

/**
 * JS object construction.
 */
NAN_METHOD(AminoFonts::New) {
    AminoJSObject::createInstance(info, getFactory());
}

//
//  AminoFontsFactory
//

/**
 * Create AminoFonts factory.
 */
AminoFontsFactory::AminoFontsFactory(Nan::FunctionCallback callback): AminoJSObjectFactory("AminoFonts", callback) {
    //empty
}

/**
 * Create AminoFonts instance.
 */
AminoJSObject* AminoFontsFactory::create() {
    return new AminoFonts();
}

//
// AminoFont
//

AminoFont::AminoFont(): AminoJSObject(getFactory()->name) {
    //empty
}

AminoFont::~AminoFont() {
    //empty
}

/**
 * Destroy font data.
 */
void AminoFont::destroy() {
    AminoJSObject::destroy();

    //font sizes
    for (std::map<int, texture_font_t *>::iterator it = fontSizes.begin(); it != fontSizes.end(); it++) {
        texture_font_delete(it->second);
    }

    fontSizes.clear();

    //atlas
    if (atlas) {
        texture_atlas_delete(atlas);
        atlas = NULL;
    }

    //font data
    fontData.Reset();
}

/**
 * Get factory instance.
 */
AminoFontFactory* AminoFont::getFactory() {
    static AminoFontFactory *aminoFontFactory = NULL;

    if (!aminoFontFactory) {
        aminoFontFactory = new AminoFontFactory(New);
    }

    return aminoFontFactory;
}

/**
 * Initialize Group template.
 */
v8::Local<v8::Function> AminoFont::GetInitFunction() {
    v8::Local<v8::FunctionTemplate> tpl = AminoJSObject::createTemplate(getFactory());

    //no methods

    //template function
    return Nan::GetFunction(tpl).ToLocalChecked();
}

/**
 * JS object construction.
 */
NAN_METHOD(AminoFont::New) {
    AminoJSObject::createInstance(info, getFactory());
}

/**
 * Initialize fonts instance.
 */
void AminoFont::preInit(Nan::NAN_METHOD_ARGS_TYPE info) {
    AminoFonts *fonts = Nan::ObjectWrap::Unwrap<AminoFonts>(info[0]->ToObject());
    v8::Local<v8::Object> fontData = info[1]->ToObject();

    assert(fonts);

    this->fonts = fonts;

    //store font (in memory)
    v8::Local<v8::Object> bufferObj =  Nan::Get(fontData, Nan::New<v8::String>("data").ToLocalChecked()).ToLocalChecked()->ToObject();

    this->fontData.Reset(bufferObj);

    //create atlas
    atlas = texture_atlas_new(512, 512, 1); //depth must be 1

    if (!atlas) {
        Nan::ThrowTypeError("could not create atlas");
        return;
    }

    //metadata
    v8::Local<v8::Value> nameValue = Nan::Get(fontData, Nan::New<v8::String>("name").ToLocalChecked()).ToLocalChecked();
    v8::Local<v8::Value> styleValue = Nan::Get(fontData, Nan::New<v8::String>("style").ToLocalChecked()).ToLocalChecked();

    fontName = AminoJSObject::toString(nameValue);
    fontWeight = Nan::Get(fontData, Nan::New<v8::String>("weight").ToLocalChecked()).ToLocalChecked()->NumberValue();
    fontStyle = AminoJSObject::toString(styleValue);

    if (DEBUG_FONTS) {
        printf("-> new font: name=%s, style=%s, weight=%i\n", fontName.c_str(), fontStyle.c_str(), fontWeight);
    }
}

/**
 * Load font size.
 *
 * Note: has to be called in v8 thread.
 */
texture_font_t *AminoFont::getFontWithSize(int size) {
    //check cache
    std::map<int, texture_font_t *>::iterator it = fontSizes.find(size);
    texture_font_t *fontSize;

    if (it == fontSizes.end()) {
        //add new size
        v8::Local<v8::Object> bufferObj = Nan::New(fontData);
        char *buffer = node::Buffer::Data(bufferObj);
        size_t bufferLen = node::Buffer::Length(bufferObj);

        //Note: has texture id but we use our own handling
        fontSize = texture_font_new_from_memory(atlas, size, buffer, bufferLen);

        if (fontSize) {
            fontSizes[size] = fontSize;
        }

        if (DEBUG_FONTS) {
            printf("-> new font size: %i (%s/%s/%i)\n", size, fontName.c_str(), fontStyle.c_str(), fontWeight);
        }
    } else {
        fontSize = it->second;
    }

    return fontSize;
}

//
//  AminoFontFactory
//

/**
 * Create AminoFont factory.
 */
AminoFontFactory::AminoFontFactory(Nan::FunctionCallback callback): AminoJSObjectFactory("AminoFont", callback) {
    //empty
}

/**
 * Create AminoFonts instance.
 */
AminoJSObject* AminoFontFactory::create() {
    return new AminoFont();
}

//
// AminoFontSize
//

AminoFontSize::AminoFontSize(): AminoJSObject(getFactory()->name) {
    //empty
}

AminoFontSize::~AminoFontSize() {
    //empty
}

/**
 * Get factory instance.
 */
AminoFontSizeFactory* AminoFontSize::getFactory() {
    static AminoFontSizeFactory *aminoFontSizeFactory = NULL;

    if (!aminoFontSizeFactory) {
        aminoFontSizeFactory = new AminoFontSizeFactory(New);
    }

    return aminoFontSizeFactory;
}

/**
 * Initialize AminoFontSize template.
 */
v8::Local<v8::Function> AminoFontSize::GetInitFunction() {
    v8::Local<v8::FunctionTemplate> tpl = AminoJSObject::createTemplate(getFactory());

    //methods
    Nan::SetPrototypeMethod(tpl, "_calcTextWidth", CalcTextWidth);
    Nan::SetPrototypeMethod(tpl, "getFontMetrics", GetFontMetrics);

    //template function
    return Nan::GetFunction(tpl).ToLocalChecked();
}

/**
 * JS object construction.
 */
NAN_METHOD(AminoFontSize::New) {
    AminoJSObject::createInstance(info, getFactory());
}

/**
 * Initialize constructor values.
 */
void AminoFontSize::preInit(Nan::NAN_METHOD_ARGS_TYPE info) {
    AminoFont *font = Nan::ObjectWrap::Unwrap<AminoFont>(info[0]->ToObject());
    int size = (int)round(info[1]->NumberValue());

    assert(font);

    this->font = font;
    fontTexture = font->getFontWithSize(size);

    if (!fontTexture) {
        Nan::ThrowTypeError("could not create font size");
    }

    //font properties
    v8::Local<v8::Object> obj = handle();

    Nan::Set(obj, Nan::New("name").ToLocalChecked(), Nan::New<v8::String>(font->fontName).ToLocalChecked());
    Nan::Set(obj, Nan::New("size").ToLocalChecked(), Nan::New<v8::Number>(size));
    Nan::Set(obj, Nan::New("weight").ToLocalChecked(), Nan::New<v8::Number>(font->fontWeight));
    Nan::Set(obj, Nan::New("style").ToLocalChecked(), Nan::New<v8::String>(font->fontStyle).ToLocalChecked());
}

/**
 * Calculate text width.
 */
NAN_METHOD(AminoFontSize::CalcTextWidth) {
    AminoFontSize *obj = Nan::ObjectWrap::Unwrap<AminoFontSize>(info.This());
    v8::String::Utf8Value str(info[0]);

    assert(obj);

    info.GetReturnValue().Set(obj->getTextWidth(*str));
}

/**
 * Calculate text width.
 */
float AminoFontSize::getTextWidth(const char *text) {
    size_t len = utf8_strlen(text);
    char *textPos = (char *)text;
    char *lastTextPos = NULL;
    float w = 0;

    for (std::size_t i = 0; i < len; i++) {
        texture_glyph_t *glyph = texture_font_get_glyph(fontTexture, textPos);

        if (!glyph) {
            printf("Error: got empty glyph from texture_font_get_glyph\n");
            continue;
        }

        //kerning
        if (lastTextPos) {
            w += texture_glyph_get_kerning(glyph, lastTextPos);
        }

        //char width
        w += glyph->advance_x;

        //next
        size_t charLen = utf8_surrogate_len(textPos);

        lastTextPos = textPos;
        textPos += charLen;
    }

    return w;
}

/**
 * Get font metrics (height, ascender, descender).
 */
NAN_METHOD(AminoFontSize::GetFontMetrics) {
    AminoFontSize *obj = Nan::ObjectWrap::Unwrap<AminoFontSize>(info.This());

    assert(obj);

    //metrics
    v8::Local<v8::Object> metricsObj = Nan::New<v8::Object>();

    Nan::Set(metricsObj, Nan::New("height").ToLocalChecked(), Nan::New<v8::Number>(obj->fontTexture->ascender - obj->fontTexture->descender));
    Nan::Set(metricsObj, Nan::New("ascender").ToLocalChecked(), Nan::New<v8::Number>(obj->fontTexture->ascender));
    Nan::Set(metricsObj, Nan::New("descender").ToLocalChecked(), Nan::New<v8::Number>(obj->fontTexture->descender));

    info.GetReturnValue().Set(metricsObj);
}

//
//  AminoFontSizeFactory
//

/**
 * Create AminoFontSize factory.
 */
AminoFontSizeFactory::AminoFontSizeFactory(Nan::FunctionCallback callback): AminoJSObjectFactory("AminoFontSize", callback) {
    //empty
}

/**
 * Create AminoFonts instance.
 */
AminoJSObject* AminoFontSizeFactory::create() {
    return new AminoFontSize();
}

//
// AminoFontShader
//

AminoFontShader::AminoFontShader() : TextureShader() {
    //shader

    //Note: using unmodified vertex shader
    fragmentShader = R"(
        #ifdef GL_ES
            precision mediump float;
        #endif

        uniform float opacity;
        uniform vec3 color;
        uniform sampler2D tex;

        varying vec2 uv;

        void main() {
            float a = texture2D(tex, uv).a;

            gl_FragColor = vec4(color, opacity * a);
        }
    )";
}

/**
 * Initialize the font shader.
 */
void AminoFontShader::initShader() {
    TextureShader::initShader();

    //uniforms
    uColor = getUniformLocation("color");
}

/**
 * Set color.
 */
void AminoFontShader::setColor(GLfloat color[3]) {
    glUniform3f(uColor, color[0], color[1], color[2]);
}

/**
 * Get texture for atlas.
 *
 * Note: has to be called on OpenGL thread.
 */
amino_atlas_t AminoFontShader::getAtlasTexture(texture_atlas_t *atlas) {
    std::map<texture_atlas_t *, amino_atlas_t>::iterator it = atlasTextures.find(atlas);

    if (it == atlasTextures.end()) {
        //create new one
        GLuint id;

        //see https://webcache.googleusercontent.com/search?q=cache:EZ3HLutV3zwJ:https://github.com/rougier/freetype-gl/blob/master/texture-atlas.c+&cd=1&hl=de&ct=clnk&gl=ch
        glGenTextures(1, &id);
        glBindTexture(GL_TEXTURE_2D, id);

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

        //FIXME seeing vertical lines on macOS retina displays!
        //-> https://github.com/rougier/freetype-gl/issues/123
        //subpixel error on Mac retina display at edges
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

        //worse quality on macOS retina (but still a few pixels errors)
        //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

        amino_atlas_t item;

        item.textureId = id;
        item.lastGlyphUpdate = 0;

        atlasTextures[atlas] = item;

        //debug
        //printf("create new atlas texture: %i\n", id);

        return item;
    }

    return it->second;
}
<|endoftext|>


<commit_before>#ifndef MGF_DRIVER_HPP
#define MGF_DRIVER_HPP

#include <iostream>

#include <mgf/Spectrum.hpp>
#include <mgf/GlobalHeader.hpp>
#include <mgf/Analyse.hpp>

#include <mgf/Scanner.hpp>

namespace mgf
{
    class Analyse;
    class Spectrum;

    /**
     * A class that have to be use to parse a MGF input
     */
    class Driver
    {
        public:
            /**
             * \brief Construct a Driver from a stream
             * \param in input stream
             */
            Driver(std::istream& in);

            Driver(const Driver&) = delete;
            Driver& operator=(const Driver&) = delete;

            /**
             * \brief Destructor
             */
            ~Driver();

            /**
             * \brief Parse all the input (until \0)
             * \result A analyse tha contain all the datas
             */
            Analyse parse();

            /**
             * \brief PArse only the next spectrum
             * \result a pointer to the Spectrum. if nullptr is recive, all the input have been pase. You have to manualy delete the Spectrum
             */
            Spectrum* next();

            /**
             * \brief Parse a input
             * \param in The input stream to parse
             * \result The analyse tha contain all the datas
             */
            static Analyse parse(std::istream& in);

            /**
             * \brief Parse a input, and add the data parse to the analyse
             * \param in Input to parse
             * \param a Analyse where data will be saves
             * \result number of spectrum parsed
             */
            static int parse(std::istream& in,Analyse& a);

            /**
             * \brief Parse a file and return a Analyse
             * \param filename the mgf file name
             * \return A Analyse tha contain all the datas parsed
             */
            static Analyse parse_file(const std::string& filename);

            /**
             * \brief Parse a file, and store data in the analyse
             * \param filename file to parse
             * \param a Analyse where data will be saved
             * \result number of spectrum parsed
             */
            static int parse_file(const std::string& filename,Analyse& a);

            /**
             * \return The header of the MGF file.
             * Use it if you use next() to get all Spectrum.
             */
            inline const mgf::GlobalHeader& getHeader(){return header;}

            /**
             * \return true if the stream is a valid MGF format, else, false.
             */
            inline bool getValitity()const{return validity;}

        private:
            friend class Parser;

            Scanner scanner; ///< The lexer
            Parser parser; ///< The parser

            mgf::GlobalHeader header; ///< the tmp global header
            mgf::Spectrum currentSpectrum; ///< the current spectrum parsed
            bool validity;
    };
}
#endif
<commit_msg>change getter name<commit_after>#ifndef MGF_DRIVER_HPP
#define MGF_DRIVER_HPP

#include <iostream>

#include <mgf/Spectrum.hpp>
#include <mgf/GlobalHeader.hpp>
#include <mgf/Analyse.hpp>

#include <mgf/Scanner.hpp>

namespace mgf
{
    class Analyse;
    class Spectrum;

    /**
     * A class that have to be use to parse a MGF input
     */
    class Driver
    {
        public:
            /**
             * \brief Construct a Driver from a stream
             * \param in input stream
             */
            Driver(std::istream& in);

            Driver(const Driver&) = delete;
            Driver& operator=(const Driver&) = delete;

            /**
             * \brief Destructor
             */
            ~Driver();

            /**
             * \brief Parse all the input (until \0)
             * \result A analyse tha contain all the datas
             */
            Analyse parse();

            /**
             * \brief PArse only the next spectrum
             * \result a pointer to the Spectrum. if nullptr is recive, all the input have been pase. You have to manualy delete the Spectrum
             */
            Spectrum* next();

            /**
             * \brief Parse a input
             * \param in The input stream to parse
             * \result The analyse tha contain all the datas
             */
            static Analyse parse(std::istream& in);

            /**
             * \brief Parse a input, and add the data parse to the analyse
             * \param in Input to parse
             * \param a Analyse where data will be saves
             * \result number of spectrum parsed
             */
            static int parse(std::istream& in,Analyse& a);

            /**
             * \brief Parse a file and return a Analyse
             * \param filename the mgf file name
             * \return A Analyse tha contain all the datas parsed
             */
            static Analyse parse_file(const std::string& filename);

            /**
             * \brief Parse a file, and store data in the analyse
             * \param filename file to parse
             * \param a Analyse where data will be saved
             * \result number of spectrum parsed
             */
            static int parse_file(const std::string& filename,Analyse& a);

            /**
             * \return The header of the MGF file.
             * Use it if you use next() to get all Spectrum.
             */
            inline const mgf::GlobalHeader& getHeader(){return header;}

            /**
             * \return true if the stream is a valid MGF format, else, false.
             */
            inline bool isValid()const{return validity;}

        private:
            friend class Parser;

            Scanner scanner; ///< The lexer
            Parser parser; ///< The parser

            mgf::GlobalHeader header; ///< the tmp global header
            mgf::Spectrum currentSpectrum; ///< the current spectrum parsed
            bool validity;
    };
}
#endif
<|endoftext|>


<commit_before>#pragma once

enum fatigue_model {
    /*
     * Horrible inaccurate fatigue model that does not assign a fatigue-related
     * cost at all.
     */
    FATIGUE_IGNORE,

    /*
     * Uses the reactivation timer as the cost for a jump. Doesn't account for
     * fatigue and may incurr large amount of fatigue.
     */
    FATIGUE_REACTIVATION_COST,

    /*
     * Uses the fatigue timer itself (minus 10 minutes) as the cost. This is a
     * very conservative model and assumes completely waiting out fatigue.
     */
    FATIGUE_FATIGUE_COST,

    FATIGUE_REACTIVATION_COUNTDOWN,
    FATIGUE_FATIGUE_COUNTDOWN,

    FATIGUE_FULL
};

class Parameters {
public:
    Parameters(float w, float a, float g, float j, float r) {
        this->warp_speed = w;
        this->align_time = a;
        this->gate_cost = g;
        this->jump_range = j;
        this->jump_range_reduction = r;
    }

    Parameters(float w, float a, float g, float j) {
        this->warp_speed = w;
        this->align_time = a;
        this->gate_cost = g;
        this->jump_range = j;
    }

    Parameters(float w, float a, float g) {
        this->warp_speed = w;
        this->align_time = a;
        this->gate_cost = g;
    }

    Parameters(float w, float a) {
        this->warp_speed = w;
        this->align_time = a;
    }

    float jump_range = NAN, warp_speed, align_time = 0.0, gate_cost = 14.0, jump_range_reduction = 0.0;
    enum fatigue_model fatigue_model = FATIGUE_REACTIVATION_COUNTDOWN;
};

static const Parameters FRIGATE = Parameters(5.0, 3.0, 10.0);
static const Parameters DESTROYER = Parameters(4.5, 4.0, 10.0);
static const Parameters INDUSTRIAL = Parameters(4.5, 4.0, 10.0, NAN, 0.9);
static const Parameters CRUISER = Parameters(3.0, 7.0, 10.0);
static const Parameters BATTLECRUISER = Parameters(2.7, 8.0, 10.0);
static const Parameters BATTLESHIP = Parameters(2.0, 12.0, 10.0);

static const Parameters BLACK_OPS = Parameters(2.2, 10.0, 10.0, 8.0, 0.75);

static const Parameters CARRIER = Parameters(1.5, 30.0, -1.0, 7.0);
static const Parameters DREADNOUGHT = Parameters(1.5, 40.0, -1.0, 7.0);
static const Parameters SUPERCARRIER = Parameters(1.5, 40.0, -1.0, 6.0);
static const Parameters TITAN = Parameters(1.37, 60.0, -1.0, 6.0);

static const Parameters RORQUAL = Parameters(1.5, 50.0, -1.0, 10.0, 0.9);
static const Parameters JUMP_FREIGHTER = Parameters(1.5, 40.0, 10.0, 10.0, 0.9);
<commit_msg>Simplify and improve the parameter class.<commit_after>#pragma once

enum fatigue_model {
    /*
     * Horrible inaccurate fatigue model that does not assign a fatigue-related
     * cost at all.
     */
    FATIGUE_IGNORE,

    /*
     * Uses the reactivation timer as the cost for a jump. Doesn't account for
     * fatigue and may incurr large amount of fatigue.
     */
    FATIGUE_REACTIVATION_COST,

    /*
     * Uses the fatigue timer itself (minus 10 minutes) as the cost. This is a
     * very conservative model and assumes completely waiting out fatigue.
     */
    FATIGUE_FATIGUE_COST,

    FATIGUE_REACTIVATION_COUNTDOWN,
    FATIGUE_FATIGUE_COUNTDOWN,

    FATIGUE_FULL
};

class Parameters {
    #ifdef SWIG
    %feature("kwargs") Parameters;
    #endif

public:
    Parameters(float warp_speed=3.0, float align_time=5.0, float gate_cost=14.0, float jump_range=NAN, float jump_range_reduction=0.0) {
        this->warp_speed = warp_speed;
        this->align_time = align_time;
        this->gate_cost = gate_cost;
        this->jump_range = jump_range;
        this->jump_range_reduction = jump_range_reduction;
    }

    float jump_range = NAN, warp_speed, align_time, gate_cost, jump_range_reduction;
    enum fatigue_model fatigue_model = FATIGUE_REACTIVATION_COUNTDOWN;
};

static const Parameters FRIGATE = Parameters(5.0, 3.0);
static const Parameters DESTROYER = Parameters(4.5, 4.0);
static const Parameters INDUSTRIAL = Parameters(4.5, 4.0, 14.0, NAN, 0.9);
static const Parameters CRUISER = Parameters(3.0, 7.0);
static const Parameters BATTLECRUISER = Parameters(2.7, 8.0);
static const Parameters BATTLESHIP = Parameters(2.0, 12.0);

static const Parameters BLACK_OPS = Parameters(2.2, 10.0, 14.0, 8.0, 0.75);

static const Parameters CARRIER = Parameters(1.5, 30.0, NAN, 7.0);
static const Parameters DREADNOUGHT = Parameters(1.5, 40.0, NAN, 7.0);
static const Parameters SUPERCARRIER = Parameters(1.5, 40.0, NAN, 6.0);
static const Parameters TITAN = Parameters(1.37, 60.0, NAN, 6.0);

static const Parameters RORQUAL = Parameters(1.5, 50.0, NAN, 10.0, 0.9);
static const Parameters JUMP_FREIGHTER = Parameters(1.5, 40.0, 14.0, 10.0, 0.9);
<|endoftext|>


<commit_before>/* Basic type aliases and forward declarations.
 *
 * Copyright (c) 2000-2021, Jeroen T. Vermeulen
 *
 * See COPYING for copyright license.  If you did not receive a file called
 * COPYING with this source code, please notify the distributor of this
 * mistake, or contact the author.
 */
#ifndef PQXX_H_TYPES
#define PQXX_H_TYPES

#include <cstddef>
#include <cstdint>
#include <iterator>

#if defined(PQXX_HAVE_CONCEPTS) && __has_include(<ranges>)
#  include <ranges>
#endif

namespace pqxx
{
/// Number of rows in a result set.
using result_size_type = int;

/// Difference between result sizes.
using result_difference_type = int;

/// Number of fields in a row of database data.
using row_size_type = int;

/// Difference between row sizes.
using row_difference_type = int;

/// Number of bytes in a field of database data.
using field_size_type = std::size_t;

/// Number of bytes in a large object.
using large_object_size_type = int64_t;

// Forward declarations, to help break compilation dependencies.
// These won't necessarily include all classes in libpqxx.
class binarystring;
class connection;
class const_result_iterator;
class const_reverse_result_iterator;
class const_reverse_row_iterator;
class const_row_iterator;
class dbtransaction;
class field;
class largeobjectaccess;
class notification_receiver;
struct range_error;
class result;
class row;
class stream_from;
class transaction_base;

/// Marker for @c stream_from constructors: "stream from table."
/** @deprecated Use stream_from::table() instead.
 */
struct from_table_t
{};

/// Marker for @c stream_from constructors: "stream from query."
/** @deprecated Use stream_from::query() instead.
 */
struct from_query_t
{};

/// Format code: is data text or binary?
/** Binary-compatible with libpq's format codes.
 */
enum class format : int
{
  text = 0,
  binary = 1,
};

/// Remove any constness, volatile, and reference-ness from a type.
/** @deprecated In C++20 we'll replace this with std::remove_cvref.
 */
template<typename TYPE>
using strip_t = std::remove_cv_t<std::remove_reference_t<TYPE>>;

#if defined(PQXX_HAVE_CONCEPTS)
/// The type of a container's elements.
/** At the time of writing there's a similar thing in @c std::experimental,
 * which we may or may not end up using for this.
 */
template<std::ranges::range CONTAINER>
using value_type = decltype(*std::begin(std::declval<CONTAINER>()));
#else  // PQXX_HAVE_CONCEPTS
/// The type of a container's elements.
/** At the time of writing there's a similar thing in @c std::experimental,
 * which we may or may not end up using for this.
 */
template<typename CONTAINER>
using value_type = decltype(*std::begin(std::declval<CONTAINER>()));
#endif // PQXX_HAVE_CONCEPTS

#if defined(PQXX_HAVE_CONCEPTS)
/// Concept: Any type that we can read as a string of @c char.
template<typename STRING>
concept char_string = std::ranges::contiguous_range<STRING>
  and std::same_as<strip_t<value_type<STRING>>, char>;

/// Concept: Anything we can iterate to get things we can read as strings.
template<typename RANGE>
concept char_strings =
  std::ranges::range<RANGE> and char_string<strip_t<value_type<RANGE>>>;

/// Concept: Anything we might want to treat as binary data.
template<typename DATA>
concept potential_binary = std::ranges::contiguous_range<DATA> and
                           (sizeof(value_type<DATA>) == 1);
#endif // PQXX_HAVE_CONCEPTS

// TODO: Retire these compatibility definitions once we're on C++20.
#if defined(PQXX_HAVE_CONCEPTS)

/// Template argument type for a range.
/** This is a concept, so only available in C++20 or better.  In pre-C++20
 * environments it's just an alias for @c typename.
 */
#define PQXX_RANGE_ARG std::ranges::range

/// Template argument type for @c char_string.
/** This is a concept, so only available in C++20 or better.  In pre-C++20
 * environments it's just an alias for @c typename.
 */
#  define PQXX_CHAR_STRING_ARG pqxx::char_string

/// Template argument type for @c char_strings
/** This is a concept, so only available in C++20 or better.  In pre-C++20
 * environments it's just an alias for @c typename.
 */
#  define PQXX_CHAR_STRINGS_ARG pqxx::char_strings

#else // PQXX_HAVE_CONCEPTS

/// Template argument type for a range.
/** This is a concept, so only available in C++20 or better.  In pre-C++20
 * environments it's just an alias for @c typename.
 */
#define PQXX_RANGE_ARG typename

/// Template argument type for @c char_string.
/** This is a concept, so only available in C++20 or better.  In pre-C++20
 * environments it's just an alias for @c typename.
 */
#  define PQXX_CHAR_STRING_ARG typename

/// Template argument type for @c char_strings
/** This is a concept, so only available in C++20 or better.  In pre-C++20
 * environments it's just an alias for @c typename.
 */
#  define PQXX_CHAR_STRINGS_ARG typename

#endif // PQXX_HAVE_CONCEPTS

} // namespace pqxx
#endif
<commit_msg>Reformat.<commit_after>/* Basic type aliases and forward declarations.
 *
 * Copyright (c) 2000-2021, Jeroen T. Vermeulen
 *
 * See COPYING for copyright license.  If you did not receive a file called
 * COPYING with this source code, please notify the distributor of this
 * mistake, or contact the author.
 */
#ifndef PQXX_H_TYPES
#define PQXX_H_TYPES

#include <cstddef>
#include <cstdint>
#include <iterator>

#if defined(PQXX_HAVE_CONCEPTS) && __has_include(<ranges>)
#  include <ranges>
#endif

namespace pqxx
{
/// Number of rows in a result set.
using result_size_type = int;

/// Difference between result sizes.
using result_difference_type = int;

/// Number of fields in a row of database data.
using row_size_type = int;

/// Difference between row sizes.
using row_difference_type = int;

/// Number of bytes in a field of database data.
using field_size_type = std::size_t;

/// Number of bytes in a large object.
using large_object_size_type = int64_t;

// Forward declarations, to help break compilation dependencies.
// These won't necessarily include all classes in libpqxx.
class binarystring;
class connection;
class const_result_iterator;
class const_reverse_result_iterator;
class const_reverse_row_iterator;
class const_row_iterator;
class dbtransaction;
class field;
class largeobjectaccess;
class notification_receiver;
struct range_error;
class result;
class row;
class stream_from;
class transaction_base;

/// Marker for @c stream_from constructors: "stream from table."
/** @deprecated Use stream_from::table() instead.
 */
struct from_table_t
{};

/// Marker for @c stream_from constructors: "stream from query."
/** @deprecated Use stream_from::query() instead.
 */
struct from_query_t
{};

/// Format code: is data text or binary?
/** Binary-compatible with libpq's format codes.
 */
enum class format : int
{
  text = 0,
  binary = 1,
};

/// Remove any constness, volatile, and reference-ness from a type.
/** @deprecated In C++20 we'll replace this with std::remove_cvref.
 */
template<typename TYPE>
using strip_t = std::remove_cv_t<std::remove_reference_t<TYPE>>;

#if defined(PQXX_HAVE_CONCEPTS)
/// The type of a container's elements.
/** At the time of writing there's a similar thing in @c std::experimental,
 * which we may or may not end up using for this.
 */
template<std::ranges::range CONTAINER>
using value_type = decltype(*std::begin(std::declval<CONTAINER>()));
#else  // PQXX_HAVE_CONCEPTS
/// The type of a container's elements.
/** At the time of writing there's a similar thing in @c std::experimental,
 * which we may or may not end up using for this.
 */
template<typename CONTAINER>
using value_type = decltype(*std::begin(std::declval<CONTAINER>()));
#endif // PQXX_HAVE_CONCEPTS

#if defined(PQXX_HAVE_CONCEPTS)
/// Concept: Any type that we can read as a string of @c char.
template<typename STRING>
concept char_string = std::ranges::contiguous_range<STRING>
  and std::same_as<strip_t<value_type<STRING>>, char>;

/// Concept: Anything we can iterate to get things we can read as strings.
template<typename RANGE>
concept char_strings =
  std::ranges::range<RANGE> and char_string<strip_t<value_type<RANGE>>>;

/// Concept: Anything we might want to treat as binary data.
template<typename DATA>
concept potential_binary = std::ranges::contiguous_range<DATA> and
                           (sizeof(value_type<DATA>) == 1);
#endif // PQXX_HAVE_CONCEPTS

// TODO: Retire these compatibility definitions once we're on C++20.
#if defined(PQXX_HAVE_CONCEPTS)

/// Template argument type for a range.
/** This is a concept, so only available in C++20 or better.  In pre-C++20
 * environments it's just an alias for @c typename.
 */
#  define PQXX_RANGE_ARG std::ranges::range

/// Template argument type for @c char_string.
/** This is a concept, so only available in C++20 or better.  In pre-C++20
 * environments it's just an alias for @c typename.
 */
#  define PQXX_CHAR_STRING_ARG pqxx::char_string

/// Template argument type for @c char_strings
/** This is a concept, so only available in C++20 or better.  In pre-C++20
 * environments it's just an alias for @c typename.
 */
#  define PQXX_CHAR_STRINGS_ARG pqxx::char_strings

#else // PQXX_HAVE_CONCEPTS

/// Template argument type for a range.
/** This is a concept, so only available in C++20 or better.  In pre-C++20
 * environments it's just an alias for @c typename.
 */
#  define PQXX_RANGE_ARG typename

/// Template argument type for @c char_string.
/** This is a concept, so only available in C++20 or better.  In pre-C++20
 * environments it's just an alias for @c typename.
 */
#  define PQXX_CHAR_STRING_ARG typename

/// Template argument type for @c char_strings
/** This is a concept, so only available in C++20 or better.  In pre-C++20
 * environments it's just an alias for @c typename.
 */
#  define PQXX_CHAR_STRINGS_ARG typename

#endif // PQXX_HAVE_CONCEPTS

} // namespace pqxx
#endif
<|endoftext|>